@linzumi/cli 1.0.170 → 1.0.172
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/index.js +1 -1
- package/dist/impl-ts/index.js +238 -238
- package/package.json +1 -1
- package/scripts/codex-wire-canary.sh +56 -0
- package/scripts/replay-agent-backend.ts +45 -2
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex wire canary launcher (spec/codex-wire-capture-replay.spec.md, "Live
|
|
3
|
+
# canary lane"): resolves the wire corpus + the pinned @openai/codex version
|
|
4
|
+
# and runs the ReScript canary bin (HarnessCodexWireCanaryMain.res).
|
|
5
|
+
#
|
|
6
|
+
# codex-wire-canary.sh corpus the scheduled corpus check
|
|
7
|
+
# (fidelity + shape baseline +
|
|
8
|
+
# freshness vs the pinned codex)
|
|
9
|
+
# codex-wire-canary.sh fresh <capture> drift-diff a freshly recorded
|
|
10
|
+
# canary capture BEFORE promotion
|
|
11
|
+
#
|
|
12
|
+
# The canary corpus is every wire capture the replay lane treats as real
|
|
13
|
+
# wire truth: test/fixtures/agent-raw-replay/wire-corpus/*.ndjson plus the
|
|
14
|
+
# real-probe session (test/fixtures/agent-raw-replay/real-probe/codex.ndjson).
|
|
15
|
+
# The committed shape baseline lives beside the corpus
|
|
16
|
+
# (wire-corpus/shape-baseline.json); the vitest corpus gate pins the same
|
|
17
|
+
# set, so this script and the test cannot disagree silently.
|
|
18
|
+
#
|
|
19
|
+
# Build the ReScript package first (`npx rescript build
|
|
20
|
+
# packages/linzumi-cli-rescript`); the CLI test pipeline already does.
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
cli_root="$(cd "$here/.." && pwd)"
|
|
25
|
+
bin_module="$cli_root/../linzumi-cli-rescript/src/harness/HarnessCodexWireCanaryMain.res.mjs"
|
|
26
|
+
baseline="$cli_root/test/fixtures/agent-raw-replay/wire-corpus/shape-baseline.json"
|
|
27
|
+
|
|
28
|
+
if [[ ! -f "$bin_module" ]]; then
|
|
29
|
+
echo "codex-wire-canary: compiled module missing at $bin_module - run: npx rescript build <repo>/packages/linzumi-cli-rescript" >&2
|
|
30
|
+
exit 66
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
mode="${1:-}"
|
|
34
|
+
case "$mode" in
|
|
35
|
+
corpus)
|
|
36
|
+
pinned_version="$(node -p "require('$cli_root/package.json').dependencies['@openai/codex'].replace(/^[^0-9]*/, '')")"
|
|
37
|
+
captures=("$cli_root"/test/fixtures/agent-raw-replay/wire-corpus/*.ndjson)
|
|
38
|
+
captures+=("$cli_root/test/fixtures/agent-raw-replay/real-probe/codex.ndjson")
|
|
39
|
+
exec node "$bin_module" corpus \
|
|
40
|
+
--baseline "$baseline" \
|
|
41
|
+
--pinned-codex-version "$pinned_version" \
|
|
42
|
+
"${captures[@]}"
|
|
43
|
+
;;
|
|
44
|
+
fresh)
|
|
45
|
+
shift
|
|
46
|
+
if [[ $# -lt 1 ]]; then
|
|
47
|
+
echo "codex-wire-canary: fresh mode needs the freshly recorded capture path" >&2
|
|
48
|
+
exit 64
|
|
49
|
+
fi
|
|
50
|
+
exec node "$bin_module" fresh --baseline "$baseline" "$@"
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
echo "codex-wire-canary: unknown mode '${mode}' (use corpus or fresh)" >&2
|
|
54
|
+
exit 64
|
|
55
|
+
;;
|
|
56
|
+
esac
|
|
@@ -67,6 +67,15 @@ type BackendReplayOptions = {
|
|
|
67
67
|
// machinery is exercised against the REAL backend.
|
|
68
68
|
readonly wire: boolean;
|
|
69
69
|
readonly wireStrictness: string | undefined;
|
|
70
|
+
// Replay-to-a-point (spec §Replay-to-a-point): --wire-breakpoint specs
|
|
71
|
+
// for the wire stub (`ordinal:<n>`, `method:<rpcMethod>[:<n>]`,
|
|
72
|
+
// `first-delta`, `turn-started[:<n>]`, `turn-completed[:<n>]`), in hold
|
|
73
|
+
// order. While the stub holds, the whole stack (runner -> backend ->
|
|
74
|
+
// client projection) is frozen at the recorded prefix; an external
|
|
75
|
+
// driver (Playwright DOM assertions, the film rig) observes and releases
|
|
76
|
+
// the hold over the stub's HTTP control routes (GET /replay/breakpoint,
|
|
77
|
+
// POST /replay/resume against the printed control URL).
|
|
78
|
+
readonly wireBreakpoints: readonly string[];
|
|
70
79
|
};
|
|
71
80
|
|
|
72
81
|
type WireReplayServerHandle = {
|
|
@@ -93,6 +102,7 @@ async function startWireReplayServerForFixture(
|
|
|
93
102
|
readonly capturePath?: string;
|
|
94
103
|
readonly strictness?: string | undefined;
|
|
95
104
|
readonly clock?: string | undefined;
|
|
105
|
+
readonly breakpoints?: readonly string[];
|
|
96
106
|
}) => Promise<WireReplayServerHandle>;
|
|
97
107
|
wireReplayClockForBackendSpeed: (
|
|
98
108
|
speed: string | undefined
|
|
@@ -105,13 +115,27 @@ async function startWireReplayServerForFixture(
|
|
|
105
115
|
// test/agentReplayFixture.test.ts.
|
|
106
116
|
const wireClock = wireModule.wireReplayClockForBackendSpeed(options.speed);
|
|
107
117
|
|
|
108
|
-
|
|
118
|
+
const server = await wireModule.startWireReplayServerJs({
|
|
109
119
|
capturePath: options.fixturePath,
|
|
110
120
|
...(options.wireStrictness === undefined
|
|
111
121
|
? {}
|
|
112
122
|
: { strictness: options.wireStrictness }),
|
|
113
123
|
...(wireClock === undefined ? {} : { clock: wireClock }),
|
|
124
|
+
...(options.wireBreakpoints.length === 0
|
|
125
|
+
? {}
|
|
126
|
+
: { breakpoints: options.wireBreakpoints }),
|
|
114
127
|
});
|
|
128
|
+
if (options.wireBreakpoints.length > 0) {
|
|
129
|
+
// The external driver's handle on the frozen stack: poll GET
|
|
130
|
+
// /replay/breakpoint until held, assert on the frozen DOM/projection,
|
|
131
|
+
// then POST /replay/resume.
|
|
132
|
+
console.error(
|
|
133
|
+
`[wire-breakpoint] control http://127.0.0.1:${server.port} breakpoints=${options.wireBreakpoints.join(
|
|
134
|
+
','
|
|
135
|
+
)}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return server;
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
type BackendReplayBrowserAuth = {
|
|
@@ -403,6 +427,7 @@ function parseArgs(args: readonly string[]): BackendReplayOptions {
|
|
|
403
427
|
oracleFeatureId: argValue(args, '--oracle-feature'),
|
|
404
428
|
wire: args.includes('--wire'),
|
|
405
429
|
wireStrictness: argValue(args, '--wire-strictness'),
|
|
430
|
+
wireBreakpoints: argValues(args, '--wire-breakpoint'),
|
|
406
431
|
};
|
|
407
432
|
}
|
|
408
433
|
|
|
@@ -1888,6 +1913,24 @@ function evaluateRequiredFeatureGate(
|
|
|
1888
1913
|
}
|
|
1889
1914
|
}
|
|
1890
1915
|
|
|
1916
|
+
// Every value of a repeatable flag, in argv order (--wire-breakpoint may
|
|
1917
|
+
// name several ordered holds).
|
|
1918
|
+
function argValues(args: readonly string[], name: string): readonly string[] {
|
|
1919
|
+
const values: string[] = [];
|
|
1920
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1921
|
+
if (args[index] !== name) {
|
|
1922
|
+
continue;
|
|
1923
|
+
}
|
|
1924
|
+
const value = args[index + 1];
|
|
1925
|
+
if (value === undefined) {
|
|
1926
|
+
throw new Error(`${name} requires a value`);
|
|
1927
|
+
}
|
|
1928
|
+
values.push(value);
|
|
1929
|
+
index += 1;
|
|
1930
|
+
}
|
|
1931
|
+
return values;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1891
1934
|
function argValue(args: readonly string[], name: string): string | undefined {
|
|
1892
1935
|
const index = args.indexOf(name);
|
|
1893
1936
|
|
|
@@ -1906,7 +1949,7 @@ function argValue(args: readonly string[], name: string): string | undefined {
|
|
|
1906
1949
|
|
|
1907
1950
|
function printHelp(): void {
|
|
1908
1951
|
process.stdout.write(
|
|
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`
|
|
1952
|
+
`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 --wire-breakpoint <spec> Replay-to-a-point hold (repeatable, ordered): ordinal:<n> | method:<rpcMethod>[:<n>] | first-delta | turn-started[:<n>] | turn-completed[:<n>]. The stub freezes the stack at the hold; observe/release via GET /replay/breakpoint + POST /replay/resume on the printed control URL\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`
|
|
1910
1953
|
);
|
|
1911
1954
|
}
|
|
1912
1955
|
|