Skip to content

v0.9.4#15

Merged
dzikowski merged 21 commits into
mainfrom
nightly
May 13, 2026
Merged

v0.9.4#15
dzikowski merged 21 commits into
mainfrom
nightly

Conversation

@dzikowski
Copy link
Copy Markdown
Contributor

No description provided.

dzikowski and others added 5 commits May 5, 2026 11:45
…idation

- Execute interpolated shell steps via sh -c with script CWD semantics
- validateReferences: send-arrow errors, managed run for bare names, dotted refs
- Update compiler and acceptance tests; refresh validate error fixtures
- Queue: add performance tasks for slow install and workflow cold start

Made-with: Cursor
…nterpolation sugar

Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
artifacts library now exports one `save(paths)` workflow that accepts either
a single file path or a newline-separated list. Destination relpath is
derived from the source (leading `./` stripped; absolute sources use
basename only). Replaces the prior two-arg `save(local_path, name)`.

Engineer workflow switches from `git.patch` to `git.commit` (returns a
patch file produced via `git format-patch -1`) and publishes the result
through the new `artifacts.save`. Adds a small `.jaiph/sandbox.jh` sample
demonstrating the single-arg form.

Docs (libraries, sandboxing), CHANGELOG, and the artifacts e2e test are
aligned with the new signature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dzikowski and others added 16 commits May 5, 2026 16:53
… bash-era code

Dead code removal (no user-visible change):
- Delete kernel CLI shims (run-step-exec, seq-alloc, fs-lock, emit modes,
  stream-parser/schema CLI tails, prompt tail-watchdog) — all leftovers from
  the removed bash backend.
- Remove legacy migration shims: `local NAME` rejection, `script:lang`
  syntax rejection, `runtime.docker_*` rename map.

Parser dedupe:
- Move rejectTrailingContent to core; collapse import parsers; consolidate
  the 5x namespace-collision loop in parser.ts; replace the 90-line
  assignConfigKey switch with a key-table; tighten top-level dispatch to
  strict prefix regex (no more substring matches on `script `/`rule `).

Runtime bug fixes:
- executeScript/executeShLine/executeMockShellBody now return returnValue
  only on status === 0 (was leaking failed-script stdout as return values).
- Async run+catch now propagates recoverReturn through the implicit-join
  site, matching sync ensure semantics (was silently dropped).
- Reject `return 0` / `return $?` / `return INTEGER` in workflows/rules
  with a clear error instead of silently degrading to a useless shell line.
- Replace executeMockShellBody tempfile dance with `bash -c`; delete the
  unused resolveArgsRawSync fast path.
- Restore Claude config cpSync seed so workspace fallback preserves auth
  when only session-env is unwritable.

Repo housekeeping:
- Move .jaiph/git.jh to .jaiph/libs/jaiphlang/git.jh and update import
  paths to use `import "jaiphlang/git" as git` (matches existing
  jaiphlang/queue and jaiphlang/artifacts convention).

AUDIT_PROGRESS.md tracks what's applied vs deferred for follow-up PRs.

All 76/76 e2e scripts pass. Unit tests 1213/1215 (one TTY flake; one
pre-existing failure caused by stale .jaiph/runs/.sandbox-* dirs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three structural dedupes, no user-visible change.

B1 (~440 LOC) — workflows.ts step loop merged into parseBraceBlockBody.
  parseBraceBlockBody gains preserveBlankLines and onConfigBlock opts so
  workflow-specific concerns become callbacks instead of a duplicate grammar.
  workflow-brace.ts also gains run-async + recover/catch handling (was only
  in workflows.ts). workflows.ts shrinks from 730 to 186 lines and now just
  parses the workflow header then delegates body parsing.

B10 (~50 LOC) — extract runRecoverBody helper. The 5 sites that did
  "build vars-with-failure / run recover steps" each now call one helper.
  Per-site propagation logic stays where it is, since sync ensure / sync run /
  async branches have subtly different propagation semantics.

B11 (~110 LOC) — extract runPromptStep. The two prompt-step paths (plain
  prompt and `const x = prompt`) now share one implementation. Fixes a real
  bug noted in the audit: the const-prompt path was missing the per-field
  schema-export (`captureName_field` for `${result_role}` interpolation),
  while the plain-prompt path had it. Both paths now expand fields uniformly.

All 1214/1215 unit tests pass (only the pre-existing baseline). 76/76 e2e.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… D2)

Parser dedupe + grammar simplification:
- B5: drop the inline `config { k = v }` form. config now requires the
  multiline `config {\n  k = v\n}` form (the canonical, documented one).
  Saves ~60 LOC and removes asymmetric "no array support inline" behavior.
  Updated examples/async.jh and .jaiph/async.jh to multiline form.
- B6: extract parseSingleBacktickBody helper used by both inline-script.ts
  (anonymous `run \`body\`(args)`) and scripts.ts (named `script foo = \`body\``).
- B7: parseFencedBlock now returns `afterClose: string` (text after the
  closing ```), letting callers parse their own trailing content
  (`(args)` for inline scripts, blank for named scripts). Removed the
  bespoke `returns "…"` branch — no caller used it.
- B8: extract consumeTripleQuotedArg for the 4-line "splice arg back, parse
  triple-quote, reject trailing content" dance. Used by fail/log/logerr/return.

D1 + D2 — drop two undocumented language features:
- D1: drop inline single-line `workflow foo() { run a; run b }` form.
  The grammar already implies one-statement-per-line; no docs/e2e exercised it.
- D2: drop semicolon-as-statement-separator inside Jaiph workflow/rule
  bodies. `splitStatementsOnSemicolons` is kept for `match.ts` arms (the
  legitimate consumer). Workflow/rule bodies now require one statement per
  line, matching grammar.md:47.

C6 + C15 — replace bash-protocol mock plumbing with in-process JS:
- C15: writeMockDispatchScript no longer emits a bash dispatcher; mock arms
  are passed structurally as JSON via JAIPH_MOCK_PROMPT_ARMS_JSON. New
  dispatchMockArms in mock.ts pattern-matches in JS. Eliminates bash quoting
  hazards.
- C6: sequential mock responses now flow through JAIPH_MOCK_RESPONSES_JSON
  + an in-memory queue (consumeNextMockResponse), removing the Θ(n²)
  read-modify-write of the mock-responses file.

C9: inbox files are now written only when a route consumes the channel.
  Audit-only files for unrouted sends are gone (they were dead data).

Formatter:
- Drop emitCompactInlineWorkflowConfig — it was emitting the inline
  `config { agent.backend = "…" }` form that the parser no longer accepts,
  producing un-parseable output. The formatter now always emits the
  multiline canonical form.

C7 (rename AST recover ↔ recoverLoop) was attempted via mass sed but the
substitution was over-aggressive (caught source-keyword strings, regex
patterns, error messages, and test fixtures). Reverted; deferred for a
careful hand-edit.

C11/C12/C13 explicitly skipped (small wins, not worth the churn or break
real usage).

All 1214/1215 unit tests pass (only the pre-existing baseline failure).
76/76 e2e pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… C2)

C2: parser.ts now produces a clear `E_PARSE` error when a `test` block
appears in a non-`*.test.jh` file ("test blocks belong in *.test.jh files;
rename the file or remove the test block"). Previously the file-suffix check
silently routed the line to the default "unsupported top-level statement"
branch, hiding the real intent.

A10: strip stale bash-era references from docs:
- architecture.md no longer claims `run-step-exec.ts` and `seq-alloc.ts`
  exist (both were deleted in the audit-pass-1 cleanup); the runtime now
  spawns script subprocesses directly.
- inbox.md drops the `JAIPH_DISPATCH_CHANNEL` / `JAIPH_DISPATCH_SENDER`
  env-var note (those were never set by NodeWorkflowRuntime) and corrects
  the inbox-file claim to match the C9 change ("written only when a route
  consumes the channel").

C10 explicitly skipped — the dual-write in `executeManagedStep` is
structurally redundant but functionally correct. Eliminating cleanly would
require propagating the `io` streaming hook through mock-body / mock-script
paths; not worth the surgery given current behaviour is right.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rds (C7)

Source-level keywords are unchanged: workflows still use `run foo() recover(e) { … }`
for retry-loop semantics and `run foo() catch(e) { … }` for single-shot recovery.
Only the AST field names and code references were renamed:

  AST field: `step.recover`     → `step.catch`     (catch-semantic, single-shot)
  AST field: `step.recoverLoop` → `step.recover`   (loop-semantic, repair-and-retry)

Now the AST self-documents which keyword produced each branch. Previously
readers had to mentally translate "recover field actually means catch" — a
permanent source of cognitive friction in validate.ts, runtime, formatter,
progress, and tests.

The rename touched 13 files. The earlier mass-sed attempt was over-aggressive
(caught source-keyword strings, regex patterns, error messages, test
fixtures). This pass uses whole-word + AST-shape patterns:

  - `\brecoverLoop\b`  → `recover` (whole-word; no false positives)
  - `\brecover:`       → `catch:`  (object-literal key only)
  - `\brecover\?:`     → `catch?:` (TS optional field)
  - `\.recover\b`      → `.catch`  (member access)

Because TypeScript reserves `catch` as a keyword in parameter positions,
helper params that hold the catch-semantic AST node use `catchDef` instead
of `catch`. The AST field name is still `catch`.

All 1214/1215 unit tests pass (only the pre-existing baseline failure).
76/76 e2e pass — source `recover` and `catch` keywords still parse correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds four tasks for the remaining audit items:
- Drop `JAIPH_INBOX_PARALLEL` parallel inbox dispatch (D9) — #dev-ready
- Remove `JAIPH_TEST_MODE` event suppression in production code (C8) — #dev-ready
- Plus the existing test consolidation and runtime split tasks already in queue

Updated the runtime-split task with current LoC (1915, was 1901) and removed
the stale `run-step-exec.ts` "do not touch" reference (that file was deleted in
the audit cleanup). Noted the two helpers I added during the audit
(runRecoverBody, runPromptStep) belong with the orchestrator.

Test consolidation task: corrected stale numbers — 60 (not 66) unit tests in
src/, sample-build.test.ts is 2814 LoC (not 2427), test/ totals ~3347 LoC
(not 2960), tests/e2e-samples/ has two files (landing-page.spec.ts plus the
shared docs-site.ts constants module).

Ordering rationale: language/feature cleanup before the runtime split (so the
split inherits simpler code), C8 explicitly after the runtime split (the new
runtime-event-emitter.ts is the natural home for the constructor-option
replacement), perf tasks last (exploratory).

D3 (drop `mock prompt { arms }`), D4 (drop multi-line `returns`), D5+D6 (drop
`prompt myVar` bare-ident body) intentionally NOT in the queue — keeping
those forms.

AUDIT_PROGRESS.md deleted; its remaining open items have all been folded into
the queue or explicitly skipped during the audit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Added platform-specific entries for ffi: `1.17.3-arm64-darwin` and `1.17.3-x86_64-linux-gnu`. Updated the PLATFORMS section to include `arm64-darwin-25` alongside existing platforms.

Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
Reorganize the test layout from five scattered directories into three
well-defined locations (src/-adjacent unit tests, integration/, e2e/)
plus two support directories (test-fixtures/, test-infra/).

File-move map:
  src/compiler-test-runner.ts        → test-infra/compiler-test-runner.ts
  src/golden-ast-runner.ts           → test-infra/golden-ast-runner.ts
  compiler-tests/                    → test-fixtures/compiler-txtar/
  golden-ast/                        → test-fixtures/golden-ast/
  test/expected/, test/fixtures/     → test-fixtures/sample-build/
  test/run-summary-jsonl.test.ts     → integration/run-summary-jsonl.test.ts
  test/signal-lifecycle.test.ts      → integration/signal-lifecycle.test.ts
  test/tty-running-timer.test.ts     → integration/tty-running-timer.test.ts
  test/sample-build.test.ts (2814L) → integration/sample-build/*.test.ts (7 files, split by subsystem)
  tests/e2e-samples/                 → e2e/playwright/

Updates package.json test scripts, tsconfig.json, playwright.config.ts,
docs/contributing.md, and docs/testing.md to reference new paths.
Deletes the now-empty test/, tests/, compiler-tests/, and golden-ast/
directories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
git format-patch without --stdout only prints the generated filename to
stdout and writes the patch elsewhere. Use HEAD as the revision and
--stdout so the workflow target file contains the full mailbox patch.

Co-authored-by: Cursor <cursoragent@cursor.com>
Selecting the first non-zero STEP_END could show unrelated output when
recover/catch retries or stray records preceded the terminal failure.
Append order makes the last failure match the step the tree marks as
failed. Document in cli.md and add regression test.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop run.inbox_parallel, JAIPH_INBOX_PARALLEL, and the Promise.all branch in drainWorkflowQueue so routed targets always run in declaration order inside NodeWorkflowRuntime. Config parse now rejects run.inbox_parallel; CLI env locking and emit paths no longer mention the feature. Docs, grammar, CHANGELOG, and E2E (91/88/93) match sequential-only semantics, with stress failure-aggregation reordered for fail-fast behavior. E2E prepare_shared_context clears inherited JAIPH_* variables; integration tests pin JAIPH_RUNS_DIR and tighten PATH / signal polling so npm test stays reliable when the suite inherits a polluted agent environment.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pre-implementation reference for the Phantom Token credential proxy
that lets sandboxed Claude/agent CLIs authenticate via host-side
credentials without forwarding secrets into the container.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
Carve three focused sibling modules out of the 1915-LoC
src/runtime/kernel/node-workflow-runtime.ts god file so each concern
lives on its own. Pure relocation — no behavior changes, existing
tests pass unchanged.

- runtime-arg-parser.ts: stateless interpolation/arg-parsing helpers
  (interpolate, parseInlineCaptureCall, commaArgsToInterpolated,
  parseArgsRaw, parseInlineScriptAt, parseManagedArgAt, parseArgTokens,
  stripOuterQuotes, parsePromptSchema, sanitizeName, nowIso), the
  shared constants, and the ParsedArgToken / PromptSchemaField types.
  Direct unit tests in runtime-arg-parser.test.ts.
- runtime-event-emitter.ts: RuntimeEventEmitter owns the
  __JAIPH_EVENT__ stderr stream and run_summary.jsonl writes plus the
  monotonic step/prompt counters; the runtime delegates all event
  emission to it.
- runtime-mock.ts: executeMockBodyDef / executeMockShellBody move out
  as exported functions taking an executeStepsBack callback for
  steps-kind mocks; the require("node:child_process") that shadowed
  ESM imports is replaced by a top-of-file import.

Dependency direction is one-way (orchestrator → helpers/emitter/mock);
no circular imports back into node-workflow-runtime.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove the per-call `this.env.JAIPH_TEST_MODE !== "1"` check from
`RuntimeEventEmitter.emitStep` / `emitLog` in favor of an explicit
construction-time `suppressLiveEvents?: boolean` option. The flag is
forwarded from `NodeWorkflowRuntime`'s options to the emitter; when set,
`__JAIPH_EVENT__` stderr writes are skipped while durable
`appendRunSummaryLine` writes to `run_summary.jsonl` remain unchanged.
`node-test-runner.ts` now passes `suppressLiveEvents: true` when
constructing the in-process runtime for `test_run_workflow` steps so
`node --test` reporter output stays clean. `JAIPH_TEST_MODE: "1"` is
still set in the test runner env, but only for `prompt.ts`'s mock
dispatch selection — it no longer affects event emission. The spawned
`node-workflow-runner.js` production child does not set the option, so
live events stream to stderr exactly as before. Existing in-process
artifact tests pass the new flag through their constructor sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refactor QA scripts to improve readability and maintainability by standardizing file paths and indentation. Update the `read_txtar_format_spec` and `read_txtar_fixture_names` scripts to point to the new test fixture locations.

Add new E2E tests for script imports, including scenarios for importing shell and Python scripts, capturing output, and handling missing files. Extend error handling in the compiler with additional test cases for various parse and validate errors.

This update enhances the testing framework and ensures better coverage for script import functionality.

Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
@dzikowski dzikowski merged commit c05d91a into main May 13, 2026
8 checks passed
@dzikowski dzikowski deleted the nightly branch May 13, 2026 11:24
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