@asterxsk/kiln 0.1.0 → 0.2.0
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/LICENSE +21 -21
- package/README.md +170 -170
- package/agent/AGENTS.md +67 -67
- package/agent/README.md +5 -5
- package/agent/extensions/AGENTS.md +68 -68
- package/agent/extensions/ask-user/index.ts +418 -418
- package/agent/extensions/ask-user/package-lock.json +769 -769
- package/agent/extensions/ask-user/package.json +19 -19
- package/agent/extensions/ask-user/prompt.ts +45 -45
- package/agent/extensions/ask-user/tsconfig.json +7 -7
- package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -942
- package/agent/extensions/background-terminals/index.ts +627 -627
- package/agent/extensions/background-terminals/manager.test.ts +735 -735
- package/agent/extensions/background-terminals/output.test.ts +109 -109
- package/agent/extensions/background-terminals/package-lock.json +769 -769
- package/agent/extensions/background-terminals/package.json +17 -17
- package/agent/extensions/background-terminals/prompt.test.ts +125 -125
- package/agent/extensions/background-terminals/ps.test.ts +82 -82
- package/agent/extensions/background-terminals/result-delivery.test.ts +44 -44
- package/agent/extensions/background-terminals/src/domain.ts +87 -87
- package/agent/extensions/background-terminals/src/manager.ts +907 -907
- package/agent/extensions/background-terminals/src/output.ts +84 -84
- package/agent/extensions/background-terminals/src/prompt.ts +142 -142
- package/agent/extensions/background-terminals/src/result-delivery.ts +27 -27
- package/agent/extensions/background-terminals/src/runtime.ts +36 -36
- package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -79
- package/agent/extensions/background-terminals/src/ui/ps.ts +621 -621
- package/agent/extensions/background-terminals/tsconfig.json +7 -7
- package/agent/extensions/file-search/index.spec.ts +443 -443
- package/agent/extensions/file-search/index.ts +459 -459
- package/agent/extensions/file-search/package-lock.json +2253 -2253
- package/agent/extensions/file-search/package.json +23 -23
- package/agent/extensions/file-search/src/args.ts +122 -122
- package/agent/extensions/file-search/src/binaries.ts +422 -422
- package/agent/extensions/file-search/src/output.ts +126 -126
- package/agent/extensions/file-search/src/process.ts +146 -146
- package/agent/extensions/file-search/src/prompt.ts +52 -52
- package/agent/extensions/file-search/tsconfig.json +7 -7
- package/agent/extensions/modelconf/PLAN.md +915 -915
- package/agent/extensions/modelconf/index.ts +296 -296
- package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -1101
- package/agent/extensions/pi-web-access/CHANGELOG.md +690 -690
- package/agent/extensions/pi-web-access/LICENSE +21 -21
- package/agent/extensions/pi-web-access/README.md +470 -470
- package/agent/extensions/pi-web-access/SECURITY.md +5 -5
- package/agent/extensions/pi-web-access/activity.ts +101 -101
- package/agent/extensions/pi-web-access/auth-fetch.ts +148 -148
- package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -272
- package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -669
- package/agent/extensions/pi-web-access/content-find.ts +139 -139
- package/agent/extensions/pi-web-access/credential-source.ts +191 -191
- package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -406
- package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -568
- package/agent/extensions/pi-web-access/declared-web-links.ts +173 -173
- package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -496
- package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -140
- package/agent/extensions/pi-web-access/exa.ts +526 -526
- package/agent/extensions/pi-web-access/extract.ts +1196 -1196
- package/agent/extensions/pi-web-access/feature-config.ts +29 -29
- package/agent/extensions/pi-web-access/fetch-params.ts +111 -111
- package/agent/extensions/pi-web-access/gemini-adc.ts +298 -298
- package/agent/extensions/pi-web-access/gemini-api.ts +353 -353
- package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -108
- package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -128
- package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -101
- package/agent/extensions/pi-web-access/gemini-web.ts +487 -487
- package/agent/extensions/pi-web-access/github-api.ts +197 -197
- package/agent/extensions/pi-web-access/github-extract.ts +746 -746
- package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -700
- package/agent/extensions/pi-web-access/index.ts +1737 -1737
- package/agent/extensions/pi-web-access/package-lock.json +5808 -5808
- package/agent/extensions/pi-web-access/package.json +64 -64
- package/agent/extensions/pi-web-access/page-query.ts +96 -96
- package/agent/extensions/pi-web-access/pdf-extract.ts +409 -409
- package/agent/extensions/pi-web-access/promise-try.d.ts +7 -7
- package/agent/extensions/pi-web-access/query-rewrite.ts +51 -51
- package/agent/extensions/pi-web-access/render-search-error.ts +170 -170
- package/agent/extensions/pi-web-access/rsc-extract.ts +338 -338
- package/agent/extensions/pi-web-access/source-check.ts +282 -282
- package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -526
- package/agent/extensions/pi-web-access/storage.ts +521 -521
- package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -125
- package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -208
- package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -840
- package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -441
- package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -283
- package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -25
- package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -210
- package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -552
- package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -212
- package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -40
- package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -334
- package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -95
- package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -53
- package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -92
- package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -86
- package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -34
- package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -173
- package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -257
- package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -170
- package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -133
- package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -178
- package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -148
- package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -223
- package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -378
- package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -565
- package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -99
- package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -118
- package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -50
- package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -51
- package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -140
- package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -500
- package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -286
- package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -52
- package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -102
- package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -152
- package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -274
- package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -179
- package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -205
- package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -456
- package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -182
- package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -64
- package/agent/extensions/pi-web-access/tsconfig.json +11 -11
- package/agent/extensions/pi-web-access/utils.ts +451 -451
- package/agent/extensions/pi-web-access/video-extract.ts +392 -392
- package/agent/extensions/pi-web-access/youtube-extract.ts +328 -328
- package/agent/extensions/shared/activity-status.ts +31 -31
- package/agent/extensions/shared/child-session.test.ts +270 -270
- package/agent/extensions/shared/child-session.ts +148 -148
- package/agent/extensions/shared/context-utilization.test.ts +48 -48
- package/agent/extensions/shared/context-utilization.ts +47 -47
- package/agent/extensions/shared/dashboard-state.ts +99 -99
- package/agent/extensions/shared/tool-call-timeout.test.ts +117 -117
- package/agent/extensions/shared/tool-call-timeout.ts +104 -104
- package/agent/extensions/subagents/by-the-way.test.ts +29 -29
- package/agent/extensions/subagents/claude.test.ts +119 -119
- package/agent/extensions/subagents/codex.test.ts +102 -102
- package/agent/extensions/subagents/context-usage.test.ts +107 -107
- package/agent/extensions/subagents/docs/design-plan.md +568 -568
- package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -354
- package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -571
- package/agent/extensions/subagents/index.ts +779 -779
- package/agent/extensions/subagents/manager.test.ts +276 -276
- package/agent/extensions/subagents/package-lock.json +2244 -2244
- package/agent/extensions/subagents/package.json +19 -19
- package/agent/extensions/subagents/result-delivery.test.ts +27 -27
- package/agent/extensions/subagents/src/backend.ts +73 -73
- package/agent/extensions/subagents/src/backends/claude.ts +701 -701
- package/agent/extensions/subagents/src/backends/codex.ts +1060 -1060
- package/agent/extensions/subagents/src/backends/pi.ts +575 -575
- package/agent/extensions/subagents/src/backends/stub.ts +300 -300
- package/agent/extensions/subagents/src/by-the-way.ts +21 -21
- package/agent/extensions/subagents/src/domain.ts +253 -253
- package/agent/extensions/subagents/src/format.ts +74 -74
- package/agent/extensions/subagents/src/manager.ts +736 -736
- package/agent/extensions/subagents/src/prompt.ts +92 -92
- package/agent/extensions/subagents/src/result-delivery.ts +20 -20
- package/agent/extensions/subagents/src/runtime.ts +53 -53
- package/agent/extensions/subagents/src/ui/takeover.ts +583 -583
- package/agent/extensions/subagents/src/ui/transcript.ts +201 -201
- package/agent/extensions/subagents/takeover.test.ts +29 -29
- package/agent/extensions/subagents/tsconfig.json +7 -7
- package/agent/extensions/todo/AGENTS.md +38 -38
- package/agent/extensions/todo/LICENSE +21 -21
- package/agent/extensions/todo/config.ts +55 -55
- package/agent/extensions/todo/index.ts +151 -151
- package/agent/extensions/todo/locales/de.json +17 -17
- package/agent/extensions/todo/locales/en.json +15 -15
- package/agent/extensions/todo/locales/es.json +17 -17
- package/agent/extensions/todo/locales/fr.json +17 -17
- package/agent/extensions/todo/locales/pt-BR.json +17 -17
- package/agent/extensions/todo/locales/pt.json +17 -17
- package/agent/extensions/todo/locales/ru.json +17 -17
- package/agent/extensions/todo/locales/uk.json +17 -17
- package/agent/extensions/todo/locales/zh.json +17 -17
- package/agent/extensions/todo/package-lock.json +3358 -3358
- package/agent/extensions/todo/package.json +67 -67
- package/agent/extensions/todo/state/i18n-bridge.ts +64 -64
- package/agent/extensions/todo/state/invariants.ts +20 -20
- package/agent/extensions/todo/state/replay.ts +38 -38
- package/agent/extensions/todo/state/selectors.ts +107 -107
- package/agent/extensions/todo/state/state-reducer.ts +326 -326
- package/agent/extensions/todo/state/state.ts +18 -18
- package/agent/extensions/todo/state/store.ts +82 -82
- package/agent/extensions/todo/state/task-graph.ts +57 -57
- package/agent/extensions/todo/todo-overlay.ts +200 -200
- package/agent/extensions/todo/todo.ts +155 -155
- package/agent/extensions/todo/tool/response-envelope.ts +109 -109
- package/agent/extensions/todo/tool/types.ts +206 -206
- package/agent/extensions/todo/view/format.ts +177 -177
- package/agent/install.ps1 +637 -527
- package/agent/install.sh +620 -511
- package/agent/keybindings.json +7 -7
- package/bin/kiln.js +124 -11
- package/package.json +8 -2
- package/agent/extensions/taste/index.ts +0 -443
- package/agent/extensions/taste/install.ps1 +0 -23
- package/agent/extensions/taste/install.sh +0 -21
- /package/agent/extensions/{status line → statusline}/index.ts +0 -0
- /package/agent/extensions/{status line → statusline}/install.ps1 +0 -0
- /package/agent/extensions/{status line → statusline}/install.sh +0 -0
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
BTW_TITLE_MAX_LENGTH,
|
|
5
|
-
deriveBtwTitle,
|
|
6
|
-
isModelVisible,
|
|
7
|
-
} from "./src/by-the-way.ts";
|
|
8
|
-
|
|
9
|
-
test("deriveBtwTitle uses the first non-empty line and bounds the title", () => {
|
|
10
|
-
assert.equal(
|
|
11
|
-
deriveBtwTitle("\n Why does this work? \nignore me"),
|
|
12
|
-
"Why does this work?",
|
|
13
|
-
);
|
|
14
|
-
assert.equal(deriveBtwTitle(" \n\t"), "by the way");
|
|
15
|
-
|
|
16
|
-
const title = deriveBtwTitle("x".repeat(BTW_TITLE_MAX_LENGTH + 10));
|
|
17
|
-
assert.equal(title.length, BTW_TITLE_MAX_LENGTH);
|
|
18
|
-
assert.equal(title, `${"x".repeat(BTW_TITLE_MAX_LENGTH - 1)}…`);
|
|
19
|
-
|
|
20
|
-
const emojiTitle = deriveBtwTitle(
|
|
21
|
-
`${"x".repeat(BTW_TITLE_MAX_LENGTH - 2)}😀 more`,
|
|
22
|
-
);
|
|
23
|
-
assert.equal(emojiTitle, `${"x".repeat(BTW_TITLE_MAX_LENGTH - 2)}😀…`);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("only model-origin snapshots are visible to model-facing tools", () => {
|
|
27
|
-
assert.equal(isModelVisible({ origin: "model" }), true);
|
|
28
|
-
assert.equal(isModelVisible({ origin: "btw" }), false);
|
|
29
|
-
});
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
BTW_TITLE_MAX_LENGTH,
|
|
5
|
+
deriveBtwTitle,
|
|
6
|
+
isModelVisible,
|
|
7
|
+
} from "./src/by-the-way.ts";
|
|
8
|
+
|
|
9
|
+
test("deriveBtwTitle uses the first non-empty line and bounds the title", () => {
|
|
10
|
+
assert.equal(
|
|
11
|
+
deriveBtwTitle("\n Why does this work? \nignore me"),
|
|
12
|
+
"Why does this work?",
|
|
13
|
+
);
|
|
14
|
+
assert.equal(deriveBtwTitle(" \n\t"), "by the way");
|
|
15
|
+
|
|
16
|
+
const title = deriveBtwTitle("x".repeat(BTW_TITLE_MAX_LENGTH + 10));
|
|
17
|
+
assert.equal(title.length, BTW_TITLE_MAX_LENGTH);
|
|
18
|
+
assert.equal(title, `${"x".repeat(BTW_TITLE_MAX_LENGTH - 1)}…`);
|
|
19
|
+
|
|
20
|
+
const emojiTitle = deriveBtwTitle(
|
|
21
|
+
`${"x".repeat(BTW_TITLE_MAX_LENGTH - 2)}😀 more`,
|
|
22
|
+
);
|
|
23
|
+
assert.equal(emojiTitle, `${"x".repeat(BTW_TITLE_MAX_LENGTH - 2)}😀…`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("only model-origin snapshots are visible to model-facing tools", () => {
|
|
27
|
+
assert.equal(isModelVisible({ origin: "model" }), true);
|
|
28
|
+
assert.equal(isModelVisible({ origin: "btw" }), false);
|
|
29
|
+
});
|
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
import { SubagentManager } from "./src/manager.ts";
|
|
5
|
-
import { claudeBackend } from "./src/backends/claude.ts";
|
|
6
|
-
import type { ParentContext, SpawnTask } from "./src/domain.ts";
|
|
7
|
-
import { createSubagentRuntime, runTool } from "./src/runtime.ts";
|
|
8
|
-
|
|
9
|
-
const parent: ParentContext = {
|
|
10
|
-
parentCwd: process.cwd(),
|
|
11
|
-
projectTrusted: false,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function task(prompt: string): SpawnTask {
|
|
15
|
-
return {
|
|
16
|
-
prompt,
|
|
17
|
-
title: "live Claude test",
|
|
18
|
-
cwd: process.cwd(),
|
|
19
|
-
model: "haiku",
|
|
20
|
-
reasoningEffort: "off",
|
|
21
|
-
parent,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function claudeAvailable() {
|
|
26
|
-
return Effect.runPromise(claudeBackend.available);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Rejecting deadline so a hung wait still reaches finally() and disposes. */
|
|
30
|
-
function deadline<A>(operation: Promise<A>, timeoutMs: number) {
|
|
31
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
32
|
-
const timeout = new Promise<never>((_resolve, reject) => {
|
|
33
|
-
timer = setTimeout(
|
|
34
|
-
() => reject(new Error(`Live Claude test exceeded ${timeoutMs}ms`)),
|
|
35
|
-
timeoutMs,
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
return Promise.race([operation, timeout]).finally(() => {
|
|
39
|
-
if (timer) clearTimeout(timer);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
test(
|
|
44
|
-
"Claude backend completes a live manager run",
|
|
45
|
-
{ timeout: 60_000 },
|
|
46
|
-
async (t) => {
|
|
47
|
-
if (!(await claudeAvailable())) {
|
|
48
|
-
t.skip("Claude Code executable is unavailable");
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const runtime = createSubagentRuntime();
|
|
53
|
-
try {
|
|
54
|
-
const manager = await runtime.runPromise(SubagentManager);
|
|
55
|
-
const started = await runTool(
|
|
56
|
-
runtime,
|
|
57
|
-
manager.spawn("claude", task("Reply with exactly: hello claude")),
|
|
58
|
-
);
|
|
59
|
-
await deadline(runTool(runtime, manager.waitFor([started.id])), 45_000);
|
|
60
|
-
|
|
61
|
-
const done = manager.view.get(started.id);
|
|
62
|
-
assert.equal(done?.status, "done");
|
|
63
|
-
assert.match(done?.finalText ?? "", /hello claude/i);
|
|
64
|
-
assert.ok(done?.meta.nativeSessionId);
|
|
65
|
-
assert.ok(done?.meta.sessionFilePath?.endsWith(".jsonl"));
|
|
66
|
-
} finally {
|
|
67
|
-
await runtime.dispose();
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
test(
|
|
73
|
-
"Claude backend interrupt settles a live run as aborted",
|
|
74
|
-
{ timeout: 60_000 },
|
|
75
|
-
async (t) => {
|
|
76
|
-
if (!(await claudeAvailable())) {
|
|
77
|
-
t.skip("Claude Code executable is unavailable");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const runtime = createSubagentRuntime();
|
|
82
|
-
try {
|
|
83
|
-
const manager = await runtime.runPromise(SubagentManager);
|
|
84
|
-
const started = await runTool(
|
|
85
|
-
runtime,
|
|
86
|
-
manager.spawn(
|
|
87
|
-
"claude",
|
|
88
|
-
task(
|
|
89
|
-
"Write a detailed 10,000-word essay about the history of computing.",
|
|
90
|
-
),
|
|
91
|
-
),
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// Wait for streamed output so cancellation definitely lands mid-run and
|
|
95
|
-
// exercises the SDK's normal interrupt receipt/result path.
|
|
96
|
-
const streamDeadline = Date.now() + 15_000;
|
|
97
|
-
while (
|
|
98
|
-
manager.view.get(started.id)?.status === "running" &&
|
|
99
|
-
!manager.view.get(started.id)?.liveAssistant?.text &&
|
|
100
|
-
Date.now() < streamDeadline
|
|
101
|
-
) {
|
|
102
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
103
|
-
}
|
|
104
|
-
assert.equal(manager.view.get(started.id)?.status, "running");
|
|
105
|
-
assert.ok(manager.view.get(started.id)?.liveAssistant?.text);
|
|
106
|
-
|
|
107
|
-
const report = await deadline(
|
|
108
|
-
runTool(runtime, manager.cancel([started.id])),
|
|
109
|
-
20_000,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
assert.equal(report[0]?.cancelled, true);
|
|
113
|
-
assert.equal(manager.view.get(started.id)?.status, "error");
|
|
114
|
-
assert.equal(manager.view.get(started.id)?.errorText, "Run was aborted");
|
|
115
|
-
} finally {
|
|
116
|
-
await runtime.dispose();
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
);
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { SubagentManager } from "./src/manager.ts";
|
|
5
|
+
import { claudeBackend } from "./src/backends/claude.ts";
|
|
6
|
+
import type { ParentContext, SpawnTask } from "./src/domain.ts";
|
|
7
|
+
import { createSubagentRuntime, runTool } from "./src/runtime.ts";
|
|
8
|
+
|
|
9
|
+
const parent: ParentContext = {
|
|
10
|
+
parentCwd: process.cwd(),
|
|
11
|
+
projectTrusted: false,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function task(prompt: string): SpawnTask {
|
|
15
|
+
return {
|
|
16
|
+
prompt,
|
|
17
|
+
title: "live Claude test",
|
|
18
|
+
cwd: process.cwd(),
|
|
19
|
+
model: "haiku",
|
|
20
|
+
reasoningEffort: "off",
|
|
21
|
+
parent,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function claudeAvailable() {
|
|
26
|
+
return Effect.runPromise(claudeBackend.available);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Rejecting deadline so a hung wait still reaches finally() and disposes. */
|
|
30
|
+
function deadline<A>(operation: Promise<A>, timeoutMs: number) {
|
|
31
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
32
|
+
const timeout = new Promise<never>((_resolve, reject) => {
|
|
33
|
+
timer = setTimeout(
|
|
34
|
+
() => reject(new Error(`Live Claude test exceeded ${timeoutMs}ms`)),
|
|
35
|
+
timeoutMs,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
return Promise.race([operation, timeout]).finally(() => {
|
|
39
|
+
if (timer) clearTimeout(timer);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
test(
|
|
44
|
+
"Claude backend completes a live manager run",
|
|
45
|
+
{ timeout: 60_000 },
|
|
46
|
+
async (t) => {
|
|
47
|
+
if (!(await claudeAvailable())) {
|
|
48
|
+
t.skip("Claude Code executable is unavailable");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const runtime = createSubagentRuntime();
|
|
53
|
+
try {
|
|
54
|
+
const manager = await runtime.runPromise(SubagentManager);
|
|
55
|
+
const started = await runTool(
|
|
56
|
+
runtime,
|
|
57
|
+
manager.spawn("claude", task("Reply with exactly: hello claude")),
|
|
58
|
+
);
|
|
59
|
+
await deadline(runTool(runtime, manager.waitFor([started.id])), 45_000);
|
|
60
|
+
|
|
61
|
+
const done = manager.view.get(started.id);
|
|
62
|
+
assert.equal(done?.status, "done");
|
|
63
|
+
assert.match(done?.finalText ?? "", /hello claude/i);
|
|
64
|
+
assert.ok(done?.meta.nativeSessionId);
|
|
65
|
+
assert.ok(done?.meta.sessionFilePath?.endsWith(".jsonl"));
|
|
66
|
+
} finally {
|
|
67
|
+
await runtime.dispose();
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
test(
|
|
73
|
+
"Claude backend interrupt settles a live run as aborted",
|
|
74
|
+
{ timeout: 60_000 },
|
|
75
|
+
async (t) => {
|
|
76
|
+
if (!(await claudeAvailable())) {
|
|
77
|
+
t.skip("Claude Code executable is unavailable");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const runtime = createSubagentRuntime();
|
|
82
|
+
try {
|
|
83
|
+
const manager = await runtime.runPromise(SubagentManager);
|
|
84
|
+
const started = await runTool(
|
|
85
|
+
runtime,
|
|
86
|
+
manager.spawn(
|
|
87
|
+
"claude",
|
|
88
|
+
task(
|
|
89
|
+
"Write a detailed 10,000-word essay about the history of computing.",
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Wait for streamed output so cancellation definitely lands mid-run and
|
|
95
|
+
// exercises the SDK's normal interrupt receipt/result path.
|
|
96
|
+
const streamDeadline = Date.now() + 15_000;
|
|
97
|
+
while (
|
|
98
|
+
manager.view.get(started.id)?.status === "running" &&
|
|
99
|
+
!manager.view.get(started.id)?.liveAssistant?.text &&
|
|
100
|
+
Date.now() < streamDeadline
|
|
101
|
+
) {
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
103
|
+
}
|
|
104
|
+
assert.equal(manager.view.get(started.id)?.status, "running");
|
|
105
|
+
assert.ok(manager.view.get(started.id)?.liveAssistant?.text);
|
|
106
|
+
|
|
107
|
+
const report = await deadline(
|
|
108
|
+
runTool(runtime, manager.cancel([started.id])),
|
|
109
|
+
20_000,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
assert.equal(report[0]?.cancelled, true);
|
|
113
|
+
assert.equal(manager.view.get(started.id)?.status, "error");
|
|
114
|
+
assert.equal(manager.view.get(started.id)?.errorText, "Run was aborted");
|
|
115
|
+
} finally {
|
|
116
|
+
await runtime.dispose();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
);
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
import { codexBackend } from "./src/backends/codex.ts";
|
|
5
|
-
import type { ParentContext, SpawnTask } from "./src/domain.ts";
|
|
6
|
-
import { SubagentManager } from "./src/manager.ts";
|
|
7
|
-
import { createSubagentRuntime, runTool } from "./src/runtime.ts";
|
|
8
|
-
|
|
9
|
-
const parent: ParentContext = {
|
|
10
|
-
parentCwd: process.cwd(),
|
|
11
|
-
projectTrusted: false,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function task(prompt: string): SpawnTask {
|
|
15
|
-
return {
|
|
16
|
-
prompt,
|
|
17
|
-
title: "live Codex test",
|
|
18
|
-
cwd: process.cwd(),
|
|
19
|
-
parent,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function deadline<A>(operation: Promise<A>, timeoutMs: number) {
|
|
24
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
-
const timeout = new Promise<never>((_resolve, reject) => {
|
|
26
|
-
timer = setTimeout(
|
|
27
|
-
() => reject(new Error(`Live Codex test exceeded ${timeoutMs}ms`)),
|
|
28
|
-
timeoutMs,
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
return Promise.race([operation, timeout]).finally(() => {
|
|
32
|
-
if (timer) clearTimeout(timer);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function codexAvailable() {
|
|
37
|
-
return Effect.runPromise(codexBackend.available);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
test(
|
|
41
|
-
"Codex backend completes a live manager run",
|
|
42
|
-
{ timeout: 75_000 },
|
|
43
|
-
async (t) => {
|
|
44
|
-
if (!(await codexAvailable())) {
|
|
45
|
-
t.skip("codex executable is unavailable");
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const runtime = createSubagentRuntime();
|
|
50
|
-
try {
|
|
51
|
-
const manager = await runtime.runPromise(SubagentManager);
|
|
52
|
-
const spawned = await runTool(
|
|
53
|
-
runtime,
|
|
54
|
-
manager.spawn("codex", task("Reply with exactly: hello codex")),
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
await deadline(runTool(runtime, manager.waitFor([spawned.id])), 60_000);
|
|
58
|
-
const done = manager.view.get(spawned.id);
|
|
59
|
-
assert.equal(done?.status, "done");
|
|
60
|
-
assert.match(done?.finalText ?? "", /hello codex/i);
|
|
61
|
-
assert.equal(done?.meta.backend, "codex");
|
|
62
|
-
assert.ok(done?.meta.nativeSessionId);
|
|
63
|
-
assert.ok(done?.meta.sessionFilePath);
|
|
64
|
-
} finally {
|
|
65
|
-
await runtime.dispose();
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
test(
|
|
71
|
-
"Codex backend interrupt settles a live manager run",
|
|
72
|
-
{ timeout: 30_000 },
|
|
73
|
-
async (t) => {
|
|
74
|
-
if (!(await codexAvailable())) {
|
|
75
|
-
t.skip("codex executable is unavailable");
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const runtime = createSubagentRuntime();
|
|
80
|
-
try {
|
|
81
|
-
const manager = await runtime.runPromise(SubagentManager);
|
|
82
|
-
const spawned = await runTool(
|
|
83
|
-
runtime,
|
|
84
|
-
manager.spawn(
|
|
85
|
-
"codex",
|
|
86
|
-
task("Run `sleep 30`, then reply with the word finished."),
|
|
87
|
-
),
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
91
|
-
const result = await deadline(
|
|
92
|
-
runTool(runtime, manager.cancel([spawned.id])),
|
|
93
|
-
10_000,
|
|
94
|
-
);
|
|
95
|
-
assert.equal(result[0]?.cancelled, true);
|
|
96
|
-
assert.equal(manager.view.get(spawned.id)?.status, "error");
|
|
97
|
-
assert.equal(manager.view.get(spawned.id)?.errorText, "Run was aborted");
|
|
98
|
-
} finally {
|
|
99
|
-
await runtime.dispose();
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
);
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { codexBackend } from "./src/backends/codex.ts";
|
|
5
|
+
import type { ParentContext, SpawnTask } from "./src/domain.ts";
|
|
6
|
+
import { SubagentManager } from "./src/manager.ts";
|
|
7
|
+
import { createSubagentRuntime, runTool } from "./src/runtime.ts";
|
|
8
|
+
|
|
9
|
+
const parent: ParentContext = {
|
|
10
|
+
parentCwd: process.cwd(),
|
|
11
|
+
projectTrusted: false,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function task(prompt: string): SpawnTask {
|
|
15
|
+
return {
|
|
16
|
+
prompt,
|
|
17
|
+
title: "live Codex test",
|
|
18
|
+
cwd: process.cwd(),
|
|
19
|
+
parent,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function deadline<A>(operation: Promise<A>, timeoutMs: number) {
|
|
24
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
+
const timeout = new Promise<never>((_resolve, reject) => {
|
|
26
|
+
timer = setTimeout(
|
|
27
|
+
() => reject(new Error(`Live Codex test exceeded ${timeoutMs}ms`)),
|
|
28
|
+
timeoutMs,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
return Promise.race([operation, timeout]).finally(() => {
|
|
32
|
+
if (timer) clearTimeout(timer);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function codexAvailable() {
|
|
37
|
+
return Effect.runPromise(codexBackend.available);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test(
|
|
41
|
+
"Codex backend completes a live manager run",
|
|
42
|
+
{ timeout: 75_000 },
|
|
43
|
+
async (t) => {
|
|
44
|
+
if (!(await codexAvailable())) {
|
|
45
|
+
t.skip("codex executable is unavailable");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const runtime = createSubagentRuntime();
|
|
50
|
+
try {
|
|
51
|
+
const manager = await runtime.runPromise(SubagentManager);
|
|
52
|
+
const spawned = await runTool(
|
|
53
|
+
runtime,
|
|
54
|
+
manager.spawn("codex", task("Reply with exactly: hello codex")),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await deadline(runTool(runtime, manager.waitFor([spawned.id])), 60_000);
|
|
58
|
+
const done = manager.view.get(spawned.id);
|
|
59
|
+
assert.equal(done?.status, "done");
|
|
60
|
+
assert.match(done?.finalText ?? "", /hello codex/i);
|
|
61
|
+
assert.equal(done?.meta.backend, "codex");
|
|
62
|
+
assert.ok(done?.meta.nativeSessionId);
|
|
63
|
+
assert.ok(done?.meta.sessionFilePath);
|
|
64
|
+
} finally {
|
|
65
|
+
await runtime.dispose();
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
test(
|
|
71
|
+
"Codex backend interrupt settles a live manager run",
|
|
72
|
+
{ timeout: 30_000 },
|
|
73
|
+
async (t) => {
|
|
74
|
+
if (!(await codexAvailable())) {
|
|
75
|
+
t.skip("codex executable is unavailable");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const runtime = createSubagentRuntime();
|
|
80
|
+
try {
|
|
81
|
+
const manager = await runtime.runPromise(SubagentManager);
|
|
82
|
+
const spawned = await runTool(
|
|
83
|
+
runtime,
|
|
84
|
+
manager.spawn(
|
|
85
|
+
"codex",
|
|
86
|
+
task("Run `sleep 30`, then reply with the word finished."),
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
91
|
+
const result = await deadline(
|
|
92
|
+
runTool(runtime, manager.cancel([spawned.id])),
|
|
93
|
+
10_000,
|
|
94
|
+
);
|
|
95
|
+
assert.equal(result[0]?.cancelled, true);
|
|
96
|
+
assert.equal(manager.view.get(spawned.id)?.status, "error");
|
|
97
|
+
assert.equal(manager.view.get(spawned.id)?.errorText, "Run was aborted");
|
|
98
|
+
} finally {
|
|
99
|
+
await runtime.dispose();
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
);
|