Skip to content

Remove legacy TypeScript runtime#78

Merged
gnanam1990 merged 3 commits into
mainfrom
feat/remove-legacy-ts-runtime
Jun 6, 2026
Merged

Remove legacy TypeScript runtime#78
gnanam1990 merged 3 commits into
mainfrom
feat/remove-legacy-ts-runtime

Conversation

@Vasanthdev2004

@Vasanthdev2004 Vasanthdev2004 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Remove the stale TypeScript runtime under src/ now that the Go implementation is the source of truth.
  • Remove TS tests that only covered the deleted runtime and keep the Bun tests for npm/build/release support scripts.
  • Rework scripts/perf-bench.ts so perf smoke no longer imports the TS agent loop and instead probes the built Go binary offline.
  • Drop unused runtime npm dependencies (execa, openai, zod) and update the README example path to internal/agent/loop.go.

Validation

  • bun run typecheck
  • bun test ./tests --timeout 15000
  • go test ./...
  • bun run build
  • bun run smoke:build
  • bun run smoke:go
  • bun run perf:smoke
  • git diff --cached --check

Notes

Remaining TypeScript is intentionally limited to the npm wrapper, build/release scripts, and their Bun tests. The Go runtime remains covered by go test ./....

Summary by CodeRabbit

  • Removals

    • Removed the agent runtime, tool system, provider integrations, config/session/search/hooks/MCP/model-registry features, redaction, usage tracking, and related CLI/runtime functionality.
  • Refactor

    • Performance benchmark now measures external binary "first output" and harness-end RSS instead of in-process TTFT/agent metrics.
  • Documentation

    • README updated to show Go-native project layout and revised headless example.
  • Chores

    • Project runtime dependency declarations removed from package metadata.

@Vasanthdev2004
Vasanthdev2004 marked this pull request as ready for review June 5, 2026 13:56
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Typecheck: bun run typecheck
  • [pass] Tests: bun run test
  • [pass] Build: bun run build
  • [pass] Smoke build: bun run smoke:build

Scope

Head: acf19053ff69
Changed files (105): README.md, bun.lock, docs/PERFORMANCE.md, docs/WORK_SPLIT_PRD.md, index.ts, package.json, scripts/perf-bench.ts, src/agent/loop.ts, src/agent/prompts.ts, src/config/loader.ts, src/config/manager.ts, src/config/provider.ts, and 93 more

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e24be384-8380-411f-9e5d-58fe2a684c70

📥 Commits

Reviewing files that changed from the base of the PR and between 4bf3b0c and acf1905.

📒 Files selected for processing (4)
  • docs/PERFORMANCE.md
  • docs/WORK_SPLIT_PRD.md
  • scripts/perf-bench.ts
  • tests/perf-bench.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/PERFORMANCE.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/WORK_SPLIT_PRD.md
  • tests/perf-bench.test.ts
  • scripts/perf-bench.ts

Walkthrough

Switches perf benchmark from TTFT/in-process sampling to spawn-based binary "first-output" + process-drain measurement with harness RSS; updates README/project layout to Go-native paths, removes several TypeScript barrel/type re-exports and small re-exports, and updates perf tests/docs/CLI/env flags to the new metrics and schemaVersion 2.

Changes

TypeScript-to-Go migration + Perf-first-output redesign

Surface & barrel export removals

Layer / File(s) Summary
Surface & barrel export removals
index.ts, package.json, src/tools/edit-file.ts, src/zero-mcp/index.ts, src/zero-redaction/index.ts, src/zero-usage/index.ts, src/zero-usage/types.ts
Removed console side-effect, removed runtime dependencies from package.json, removed several barrel re-exports and a small edit-file re-export to reflect the Go-native layout and deleted TS modules.

Docs & README

Layer / File(s) Summary
Docs & README
README.md, docs/PERFORMANCE.md, docs/WORK_SPLIT_PRD.md
Updated example zero exec target to internal/agent/loop.go, converted the project layout diagram to cmd/ + internal/, and changed PERFORMANCE docs to describe “Binary first output” and “Harness end RSS” with matching flags/env var names.

Perf thresholds, types & CLI/env flags

Layer / File(s) Summary
Perf thresholds, types & CLI/env flags
scripts/perf-bench.ts
Replaced TTFT/agent-RSS fields with firstOutput*, processDrain*, and harnessEndRss*; bumped PerfBenchResult schema to v2; added firstOutputCommand?: string[]; updated CLI flags and env var names to the new metric set.

Spawn-based first-output measurement implementation

Layer / File(s) Summary
Spawn-based measurement and helpers
scripts/perf-bench.ts
Refactored runPerfBench to resolve and spawn firstOutputCommand, detect first stdout/stderr chunk time, compute processDrainMs and harness end RSS/delta, and use an offline-sanitized environment. Added readTimedSpawnStream, joinChunks, and offlineBenchmarkEnv.

Perf tests updated

Layer / File(s) Summary
Perf tests updated
tests/perf-bench.test.ts
Added guard test ensuring scripts/perf-bench.ts does not import legacy TypeScript agent modules and updated fixtures/assertions to the firstOutput* / harness-RSS schema and CLI/env names.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Gitlawb/zero#43: Overlaps on removal/addition of zero-hooks backend and related modules.
  • Gitlawb/zero#71: Related perf/CLI changes; both PRs modify perf harness and binary expectations.
  • Gitlawb/zero#40: Touches agent/MCP permission areas that this PR removes.

Suggested reviewers

  • gnanam1990
  • anandh8x
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: removing the legacy TypeScript runtime from the codebase, which aligns with the primary intent shown in the raw summary and PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/remove-legacy-ts-runtime

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
scripts/perf-bench.ts (2)

367-373: 💤 Low value

Consider extracting shared resolution logic.

resolveTtftCommand and resolveColdStartCommand are identical. If they're expected to diverge (different flags, prompts), keeping them separate is fine. Otherwise, a small helper like resolveZeroBinaryCommand(args: string[]) avoids duplication.

🔧 Optional consolidation
-async function resolveColdStartCommand(): Promise<string[]> {
-  if (await Bun.file(zeroArtifactPath).exists()) {
-    return [zeroArtifactPath, '--version'];
-  }
-
-  throw new Error(`No ${zeroArtifactName} binary found. Run \`bun run build\` before running the performance benchmark.`);
-}
-
-async function resolveTtftCommand(): Promise<string[]> {
-  if (await Bun.file(zeroArtifactPath).exists()) {
-    return [zeroArtifactPath, '--version'];
-  }
-
-  throw new Error(`No ${zeroArtifactName} binary found. Run \`bun run build\` before running the performance benchmark.`);
-}
+async function resolveZeroBinaryCommand(): Promise<string[]> {
+  if (await Bun.file(zeroArtifactPath).exists()) {
+    return [zeroArtifactPath, '--version'];
+  }
+
+  throw new Error(`No ${zeroArtifactName} binary found. Run \`bun run build\` before running the performance benchmark.`);
+}
+
+const resolveColdStartCommand = resolveZeroBinaryCommand;
+const resolveTtftCommand = resolveZeroBinaryCommand;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/perf-bench.ts` around lines 367 - 373, Both resolveTtftCommand and
resolveColdStartCommand contain identical logic; extract that shared logic into
a helper like resolveZeroBinaryCommand(args: string[]) that checks
Bun.file(zeroArtifactPath).exists(), throws the same Error if missing, and
returns [zeroArtifactPath, ...args] on success, then have resolveTtftCommand
call resolveZeroBinaryCommand(['--version']) and resolveColdStartCommand call
resolveZeroBinaryCommand([]) or their respective args to remove duplication
while preserving behavior.

402-437: ⚡ Quick win

RSS metrics now measure the benchmark harness, not the spawned agent.

With the spawn-based approach, process.memoryUsage().rss captures this process's memory, not the child Go binary's. The agentRssMb / agentRssDeltaMb names suggest otherwise.

If the goal is measuring harness overhead (buffered stdout/stderr), consider renaming to harnessRssMb or adding a brief comment. If spawned-process memory is desired, that would require platform-specific tooling (e.g., /proc/[pid]/statm on Linux).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/perf-bench.ts` around lines 402 - 437, The RSS values returned by
measureTtft currently call readRssMb() (measuring the benchmark harness process)
but are named agentRssMb/agentRssDeltaMb which is misleading; rename those
return properties to harnessRssMb and harnessRssDeltaMb (and update any
callers/tests) or, if you prefer not to rename, add a clear comment above
measureTtft and next to readRssMb() stating that the RSS is for the harness
process (not the spawned child) and that measuring the child would require
platform-specific code (e.g., /proc/[pid]/statm on Linux); update all references
to agentRssMb/agentRssDeltaMb accordingly to keep names and docs consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/perf-bench.ts`:
- Around line 367-373: Both resolveTtftCommand and resolveColdStartCommand
contain identical logic; extract that shared logic into a helper like
resolveZeroBinaryCommand(args: string[]) that checks
Bun.file(zeroArtifactPath).exists(), throws the same Error if missing, and
returns [zeroArtifactPath, ...args] on success, then have resolveTtftCommand
call resolveZeroBinaryCommand(['--version']) and resolveColdStartCommand call
resolveZeroBinaryCommand([]) or their respective args to remove duplication
while preserving behavior.
- Around line 402-437: The RSS values returned by measureTtft currently call
readRssMb() (measuring the benchmark harness process) but are named
agentRssMb/agentRssDeltaMb which is misleading; rename those return properties
to harnessRssMb and harnessRssDeltaMb (and update any callers/tests) or, if you
prefer not to rename, add a clear comment above measureTtft and next to
readRssMb() stating that the RSS is for the harness process (not the spawned
child) and that measuring the child would require platform-specific code (e.g.,
/proc/[pid]/statm on Linux); update all references to agentRssMb/agentRssDeltaMb
accordingly to keep names and docs consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7eda09cb-505b-4085-bd79-7d6de8a9c65e

📥 Commits

Reviewing files that changed from the base of the PR and between 29aec1b and d12d112.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (102)
  • README.md
  • index.ts
  • package.json
  • scripts/perf-bench.ts
  • src/agent/loop.ts
  • src/agent/prompts.ts
  • src/config/loader.ts
  • src/config/manager.ts
  • src/config/provider.ts
  • src/config/types.ts
  • src/providers/anthropic.ts
  • src/providers/base.ts
  • src/providers/gemini.ts
  • src/providers/openai.ts
  • src/providers/types.ts
  • src/tools/apply_patch.ts
  • src/tools/base.ts
  • src/tools/bash.ts
  • src/tools/edit-file.ts
  • src/tools/edit_file.ts
  • src/tools/glob.ts
  • src/tools/grep.ts
  • src/tools/index.ts
  • src/tools/list-directory.ts
  • src/tools/plan.ts
  • src/tools/read-file.ts
  • src/tools/read_file.ts
  • src/tools/registry.ts
  • src/tools/types.ts
  • src/tools/write_file.ts
  • src/version.ts
  • src/zero-config-inspection/index.ts
  • src/zero-config-inspection/inspection.ts
  • src/zero-config-inspection/types.ts
  • src/zero-doctor/index.ts
  • src/zero-doctor/report.ts
  • src/zero-doctor/types.ts
  • src/zero-hooks/audit.ts
  • src/zero-hooks/config.ts
  • src/zero-hooks/index.ts
  • src/zero-hooks/types.ts
  • src/zero-mcp/config.ts
  • src/zero-mcp/index.ts
  • src/zero-mcp/manager.ts
  • src/zero-mcp/permissions.ts
  • src/zero-mcp/tools.ts
  • src/zero-mcp/transport.ts
  • src/zero-mcp/types.ts
  • src/zero-model-registry/cost.ts
  • src/zero-model-registry/index.ts
  • src/zero-model-registry/profiles.ts
  • src/zero-model-registry/registry.ts
  • src/zero-model-registry/types.ts
  • src/zero-provider-runtime/index.ts
  • src/zero-provider-runtime/resolver.ts
  • src/zero-provider-runtime/types.ts
  • src/zero-redaction/index.ts
  • src/zero-redaction/redactor.ts
  • src/zero-redaction/types.ts
  • src/zero-runtime/context.ts
  • src/zero-runtime/index.ts
  • src/zero-runtime/types.ts
  • src/zero-search/index.ts
  • src/zero-search/search.ts
  • src/zero-search/session-index.ts
  • src/zero-search/types.ts
  • src/zero-sessions/exec-session.ts
  • src/zero-sessions/index.ts
  • src/zero-sessions/store.ts
  • src/zero-sessions/types.ts
  • src/zero-stream-json/index.ts
  • src/zero-stream-json/protocol.ts
  • src/zero-stream-json/types.ts
  • src/zero-usage/index.ts
  • src/zero-usage/tracker.ts
  • src/zero-usage/types.ts
  • tests/agent-loop.test.ts
  • tests/anthropic-provider.test.ts
  • tests/config-loader.test.ts
  • tests/file-tools.test.ts
  • tests/foundation-tools.test.ts
  • tests/gemini-provider.test.ts
  • tests/openai-provider.test.ts
  • tests/perf-bench.test.ts
  • tests/plan.test.ts
  • tests/provider-base.test.ts
  • tests/registry.test.ts
  • tests/tool-base.test.ts
  • tests/tool-schema.test.ts
  • tests/zero-config-inspection.test.ts
  • tests/zero-doctor.test.ts
  • tests/zero-exec-session.test.ts
  • tests/zero-hooks.test.ts
  • tests/zero-model-registry.test.ts
  • tests/zero-provider-runtime.test.ts
  • tests/zero-redaction.test.ts
  • tests/zero-runtime.test.ts
  • tests/zero-search-index.test.ts
  • tests/zero-search.test.ts
  • tests/zero-session-events.test.ts
  • tests/zero-stream-json.test.ts
  • tests/zero-usage.test.ts
💤 Files with no reviewable changes (99)
  • index.ts
  • src/zero-doctor/index.ts
  • src/zero-mcp/index.ts
  • src/config/types.ts
  • tests/zero-doctor.test.ts
  • src/tools/write_file.ts
  • src/zero-config-inspection/types.ts
  • tests/plan.test.ts
  • src/agent/prompts.ts
  • src/providers/anthropic.ts
  • tests/config-loader.test.ts
  • src/zero-search/types.ts
  • src/tools/plan.ts
  • tests/zero-provider-runtime.test.ts
  • tests/zero-hooks.test.ts
  • tests/zero-stream-json.test.ts
  • src/zero-mcp/manager.ts
  • tests/zero-usage.test.ts
  • tests/file-tools.test.ts
  • src/providers/types.ts
  • src/version.ts
  • src/zero-usage/types.ts
  • src/zero-provider-runtime/types.ts
  • src/config/manager.ts
  • tests/registry.test.ts
  • src/zero-model-registry/types.ts
  • tests/openai-provider.test.ts
  • tests/tool-schema.test.ts
  • tests/zero-config-inspection.test.ts
  • tests/zero-search-index.test.ts
  • tests/zero-exec-session.test.ts
  • tests/tool-base.test.ts
  • tests/anthropic-provider.test.ts
  • src/tools/read-file.ts
  • src/zero-usage/tracker.ts
  • src/zero-provider-runtime/index.ts
  • src/zero-mcp/config.ts
  • src/zero-sessions/exec-session.ts
  • src/zero-model-registry/cost.ts
  • src/zero-stream-json/index.ts
  • src/zero-runtime/types.ts
  • src/config/provider.ts
  • src/agent/loop.ts
  • src/zero-stream-json/types.ts
  • src/tools/edit-file.ts
  • src/tools/bash.ts
  • tests/zero-redaction.test.ts
  • src/zero-usage/index.ts
  • src/zero-hooks/audit.ts
  • tests/foundation-tools.test.ts
  • src/providers/base.ts
  • src/zero-mcp/tools.ts
  • src/tools/index.ts
  • src/zero-config-inspection/inspection.ts
  • tests/zero-model-registry.test.ts
  • src/zero-provider-runtime/resolver.ts
  • src/zero-redaction/types.ts
  • package.json
  • tests/gemini-provider.test.ts
  • src/tools/edit_file.ts
  • src/zero-config-inspection/index.ts
  • src/tools/types.ts
  • src/zero-mcp/permissions.ts
  • src/zero-runtime/context.ts
  • src/tools/base.ts
  • tests/zero-runtime.test.ts
  • src/zero-runtime/index.ts
  • src/zero-stream-json/protocol.ts
  • src/zero-model-registry/profiles.ts
  • src/tools/grep.ts
  • src/zero-hooks/config.ts
  • src/zero-search/session-index.ts
  • src/tools/apply_patch.ts
  • src/config/loader.ts
  • src/zero-hooks/index.ts
  • src/tools/list-directory.ts
  • src/tools/read_file.ts
  • src/zero-sessions/types.ts
  • src/zero-mcp/transport.ts
  • src/tools/glob.ts
  • tests/zero-session-events.test.ts
  • src/zero-sessions/index.ts
  • src/zero-search/index.ts
  • src/zero-doctor/types.ts
  • src/zero-redaction/redactor.ts
  • src/tools/registry.ts
  • src/zero-mcp/types.ts
  • tests/zero-search.test.ts
  • src/providers/gemini.ts
  • src/zero-sessions/store.ts
  • tests/agent-loop.test.ts
  • src/zero-search/search.ts
  • src/providers/openai.ts
  • src/zero-model-registry/registry.ts
  • src/zero-doctor/report.ts
  • src/zero-model-registry/index.ts
  • src/zero-redaction/index.ts
  • tests/provider-base.test.ts
  • src/zero-hooks/types.ts

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blockers

  • The performance benchmark no longer measures the metric names it reports. scripts/perf-bench.ts now resolves the TTFT command to zero --version and measures first stdout/stderr output from that process. The RSS values also come from the Bun benchmark harness process via process.memoryUsage().rss, not the spawned Go agent. However the summary and docs still label these as TTFT and agent RSS, and docs/PERFORMANCE.md still describes TTFT as the first streamed text event from a deterministic provider plus memory as the in-process agent path. Please either restore a Go-native deterministic agent/stream benchmark, or rename/update the metric/schema/docs to describe binary first-output latency and harness RSS accurately.

  • The README project layout is stale after this removal. PR #78 deletes the src/agent, src/providers, src/tools, and src/zero-* runtime trees, but the README still lists src/ as the project layout with the transitional TS agent loop, providers, tools, sessions, usage, doctor, stream-json, and other modules. Please update that section to the current Go layout (cmd/*, internal/*, remaining scripts/*, and remaining tests/*) so users do not follow deleted paths.

Validation

I checked the PR branch and a temporary merge onto current origin/main.

  • git diff --check
  • go test -count=1 -p 1 ./...
  • bun install --frozen-lockfile
  • bun run typecheck
  • bun test ./tests --timeout 15000
  • bun run build
  • bun run smoke:build
  • bun run smoke:go
  • bun run perf:bench --iterations 1 --warmup 0 --json

The local gates pass and the merge simulation applies cleanly. The request is for correctness of user-facing docs and performance metric semantics before merging.

@anandh8x anandh8x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's good

  • The deletion is the right call now that the Go runtime is the source of truth. The Go side already has full coverage of the M0–M6 surface (agent loop, providers, tools, mcp, hooks, sessions, search, redaction, runtime, model-registry, doctor, config-inspection, usage, stream-json), and the TS modules were dead weight that confused the contribution path. Removing them at the same time as adding the Go versions is exactly the right sequencing.
  • Dependency cleanup is real. execa, openai, and zod are gone from package.json and bun.lock (-57 lines in the lockfile, no more openai/zod/@sec-ant/readable-stream/@sindresorhus/merge-streams/cross-spawn/figures/get-stream/human-signals/is-plain-obj/is-stream/is-unicode-supported/isexe/npm-run-path/parse-ms/path-key/pretty-ms/shebang-command/shebang-regex/signal-exit/strip-final-newline/unicorn-magic/which/ws/yoctocolors). That is a smaller install footprint, a faster CI cold start, and one less attack surface for supply-chain review.
  • scripts/perf-bench.ts is rewritten to measure what matters. The old benchmark ran an in-process TS agent with a stub ImmediateTextProvider; that proved the TS loop was fast, not that the shipped binary is fast. The new measureTtft spawns the built Go binary, strips provider env vars via offlineBenchmarkEnv, and times the first byte of stdout/stderr. That is a real cold-start + first-byte measurement of the production binary in a way that can run in CI without network access. resolveTtftCommand and resolveColdStartCommand both fail loudly if the artifact is missing, so the perf job will surface a missing bun run build step instead of silently timing a bun --version call.
  • The regression test prevents reintroduction. tests/perf-bench.test.ts reads scripts/perf-bench.ts and asserts it does not contain ../src/agent/loop or ../src/providers/types. That is a one-line migration safeguard; if a future PR imports the legacy runtime back into perf-bench, the test fails before the perf numbers become misleading.
  • index.ts is gone. The console.log("Hello via Bun!") placeholder was misleading after the Go CLI took over. The npm wrapper path is now bin/zero.tsscripts/npm-wrapper.ts → native binary, with the package.json module and bin fields pointing at the wrapper, so removing the root placeholder is the right cleanup.
  • src/version.ts is also gone. The Go binary owns the version string via the var version = "dev" linker injection (scripts/build.ts injects -X main.version=...), so the TS version module was redundant.
  • README example path is updated. zero exec "explain src/agent/loop.ts and suggest one improvement" becomes zero exec "explain internal/agent/loop.go and suggest one improvement", which matches the new home of the loop. Small but important for new contributors following the example.
  • CI does not need a follow-up. .github/workflows/ci.yml already runs bun run test:go, bun run test, bun run typecheck, bun run build, bun run smoke:build, bun run smoke:go, and bun run scripts/perf-bench.ts --ci --output dist/perf/perf-bench.json. All of those still work with the new perf-bench; no workflow edits are required.
  • package.json becomes devDependencies-only. execa, openai, zod are removed, and there are no dependencies left. That is the cleanest possible npm state for a project whose npm package is a thin wrapper around a Go binary.

Observations (non-blocking)

  1. ttftMs is no longer "time to first text" in the LLM-stream sense. The new measureTtft runs <binary> --version, which exits immediately after writing a single short line. The metric is now "cold-start + first-byte" of the binary, not "time to first model token". A future benchmark that wants a real TTFT would need to either (a) call a --smoke-stream subcommand that streams a canned response, or (b) hit a fixed offline endpoint. Consider renaming ttftMs to startupMs or firstByteMs (and updating formatPerfSummary and the JSON schema) so the metric name matches what it measures. The new name would also be more honest in the threshold config (ttftP95Ms becomes firstByteP95Ms).

  2. streamOverheadMs semantics shifted with the rewrite. Previously it was firstTextAt - providerFirstByteAt (the gap between the provider starting to stream and the agent emitting text). It is now finishedAt - observedFirstOutputAt, i.e., the time from the first byte to process exit. For --version that is a few milliseconds; it is still collected, but the number is no longer comparable to the old metric. If the new metric is kept, document it in PerfBenchResult's docstring.

  3. offlineBenchmarkEnv is a hardcoded env-var deletion list. A future provider (e.g., a MISTRAL_API_KEY or BEDROCK_* env) would not be stripped, so a future --version-style smoke that reads those vars could behave differently in CI vs. dev. A more robust pattern is to start from { PATH: process.env.PATH, NO_COLOR: '1' } and explicitly add only what the binary needs, instead of cloning process.env and deleting entries. The current approach is fine for the immediate need, but the comment should note that adding new provider env vars requires updating this list.

  4. resolveColdStartCommand and resolveTtftCommand are 80% duplicate. Both call Bun.file(zeroArtifactPath).exists() and throw the same No ${zeroArtifactName} binary found error. A small helper like resolveArtifactPath() returning the validated path (or throwing) would DRY this and ensure the error message stays consistent. Cosmetic.

  5. The regression test is a string check on source text. expect(source).not.toContain('../src/agent/loop') will also fail if a comment, docstring, or string literal contains that exact substring. For a one-off migration safeguard that is acceptable, but if anyone refactors perf-bench and adds a doc comment that mentions the legacy runtime for context, the test breaks. A more robust check would be to import perf-bench and assert it does not export runAgent (or to scan for ^import .* from '\.\./src/ regex with proper escaping).

  6. PerfBenchResult adds ttftCommand but the old coldStartCommand is still typed string[] only. A command description for both would be cleaner. Minor; the text formatter already prints both.

  7. The legacy TS source had a default export from src/zero-runtime/index.ts and a few other modules. No one outside the deleted files referenced those exports, so the deletion is safe. The Go side has the corresponding types in internal/zeroruntime/ (kebab-case stream events, agent.Message, agent.Provider, etc.), which the npm wrapper never needs to touch because the Go binary is the entry point.

  8. No mention of removing AGENTS.MD references to the TS API surface. AGENTS.MD (the Bun guidance file) is a generic Bun cookbook and does not mention Zero-specific code paths, so it is unaffected. If any internal docs in docs/ reference the TS API surface, a follow-up grep is worth running. From the diff, docs/INSTALL.md, docs/PRD.md, etc. were not touched, which suggests they do not reference the TS surface.

  9. bun.lock still has bun-types and the @types/bun block. Those are dev-time, not runtime, so they should stay. The deletion is correctly limited to dependencies.

  10. The PR description mentions bun run smoke:build and bun run smoke:go in the validation list. Both of those scripts likely depend on the built Go binary, so the bun run build step must run first. The validation list is in the right order; the perf-bench ttftCommand default also assumes bun run build has produced dist/zero/zero(.exe).

  11. scripts/perf-bench.ts no longer imports any TS runtime, but it still imports from node:fs/promises, node:path, and Bun. That is the right surface for a build-script that only manipulates the filesystem and spawns a child. No leftover execa, zod, or openai references in the new code.

  12. tsconfig.json is not updated. The "include" (or lack thereof) still applies to src/, but with src/ removed, TypeScript will only typecheck bin/, scripts/, and tests/. Worth verifying that bun run typecheck still passes — the validation list includes it, so it should. A small "include" array in tsconfig.json would make the new scope explicit and prevent accidental reintroduction of src/ references.

  13. No deprecation notice for downstream consumers. If any external tool imports zero/agent/loop or another deleted path from the npm package, the next bun install will fail to resolve. For an unreleased CLI this is fine; for a published package a major-version bump and a CHANGELOG.md entry would be required. The PR description notes this is a Go-first rewrite, so consumers are expected to switch to the native binary.

  14. The providerFirstByteAt and firstTextAt locals are gone, along with the ImmediateTextProvider class. If a future benchmark wants to bring back real-provider TTFT, the previous test coverage of the immediate provider is also gone. That is a deliberate trade-off; the old test only verified a synthetic path. If a real offline smoke provider is added later, it should land with its own test.

  15. formatPerfSummary adds a TTFT command: line. The coldStartCommand is rendered above it and ttftCommand is rendered with the same formatCommand helper, which is consistent. A small consistency win: the JSON shape (PerfBenchResult) and the text shape should agree on field names; currently metrics.ttftMs exists in both, but the command itself was added as ttftCommand everywhere. Good.

  16. measureTtft uses Promise.all([child.exited, ...]) to await exit and read both streams concurrently. If the binary hangs (e.g., a provider call without offline env), the streams never resolve. There is no timeout on the benchmark itself. A future runPerfBench could add a per-iteration AbortController so a hung binary fails the perf job instead of blocking CI for the default 6-hour GitHub Actions timeout.

  17. The streamOverheadMs value is computed but unused by formatPerfSummary. The text format prints ttftMs and coldStartMs only. Either drop streamOverheadMs from the result (it is noise on --version) or add a one-line summary that prints it. Right now it is collected and forgotten.

  18. The PR removes src/zero-runtime (the canonical TS runtime types) but the Go equivalent in internal/zeroruntime/ is untouched. That is correct — the Go runtime is the source of truth, and the npm wrapper does not need TS runtime types. Worth a one-line AGENTS.MD or CONTRIBUTING.md note that TS code should not redefine runtime types.

  19. No new test asserts that the npm wrapper still resolves to a native target. The wrapper has its own tests in tests/build-scripts.test.ts (from the file list). If those cover the resolveNpmWrapperTarget happy path, the deletion of legacy code does not regress them; if not, a follow-up is worth adding. The PR validation list does not call them out explicitly, so I assume bun test ./tests covers them.

  20. git diff --check origin/main...HEAD is in the validation list but the diff is large (103 files, 13k lines). On a typical CI runner that check is fast; on a developer machine the diff stats are large enough that git diff --check is the cheapest guard. Good to see it included.

No blockers. The deletion is thorough, the perf-bench rewrite is more honest than what it replaced, the regression test is small and correct, and the dependency cleanup is a real win. The two follow-ups I would prioritize next: (1) rename ttftMs/ttftCommand/ttftP95Ms to firstByte* so the metric name matches what is actually measured, and (2) add a per-iteration timeout in runPerfBench so a hung binary fails fast in CI.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/perf-bench.test.ts (1)

52-75: ⚡ Quick win

Cover ZERO_PERF_FIRST_OUTPUT_WARN_MS env parsing explicitly.

This test validates the renamed CLI flag, but not the renamed env key for first-output thresholds. Add one env-only assertion to lock that contract and prevent silent regressions.

Suggested test extension
   it('parses CLI and environment overrides', () => {
@@
     expect(options.failOnWarning).toBe(true);
+
+    const envOnly = parsePerfBenchArgs([], {
+      ZERO_PERF_FIRST_OUTPUT_WARN_MS: '610',
+    });
+    expect(envOnly.thresholds.firstOutputP95Ms).toBe(610);
   });

As per coding guidelines, tests/**/*.ts should provide deterministic and meaningful coverage for provider/runtime flow decisions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/perf-bench.test.ts` around lines 52 - 75, The test parsePerfBenchArgs
coverage is missing an env-only check for the renamed
ZERO_PERF_FIRST_OUTPUT_WARN_MS key; update tests/perf-bench.test.ts to include
an additional invocation of parsePerfBenchArgs (or extend the existing call)
that supplies ZERO_PERF_FIRST_OUTPUT_WARN_MS in the env map and assert that the
returned options.thresholds.firstOutputP95Ms equals that value (similar to
existing assertions for ZERO_PERF_COLD_START_WARN_MS and
ZERO_PERF_HARNESS_RSS_WARN_MB), ensuring the parsing logic in parsePerfBenchArgs
correctly picks up the env-only variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/perf-bench.ts`:
- Around line 442-445: measureFirstOutput currently sets harnessRssMb to
rssAfter (end-state RSS) which contradicts its "peak" semantics and the CLI
gating on metrics.harnessRssMb.max; update measureFirstOutput to either (A)
sample process.memoryUsage().rss periodically during the measured window and set
harnessRssMb to the max observed RSS (use symbols rssBefore, rssAfter, and the
measurement loop inside measureFirstOutput to compute a peak) or (B) change the
metric name/CLI/messages to reflect "end-state RSS" (rename harnessRssMb and any
references to metrics.harnessRssMb.max, help text, and warnings) so the reported
value matches the current two-sample measurement; pick one approach and update
all identifiers and messaging consistently.

---

Nitpick comments:
In `@tests/perf-bench.test.ts`:
- Around line 52-75: The test parsePerfBenchArgs coverage is missing an env-only
check for the renamed ZERO_PERF_FIRST_OUTPUT_WARN_MS key; update
tests/perf-bench.test.ts to include an additional invocation of
parsePerfBenchArgs (or extend the existing call) that supplies
ZERO_PERF_FIRST_OUTPUT_WARN_MS in the env map and assert that the returned
options.thresholds.firstOutputP95Ms equals that value (similar to existing
assertions for ZERO_PERF_COLD_START_WARN_MS and ZERO_PERF_HARNESS_RSS_WARN_MB),
ensuring the parsing logic in parsePerfBenchArgs correctly picks up the env-only
variable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d5731b45-4a74-4a17-b71f-7821013bbc0a

📥 Commits

Reviewing files that changed from the base of the PR and between d12d112 and 4bf3b0c.

📒 Files selected for processing (5)
  • README.md
  • docs/PERFORMANCE.md
  • docs/WORK_SPLIT_PRD.md
  • scripts/perf-bench.ts
  • tests/perf-bench.test.ts
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • docs/WORK_SPLIT_PRD.md

Comment thread scripts/perf-bench.ts Outdated

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after rereview.

The previous blockers are fixed on current head acf1905:

  • Performance benchmark/docs now describe binary first-output and harness end RSS semantics instead of provider TTFT or agent RSS.
  • README project layout now points contributors at the Go runtime layout under cmd/, internal/, remaining scripts/, tests/, and docs/.

Validation run locally on a detached PR head:

  • git diff --check origin/main...HEAD
  • go test -count=1 -p 1 ./...
  • bun install --frozen-lockfile
  • bun run typecheck
  • bun test ./tests --timeout 15000
  • bun run build
  • bun run smoke:build
  • bun run smoke:go
  • bun run perf:bench --iterations 1 --warmup 0 --json

@gnanam1990
gnanam1990 merged commit ca4c57f into main Jun 6, 2026
6 checks passed
@gnanam1990

gnanam1990 commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Review: PR #78 — Remove legacy TypeScript runtime (Vasanthdev2004 / Vasanth)

URL: #78 (MERGED)
Size: +218 / -13,548 (massive net removal)
Significance: Foundational migration milestone.

Ownership & Strategic Fit

Vasanth (TUI + overall Go-native direction) appropriately drove the final "the Go runtime is now the source of truth" step.

  • Directly enables the baseline stated in WORK_SPLIT: "The current main branch is Go-native for the runtime and CLI." "Remaining TypeScript should be treated as npm/package support, scripts, or legacy test support until each file is explicitly retired."
  • Pairs with many of his earlier "Go-first TUI", "make Go runtime the app path", command center, etc. PRs.
  • The perf script rework (now probes the built binary) directly unblocks Anandan's Move performance benchmark to Go #87 (perf to Go).

Approved by Anandan + gnanam1990 + CodeRabbit at merge time.

What Was Removed / Changed

  • Deleted the entire old src/ runtime (agent, tools, providers, config, sessions, MCP, hooks, model registry, redaction, usage — everything that had been ported).
  • Kept only Bun-relevant: npm wrapper entry, build/release/installer scripts, and their supporting Bun tests.
  • scripts/perf-bench.ts reworked to be an external probe (no longer imports TS agent).
  • Dropped runtime npm deps (execa, openai, zod).
  • README and project layout docs updated to show internal/agent/loop.go etc.
  • Validation: full Go tests + Bun typecheck/test/build/smoke + perf smoke.

Impact on Shared Contracts (Runtime Owner View)

  • Positive: Removes the last duplicate implementations. The single source of truth for events, tools, providers, sessions, permissions policy etc. is now the Go code in internal/.
  • The TUI (still under active development in Vasanth's lane) now only talks to the Go runtime surface (or the built binary for some smokes). This reduces the surface area where drift could occur between "old TS contracts" and the ones Gnanam is responsible for (stream events, permission grants, session schema, provider/model registry).
  • Perf measurement is now forced to treat Zero as an opaque CLI — correct for a product that ships a binary.

Review Notes

  • Cleanup quality: The diff is mostly pure deletion + small targeted updates to the remaining wrapper/perf surface. Low risk of accidental breakage in the kept Bun code.
  • Remaining TS contract: The package.json still exposes bin/zero.ts as the npm entry (the thin launcher for the Go binary). This is the intended end state.
  • One small risk area: Any test or script that previously exercised the TS agent loop for "realistic" perf or integration now has to go through the built binary or Go test doubles. Move performance benchmark to Go #87 (perf) and future smokes will need to keep proving they still catch real regressions.
  • Docs: The updated README layout in the PR is accurate.

Verdict (Post-Merge)

Correct and necessary. This PR (combined with the preceding Go M0-M5 ports by both Vasanth and Anandan, and Gnanam's runtime contracts) marks the end of the migration era and the beginning of the "mature daily-driver" phase described in the v3 WORK_SPLIT.

The project is now in a much healthier state for parallel ownership:

  • Vasanth can iterate TUI polish (feat(tui): premium splash + working-view redesign #83 etc.) on a stable Go event surface.
  • Anandan can harden platform/release/CI/perf without a parallel TS world.
  • Gnanam (runtime) owns the single source of truth for the contracts the other two consume.

Excellent milestone PR.

@gnanam1990

gnanam1990 commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Non-gnanam1990 PR Reviews (Zero repo)

Context: Analysis of https://github.com/Gitlawb/zero.git PRs, excluding all PRs authored by gnanam1990 (Gnanam / runtime core owner per WORK_SPLIT_PRD.md).

Date of analysis: 2026-06 (active sprint)

Team lanes (from docs/WORK_SPLIT_PRD.md):

  • Vasanthdev2004 (Vasanth): Product UX and TUI owner (splash, themes, tool rendering, command UX, daily CLI feel).
  • anandh8x (Anandan): Platform product owner (install/update/release trust, binary smoke, platform sandbox adapters + Windows, PR/review automation CLI, performance/release checks, CI that proves real commands).
  • gnanam1990 (Gnanam): Runtime core (excluded from this review set): providers/registry, agent protocols, stream-json, sessions, config/doctor/usage/redaction, MCP backend, sandbox policy/grants + permission event contract.

Currently Open (at time of review)

  • Move performance benchmark to Go #87 anandh8x — Move performance benchmark to Go (feat/go-perf-bench)

    • Strong ownership fit. Large new Go perf harness + cleanup of legacy TS perf. Recommend approve after CodeRabbit items + measurement prompt confirmation.
  • feat(tui): premium splash + working-view redesign #83 Vasanthdev2004 — feat(tui): premium splash + working-view redesign (feat/tui-premium-splash)

    • Excellent TUI polish (central theme, splash, 3-zone view with diff cards, role gutters, usage in status). Note: gnanam1990 already flagged "Changes requested". Focus areas: runtime event consumption fidelity + coordination with upcoming permission UX.

Key Recently Merged (platform + migration, non-gnanam)

  • Verify update release assets #84 anandh8x — Verify update release assets (feat/update-release-verification)

    • Perfect Anandan deliverable. zero update --check now does real asset + sha256 validation with rich JSON/text output + good tests. Runnable behavior + release trust.
  • Report sandbox platform capabilities #81 anandh8x — Report sandbox platform capabilities (feat/windows-sandbox-platform)

    • Makes Windows "policy-only fallback" explicit and machine-readable via zero sandbox policy --json. Clear restrictions. Matches split requirements for platform fallback reporting.
  • Move build smoke tooling to Go #86 / Move release packaging to Go #85 anandh8x — Move build smoke tooling to Go + Move release packaging to Go

    • These continue the pattern of moving platform/release verification into Go (Anandan's remit). Good follow-through on "binary/package smoke tests" and "CI proves real commands after install".
  • Remove legacy TypeScript runtime #78 Vasanthdev2004 — Remove legacy TypeScript runtime (feat/remove-legacy-ts-runtime)

    • Massive, correct deletion of the old src/ runtime (13k+ lines). Remaining Bun only for wrapper/scripts. Unblocks pure-Go perf (Move performance benchmark to Go #87), makes the Go event surface the single source of truth. Foundational for the whole team.
  • docs: update work split ownership plan #80 Vasanthdev2004 — docs: update work split ownership plan

    • Doc maintenance of the v3 split itself. Useful but secondary to executable behavior PRs.
  • Many earlier M0-M3 "codex" and "feat/go-m0-" / "feat/mX-" PRs by Vasanth and Anandan (foundation tools, TUI session controls, Go runtime takeover, command center, headless protocol, model selector, etc.). These built the Go baseline that the current sprint is now hardening.

Other (older / external)

  • jatmn (closed, early exploration: providers, OpenTUI experiments, contributing).
  • kevincodex1 (fix plan mode and add test #2 — fix plan mode + test, merged early).

Overall Observations (as Runtime Owner)

  1. Lane discipline is good: Recent Anandan PRs are delivering exactly the "platform product behavior" the split demands (runnable update --check, sandbox policy, perf smoke against the real binary, release packaging/checksums, PR automation). Not docs/CI-only.

  2. Vasanth is driving the "daily CLI feel": The TUI redesign (feat(tui): premium splash + working-view redesign #83) + legacy removal (Remove legacy TypeScript runtime #78) + earlier session controls / command center / Go runtime app path work are cohesive.

  3. Shared contracts: Most changes respect boundaries. TUI (Vasanth) and platform (Anandan) consume rather than redefine the runtime events, permission grants, session schema, and provider contracts (Gnanam's DRI). The feat(tui): premium splash + working-view redesign #83 review calls out a small coordination item around permission status + event fidelity.

  4. Migration era is ending: Remove legacy TypeScript runtime #78 + the Go perf move + update/sanbox platform reporting = the project has a clear "Go is the product" baseline. Future work per the split can focus on safe autonomy (permissions), polish, and release trust instead of porting.

  5. CodeRabbit + human review process: Active on most PRs. Several have approvals from the other two owners + CodeRabbit. The open ones (Move performance benchmark to Go #87 has "changes requested" from CR; feat(tui): premium splash + working-view redesign #83 has from both CR and gnanam1990) are the ones needing attention now.

How to Use These Reviews

  • The individual reviews include concrete suggestions (event mapping for TUI, first-output fidelity for perf, etc.).
  • For open PRs: re-run bun run build / go test ./... / the new perf:smoke etc. after merges.

Next suggested reviews (when new activity appears):

  • Any new TUI permission prompt work (Vasanth feat/tui-sandbox-permissions).
  • Further Anandan release trust / Windows sandbox adapter PRs.

@Vasanthdev2004
Vasanthdev2004 deleted the feat/remove-legacy-ts-runtime branch June 28, 2026 08:27
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.

3 participants