Skip to content

feat: migrate workflows to TypeScript orchestration - #30

Draft
devagrawal09 wants to merge 3 commits into
masterfrom
fable/typescript-orchestration-migration
Draft

devagrawal09 wants to merge 3 commits into
masterfrom
fable/typescript-orchestration-migration

Conversation

@devagrawal09

Copy link
Copy Markdown
Collaborator

Summary

Migrates Solid Migration Assistant from the YAML/Butterflow workflows (workflow.yaml, transform.yaml, codemod.yaml, 41 per-rule scripts/ entrypoints, emit-report.ts, and codemod:workflow shared state) to two inline TypeScript orchestration workflows on @codemod.com/orchestration.

  • workflows/analyze.ts: each of the 37 named analyzers is its own inline jssg() definition, awaited as its own sequential workspace-semantic command, in the order the YAML workflow ran its steps.
  • workflows/transform.ts: the three deterministic rewrites stay three separate sequential commands, so later rules see earlier output.
  • shared/entrypoint.ts is now a per-file adapter (analyzeFile / transformFile) returning structured { content, output } results instead of accumulating into workflow state under a lock. It is bundled into every transform artifact and imports nothing from the runtime.
  • shared/workflow.ts holds the shared include/exclude globs, the FileStrings output guard, and aggregateReport, which flattens, exact-deduplicates, and sorts each command's per-file strings exactly as the removed report emitter did.
  • shared/run-workflow.mjs no longer spawns the Codemod CLI. launch() re-runs the module as a Node 24 workflow process (--experimental-transform-types plus shared/register-ts.mjs, a module hook that strips types for .ts under node_modules), loads the workflow through the orchestration build step, and runs it with one BridgeExecutor per command. SIGINT/SIGTERM are forwarded and cancel the command in flight.

Behavior changes

  • CLI gains a transform subcommand: solid-migration-assistant [analyze|transform] [--target <dir>]. analyze remains the default.
  • Guidance and transform report lines are printed to stdout by the launcher; only the final disclosure (analyze only) goes to stderr. There are no runtime progress lines anymore.
  • Usage/target errors exit 2; a failed or cancelled command exits 1. The launcher fails before starting anything when no bridge binary exists.
  • Exact guidance output, deterministic ordering, cross-file references() resolution, analyzer immutability, and transform idempotency are unchanged and covered by the same fixtures.
  • Node engine bumped to >=24.0.0 (needed for registerHooks/stripTypeScriptTypes and type transformation).
  • pnpm validate (YAML schema validation) is gone; check-types now typechecks both the sandbox-side program (tsconfig.json) and the workflow-side program (tsconfig.workflows.json).
  • The opt-in benchmark generates temporary inline workflow modules instead of YAML and times in-process workflow runs.

Validation

pnpm verify passes from codemods/solid-migration-assistant (Node v24.18.0, pnpm 11.20.0):

Suite Result
architecture 7/7 pass
cli + packaging 13/13 pass
rules (per-rule jssg run) 28 adapters, 48 fixture cases, 0 targets changed
transform-rules 3 adapters, 29 fixture cases, 0 targets changed
workflow (exact output, cross-file semantics, missing bridge, failed command, SIGINT cancellation, artifact bundling, scripted command sequencing) 12/12 pass
transform (exact tree, idempotency, cwd default, usage failure) 3/3 pass
tsc --noEmit for both programs clean
git diff --check clean

The packaging test packs the tarball, extracts it by hand into a consumer's node_modules, links the orchestration prototype in, and runs the analyzer twice from that layout with pnpm off PATH.

Publication blocker

This version is not publishable, and this PR does not claim npm publish readiness.

  • @codemod.com/orchestration is private: true and unpublished. The committed dependency is a relative link to a sibling checkout: "@codemod.com/orchestration": "link:../../../codemod/packages/orchestration" (the codemod monorepo on its prototype/typescript-orchestration branch, at 97a3695).
  • The Rust execution bridge (butterflow-execution-bridge) is not distributed; the launcher resolves it from that checkout's target/debug/ or from CODEMOD_BRIDGE_BIN.
  • A registry install cannot resolve the link: dependency, so npm install of the packed tarball fails. Both READMEs document this and the local setup steps.

Not in scope

  • No changes to rule logic, guidance text, fixtures, or the per-rule jssg run tests.
  • Nothing in the sibling codemod checkout is modified by this PR.

🤖 Generated with Claude Code

devagrawal09 and others added 3 commits September 12, 2026 11:38
Replace the YAML/Butterflow workflows (workflow.yaml, transform.yaml,
codemod.yaml, the 41 per-rule scripts/ entrypoints, emit-report.ts, and
the codemod:workflow shared-state accumulation) with two inline
TypeScript workflows on @codemod.com/orchestration.

- workflows/analyze.ts defines each of the 37 named analyzers as its own
  inline jssg() transform and awaits them as 37 sequential
  workspace-semantic commands, in the former step order.
- workflows/transform.ts keeps the three deterministic rewrites as three
  sequential commands so later rules see earlier output.
- shared/entrypoint.ts becomes a per-file adapter (analyzeFile,
  transformFile) returning structured { content, output } results; it
  is bundled into every artifact and imports nothing from the runtime.
- shared/workflow.ts holds the shared applicability globs, the
  FileStrings output guard, and aggregateReport (flatten, exact-dedupe,
  whole-string sort), matching the removed report emitter.
- shared/run-workflow.mjs no longer spawns the Codemod CLI: launch()
  re-runs the module as a Node 24 workflow process with
  --experimental-transform-types and shared/register-ts.mjs (a module
  hook that strips types for .ts under node_modules), loads the workflow
  through the orchestration build step, runs one BridgeExecutor per
  command, forwards SIGINT/SIGTERM to cancel the command in flight, and
  prints the returned guidance or report to stdout.
- The CLI gains a `transform` subcommand; `analyze` stays the default.
  Usage/target errors exit 2, failed or cancelled commands exit 1, and
  the launcher refuses to start without a bridge binary
  (CODEMOD_BRIDGE_BIN or the linked checkout's target/debug build).
- package.json drops the pinned codemod CLI, links
  @codemod.com/orchestration from the sibling checkout, requires Node
  >=24, removes the YAML validate script, and typechecks both the
  sandbox-side (tsconfig.json) and workflow-side
  (tsconfig.workflows.json) programs.
- Tests cover the inline composition, launcher behavior, exact guidance,
  cross-file semantic resolution, missing-bridge and failed-command
  reporting, SIGINT cancellation, artifact bundling, scripted command
  sequencing, transform idempotency, and the packed file list. The
  benchmark generates inline workflow modules instead of YAML.

Publication blocker: @codemod.com/orchestration is private and
unpublished, the dependency is a relative link to the sibling codemod
checkout, and the execution bridge is not distributed. This version is
not publishable; both READMEs document the setup and the blocker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The 37 analyzers only read the target and share nothing, so
`workflows/analyze.ts` now declares all of them as one `parallel()` group
instead of awaiting them one at a time. The group states only that the
commands are eligible to overlap: the engine's weighted admission
scheduler owns how many actually run, and this package declares no
chunking, no concurrency level, no scheduler of its own, and no
author-facing knob.

Nothing observable changes. Commands are still issued in declaration
order, `parallel()` returns one output per member in that order however
the commands interleave, and `aggregateReport` still flattens,
exact-deduplicates, and sorts as whole strings, so stdout stays
byte-identical. The analyzers stay 37 separate JSSG commands, each a
complete workspace-semantic pass over the whole selected file set, and
the three mutating rewrites in `workflows/transform.ts` stay sequential
because their order is a correctness property of the files they write.

Because members overlap, a failure or cancellation now names whichever
command reported first rather than a fixed one, and a cancelled member
is either an admitted command whose bridge is killed or a queued one
refused without spawning anything. The launcher tests pin everything
around that name and accept either cancellation reason.

Tests cover the group's declaration in the analyze body, all 37 outputs
aggregating correctly under deterministic reverse-order completion, the
scheduler's own peak accounting at a fixed capacity, and a real
launcher run whose stand-in bridges must see a peer to finish and
record the most they ever saw alive, which bounds real bridge
concurrency without timing assertions. The benchmark now generates
parallel groups so it keeps mirroring production, and reports the host
capacity its numbers depend on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant