@linzumi/cli 1.0.166 → 1.0.168

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "1.0.166",
3
+ "version": "1.0.168",
4
4
  "description": "Linzumi CLI \u2014 point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -246,7 +246,21 @@ function scanTargets() {
246
246
  }
247
247
 
248
248
  for (const entry of entries) {
249
- files.push(relative(packageRoot, entry));
249
+ const relativePath = relative(packageRoot, entry);
250
+
251
+ // Recorded agent-replay captures are FROZEN evidence (the same
252
+ // doctrine as the replay_harness corpus): a capture recorded while
253
+ // the CLI was at version X legitimately carries that version string
254
+ // in its recorded wire payloads forever, and the bump must neither
255
+ // rewrite it nor refuse because of it
256
+ // (spec/codex-wire-capture-replay.spec.md).
257
+ if (
258
+ relativePath.startsWith(join('test', 'fixtures', 'agent-raw-replay'))
259
+ ) {
260
+ continue;
261
+ }
262
+
263
+ files.push(relativePath);
250
264
  }
251
265
  }
252
266
 
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+ # Codex wire replay thin launcher (spec/codex-wire-capture-replay.spec.md).
3
+ #
4
+ # Point the commander's `--codex-bin` at this script to swap the real codex
5
+ # engine for the wire replay server: same spawn contract (`--version`,
6
+ # `login status`, `app-server ... --listen <ws-url>`), zero runner code
7
+ # changes, no codex auth anywhere. The implementation is ReScript
8
+ # (HarnessCodexWireReplayBinMain.res); this launcher only resolves the
9
+ # compiled module beside this checkout and execs node on it - build first
10
+ # with `npx rescript build packages/linzumi-cli-rescript` (the CLI test
11
+ # script already does).
12
+ #
13
+ # Env (read by the bin): LINZUMI_WIRE_REPLAY_CAPTURE (required),
14
+ # LINZUMI_WIRE_REPLAY_STRICTNESS, LINZUMI_WIRE_REPLAY_CLOCK,
15
+ # LINZUMI_WIRE_REPLAY_REPORT.
16
+ set -euo pipefail
17
+
18
+ here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ bin_module="$here/../../linzumi-cli-rescript/src/harness/HarnessCodexWireReplayBinMain.res.mjs"
20
+
21
+ if [[ ! -f "$bin_module" ]]; then
22
+ echo "codex-wire-replay-bin: compiled module missing at $bin_module - run: npx rescript build <repo>/packages/linzumi-cli-rescript" >&2
23
+ exit 66
24
+ fi
25
+
26
+ exec node "$bin_module" "$@"
@@ -61,8 +61,59 @@ type BackendReplayOptions = {
61
61
  readonly browserAuth: BackendReplayBrowserAuth | undefined;
62
62
  readonly requiredFeatureId: string | undefined;
63
63
  readonly oracleFeatureId: string | undefined;
64
+ // Wire replay mode (spec/codex-wire-capture-replay.spec.md): serve the
65
+ // fixture from the stub codex app-server websocket instead of the
66
+ // in-process provider-boundary client, so the runner's REAL socket
67
+ // machinery is exercised against the REAL backend.
68
+ readonly wire: boolean;
69
+ readonly wireStrictness: string | undefined;
64
70
  };
65
71
 
72
+ type WireReplayServerHandle = {
73
+ readonly url: string;
74
+ readonly port: number;
75
+ readonly report: () => JsonObject;
76
+ readonly waitForCompletion: (timeoutMs: number) => Promise<boolean>;
77
+ readonly close: () => Promise<void>;
78
+ };
79
+
80
+ async function startWireReplayServerForFixture(
81
+ options: BackendReplayOptions
82
+ ): Promise<WireReplayServerHandle> {
83
+ // The implementation is ReScript (zero-TS/zero-raw-JS ratchets); the
84
+ // compiled module is loaded through a non-literal specifier so the type
85
+ // checker does not require declarations. The CLI test/build pipeline
86
+ // compiles the package (`rescript build ../linzumi-cli-rescript`).
87
+ const wireModulePath = new URL(
88
+ '../../linzumi-cli-rescript/src/harness/HarnessCodexWireReplay.res.mjs',
89
+ import.meta.url
90
+ ).href;
91
+ const wireModule = (await import(wireModulePath)) as {
92
+ startWireReplayServerJs: (serverOptions: {
93
+ readonly capturePath?: string;
94
+ readonly strictness?: string | undefined;
95
+ readonly clock?: string | undefined;
96
+ }) => Promise<WireReplayServerHandle>;
97
+ wireReplayClockForBackendSpeed: (
98
+ speed: string | undefined
99
+ ) => string | undefined;
100
+ };
101
+
102
+ // Translate the orchestrator's --speed grammar into the wire clock
103
+ // grammar (realtime -> recorded, <n>x passes through, <n>ms refuses
104
+ // loudly - it has no wire counterpart); property-pinned in
105
+ // test/agentReplayFixture.test.ts.
106
+ const wireClock = wireModule.wireReplayClockForBackendSpeed(options.speed);
107
+
108
+ return wireModule.startWireReplayServerJs({
109
+ capturePath: options.fixturePath,
110
+ ...(options.wireStrictness === undefined
111
+ ? {}
112
+ : { strictness: options.wireStrictness }),
113
+ ...(wireClock === undefined ? {} : { clock: wireClock }),
114
+ });
115
+ }
116
+
66
117
  type BackendReplayBrowserAuth = {
67
118
  readonly accessToken: string;
68
119
  readonly refreshToken: string | undefined;
@@ -350,6 +401,8 @@ function parseArgs(args: readonly string[]): BackendReplayOptions {
350
401
  browserAuth: undefined,
351
402
  requiredFeatureId: argValue(args, '--require-feature'),
352
403
  oracleFeatureId: argValue(args, '--oracle-feature'),
404
+ wire: args.includes('--wire'),
405
+ wireStrictness: argValue(args, '--wire-strictness'),
353
406
  };
354
407
  }
355
408
 
@@ -753,24 +806,38 @@ async function runBackendReplay(
753
806
  }
754
807
 
755
808
  const runnerToken = await resolveBackendReplayToken(options);
756
- const runner = await runLocalCodexRunner(
757
- backendReplayRunnerOptions(options, provider, runnerToken)
758
- );
809
+ const wireServer = options.wire
810
+ ? await startWireReplayServerForFixture(options)
811
+ : undefined;
759
812
 
760
813
  try {
761
- const start = await startLocalCodexRunnerInstance(options, provider);
762
- const oracles = await runBackendReplayOracles(options, start, provider);
814
+ const runner = await runLocalCodexRunner(
815
+ backendReplayRunnerOptions(
816
+ options,
817
+ provider,
818
+ runnerToken,
819
+ wireServer?.url
820
+ )
821
+ );
763
822
 
764
- return {
765
- runnerId: options.runnerId,
766
- instanceId: runner.instanceId,
767
- codexUrl: runner.codexUrl,
768
- frontendTarget: frontendReplayTarget(options, start.threadId),
769
- start,
770
- oracles,
771
- };
823
+ try {
824
+ const start = await startLocalCodexRunnerInstance(options, provider);
825
+ const oracles = await runBackendReplayOracles(options, start, provider);
826
+
827
+ return {
828
+ runnerId: options.runnerId,
829
+ instanceId: runner.instanceId,
830
+ codexUrl: runner.codexUrl,
831
+ frontendTarget: frontendReplayTarget(options, start.threadId),
832
+ start,
833
+ oracles,
834
+ ...(wireServer === undefined ? {} : { wire: wireServer.report() }),
835
+ };
836
+ } finally {
837
+ await runner.close();
838
+ }
772
839
  } finally {
773
- await runner.close();
840
+ await wireServer?.close();
774
841
  }
775
842
  }
776
843
 
@@ -1357,7 +1424,8 @@ const backendReplayThreadOutputQuery = `
1357
1424
  function backendReplayRunnerOptions(
1358
1425
  options: BackendReplayOptions,
1359
1426
  provider: string,
1360
- token: string
1427
+ token: string,
1428
+ wireCodexUrl?: string | undefined
1361
1429
  ): RunnerOptions {
1362
1430
  return {
1363
1431
  kandanUrl: options.backendUrl ?? '',
@@ -1367,15 +1435,21 @@ function backendReplayRunnerOptions(
1367
1435
  workspaceSlug: options.workspace,
1368
1436
  cwd: options.cwd,
1369
1437
  codexBin: process.env.CODEX_BIN ?? 'codex',
1370
- codexUrl: undefined,
1438
+ // Wire mode: the runner connects its REAL websocket client to the stub
1439
+ // codex app-server through the same --codex-url seam it uses for a real
1440
+ // pre-started codex, instead of substituting an in-process fake client.
1441
+ codexUrl: wireCodexUrl,
1371
1442
  launchTui: false,
1372
1443
  allowedCwds: [options.cwd],
1373
1444
  channelSession: undefined,
1374
- agentReplay: {
1375
- fixturePath: options.fixturePath,
1376
- provider: options.provider,
1377
- clockMode: parseAgentReplayClockMode(options.speed),
1378
- },
1445
+ agentReplay:
1446
+ wireCodexUrl !== undefined
1447
+ ? undefined
1448
+ : {
1449
+ fixturePath: options.fixturePath,
1450
+ provider: options.provider,
1451
+ clockMode: parseAgentReplayClockMode(options.speed),
1452
+ },
1379
1453
  };
1380
1454
  }
1381
1455
 
@@ -1832,7 +1906,7 @@ function argValue(args: readonly string[], name: string): string | undefined {
1832
1906
 
1833
1907
  function printHelp(): void {
1834
1908
  process.stdout.write(
1835
- `Usage: pnpm run replay:agent-backend -- --fixture <path> [options]\n\nOptions:\n --dry-run Validate fixture/manifest/diagnostics without backend connection\n --probe-backend Also join the real Phoenix local_runner channel, then exit\n --provider auto|codex|claude-code Replay provider. Default: auto\n --speed immediate|realtime|<n>x|<n>ms\n Replay speed. Default: immediate\n --backend-url <url> Local Phoenix backend URL; required by --probe-backend/replay\n --setup-fixture Create a throwaway fixture user/workspace/channel first; requires local fixture registration\n --setup-label <label> Prefix for throwaway fixture setup. Default: agent-backend-replay\n --workspace <slug> Target workspace slug for session-token exchange and future replay\n --channel <slug> Target channel slug for token scoping and future replay\n --thread-id <id> Target thread id for the future backend replay slice\n --runner-id <id> Local runner id for backend probing. Default: generated\n --cwd <path> Cwd advertised in backend probe/replay. Default: current directory\n --work-description <text> Work description sent through the normal start mutation\n --token <token> Local-runner token; also reads LINZUMI_AGENT_BACKEND_REPLAY_TOKEN\n --session-token <token> Browser/session token to exchange for a local-runner token; also reads LINZUMI_AGENT_BACKEND_REPLAY_SESSION_TOKEN\n --out-dir <path> Artifact directory for summary.json. Default: agent-backend-replay-output\n --require-feature <featureId> Fail before backend setup unless manifest readiness says the feature is ready\n --oracle-feature <featureId> Run feature-specific backend oracles without using readiness as a preflight gate\n --no-summary Do not write summary.json; stdout JSON is still printed\n\nExamples:\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --dry-run\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --probe-backend --backend-url http://127.0.0.1:4140 --workspace default --session-token <browser-session-token>\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --backend-url http://127.0.0.1:4140 --setup-fixture\n`
1909
+ `Usage: pnpm run replay:agent-backend -- --fixture <path> [options]\n\nOptions:\n --dry-run Validate fixture/manifest/diagnostics without backend connection\n --probe-backend Also join the real Phoenix local_runner channel, then exit\n --provider auto|codex|claude-code Replay provider. Default: auto\n --speed immediate|realtime|<n>x|<n>ms\n Replay speed. Default: immediate\n --backend-url <url> Local Phoenix backend URL; required by --probe-backend/replay\n --setup-fixture Create a throwaway fixture user/workspace/channel first; requires local fixture registration\n --setup-label <label> Prefix for throwaway fixture setup. Default: agent-backend-replay\n --workspace <slug> Target workspace slug for session-token exchange and future replay\n --channel <slug> Target channel slug for token scoping and future replay\n --thread-id <id> Target thread id for the future backend replay slice\n --runner-id <id> Local runner id for backend probing. Default: generated\n --cwd <path> Cwd advertised in backend probe/replay. Default: current directory\n --work-description <text> Work description sent through the normal start mutation\n --token <token> Local-runner token; also reads LINZUMI_AGENT_BACKEND_REPLAY_TOKEN\n --session-token <token> Browser/session token to exchange for a local-runner token; also reads LINZUMI_AGENT_BACKEND_REPLAY_SESSION_TOKEN\n --out-dir <path> Artifact directory for summary.json. Default: agent-backend-replay-output\n --wire Serve the fixture from the stub codex app-server websocket (spec/codex-wire-capture-replay.spec.md) so the runner's real socket machinery is exercised\n --wire-strictness shape|exact Wire mode validation of runner-sent packets against the recording. Default: shape\n --require-feature <featureId> Fail before backend setup unless manifest readiness says the feature is ready\n --oracle-feature <featureId> Run feature-specific backend oracles without using readiness as a preflight gate\n --no-summary Do not write summary.json; stdout JSON is still printed\n\nExamples:\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --dry-run\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --probe-backend --backend-url http://127.0.0.1:4140 --workspace default --session-token <browser-session-token>\n pnpm --filter @linzumi/cli run replay:agent-backend -- --fixture test/fixtures/agent-raw-replay/real-probe/claude.ndjson --provider claude-code --backend-url http://127.0.0.1:4140 --setup-fixture\n`
1836
1910
  );
1837
1911
  }
1838
1912