@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/README.md +1 -1
- package/dist/impl-res/cloud-supervisor.mjs +11 -11
- package/dist/impl-res/index.js +1 -1
- package/dist/impl-ts/cloud-supervisor.mjs +11 -11
- package/dist/impl-ts/index.js +431 -431
- package/package.json +1 -1
- package/scripts/bump-cli-version.mjs +15 -1
- package/scripts/codex-wire-replay-bin.sh +26 -0
- package/scripts/replay-agent-backend.ts +96 -22
package/package.json
CHANGED
|
@@ -246,7 +246,21 @@ function scanTargets() {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
for (const entry of entries) {
|
|
249
|
-
|
|
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
|
|
757
|
-
|
|
758
|
-
|
|
809
|
+
const wireServer = options.wire
|
|
810
|
+
? await startWireReplayServerForFixture(options)
|
|
811
|
+
: undefined;
|
|
759
812
|
|
|
760
813
|
try {
|
|
761
|
-
const
|
|
762
|
-
|
|
814
|
+
const runner = await runLocalCodexRunner(
|
|
815
|
+
backendReplayRunnerOptions(
|
|
816
|
+
options,
|
|
817
|
+
provider,
|
|
818
|
+
runnerToken,
|
|
819
|
+
wireServer?.url
|
|
820
|
+
)
|
|
821
|
+
);
|
|
763
822
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
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
|
|