Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@revisium/revo-scripts

Bounded, versioned Git and GitHub operations behind one generic host API.

CI Quality Gate Status Coverage License: MIT

Important

Pre-release package. It is not published to npm; the API and built-in operations remain under review.

About

@revisium/revo-scripts defines and executes one bounded operation. It owns versioned script definitions, schema validation, provider adapters, permissions and operations, timeout and retry policy, idempotency, event redaction, and structured results. The current built-ins cover system echo, Git, GitHub pull requests, review threads, merge, and approval subject operations.

The consumer owns pipeline routing, durable state, workspace lifecycle, credential storage, grants, event/artifact persistence, and human gates. It creates one facade and never implements a script-specific dispatch branch.

Built-in families are included in the package build. Each operation has an exact id, version, manifest, schemas, provider requirements, and bounded result. The package does not scan the filesystem to find additional definitions.

Quick start

Create the facade once. The package registers built-in definitions and package-owned Git/GitHub providers; the consumer supplies only its host ports.

import { createRevoScripts } from '@revisium/revo-scripts';

const scripts = createRevoScripts({
  host: {
    resources: resourceResolver,
    workspaces: workspaceResolver,
    credentials: credentialResolver,
    clock,
  },
});

const binding = await scripts.prepareBinding(
  {
    script: {
      id: 'script:git/status',
      version: 1,
    },
    resources: {
      repository: { resourceRef: 'resource:repository-123', workspaceRef: 'workspace:456' },
    },
    credentials: {},
  },
  { signal },
);

const result = await scripts.executeAttempt(
  {
    executionId: 'run-123:git-status',
    attemptId: 'run-123:git-status:1',
    attemptOrdinal: 1,
    script: binding.script,
    binding,
    input: {
      resource: 'repository',
      baseCapture: `git-commit:${'0'.repeat(40)}`,
      headCapture: `git-tree:${'1'.repeat(40)}`,
    },
  },
  { signal, events: attemptEventSink },
);

if (result.kind === 'succeeded') {
  consumeStatus(result.value);
} else if (result.kind === 'failed' || result.kind === 'timedOut') {
  reportFailure(result.error.code, result.error.message);
} else if (result.kind === 'uncertain') {
  persistUncertainAttempt(result);
}

if (result.kind !== 'uncertain') {
  // Persist the proven outcome and this event in one durable transaction.
  persistTerminalAttempt({ result, terminalEvent: result.terminalEvent });
}

ScriptBindingInput, PreparedScriptBinding, and ScriptAttemptInput are defined in the runtime specification. The consumer passes data and grants; it does not construct a Git client, choose a provider implementation, or branch on script:git/status.

For mutation operations, the input includes the relevant stale-state fence. The central pipeline may decide what to do after the returned result, but the script performs only its one bounded operation.

An uncertain result is deliberately not terminal. It means the package could not prove that the physical attempt stopped within the fixed grace period, so the host preserves the exact identity and later calls reconcileAttempt instead of starting a duplicate. cancelAttempt and reconcileAttempt return a terminal outcome only when it is known; otherwise they return the current uncertain observation or conservative unknown.

attemptEventSink receives live revo.script.started and declared custom events only. A terminal result instead carries its final terminalEvent; the consumer must persist and publish that result/event pair atomically. A late reconcileAttempt terminal result carries the same sealed event and never publishes it through the old live sink.

Data-driven scripts

  • Scripts use positive integer revisions. Each exact (id, revision) is immutable.
  • A definition contains a manifest, input/result schemas, permissions/operations, and provider requirements.
  • The pipeline selects an exact script id/version and passes input, bindings, and grants.
  • The consumer uses one generic executor for every script; it has no per-script executor or dispatch branch.
  • Provider contracts, adapters, validation, retries, redaction, and execution belong to this npm package.
  • A new script on an existing provider family requires a package change, package release, and new exact script reference, but not a generic consumer executor change.
  • A new provider contract, transport, or privileged behavior requires package implementation and a new release.
  • The installed built-in inventory is explicit and does not depend on filesystem scanning.

Built-in public Input/Result aliases are deeply readonly projections of the same runtime schemas used for validation; they are not separately maintained shape copies. defineScript accepts an authoring manifest that may omit empty redaction and events policies, then exposes a complete canonical ScriptManifestV1 with those empty collections present. Handlers receive one executionId: it is the stable operation and idempotency identity. The durable host creates an attemptId for each physical attempt and decides whether a retry is appropriate.

Built-ins and discovery

The complete installed built-in set is:

  • script:approval/subject@1
  • script:git/commit@1
  • script:git/push@1
  • script:git/status@1
  • script:github/pull-request/mark-ready@1
  • script:github/pull-request/merge@1
  • script:github/pull-request/readiness@1
  • script:github/pull-request/upsert@1
  • script:github/review-threads/resolve@1
  • script:github/review-threads/respond@1
  • script:system/echo@1

builtInScriptCatalog() returns that complete set ordered by script id and then integer version. Every call returns a new frozen array of frozen descriptor snapshots; its script identity and implementation provenance objects are also frozen. Each descriptor contains the exact script id/version plus the implementation id, implementation SemVer, and a sha256: build digest generated from the compiled JavaScript dependency closure of that built-in definition. The family modules and catalog derive from one explicit package-owned inventory; discovery never scans the filesystem or imports additional modules for side operations.

Use systemScripts() to register the system family explicitly. The @revisium/revo-scripts/system entrypoint exports systemEchoScript and its EchoInput, EchoResult, and EchoResources types.

Facade and built-in discovery API

export declare function createRevoScripts(options: RevoScriptsOptions): RevoScripts;
export declare function builtInScriptCatalog(): readonly BuiltInScriptDescriptor[];
export declare function systemScripts(): ScriptDefinitionModule;

export interface BuiltInScriptDescriptor {
  readonly script: ScriptIdentityPin;
  readonly implementation: Readonly<{
    id: string;
    version: string;
    buildDigest: `sha256:${string}`;
  }>;
}

export interface RevoScripts {
  prepareBinding(
    input: ScriptBindingInput,
    context: AttemptContext,
  ): Promise<PreparedScriptBinding>;
  executeAttempt(
    input: ScriptAttemptInput,
    context: ScriptAttemptExecutionContext,
  ): Promise<ScriptAttemptResult>;
  cancelAttempt(
    input: ScriptAttemptRef,
    context: AttemptContext,
  ): Promise<AttemptCancellationResult>;
  reconcileAttempt(
    input: ScriptAttemptInput,
    context: AttemptContext,
  ): Promise<ScriptReconciliationResult>;
  listManifests(): readonly ScriptManifestV1[];
  listProviderImplementations(): readonly ScriptProviderDescriptor[];
}

RevoScriptsOptions, attempt contracts, manifests, and provider descriptors are public typed contracts. Their exact fields and invariants live in the runtime specification and the corresponding source contracts. The root entrypoint also curates the low-level definition, registry, and execution contracts; package.json is authoritative for every public subpath.

Package and consumer boundary

pipeline exact id/version + input + grants
                    |
                    v
createRevoScripts().prepareBinding(input)
  -> exact definition/provider and host metadata validation
  -> portable prepared binding snapshot
createRevoScripts().executeAttempt(input)
  -> JIT host handle acquisition
  -> bounded provider client
  -> one handler operation
  -> typed result or structured failure
createRevoScripts().cancelAttempt(ref) / reconcileAttempt(input)
  -> known terminal result, current uncertainty, or conservative unknown

The package does not own pipeline cursors, retry scheduling across pipeline nodes, human gates, workspace allocation, credential policy, DBOS, Prisma, NestJS, or artifact persistence. Handlers receive only bounded typed provider clients and never receive raw paths, tokens, process executors, generic HTTP clients, or mutable global logging.

Script revisions are not SemVer. The consumer supplies one positive exact integer; the package performs no range, latest, tag, or SemVer lookup. Any observable definition change requires a larger revision while the npm package and implementation provenance continue to use separately named SemVer versions.

Documentation

Development

Requirements: Node.js >=24.11.1 <25, Corepack, and pnpm 11.13.0.

corepack pnpm install
corepack pnpm verify

Useful commands:

pnpm build
pnpm test
pnpm test:cov
pnpm ci:local:sonar

The package is ESM/NodeNext with strict TypeScript, declarations, explicit exports, packed-consumer validation, and SonarCloud analysis. Releases use the shared release train and tag-triggered npm publish workflows. Do not publish from a local machine; every write-mode release transition requires separate approval.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages