@wjarka/cezarion 0.14.8 → 0.14.9-dev.842
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 +76 -2
- package/dist/application-update/bin-recovery.d.ts +5 -0
- package/dist/application-update/bin-recovery.js +96 -0
- package/dist/application-update/bin-recovery.js.map +1 -0
- package/dist/application-update/discovery.d.ts +22 -0
- package/dist/application-update/discovery.js +91 -0
- package/dist/application-update/discovery.js.map +1 -0
- package/dist/application-update/helper.d.ts +57 -0
- package/dist/application-update/helper.js +374 -0
- package/dist/application-update/helper.js.map +1 -0
- package/dist/application-update/launcher.d.ts +8 -0
- package/dist/application-update/launcher.js +53 -0
- package/dist/application-update/launcher.js.map +1 -0
- package/dist/application-update/lock.d.ts +4 -0
- package/dist/application-update/lock.js +70 -0
- package/dist/application-update/lock.js.map +1 -0
- package/dist/application-update/npm-process.d.ts +17 -0
- package/dist/application-update/npm-process.js +133 -0
- package/dist/application-update/npm-process.js.map +1 -0
- package/dist/application-update/service.d.ts +69 -0
- package/dist/application-update/service.js +456 -0
- package/dist/application-update/service.js.map +1 -0
- package/dist/artifacts/cli.d.ts +1 -0
- package/dist/artifacts/cli.js +32 -0
- package/dist/artifacts/cli.js.map +1 -0
- package/dist/artifacts/lifecycle.d.ts +4 -0
- package/dist/artifacts/lifecycle.js +42 -0
- package/dist/artifacts/lifecycle.js.map +1 -0
- package/dist/artifacts/resolve.d.ts +18 -0
- package/dist/artifacts/resolve.js +102 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/artifacts/store.d.ts +8 -0
- package/dist/artifacts/store.js +323 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/ci-wait/mcp.d.ts +3 -0
- package/dist/ci-wait/mcp.js +14 -3
- package/dist/ci-wait/mcp.js.map +1 -1
- package/dist/contract/application-update.d.ts +32 -0
- package/dist/contract/artifacts.d.ts +83 -0
- package/dist/contract/ask-schema.d.ts +32 -0
- package/dist/contract/ask.d.ts +2 -32
- package/dist/contract/conversations.d.ts +165 -0
- package/dist/contract/delegation.d.ts +39 -0
- package/dist/contract/events.d.ts +49 -0
- package/dist/contract/health.d.ts +12 -0
- package/dist/contract/index.d.ts +2 -0
- package/dist/contract/index.js +1374 -1247
- package/dist/contract/runs.d.ts +143 -0
- package/dist/contract/skills.d.ts +28 -0
- package/dist/core/agent-runner.d.ts +33 -4
- package/dist/core/agent-runner.js +5 -0
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/claude-cli-runner.d.ts +6 -12
- package/dist/core/claude-cli-runner.js +89 -19
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/codex-app-server-runner.d.ts +2 -1
- package/dist/core/codex-app-server-runner.js +327 -92
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +13 -1
- package/dist/core/codex-app-server-transport.js +58 -17
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/core/cursor-acp-runner.d.ts +4 -1
- package/dist/core/cursor-acp-runner.js +3 -0
- package/dist/core/cursor-acp-runner.js.map +1 -1
- package/dist/core/cursor-provider-error.js +6 -1
- package/dist/core/cursor-provider-error.js.map +1 -1
- package/dist/core/input-submissions.d.ts +14 -0
- package/dist/core/input-submissions.js +26 -0
- package/dist/core/input-submissions.js.map +1 -0
- package/dist/core/opencode-server-runner.d.ts +4 -1
- package/dist/core/opencode-server-runner.js +144 -21
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/pi-runner.d.ts +2 -1
- package/dist/core/pi-runner.js +72 -7
- package/dist/core/pi-runner.js.map +1 -1
- package/dist/delegation/cli.js +102 -6
- package/dist/delegation/cli.js.map +1 -1
- package/dist/delegation/conversations.js +13 -5
- package/dist/delegation/conversations.js.map +1 -1
- package/dist/delegation/input.d.ts +2 -1
- package/dist/delegation/input.js +6 -1
- package/dist/delegation/input.js.map +1 -1
- package/dist/delegation/provision.js +5 -3
- package/dist/delegation/provision.js.map +1 -1
- package/dist/delegation/questions.d.ts +19 -0
- package/dist/delegation/questions.js +45 -0
- package/dist/delegation/questions.js.map +1 -0
- package/dist/delegation/results.d.ts +1 -1
- package/dist/delegation/results.js +23 -13
- package/dist/delegation/results.js.map +1 -1
- package/dist/delegation/routes.d.ts +142 -15
- package/dist/delegation/routes.js +4 -1
- package/dist/delegation/routes.js.map +1 -1
- package/dist/delegation/service.d.ts +9 -5
- package/dist/delegation/service.js +106 -7
- package/dist/delegation/service.js.map +1 -1
- package/dist/delegation/transport.d.ts +188 -61
- package/dist/index.js +72 -26
- package/dist/index.js.map +1 -1
- package/dist/open-url.d.ts +2 -0
- package/dist/open-url.js +20 -0
- package/dist/open-url.js.map +1 -0
- package/dist/release/snapshot.d.ts +3 -3
- package/dist/release/snapshot.js +6 -6
- package/dist/release/snapshot.js.map +1 -1
- package/dist/runs/client-request.d.ts +11 -0
- package/dist/runs/client-request.js +26 -0
- package/dist/runs/client-request.js.map +1 -0
- package/dist/runs/delegation-state.d.ts +17 -0
- package/dist/runs/event-history.js +6 -0
- package/dist/runs/event-history.js.map +1 -1
- package/dist/runs/store.d.ts +78 -6
- package/dist/runs/store.js +163 -1
- package/dist/runs/store.js.map +1 -1
- package/dist/server/server.d.ts +3761 -1648
- package/dist/server/server.js +170 -4
- package/dist/server/server.js.map +1 -1
- package/dist/task-cli/cli.d.ts +38 -0
- package/dist/task-cli/cli.js +463 -0
- package/dist/task-cli/cli.js.map +1 -0
- package/dist/task-cli/discovery.d.ts +22 -0
- package/dist/task-cli/discovery.js +95 -0
- package/dist/task-cli/discovery.js.map +1 -0
- package/dist/task-cli/http.d.ts +43 -0
- package/dist/task-cli/http.js +101 -0
- package/dist/task-cli/http.js.map +1 -0
- package/dist/task-cli/projections.d.ts +40 -0
- package/dist/task-cli/projections.js +45 -0
- package/dist/task-cli/projections.js.map +1 -0
- package/dist/task-cli/watch.d.ts +78 -0
- package/dist/task-cli/watch.js +336 -0
- package/dist/task-cli/watch.js.map +1 -0
- package/dist/workflows/run.d.ts +93 -0
- package/dist/workflows/run.js +816 -81
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/projects-cli.js +1 -1
- package/package.json +3 -3
- package/scripts/mock-claude.mjs +38 -2
- package/scripts/mock-codex-app-server.mjs +98 -1
- package/scripts/mock-cursor-acp.mjs +8 -0
- package/scripts/mock-opencode-serve.mjs +69 -2
- package/scripts/mock-pi-rpc.mjs +63 -2
- package/web/dist/assets/agent-accounts-JPfZPgKn.js +1 -0
- package/web/dist/assets/centered-state-HwCqQkH3.js +43 -0
- package/web/dist/assets/collapsible-CTymFdL7.js +1 -0
- package/web/dist/assets/commit-list-BZpYGQl2.js +1 -0
- package/web/dist/assets/compare-variants-9VkybaQ7.js +1 -0
- package/web/dist/assets/{diff-tRE59UNb2.js → diff-CZcD4D1r2.js} +2 -2
- package/web/dist/assets/diff-controls-CpcHG3Mm.js +1 -0
- package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-Cn7rzy1H.js} +1 -1
- package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-C46nHiP2.js} +2 -2
- package/web/dist/assets/dropdown-menu-_YAzCaoQ.js +1 -0
- package/web/dist/assets/git-toolbar-BvKDz6uS.js +1 -0
- package/web/dist/assets/github-CgjJCGrD.js +1 -0
- package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-B618kDBH.js} +1 -1
- package/web/dist/assets/index-BJtve0Pm.js +7 -0
- package/web/dist/assets/index-D0WAgmTQ.css +1 -0
- package/web/dist/assets/markdown-CFWZnvMh.js +2 -0
- package/web/dist/assets/pill-QfwkuR50.js +1 -0
- package/web/dist/assets/project-router-CkAA39N5.js +1 -0
- package/web/dist/assets/prompt-templates-Cfna_S0T.js +15 -0
- package/web/dist/assets/repo-git-DgzgJ0cP.js +1 -0
- package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-YbCEQn5I.js} +2 -2
- package/web/dist/assets/run-header-DMgIbr1d.js +1 -0
- package/web/dist/assets/skills-BW79kUTd.js +1 -0
- package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-MIHvczEm.js} +1 -1
- package/web/dist/assets/task-changes-C96ekt94.js +1 -0
- package/web/dist/assets/task-commits-DBfcMZyG.js +1 -0
- package/web/dist/assets/task-files-BKpH8dKQ.js +2 -0
- package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
- package/web/dist/assets/task-thread-Dnq7Ek6W.js +9 -0
- package/web/dist/assets/textarea-D2vAVgYW.js +1 -0
- package/web/dist/assets/thread-loading-NW8Mthco.js +1 -0
- package/web/dist/assets/token-metrics-D188e6_0.js +1 -0
- package/web/dist/assets/utils-DKheTxGD.js +64 -0
- package/web/dist/assets/workflows-BFY1hgp3.js +11 -0
- package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-YW3Qdrr_.js} +1 -1
- package/web/dist/index.html +14 -14
- package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
- package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
- package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
- package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
- package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
- package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
- package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
- package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
- package/web/dist/assets/github-D-MrkbJ7.js +0 -1
- package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
- package/web/dist/assets/index-BszfYvBq.js +0 -7
- package/web/dist/assets/index-CWh4pKP3.css +0 -1
- package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
- package/web/dist/assets/pill-BsbO6G7y.js +0 -1
- package/web/dist/assets/project-router-DbLkll25.js +0 -1
- package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
- package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
- package/web/dist/assets/run-header-IFyIGCey.js +0 -1
- package/web/dist/assets/skills-C-C4DVFY.js +0 -1
- package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
- package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
- package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
- package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
- package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
- package/web/dist/assets/textarea-FjaU370i.js +0 -1
- package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
- package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
- package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
- package/web/dist/assets/workflows-Czl0ZfXH.js +0 -11
|
@@ -10,7 +10,7 @@ const defaultIo = {
|
|
|
10
10
|
const USAGE = `usage:
|
|
11
11
|
cez projects [list] list the registered projects
|
|
12
12
|
cez projects add [<dir>] register a folder (default: --repo, else cwd)
|
|
13
|
-
cez projects remove <id>
|
|
13
|
+
cez projects remove|rm <id> drop a registry entry (the repo is untouched)
|
|
14
14
|
cez projects tag <id> [<tag>…]
|
|
15
15
|
set the grouping tags of a project (none clears them)
|
|
16
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wjarka/cezarion",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.9-dev.842",
|
|
4
4
|
"description": "Local cockpit for running and tracking AI agent tasks in your repo. Uses your logged-in `claude` CLI and `gh` — zero config, zero database.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"zod": "^4.4.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@open-mercato/cezar-api-client": "
|
|
55
|
-
"@open-mercato/cezar-contract": "
|
|
54
|
+
"@open-mercato/cezar-api-client": "0.14.9-dev.842",
|
|
55
|
+
"@open-mercato/cezar-contract": "0.14.9-dev.842",
|
|
56
56
|
"@types/node": "^20.14.0",
|
|
57
57
|
"@types/ws": "^8.18.1",
|
|
58
58
|
"esbuild": "^0.28.1",
|
package/scripts/mock-claude.mjs
CHANGED
|
@@ -11,6 +11,12 @@ import { appendFileSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
11
11
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
12
12
|
const emit = (obj) => process.stdout.write(`${JSON.stringify(obj)}\n`);
|
|
13
13
|
|
|
14
|
+
// `--help` lists the options cezar feature-detects (#505).
|
|
15
|
+
if (process.argv.includes('--help')) {
|
|
16
|
+
process.stdout.write('Usage: claude [options]\n --input-format <format>\n --replay-user-messages Re-emit user messages from stdin back on stdout\n');
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
// Testability hook: CEZ_MOCK_ARGS_FILE=<path> appends the argv this mock was
|
|
15
21
|
// spawned with (one JSON array per line), so tests and dry-run proofs can
|
|
16
22
|
// assert exactly what reached the CLI (e.g. `--append-system-prompt …`).
|
|
@@ -26,6 +32,14 @@ if (process.env.CEZ_MOCK_CI_PR) { const { probeCiTool } = await import('./mock-c
|
|
|
26
32
|
emit({ type: 'system', subtype: 'init' });
|
|
27
33
|
|
|
28
34
|
let turn = 0;
|
|
35
|
+
// #505: `--replay-user-messages` echoes each stdin line when the model consumes it.
|
|
36
|
+
const replay = process.argv.includes('--replay-user-messages') && process.env.CEZ_MOCK_CLAUDE_NO_REPLAY !== '1';
|
|
37
|
+
const emitReplay = (uuid, text) => {
|
|
38
|
+
if (replay && uuid) emit({ type: 'user', isReplay: true, uuid, message: { role: 'user', content: [{ type: 'text', text }] } });
|
|
39
|
+
};
|
|
40
|
+
// Non-null while a `mock:steer-tool` turn is inside its tool: later lines join that turn.
|
|
41
|
+
let steering = null;
|
|
42
|
+
let droppedOnce = false;
|
|
29
43
|
|
|
30
44
|
// A tiny generated PNG (320x200) standing in for a browser screenshot.
|
|
31
45
|
const MOCK_SCREENSHOT_B64 =
|
|
@@ -75,7 +89,22 @@ function writeHandoffAndTodo() {
|
|
|
75
89
|
}
|
|
76
90
|
}
|
|
77
91
|
|
|
78
|
-
async function respond(userText, imageCount) {
|
|
92
|
+
async function respond(userText, imageCount, uuid) {
|
|
93
|
+
emitReplay(uuid, userText);
|
|
94
|
+
// `mock:steer-tool` → one tool call; lines written while it runs are consumed after
|
|
95
|
+
// it (replayed with their uuid) and settled by the SAME result, like Claude 2.1.280 (#505).
|
|
96
|
+
if (userText.includes('mock:steer-tool')) {
|
|
97
|
+
steering = [];
|
|
98
|
+
emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_steer', name: 'Bash', input: { command: 'wait' } }] } });
|
|
99
|
+
await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600));
|
|
100
|
+
const steered = steering; steering = null;
|
|
101
|
+
emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_steer', content: 'waited' }] } });
|
|
102
|
+
for (const s of steered) emitReplay(s.uuid, s.userText);
|
|
103
|
+
const text = ['steer tool done', ...steered.map(s => `saw: ${s.userText}`)].join('\n');
|
|
104
|
+
emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
|
|
105
|
+
emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid, ...steered.map(s => s.uuid)].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
79
108
|
if (userText.includes('mock:ci-wait')) {
|
|
80
109
|
const { ciPrompt } = await import('./mock-ci-tool.mjs');
|
|
81
110
|
const text = await ciPrompt('claude', process.argv.slice(2), userText);
|
|
@@ -583,6 +612,7 @@ rl.on('line', (line) => {
|
|
|
583
612
|
if (!trimmed) return;
|
|
584
613
|
let userText = '(unparseable message)';
|
|
585
614
|
let imageCount = 0;
|
|
615
|
+
let uuid;
|
|
586
616
|
try {
|
|
587
617
|
const msg = JSON.parse(trimmed);
|
|
588
618
|
if (msg.type === 'control_request' && msg.request?.subtype === 'list_models') {
|
|
@@ -595,6 +625,7 @@ rl.on('line', (line) => {
|
|
|
595
625
|
})}\n`);
|
|
596
626
|
return;
|
|
597
627
|
}
|
|
628
|
+
uuid = typeof msg.uuid === 'string' ? msg.uuid : undefined;
|
|
598
629
|
const blocks = msg?.message?.content ?? [];
|
|
599
630
|
userText = blocks.filter((b) => b.type === 'text').map((b) => b.text).join('\n') || '(no text)';
|
|
600
631
|
imageCount = blocks.filter((b) => b.type === 'image').length;
|
|
@@ -613,7 +644,12 @@ rl.on('line', (line) => {
|
|
|
613
644
|
// best effort — never break the mock over the hook
|
|
614
645
|
}
|
|
615
646
|
}
|
|
616
|
-
|
|
647
|
+
// #505 liveness tests: silently drop a matching line (a harness that accepted input
|
|
648
|
+
// and never runs it). CEZ_MOCK_DROP_ONCE=1 drops only the first match.
|
|
649
|
+
const drop = process.env.CEZ_MOCK_DROP_LINES;
|
|
650
|
+
if (drop && userText.includes(drop) && !(process.env.CEZ_MOCK_DROP_ONCE === '1' && droppedOnce)) { droppedOnce = true; return; }
|
|
651
|
+
if (steering) { steering.push({ userText, uuid }); return; }
|
|
652
|
+
queue = queue.then(() => respond(userText, imageCount, uuid));
|
|
617
653
|
});
|
|
618
654
|
rl.on('close', () => {
|
|
619
655
|
// EOF = session over; finish any in-flight turn then exit cleanly.
|
|
@@ -11,10 +11,42 @@
|
|
|
11
11
|
import { createInterface } from 'node:readline';
|
|
12
12
|
import { appendFileSync } from 'node:fs';
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const write = (obj) => process.stdout.write(`${JSON.stringify(obj)}\n`);
|
|
15
|
+
// #505: like the real app-server, any active main-thread turn accepts `turn/steer`.
|
|
16
|
+
// Steers accepted by an ordinary scripted turn are read just before it completes:
|
|
17
|
+
// a userMessage item (echoing clientUserMessageId as clientId) and an echo reply.
|
|
18
|
+
let activeTurnId = null;
|
|
19
|
+
let pendingSteers = [];
|
|
20
|
+
let steerEchoSerial = 0;
|
|
21
|
+
const emit = (obj) => {
|
|
22
|
+
const ending = (obj.method === 'turn/completed' || obj.method === 'turn/failed') && (!obj.params?.threadId || obj.params.threadId === 'th_mock_1');
|
|
23
|
+
if (ending && obj.method === 'turn/completed' && pendingSteers.length) {
|
|
24
|
+
const turnId = activeTurnId ?? 'turn_mock_1';
|
|
25
|
+
for (const entry of pendingSteers.splice(0)) {
|
|
26
|
+
const item = { type: 'userMessage', id: `item_user_generic_${++steerEchoSerial}`, clientId: entry.clientId, content: [{ type: 'text', text: entry.text }] };
|
|
27
|
+
write({ method: 'item/started', params: { threadId: 'th_mock_1', turnId, item } });
|
|
28
|
+
write({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId, item } });
|
|
29
|
+
write({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId, item: { type: 'agentMessage', id: `item_steer_echo_${steerEchoSerial}`, text: entry.text } } });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (ending) { activeTurnId = null; pendingSteers = []; }
|
|
33
|
+
write(obj);
|
|
34
|
+
// #505 review: CEZ_MOCK_CODEX_LATE_START_ACK=1 answers turn/start after the turn completed.
|
|
35
|
+
if (ending && lateStartAck !== undefined) { const id = lateStartAck; lateStartAck = undefined; write({ id, result: { turn: { id: 'turn_mock_1' } } }); }
|
|
36
|
+
};
|
|
37
|
+
let lateStartAck;
|
|
38
|
+
let startSerial = 0;
|
|
15
39
|
const rl = createInterface({ input: process.stdin });
|
|
16
40
|
let echoSerial = 0;
|
|
17
41
|
let ciWire;
|
|
42
|
+
// #505 steering scenarios: the one turn that accepts `turn/steer`, while it is open.
|
|
43
|
+
let steerTurn = null;
|
|
44
|
+
let steerSerial = 0;
|
|
45
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
46
|
+
const completeSteerTurn = (turnId) => {
|
|
47
|
+
steerTurn = null;
|
|
48
|
+
emit({ method: 'turn/completed', params: { threadId: 'th_mock_1', turn: { id: turnId, status: 'completed' } } });
|
|
49
|
+
};
|
|
18
50
|
|
|
19
51
|
const ignoreEof = process.env.MOCK_CODEX_IGNORE_EOF === '1';
|
|
20
52
|
if (ignoreEof) {
|
|
@@ -43,6 +75,34 @@ rl.on('line', async (line) => {
|
|
|
43
75
|
emit((Array.isArray(answer) && answer[0] === 'Vitest') || (Array.isArray(freeText) && freeText[0] === 'Use sensible defaults')
|
|
44
76
|
? { method: 'turn/completed', params: { turn: { id: 'turn_mock_1', status: 'completed' } } }
|
|
45
77
|
: { method: 'turn/failed', params: { turn: { id: 'turn_mock_1', status: 'failed' }, error: { message: 'bad answer' } } });
|
|
78
|
+
} else if (msg.method === 'turn/steer') {
|
|
79
|
+
// #505 ambiguity: the transport dies with the steer unanswered.
|
|
80
|
+
if (process.env.CEZ_MOCK_CODEX_EXIT_ON_STEER === '1') process.exit(1);
|
|
81
|
+
const turn = steerTurn;
|
|
82
|
+
if (!turn && activeTurnId && msg.params?.expectedTurnId === activeTurnId) {
|
|
83
|
+
pendingSteers.push({ clientId: msg.params?.clientUserMessageId ?? null, text: msg.params?.input?.map?.((part) => part.text ?? '').join('\n') ?? '' });
|
|
84
|
+
emit({ id: msg.id, result: {} });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!turn || msg.params?.expectedTurnId !== turn.id) {
|
|
88
|
+
emit({ id: msg.id, error: { code: -32600, message: 'no active turn matching expectedTurnId' } });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const text = msg.params?.input?.map?.((part) => part.text ?? '').join('\n') ?? '';
|
|
92
|
+
if (turn.strand) {
|
|
93
|
+
// The turn completes first, then the server acknowledges the steer: nothing reads it.
|
|
94
|
+
completeSteerTurn(turn.id);
|
|
95
|
+
emit({ id: msg.id, result: {} });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (turn.race) {
|
|
99
|
+
// The turn ends before the server processes the steer: a definitive mismatch.
|
|
100
|
+
completeSteerTurn(turn.id);
|
|
101
|
+
emit({ id: msg.id, error: { code: -32600, message: 'no active turn matching expectedTurnId' } });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
turn.steered.push({ clientId: msg.params?.clientUserMessageId ?? null, text });
|
|
105
|
+
emit({ id: msg.id, result: {} });
|
|
46
106
|
} else if (msg.method === 'initialize') {
|
|
47
107
|
emit({ id: msg.id, result: { userAgent: 'mock-codex/0.0.0' } });
|
|
48
108
|
} else if (msg.method === 'thread/start' || msg.method === 'thread/resume') {
|
|
@@ -67,9 +127,20 @@ rl.on('line', async (line) => {
|
|
|
67
127
|
emit({ id: msg.id, result: { thread: { id: msg.params?.threadId } } });
|
|
68
128
|
}
|
|
69
129
|
} else if (msg.method === 'turn/start') {
|
|
130
|
+
activeTurnId = 'turn_mock_1';
|
|
131
|
+
// owned-input-delivery.testkit.ts patches the exact `emit(...)` line below; keep it verbatim.
|
|
132
|
+
if (process.env.CEZ_MOCK_CODEX_LATE_START_ACK === '1' && startSerial++ > 0) lateStartAck = msg.id; else {
|
|
70
133
|
emit({ id: msg.id, result: { turn: { id: 'turn_mock_1' } } });
|
|
134
|
+
}
|
|
71
135
|
emit({ method: 'turn/started', params: { turn: { id: 'turn_mock_1', status: 'inProgress', items: [] } } });
|
|
72
136
|
const turnText = msg.params?.input?.map?.((part) => part.text ?? '').join('\n') ?? '';
|
|
137
|
+
// The real app-server records the turn's own input as a userMessage item,
|
|
138
|
+
// echoing clientUserMessageId as clientId (probe 0.155.1, #505).
|
|
139
|
+
const opening = { type: 'userMessage', id: `item_user_open_${++steerEchoSerial}`, clientId: msg.params?.clientUserMessageId ?? null, content: [{ type: 'text', text: turnText }] };
|
|
140
|
+
if (process.env.CEZ_MOCK_CODEX_NO_USER_ITEM !== '1') {
|
|
141
|
+
emit({ method: 'item/started', params: { threadId: 'th_mock_1', turnId: 'turn_mock_1', item: opening } });
|
|
142
|
+
emit({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId: 'turn_mock_1', item: opening } });
|
|
143
|
+
}
|
|
73
144
|
if (turnText.includes('mock:ci-wait')) {
|
|
74
145
|
const { ciPrompt } = await import('./mock-ci-tool.mjs');
|
|
75
146
|
const text = await ciPrompt('codex', ciWire, turnText);
|
|
@@ -77,6 +148,32 @@ rl.on('line', async (line) => {
|
|
|
77
148
|
emit({ method: 'turn/completed', params: { turn: { id: 'turn_mock_1', status: 'completed' } } });
|
|
78
149
|
return;
|
|
79
150
|
}
|
|
151
|
+
const steerScenario = ['mock:steer-tool', 'mock:steer-late', 'mock:steer-race', 'mock:steer-strand'].find((marker) => turnText.includes(marker));
|
|
152
|
+
if (steerScenario) {
|
|
153
|
+
const turnId = 'turn_mock_1';
|
|
154
|
+
steerTurn = { id: turnId, steered: [], race: steerScenario === 'mock:steer-race', strand: steerScenario === 'mock:steer-strand' };
|
|
155
|
+
const agent = (text) => emit({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId, item: { type: 'agentMessage', id: `item_steer_${++steerSerial}`, text } } });
|
|
156
|
+
if (steerScenario === 'mock:steer-late') {
|
|
157
|
+
agent(`late window: final message already sent${turnText.includes('mock:done-late') ? '\n\nCEZ:DONE' : ''}`);
|
|
158
|
+
await sleep(300);
|
|
159
|
+
completeSteerTurn(turnId); // steers accepted in this window are never read
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const exec = { type: 'commandExecution', id: 'exec_steer', command: 'wait', status: 'inProgress' };
|
|
163
|
+
emit({ method: 'item/started', params: { threadId: 'th_mock_1', turnId, item: exec } });
|
|
164
|
+
await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600));
|
|
165
|
+
if (!steerTurn) return; // a race already ended it
|
|
166
|
+
emit({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId, item: { ...exec, status: 'completed' } } });
|
|
167
|
+
const steered = steerTurn.steered;
|
|
168
|
+
for (const entry of steered) {
|
|
169
|
+
const item = { type: 'userMessage', id: `item_user_${++steerSerial}`, clientId: entry.clientId, content: [{ type: 'text', text: entry.text }] };
|
|
170
|
+
emit({ method: 'item/started', params: { threadId: 'th_mock_1', turnId, item } });
|
|
171
|
+
emit({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId, item } });
|
|
172
|
+
}
|
|
173
|
+
agent(['steer tool done', ...steered.map((entry) => `saw: ${entry.text}`)].join('\n'));
|
|
174
|
+
completeSteerTurn(turnId);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
80
177
|
if (turnText.includes('mock:agent-echo')) {
|
|
81
178
|
// Same documented agentMessage/turn completion frames as the baseline below.
|
|
82
179
|
emit({ method: 'item/completed', params: { threadId: 'th_mock_1', turnId: 'turn_mock_1', item: { type: 'agentMessage', id: `item_echo_${++echoSerial}`, text: turnText } } });
|
|
@@ -34,6 +34,14 @@ async function prompt(id, content) {
|
|
|
34
34
|
if (input.includes('mock:rpc-error')) { emit({ id, error: { code: -32603, message: 'Provider rejected request' } }); return; }
|
|
35
35
|
// #443 provider-error envelopes: the specific scenarios must be matched BEFORE the
|
|
36
36
|
// bare 'mock:provider-error' prefix, which every one of them contains.
|
|
37
|
+
// #508: observed Cursor 2026.09.18-9a7762b error envelope, followed by end_turn.
|
|
38
|
+
if (input.includes('mock:provider-error-protocol') && (input.includes('-exhaust') || prompts === 1)) { text('\n\nError: RetriableError: [invalid_argument] protocol error: missing EndStreamResponse'); complete(id); return; }
|
|
39
|
+
// #531: observed run 2f891027 seq 2005 capacity envelope. Match before the bare prefix.
|
|
40
|
+
// Do not reuse the protocol mock's `includes('-exhaust')` check: that token is a
|
|
41
|
+
// substring of `resource-exhausted` and would never recover.
|
|
42
|
+
if (input.includes('mock:provider-error-resource-exhausted-exhaust')) { text('\n\nError: RetriableError: [resource_exhausted] Error'); complete(id); return; }
|
|
43
|
+
if (input.includes('mock:provider-error-resource-exhausted') && prompts === 1) { text('\n\nError: RetriableError: [resource_exhausted] Error'); complete(id); return; }
|
|
44
|
+
if (input.includes('mock:provider-error-unknown-protocol')) { text('\n\nError: [invalid_argument] protocol error: unknown frame'); complete(id); return; }
|
|
37
45
|
if (input.includes('mock:provider-error-transient') && prompts === 1) { text('\n\nError: 502 bad gateway.'); complete(id); return; }
|
|
38
46
|
if (input.includes('mock:provider-error-bare')) { text('\n\nError: 502 bad gateway.'); complete(id); return; }
|
|
39
47
|
if (input.includes('mock:provider-error-instant-near') && prompts === 1) { text(`\n\nError: 429 rate limited, try again at ${new Date(Date.now() + 300).toISOString()}.`); complete(id); return; }
|
|
@@ -22,9 +22,30 @@ const SESSION_ID = 'ses_mock_1';
|
|
|
22
22
|
const MESSAGE_ID = 'msg_mock_1';
|
|
23
23
|
|
|
24
24
|
let sse = null;
|
|
25
|
-
const
|
|
25
|
+
const write = (event) => {
|
|
26
26
|
if (sse) sse.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
27
27
|
};
|
|
28
|
+
// #505: like opencode 1.18.32, a prompt_async POSTed while the session is busy is
|
|
29
|
+
// steered into the running loop: its user message exists at once, and the next
|
|
30
|
+
// assistant message names it as parentID. Steers are read just before the turn's
|
|
31
|
+
// idle, unless the turn is `late` (the upstream lost wake: never read).
|
|
32
|
+
let turnActive = false;
|
|
33
|
+
let turnLate = false;
|
|
34
|
+
let steers = [];
|
|
35
|
+
let steerSerial = 0;
|
|
36
|
+
const send = (event) => {
|
|
37
|
+
const ownIdle = event?.type === 'session.idle' && (!event.properties?.sessionID || event.properties.sessionID === SESSION_ID);
|
|
38
|
+
if (ownIdle) {
|
|
39
|
+
if (!turnLate) for (const steer of steers) {
|
|
40
|
+
const id = `msg_steer_reply_${++steerSerial}`;
|
|
41
|
+
write({ type: 'message.updated', properties: { info: { ...info({}), id, parentID: steer.userId } } });
|
|
42
|
+
write({ type: 'message.part.updated', properties: { part: { id: `prt_${id}`, messageID: id, sessionID: SESSION_ID, type: 'text', text: steer.text } } });
|
|
43
|
+
}
|
|
44
|
+
steers = []; turnActive = false; turnLate = false;
|
|
45
|
+
}
|
|
46
|
+
write(event);
|
|
47
|
+
};
|
|
48
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
49
|
|
|
29
50
|
/** Questions the runner can look up an id for. `replyQuestion`/`rejectQuestion`
|
|
30
51
|
* resolve the id through `GET /question` before answering (see
|
|
@@ -51,10 +72,14 @@ const sendQuestionPart = (input) =>
|
|
|
51
72
|
},
|
|
52
73
|
},
|
|
53
74
|
});
|
|
75
|
+
// The user message of the prompt being answered: opencode 1.18.32 creates it at the
|
|
76
|
+
// POST and names it as the assistant's parentID (#505 probe).
|
|
77
|
+
let currentUserId;
|
|
54
78
|
const info = (extra) => ({
|
|
55
79
|
id: MESSAGE_ID,
|
|
56
80
|
sessionID: SESSION_ID,
|
|
57
81
|
role: 'assistant',
|
|
82
|
+
...(currentUserId ? { parentID: currentUserId } : {}),
|
|
58
83
|
time: { created: 1760000000000 },
|
|
59
84
|
modelID: 'mock-model',
|
|
60
85
|
providerID: 'mock',
|
|
@@ -91,7 +116,8 @@ const server = createServer((req, res) => {
|
|
|
91
116
|
send({ type: 'message.part.updated', properties: { part: {
|
|
92
117
|
id: 'prt_answer', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: `human answer: ${body}${answerDone ? '\n\nCEZ:DONE' : ''}`,
|
|
93
118
|
} } });
|
|
94
|
-
|
|
119
|
+
// #505 review: CEZ_MOCK_OPENCODE_REPLY_HOLD_MS keeps the answered turn running.
|
|
120
|
+
setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), Number(process.env.CEZ_MOCK_OPENCODE_REPLY_HOLD_MS ?? 0));
|
|
95
121
|
}, 30);
|
|
96
122
|
const acknowledge = () => { res.writeHead(200, { 'content-type': 'application/json' }); res.end('{}'); };
|
|
97
123
|
if (lateQuestionReply) setTimeout(acknowledge, 250);
|
|
@@ -112,9 +138,44 @@ const server = createServer((req, res) => {
|
|
|
112
138
|
res.end(JSON.stringify({ error: 'agent prompt rejected' }));
|
|
113
139
|
return;
|
|
114
140
|
}
|
|
141
|
+
if (turnActive && url.endsWith('/prompt_async')) {
|
|
142
|
+
const text = JSON.parse(body).parts.map(part => part.text ?? '').join('\n');
|
|
143
|
+
const userId = `msg_steer_user_${++steerSerial}`;
|
|
144
|
+
// #505 review: acknowledge a steer later than the runner's lost-wake window.
|
|
145
|
+
const ackDelay = Number(process.env.CEZ_MOCK_OPENCODE_STEER_ACK_MS ?? 0);
|
|
146
|
+
if (ackDelay > 0) setTimeout(() => { res.writeHead(204); res.end(); }, ackDelay);
|
|
147
|
+
else { res.writeHead(204); res.end(); }
|
|
148
|
+
send({ type: 'message.updated', properties: { info: { id: userId, sessionID: SESSION_ID, role: 'user', time: { created: Date.now() } } } });
|
|
149
|
+
send({ type: 'message.part.updated', properties: { part: { id: `prt_${userId}`, messageID: userId, sessionID: SESSION_ID, type: 'text', text } } });
|
|
150
|
+
steers.push({ userId, text });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
turnActive = true;
|
|
115
154
|
// `prompt_async` semantics: acknowledge now, stream the turn over SSE.
|
|
116
155
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
117
156
|
res.end(JSON.stringify({ info: info({}), parts: [] }));
|
|
157
|
+
if (url.endsWith('/prompt_async')) {
|
|
158
|
+
currentUserId = `msg_user_${++steerSerial}`;
|
|
159
|
+
const text = JSON.parse(body).parts.map(part => part.text ?? '').join('\n');
|
|
160
|
+
send({ type: 'message.updated', properties: { info: { id: currentUserId, sessionID: SESSION_ID, role: 'user', time: { created: Date.now() } } } });
|
|
161
|
+
send({ type: 'message.part.updated', properties: { part: { id: `prt_${currentUserId}`, messageID: currentUserId, sessionID: SESSION_ID, type: 'text', text } } });
|
|
162
|
+
}
|
|
163
|
+
if (body.includes('mock:steer-tool')) {
|
|
164
|
+
send({ type: 'message.updated', properties: { info: info({}) } });
|
|
165
|
+
send({ type: 'message.part.updated', properties: { part: { id: 'prt_steer_tool', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'tool', callID: 'call_steer', tool: 'bash', state: { status: 'running', input: { command: 'wait' } } } } });
|
|
166
|
+
await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600));
|
|
167
|
+
send({ type: 'message.part.updated', properties: { part: { id: 'prt_steer_tool', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'tool', callID: 'call_steer', tool: 'bash', state: { status: 'completed', input: { command: 'wait' }, output: 'waited' } } } });
|
|
168
|
+
send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (body.includes('mock:steer-late')) {
|
|
172
|
+
send({ type: 'message.updated', properties: { info: info({}) } });
|
|
173
|
+
send({ type: 'message.part.updated', properties: { part: { id: 'prt_steer_late', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: 'late window: final message already sent', time: { start: 1760000000000, end: 1760000000001 } } } });
|
|
174
|
+
turnLate = true;
|
|
175
|
+
await sleep(300);
|
|
176
|
+
send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
118
179
|
// The raw body is enough to spot a `mock:` marker — the prompt text is
|
|
119
180
|
// inside it whatever part shape the runner used to wrap it.
|
|
120
181
|
if (body.includes('mock:ci-wait')) {
|
|
@@ -183,6 +244,12 @@ const server = createServer((req, res) => {
|
|
|
183
244
|
}, 60);
|
|
184
245
|
return;
|
|
185
246
|
}
|
|
247
|
+
if (body.includes('mock:provider-error-early')) {
|
|
248
|
+
// #505 review: the provider rejects before any assistant message exists.
|
|
249
|
+
send({ type: 'session.error', properties: { sessionID: SESSION_ID, error: { name: 'ProviderAuthError', data: { message: 'API key expired' } } } });
|
|
250
|
+
setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
186
253
|
if (body.includes('mock:provider-error')) {
|
|
187
254
|
// The session-level error frame, wire shape copied verbatim from
|
|
188
255
|
// `__fixtures__/opencode/session-error.ndjson`. #53: a bare upstream
|
package/scripts/mock-pi-rpc.mjs
CHANGED
|
@@ -8,7 +8,40 @@ process.on('SIGTERM', () => process.exit(143));
|
|
|
8
8
|
|
|
9
9
|
if (process.env.CEZ_MOCK_CI_PR) { const { probeCiTool } = await import('./mock-ci-tool.mjs'); await probeCiTool('pi', process.argv.slice(2)); }
|
|
10
10
|
const sessionId = '00000000-0000-4000-8000-0000000000pi';
|
|
11
|
-
const
|
|
11
|
+
const write = (value) => process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
12
|
+
// #505: like pi 0.87, a prompt with streamingBehavior 'steer' joins the running
|
|
13
|
+
// turn. Steers accepted by a scripted turn are read just before it settles: a user
|
|
14
|
+
// message_start/end, then an echo, unless the turn is `late` (never read).
|
|
15
|
+
let activeTurn = null;
|
|
16
|
+
// The prompt a queued handler is running; pi records it as the turn's user message.
|
|
17
|
+
let currentPrompt;
|
|
18
|
+
const send = (value) => {
|
|
19
|
+
if (value?.type === 'turn_start' && !activeTurn) {
|
|
20
|
+
activeTurn = { steers: [], late: false };
|
|
21
|
+
write(value);
|
|
22
|
+
if (currentPrompt !== undefined && process.env.CEZ_MOCK_PI_NO_USER_START !== '1') {
|
|
23
|
+
const message = { role: 'user', content: [{ type: 'text', text: currentPrompt }] };
|
|
24
|
+
currentPrompt = undefined;
|
|
25
|
+
write({ type: 'message_start', message });
|
|
26
|
+
write({ type: 'message_end', message });
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (value?.type === 'agent_settled' && activeTurn) {
|
|
31
|
+
const turn = activeTurn; activeTurn = null;
|
|
32
|
+
if (!turn.late) for (const text of turn.steers) {
|
|
33
|
+
write({ type: 'message_start', message: { role: 'user', content: [{ type: 'text', text }] } });
|
|
34
|
+
write({ type: 'message_end', message: { role: 'user', content: [{ type: 'text', text }] } });
|
|
35
|
+
sendText([text]);
|
|
36
|
+
write({ type: 'message_end', message: { role: 'assistant', usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } } } });
|
|
37
|
+
}
|
|
38
|
+
write(value);
|
|
39
|
+
// A steer that arrived after the final model call runs as the next prompt.
|
|
40
|
+
if (turn.late) for (const text of turn.steers) queue = queue.then(() => { currentPrompt = text; return handle({ type: 'prompt', message: text }); });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
write(value);
|
|
44
|
+
};
|
|
12
45
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13
46
|
|
|
14
47
|
/** One valid CEZ:ASK payload (spec #473), used by the `mock:ask` scenario. */
|
|
@@ -32,8 +65,21 @@ function sendTurnEnd(usage = { input: 10, output: 5, cacheRead: 0, cacheWrite: 0
|
|
|
32
65
|
send({ type: 'agent_settled' });
|
|
33
66
|
}
|
|
34
67
|
|
|
35
|
-
|
|
68
|
+
const rl = readline.createInterface({ input: process.stdin });
|
|
69
|
+
let queue = Promise.resolve();
|
|
70
|
+
rl.on('line', (line) => {
|
|
36
71
|
const command = JSON.parse(line);
|
|
72
|
+
if (command.type === 'prompt' && command.streamingBehavior === 'steer' && activeTurn) {
|
|
73
|
+
if (process.env.CEZ_MOCK_STDIN_FILE) appendFileSync(process.env.CEZ_MOCK_STDIN_FILE, `${JSON.stringify({ userText: command.message, imageCount: 0, streamingBehavior: 'steer' })}\n`);
|
|
74
|
+
activeTurn.steers.push(command.message);
|
|
75
|
+
write({ id: command.id, type: 'response', command: 'prompt', success: true });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
queue = queue.then(() => { currentPrompt = command.type === 'prompt' ? command.message : undefined; return handle(command); });
|
|
79
|
+
});
|
|
80
|
+
rl.on('close', () => { queue.then(() => process.exit(0)); });
|
|
81
|
+
|
|
82
|
+
async function handle(command) {
|
|
37
83
|
// Testability hook, mirroring mock-claude: CEZ_MOCK_STDIN_FILE=<path> appends
|
|
38
84
|
// each inbound prompt's text and image count, so tests can assert what the
|
|
39
85
|
// runner actually wrote onto the RPC (harness parity's AgentRunSpec probes).
|
|
@@ -68,6 +114,21 @@ for await (const line of readline.createInterface({ input: process.stdin })) {
|
|
|
68
114
|
const { ciPrompt } = await import('./mock-ci-tool.mjs');
|
|
69
115
|
sendText([await ciPrompt('pi', process.argv.slice(2), command.message)]);
|
|
70
116
|
sendTurnEnd();
|
|
117
|
+
} else if (command.type === 'prompt' && command.message.includes('mock:steer-tool')) {
|
|
118
|
+
send({ id: command.id, type: 'response', command: 'prompt', success: true });
|
|
119
|
+
send({ type: 'agent_start' }); send({ type: 'turn_start' });
|
|
120
|
+
send({ type: 'tool_execution_start', toolCallId: 'tool-steer', toolName: 'bash', args: { command: 'wait' } });
|
|
121
|
+
await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600));
|
|
122
|
+
send({ type: 'tool_execution_end', toolCallId: 'tool-steer', toolName: 'bash', result: { content: [{ type: 'text', text: 'waited' }] }, isError: false });
|
|
123
|
+
sendText(['steer tool done']);
|
|
124
|
+
sendTurnEnd();
|
|
125
|
+
} else if (command.type === 'prompt' && command.message.includes('mock:steer-late')) {
|
|
126
|
+
send({ id: command.id, type: 'response', command: 'prompt', success: true });
|
|
127
|
+
send({ type: 'agent_start' }); send({ type: 'turn_start' });
|
|
128
|
+
sendText(['late window: final message already sent']);
|
|
129
|
+
activeTurn.late = true;
|
|
130
|
+
await sleep(300);
|
|
131
|
+
sendTurnEnd();
|
|
71
132
|
} else if (command.type === 'prompt' && command.message.includes('mock:agent-echo')) {
|
|
72
133
|
// rpc-lifecycle.ndjson's normal prompt/assistant/settled sequence.
|
|
73
134
|
send({ id: command.id, type: 'response', command: 'prompt', success: true });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{i as t,t as n}from"./react-runtime-CCIEwYL0.js";import{C as r,D as i,I as a,M as o,N as s,O as c,S as l,T as u,Zn as d,b as f,j as p,k as m,un as h,w as g,x as _,z as v}from"./centered-state-HwCqQkH3.js";import{t as y}from"./utils-DKheTxGD.js";import{_ as b,g as ee,h as x,m as te,p as S}from"./dropdown-menu-_YAzCaoQ.js";var C=e(t(),1),w=n(),T=`Popover`,[E,ne]=o(T,[b]),D=b(),[O,k]=E(T),A=e=>{let{__scopePopover:t,children:n,open:r,defaultOpen:a,onOpenChange:o,modal:s=!1}=e,c=D(t),l=C.useRef(null),[u,d]=C.useState(!1),[f,p]=m({prop:r,defaultProp:a??!1,onChange:o,caller:T});return(0,w.jsx)(ee,{...c,children:(0,w.jsx)(O,{scope:t,contentId:i(),triggerRef:l,open:f,onOpenChange:p,onOpenToggle:C.useCallback(()=>p(e=>!e),[p]),hasCustomAnchor:u,onCustomAnchorAdd:C.useCallback(()=>d(!0),[]),onCustomAnchorRemove:C.useCallback(()=>d(!1),[]),modal:s,children:n})})};A.displayName=T;var j=`PopoverAnchor`,M=C.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=k(j,n),a=D(n),{onCustomAnchorAdd:o,onCustomAnchorRemove:s}=i;return C.useEffect(()=>(o(),()=>s()),[o,s]),(0,w.jsx)(S,{...a,...r,ref:t})});M.displayName=j;var N=`PopoverTrigger`,P=C.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=k(N,n),a=D(n),o=v(t,i.triggerRef),c=(0,w.jsx)(s.button,{type:`button`,"aria-haspopup":`dialog`,"aria-expanded":i.open,"aria-controls":i.open?i.contentId:void 0,"data-state":Y(i.open),...r,ref:o,onClick:p(e.onClick,i.onOpenToggle)});return i.hasCustomAnchor?c:(0,w.jsx)(S,{asChild:!0,...a,children:c})});P.displayName=N;var F=`PopoverPortal`,[I,L]=E(F,{forceMount:void 0}),R=e=>{let{__scopePopover:t,forceMount:n,children:i,container:a}=e,o=k(F,t);return(0,w.jsx)(I,{scope:t,forceMount:n,children:(0,w.jsx)(c,{present:n||o.open,children:(0,w.jsx)(r,{asChild:!0,container:a,children:i})})})};R.displayName=F;var z=`PopoverContent`,B=C.forwardRef((e,t)=>{let n=L(z,e.__scopePopover),{forceMount:r=n.forceMount,...i}=e,a=k(z,e.__scopePopover);return(0,w.jsx)(c,{present:r||a.open,children:a.modal?(0,w.jsx)(H,{...i,ref:t}):(0,w.jsx)(U,{...i,ref:t})})});B.displayName=z;var V=a(`PopoverContent.RemoveScroll`),H=C.forwardRef((e,t)=>{let n=k(z,e.__scopePopover),r=C.useRef(null),i=v(t,r),a=C.useRef(!1);return C.useEffect(()=>{let e=r.current;if(e)return f(e)},[]),(0,w.jsx)(_,{as:V,allowPinchZoom:!0,children:(0,w.jsx)(W,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:p(e.onCloseAutoFocus,e=>{e.preventDefault(),a.current||n.triggerRef.current?.focus()}),onPointerDownOutside:p(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0,r=t.button===2||n;a.current=r},{checkForDefaultPrevented:!1}),onFocusOutside:p(e.onFocusOutside,e=>e.preventDefault(),{checkForDefaultPrevented:!1})})})}),U=C.forwardRef((e,t)=>{let n=k(z,e.__scopePopover),r=C.useRef(!1),i=C.useRef(!1);return(0,w.jsx)(W,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===`pointerdown`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===`focusin`&&i.current&&t.preventDefault()}})}),W=C.forwardRef((e,t)=>{let{__scopePopover:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,disableOutsidePointerEvents:o,onEscapeKeyDown:s,onPointerDownOutside:c,onFocusOutside:d,onInteractOutside:f,...p}=e,m=k(z,n),h=D(n);return l(),(0,w.jsx)(g,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,w.jsx)(u,{asChild:!0,disableOutsidePointerEvents:o,onInteractOutside:f,onEscapeKeyDown:s,onPointerDownOutside:c,onFocusOutside:d,onDismiss:()=>m.onOpenChange(!1),deferPointerDownOutside:!0,children:(0,w.jsx)(x,{"data-state":Y(m.open),role:`dialog`,id:m.contentId,...h,...p,ref:t,style:{...p.style,"--radix-popover-content-transform-origin":`var(--radix-popper-transform-origin)`,"--radix-popover-content-available-width":`var(--radix-popper-available-width)`,"--radix-popover-content-available-height":`var(--radix-popper-available-height)`,"--radix-popover-trigger-width":`var(--radix-popper-anchor-width)`,"--radix-popover-trigger-height":`var(--radix-popper-anchor-height)`}})})})}),G=`PopoverClose`,K=C.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=k(G,n);return(0,w.jsx)(s.button,{type:`button`,...r,ref:t,onClick:p(e.onClick,()=>i.onOpenChange(!1))})});K.displayName=G;var q=`PopoverArrow`,J=C.forwardRef((e,t)=>{let{__scopePopover:n,...r}=e,i=D(n);return(0,w.jsx)(te,{...i,...r,ref:t})});J.displayName=q;function Y(e){return e?`open`:`closed`}var X=A,Z=M,re=P,ie=R,ae=B;function Q(e){let t=e.visualViewport;return t?Math.max(0,Math.round(e.innerHeight-t.height-t.offsetTop)):0}function oe(e,t,n,r=250){let i=e.visualViewport;if(!i)return t(0),()=>{};let a,o=()=>{let i=Q(e);t(i),n&&(clearTimeout(a),a=setTimeout(()=>n(i),r))};return t(Q(e)),i.addEventListener(`resize`,o),i.addEventListener(`scroll`,o),()=>{clearTimeout(a),i.removeEventListener(`resize`,o),i.removeEventListener(`scroll`,o),t(0)}}function se(e){let t=e.visualViewport;return t?{top:Math.max(0,Math.round(t.offsetTop)),bottom:Q(e)}:{top:0,bottom:0}}function ce(e,t=0){let n=typeof t==`number`?{top:t,right:t,bottom:t,left:t}:t;return{top:(n.top??0)+e.top,right:n.right??0,bottom:(n.bottom??0)+e.bottom,left:n.left??0}}function le(e,t){let n=e.visualViewport;if(!n)return t({top:0,bottom:0}),()=>{};let r=()=>t(se(e));return r(),n.addEventListener(`resize`,r),n.addEventListener(`scroll`,r),()=>{n.removeEventListener(`resize`,r),n.removeEventListener(`scroll`,r)}}function ue(){let[e,t]=(0,C.useState)({top:0,bottom:0});return(0,C.useEffect)(()=>le(window,e=>t(t=>t.top===e.top&&t.bottom===e.bottom?t:e)),[]),e}function de(e){let t=(0,C.useRef)(e);t.current=e,(0,C.useEffect)(()=>{let e=document.documentElement;return oe(window,t=>e.style.setProperty(`--kb`,`${t}px`),e=>t.current?.(e))},[])}var $=C.createContext(null);function fe({...e}){let t=C.useRef(!1);return(0,w.jsx)($,{value:t,children:(0,w.jsx)(X,{"data-slot":`popover`,...e})})}function pe({onPointerDownCapture:e,onKeyDownCapture:t,...n}){let r=C.useContext($);return(0,w.jsx)(re,{"data-slot":`popover-trigger`,...n,onPointerDownCapture:t=>{r&&(r.current=t.pointerType===`touch`),e?.(t)},onKeyDownCapture:e=>{r&&(r.current=!1),t?.(e)}})}function me({className:e,align:t=`center`,sideOffset:n=4,collisionPadding:r,onOpenAutoFocus:i,...a}){let o=ue(),s=C.useContext($);return(0,w.jsx)(ie,{children:(0,w.jsx)(ae,{"data-slot":`popover-content`,align:t,sideOffset:n,onOpenAutoFocus:e=>{let t=s?.current;if(s&&(s.current=!1),i?.(e),e.defaultPrevented||!t)return;let n=e.target;n instanceof HTMLElement&&n.querySelector(`[cmdk-input]`)&&(e.preventDefault(),n.focus({preventScroll:!0}))},collisionPadding:ce(o,r),className:y(`z-50 w-72 max-w-(--radix-popover-content-available-width) [overflow-wrap:anywhere] origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95`,e),...a})})}function he({...e}){return(0,w.jsx)(Z,{"data-slot":`popover-anchor`,...e})}function ge(){let e=h(),t=d(),n=(e.data?.profiles??[]).map(e=>({provider:e.provider,id:e.id,label:e.label,configDir:e.configDir})),r=t.data?.info?.root;return{accounts:n,repoAccount:r?e.data?.selections?.[r]:void 0}}function _e(e,t){return e.filter(e=>e.provider===t).length>1}export{me as a,he as i,ge as n,pe as o,fe as r,de as s,_e as t};
|