@asterxsk/kiln 0.1.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 -0
- package/README.md +170 -0
- package/agent/AGENTS.md +67 -0
- package/agent/README.md +5 -0
- package/agent/extensions/AGENTS.md +68 -0
- package/agent/extensions/ask-user/index.ts +418 -0
- package/agent/extensions/ask-user/install.ps1 +23 -0
- package/agent/extensions/ask-user/install.sh +21 -0
- package/agent/extensions/ask-user/package-lock.json +769 -0
- package/agent/extensions/ask-user/package.json +19 -0
- package/agent/extensions/ask-user/prompt.ts +45 -0
- package/agent/extensions/ask-user/tsconfig.json +7 -0
- package/agent/extensions/background-terminals/docs/implementation-guide.md +942 -0
- package/agent/extensions/background-terminals/index.ts +627 -0
- package/agent/extensions/background-terminals/install.ps1 +23 -0
- package/agent/extensions/background-terminals/install.sh +21 -0
- package/agent/extensions/background-terminals/manager.test.ts +735 -0
- package/agent/extensions/background-terminals/output.test.ts +109 -0
- package/agent/extensions/background-terminals/package-lock.json +769 -0
- package/agent/extensions/background-terminals/package.json +17 -0
- package/agent/extensions/background-terminals/prompt.test.ts +125 -0
- package/agent/extensions/background-terminals/ps.test.ts +82 -0
- package/agent/extensions/background-terminals/result-delivery.test.ts +44 -0
- package/agent/extensions/background-terminals/src/domain.ts +87 -0
- package/agent/extensions/background-terminals/src/manager.ts +907 -0
- package/agent/extensions/background-terminals/src/output.ts +84 -0
- package/agent/extensions/background-terminals/src/prompt.ts +142 -0
- package/agent/extensions/background-terminals/src/result-delivery.ts +27 -0
- package/agent/extensions/background-terminals/src/runtime.ts +36 -0
- package/agent/extensions/background-terminals/src/ui/output-view.ts +79 -0
- package/agent/extensions/background-terminals/src/ui/ps.ts +621 -0
- package/agent/extensions/background-terminals/tsconfig.json +7 -0
- package/agent/extensions/destructive/README.md +31 -0
- package/agent/extensions/destructive/index.ts +88 -0
- package/agent/extensions/destructive/install.ps1 +23 -0
- package/agent/extensions/destructive/install.sh +21 -0
- package/agent/extensions/file-search/index.spec.ts +443 -0
- package/agent/extensions/file-search/index.ts +459 -0
- package/agent/extensions/file-search/install.ps1 +23 -0
- package/agent/extensions/file-search/install.sh +21 -0
- package/agent/extensions/file-search/package-lock.json +2253 -0
- package/agent/extensions/file-search/package.json +23 -0
- package/agent/extensions/file-search/src/args.ts +122 -0
- package/agent/extensions/file-search/src/binaries.ts +422 -0
- package/agent/extensions/file-search/src/output.ts +126 -0
- package/agent/extensions/file-search/src/process.ts +146 -0
- package/agent/extensions/file-search/src/prompt.ts +52 -0
- package/agent/extensions/file-search/tsconfig.json +7 -0
- package/agent/extensions/goal/README.md +50 -0
- package/agent/extensions/goal/index.ts +155 -0
- package/agent/extensions/goal/install.ps1 +23 -0
- package/agent/extensions/goal/install.sh +21 -0
- package/agent/extensions/modelconf/PLAN.md +915 -0
- package/agent/extensions/modelconf/README.md +66 -0
- package/agent/extensions/modelconf/index.ts +296 -0
- package/agent/extensions/modelconf/install.ps1 +23 -0
- package/agent/extensions/modelconf/install.sh +21 -0
- package/agent/extensions/modelconf/package-lock.json +1809 -0
- package/agent/extensions/modelconf/package.json +13 -0
- package/agent/extensions/modelconf/src/fuzzy.ts +26 -0
- package/agent/extensions/modelconf/src/glob.ts +13 -0
- package/agent/extensions/modelconf/src/persistence.test.ts +46 -0
- package/agent/extensions/modelconf/src/persistence.ts +164 -0
- package/agent/extensions/modelconf/src/ui/ModelConfView.test.ts +75 -0
- package/agent/extensions/modelconf/src/ui/ModelConfView.ts +1101 -0
- package/agent/extensions/modelconf/tsconfig.json +15 -0
- package/agent/extensions/pi-web-access/CHANGELOG.md +690 -0
- package/agent/extensions/pi-web-access/LICENSE +21 -0
- package/agent/extensions/pi-web-access/README.md +470 -0
- package/agent/extensions/pi-web-access/SECURITY.md +5 -0
- package/agent/extensions/pi-web-access/activity.ts +101 -0
- package/agent/extensions/pi-web-access/auth-fetch.ts +148 -0
- package/agent/extensions/pi-web-access/banner.png +0 -0
- package/agent/extensions/pi-web-access/brightdata-unlocker.ts +272 -0
- package/agent/extensions/pi-web-access/chrome-cookies.ts +669 -0
- package/agent/extensions/pi-web-access/content-find.ts +139 -0
- package/agent/extensions/pi-web-access/credential-source.ts +191 -0
- package/agent/extensions/pi-web-access/data-uri-sanitize.ts +406 -0
- package/agent/extensions/pi-web-access/datalab-pdf-extract.ts +568 -0
- package/agent/extensions/pi-web-access/declared-web-links.ts +173 -0
- package/agent/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +496 -0
- package/agent/extensions/pi-web-access/evidence/contract-probe.mjs +140 -0
- package/agent/extensions/pi-web-access/exa.ts +526 -0
- package/agent/extensions/pi-web-access/extract.ts +1196 -0
- package/agent/extensions/pi-web-access/feature-config.ts +29 -0
- package/agent/extensions/pi-web-access/fetch-params.ts +111 -0
- package/agent/extensions/pi-web-access/gemini-adc.ts +298 -0
- package/agent/extensions/pi-web-access/gemini-api.ts +353 -0
- package/agent/extensions/pi-web-access/gemini-pdf-extract.ts +108 -0
- package/agent/extensions/pi-web-access/gemini-search.ts +21 -0
- package/agent/extensions/pi-web-access/gemini-url-context.ts +128 -0
- package/agent/extensions/pi-web-access/gemini-web-config.ts +101 -0
- package/agent/extensions/pi-web-access/gemini-web.ts +487 -0
- package/agent/extensions/pi-web-access/github-api.ts +197 -0
- package/agent/extensions/pi-web-access/github-extract.ts +746 -0
- package/agent/extensions/pi-web-access/github-issue-pr.ts +700 -0
- package/agent/extensions/pi-web-access/index.ts +1737 -0
- package/agent/extensions/pi-web-access/package-lock.json +5808 -0
- package/agent/extensions/pi-web-access/package.json +64 -0
- package/agent/extensions/pi-web-access/page-query.ts +96 -0
- package/agent/extensions/pi-web-access/pdf-extract.ts +409 -0
- package/agent/extensions/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
- package/agent/extensions/pi-web-access/promise-try.d.ts +7 -0
- package/agent/extensions/pi-web-access/query-rewrite.ts +51 -0
- package/agent/extensions/pi-web-access/render-search-error.ts +170 -0
- package/agent/extensions/pi-web-access/rsc-extract.ts +338 -0
- package/agent/extensions/pi-web-access/search-types.ts +20 -0
- package/agent/extensions/pi-web-access/source-check.ts +282 -0
- package/agent/extensions/pi-web-access/ssrf-protection.ts +526 -0
- package/agent/extensions/pi-web-access/storage.ts +521 -0
- package/agent/extensions/pi-web-access/summary-model-scope.ts +125 -0
- package/agent/extensions/pi-web-access/test/auth-fetch.test.mjs +208 -0
- package/agent/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +840 -0
- package/agent/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +441 -0
- package/agent/extensions/pi-web-access/test/config-path.test.mjs +283 -0
- package/agent/extensions/pi-web-access/test/content-find.test.mjs +25 -0
- package/agent/extensions/pi-web-access/test/credential-source.test.mjs +118 -0
- package/agent/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +210 -0
- package/agent/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +552 -0
- package/agent/extensions/pi-web-access/test/declared-web-links.test.mjs +212 -0
- package/agent/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +40 -0
- package/agent/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +334 -0
- package/agent/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +95 -0
- package/agent/extensions/pi-web-access/test/fetch-modes.test.mjs +53 -0
- package/agent/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +92 -0
- package/agent/extensions/pi-web-access/test/fetch-params.test.mjs +86 -0
- package/agent/extensions/pi-web-access/test/fetch-render-call.test.mjs +34 -0
- package/agent/extensions/pi-web-access/test/fetch-routing.test.mjs +173 -0
- package/agent/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +257 -0
- package/agent/extensions/pi-web-access/test/gemini-api-transport.test.mjs +170 -0
- package/agent/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +133 -0
- package/agent/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +178 -0
- package/agent/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +148 -0
- package/agent/extensions/pi-web-access/test/get-search-content.test.mjs +223 -0
- package/agent/extensions/pi-web-access/test/github-extract.test.mjs +378 -0
- package/agent/extensions/pi-web-access/test/github-issue-pr.test.mjs +565 -0
- package/agent/extensions/pi-web-access/test/inline-content-config.test.mjs +99 -0
- package/agent/extensions/pi-web-access/test/lazy-extract-load.test.mjs +118 -0
- package/agent/extensions/pi-web-access/test/local-video-oversize.test.mjs +52 -0
- package/agent/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +50 -0
- package/agent/extensions/pi-web-access/test/page-query.test.mjs +51 -0
- package/agent/extensions/pi-web-access/test/pdf-config.test.mjs +140 -0
- package/agent/extensions/pi-web-access/test/pdf-extract.test.mjs +500 -0
- package/agent/extensions/pi-web-access/test/proxy-transport.test.mjs +286 -0
- package/agent/extensions/pi-web-access/test/query-rewrite.test.mjs +52 -0
- package/agent/extensions/pi-web-access/test/rsc-fallback.test.mjs +102 -0
- package/agent/extensions/pi-web-access/test/search-error-render.test.mjs +152 -0
- package/agent/extensions/pi-web-access/test/search-providers.test.mjs +274 -0
- package/agent/extensions/pi-web-access/test/source-check.test.mjs +179 -0
- package/agent/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +205 -0
- package/agent/extensions/pi-web-access/test/ssrf-protection.test.mjs +456 -0
- package/agent/extensions/pi-web-access/test/summary-model-scope.test.mjs +106 -0
- package/agent/extensions/pi-web-access/test/tool-registration-config.test.mjs +182 -0
- package/agent/extensions/pi-web-access/test/web-search-answer-render.test.mjs +66 -0
- package/agent/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +64 -0
- package/agent/extensions/pi-web-access/tsconfig.json +11 -0
- package/agent/extensions/pi-web-access/utils.ts +451 -0
- package/agent/extensions/pi-web-access/video-extract.ts +392 -0
- package/agent/extensions/pi-web-access/youtube-extract.ts +328 -0
- package/agent/extensions/shared/activity-status.ts +31 -0
- package/agent/extensions/shared/child-session.test.ts +270 -0
- package/agent/extensions/shared/child-session.ts +148 -0
- package/agent/extensions/shared/context-utilization.test.ts +48 -0
- package/agent/extensions/shared/context-utilization.ts +47 -0
- package/agent/extensions/shared/dashboard-state.ts +99 -0
- package/agent/extensions/shared/install.ps1 +23 -0
- package/agent/extensions/shared/install.sh +21 -0
- package/agent/extensions/shared/tool-call-timeout.test.ts +117 -0
- package/agent/extensions/shared/tool-call-timeout.ts +104 -0
- package/agent/extensions/skillsconf/README.md +74 -0
- package/agent/extensions/skillsconf/index.ts +92 -0
- package/agent/extensions/skillsconf/install.ps1 +23 -0
- package/agent/extensions/skillsconf/install.sh +21 -0
- package/agent/extensions/skillsconf/package-lock.json +1809 -0
- package/agent/extensions/skillsconf/package.json +18 -0
- package/agent/extensions/skillsconf/src/delete-skill.test.ts +64 -0
- package/agent/extensions/skillsconf/src/delete-skill.ts +45 -0
- package/agent/extensions/skillsconf/src/filter.test.ts +80 -0
- package/agent/extensions/skillsconf/src/filter.ts +74 -0
- package/agent/extensions/skillsconf/src/fuzzy.ts +26 -0
- package/agent/extensions/skillsconf/src/persistence.test.ts +72 -0
- package/agent/extensions/skillsconf/src/persistence.ts +169 -0
- package/agent/extensions/skillsconf/src/ui/SkillConfView.test.ts +337 -0
- package/agent/extensions/skillsconf/src/ui/SkillConfView.ts +758 -0
- package/agent/extensions/skillsconf/src/ui/text-input.ts +91 -0
- package/agent/extensions/skillsconf/src/ui/tui-helpers.ts +144 -0
- package/agent/extensions/skillsconf/tsconfig.json +15 -0
- package/agent/extensions/status line/index.ts +282 -0
- package/agent/extensions/status line/install.ps1 +23 -0
- package/agent/extensions/status line/install.sh +21 -0
- package/agent/extensions/subagents/by-the-way.test.ts +29 -0
- package/agent/extensions/subagents/claude.test.ts +119 -0
- package/agent/extensions/subagents/codex.test.ts +102 -0
- package/agent/extensions/subagents/context-usage.test.ts +107 -0
- package/agent/extensions/subagents/docs/design-plan.md +568 -0
- package/agent/extensions/subagents/docs/effect-v4-extension-guide.md +354 -0
- package/agent/extensions/subagents/docs/effect-v4-notes.md +571 -0
- package/agent/extensions/subagents/index.ts +779 -0
- package/agent/extensions/subagents/install.ps1 +23 -0
- package/agent/extensions/subagents/install.sh +21 -0
- package/agent/extensions/subagents/manager.test.ts +276 -0
- package/agent/extensions/subagents/package-lock.json +2244 -0
- package/agent/extensions/subagents/package.json +19 -0
- package/agent/extensions/subagents/result-delivery.test.ts +27 -0
- package/agent/extensions/subagents/src/backend.ts +73 -0
- package/agent/extensions/subagents/src/backends/claude.ts +701 -0
- package/agent/extensions/subagents/src/backends/codex.ts +1060 -0
- package/agent/extensions/subagents/src/backends/pi.ts +575 -0
- package/agent/extensions/subagents/src/backends/stub.ts +300 -0
- package/agent/extensions/subagents/src/by-the-way.ts +21 -0
- package/agent/extensions/subagents/src/domain.ts +253 -0
- package/agent/extensions/subagents/src/format.ts +74 -0
- package/agent/extensions/subagents/src/manager.ts +736 -0
- package/agent/extensions/subagents/src/prompt.ts +92 -0
- package/agent/extensions/subagents/src/result-delivery.ts +20 -0
- package/agent/extensions/subagents/src/runtime.ts +53 -0
- package/agent/extensions/subagents/src/ui/takeover.ts +583 -0
- package/agent/extensions/subagents/src/ui/transcript.ts +201 -0
- package/agent/extensions/subagents/takeover.test.ts +29 -0
- package/agent/extensions/subagents/tsconfig.json +7 -0
- package/agent/extensions/taste/index.ts +443 -0
- package/agent/extensions/taste/install.ps1 +23 -0
- package/agent/extensions/taste/install.sh +21 -0
- package/agent/extensions/todo/AGENTS.md +38 -0
- package/agent/extensions/todo/LICENSE +21 -0
- package/agent/extensions/todo/config.ts +55 -0
- package/agent/extensions/todo/index.ts +151 -0
- package/agent/extensions/todo/install.ps1 +23 -0
- package/agent/extensions/todo/install.sh +21 -0
- package/agent/extensions/todo/locales/de.json +17 -0
- package/agent/extensions/todo/locales/en.json +15 -0
- package/agent/extensions/todo/locales/es.json +17 -0
- package/agent/extensions/todo/locales/fr.json +17 -0
- package/agent/extensions/todo/locales/pt-BR.json +17 -0
- package/agent/extensions/todo/locales/pt.json +17 -0
- package/agent/extensions/todo/locales/ru.json +17 -0
- package/agent/extensions/todo/locales/uk.json +17 -0
- package/agent/extensions/todo/locales/zh.json +17 -0
- package/agent/extensions/todo/package-lock.json +3358 -0
- package/agent/extensions/todo/package.json +67 -0
- package/agent/extensions/todo/state/i18n-bridge.ts +64 -0
- package/agent/extensions/todo/state/invariants.ts +20 -0
- package/agent/extensions/todo/state/replay.ts +38 -0
- package/agent/extensions/todo/state/selectors.ts +107 -0
- package/agent/extensions/todo/state/state-reducer.ts +326 -0
- package/agent/extensions/todo/state/state.ts +18 -0
- package/agent/extensions/todo/state/store.ts +82 -0
- package/agent/extensions/todo/state/task-graph.ts +57 -0
- package/agent/extensions/todo/todo-overlay.ts +200 -0
- package/agent/extensions/todo/todo.ts +155 -0
- package/agent/extensions/todo/tool/response-envelope.ts +109 -0
- package/agent/extensions/todo/tool/types.ts +206 -0
- package/agent/extensions/todo/verify-ref-system.js +0 -0
- package/agent/extensions/todo/view/format.ts +177 -0
- package/agent/extensions/trim-context/README.md +54 -0
- package/agent/extensions/trim-context/index.ts +487 -0
- package/agent/extensions/trim-context/install.ps1 +23 -0
- package/agent/extensions/trim-context/install.sh +21 -0
- package/agent/install.ps1 +527 -0
- package/agent/install.sh +511 -0
- package/agent/keybindings.json +7 -0
- package/bin/kiln.js +359 -0
- package/package.json +21 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "background-terminals",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"check": "tsc --noEmit -p .",
|
|
7
|
+
"prepare": "effect-tsgo patch",
|
|
8
|
+
"test": "node --test --experimental-strip-types manager.test.ts output.test.ts prompt.test.ts result-delivery.test.ts ps.test.ts"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"effect": "^4.0.0-beta.99"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@effect/tsgo": "^0.24.2",
|
|
15
|
+
"typescript": "^7.0.2"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import type { OutputView, TerminalSnapshot } from "./src/domain.ts";
|
|
4
|
+
import {
|
|
5
|
+
BG_START_PARAMETER_DESCRIPTIONS,
|
|
6
|
+
BG_START_TOOL_DESCRIPTION,
|
|
7
|
+
buildKillReport,
|
|
8
|
+
buildStatusResult,
|
|
9
|
+
buildTerminalResultMessage,
|
|
10
|
+
} from "./src/prompt.ts";
|
|
11
|
+
|
|
12
|
+
test("start descriptions identify the platform-specific shell contract", () => {
|
|
13
|
+
assert.match(BG_START_TOOL_DESCRIPTION, /sh -c on POSIX/);
|
|
14
|
+
assert.match(BG_START_TOOL_DESCRIPTION, /cmd\.exe \/d \/s \/c on Windows/);
|
|
15
|
+
assert.match(BG_START_PARAMETER_DESCRIPTIONS.command, /sh -c on POSIX/);
|
|
16
|
+
assert.match(
|
|
17
|
+
BG_START_PARAMETER_DESCRIPTIONS.command,
|
|
18
|
+
/cmd\.exe \/d \/s \/c on Windows/,
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function view(overrides: Partial<OutputView> = {}): OutputView {
|
|
23
|
+
return { text: "", totalBytes: 0, truncatedBytes: 0, ...overrides };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function snap(overrides: Partial<TerminalSnapshot> = {}): TerminalSnapshot {
|
|
27
|
+
return {
|
|
28
|
+
id: "bt-1",
|
|
29
|
+
command: "sleep 999",
|
|
30
|
+
title: "test",
|
|
31
|
+
cwd: "/tmp",
|
|
32
|
+
pid: 123,
|
|
33
|
+
status: "done",
|
|
34
|
+
createdAt: Date.now() - 5_000,
|
|
35
|
+
settledAt: Date.now(),
|
|
36
|
+
exitCode: 0,
|
|
37
|
+
stdout: view(),
|
|
38
|
+
stderr: view(),
|
|
39
|
+
...overrides,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
test("kill report distinguishes killed / raced natural exit / already settled", () => {
|
|
44
|
+
const report = buildKillReport([
|
|
45
|
+
{
|
|
46
|
+
id: "bt-1",
|
|
47
|
+
title: "a",
|
|
48
|
+
status: "killed",
|
|
49
|
+
wasRunning: true,
|
|
50
|
+
killed: true,
|
|
51
|
+
exit: "SIGTERM",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "bt-2",
|
|
55
|
+
title: "b",
|
|
56
|
+
status: "done",
|
|
57
|
+
wasRunning: true,
|
|
58
|
+
killed: false,
|
|
59
|
+
exit: "exit 0",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "bt-3",
|
|
63
|
+
title: "c",
|
|
64
|
+
status: "failed",
|
|
65
|
+
wasRunning: false,
|
|
66
|
+
killed: false,
|
|
67
|
+
exit: "exit 1",
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
const lines = report.split("\n");
|
|
71
|
+
assert.equal(lines[0], 'Killed bt-1 "a" (SIGTERM).');
|
|
72
|
+
assert.match(lines[1], /exited on its own before the kill landed \(exit 0\)/);
|
|
73
|
+
assert.match(lines[2], /was already failed \(exit 1\)/);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("status result marks head-truncated output with a pointer at the full log", () => {
|
|
77
|
+
const text = buildStatusResult(
|
|
78
|
+
snap({
|
|
79
|
+
stdout: view({
|
|
80
|
+
text: "tail of the log\n",
|
|
81
|
+
totalBytes: 5 * 1024 * 1024,
|
|
82
|
+
truncatedBytes: 5 * 1024 * 1024 - 16,
|
|
83
|
+
spillPath: "/tmp/bt-1.stdout.log",
|
|
84
|
+
}),
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
assert.match(text, /stdout truncated: showing last /);
|
|
88
|
+
assert.match(text, /Full log: \/tmp\/bt-1\.stdout\.log/);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("completion message reports kill vs exit and omits empty stderr", () => {
|
|
92
|
+
const killed = buildTerminalResultMessage(
|
|
93
|
+
snap({ status: "killed", exitCode: undefined, signal: "SIGTERM" }),
|
|
94
|
+
);
|
|
95
|
+
assert.match(killed, /was killed after/);
|
|
96
|
+
assert.ok(!killed.includes("stderr"), "empty stderr section omitted");
|
|
97
|
+
|
|
98
|
+
const failed = buildTerminalResultMessage(
|
|
99
|
+
snap({
|
|
100
|
+
status: "failed",
|
|
101
|
+
exitCode: 3,
|
|
102
|
+
stderr: view({ text: "boom\n", totalBytes: 5 }),
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
assert.match(failed, /exited \(exit 3\)/);
|
|
106
|
+
assert.match(failed, /stderr:\nboom/);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("completion output is a shorter tail than the detailed status view", () => {
|
|
110
|
+
const output = Array.from(
|
|
111
|
+
{ length: 100 },
|
|
112
|
+
(_, index) => `line-${index + 1}`,
|
|
113
|
+
).join("\n");
|
|
114
|
+
const terminal = snap({
|
|
115
|
+
stdout: view({ text: output, totalBytes: Buffer.byteLength(output) }),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const completion = buildTerminalResultMessage(terminal);
|
|
119
|
+
const status = buildStatusResult(terminal);
|
|
120
|
+
|
|
121
|
+
assert.ok(!completion.includes("line-1\n"));
|
|
122
|
+
assert.match(completion, /line-100/);
|
|
123
|
+
assert.match(completion, /stdout truncated/);
|
|
124
|
+
assert.match(status, /line-1\n/);
|
|
125
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
reconcileDashboardSelection,
|
|
5
|
+
type DashboardSelection,
|
|
6
|
+
} from "./src/ui/ps.ts";
|
|
7
|
+
import {
|
|
8
|
+
buildOutputLines,
|
|
9
|
+
createOutputLineCache,
|
|
10
|
+
sanitizeText,
|
|
11
|
+
} from "./src/ui/output-view.ts";
|
|
12
|
+
|
|
13
|
+
test("dashboard selection follows its terminal id and falls back by row", () => {
|
|
14
|
+
const selection: DashboardSelection = { id: "bt-7", index: 6 };
|
|
15
|
+
|
|
16
|
+
reconcileDashboardSelection(selection, [
|
|
17
|
+
{ id: "bt-new" },
|
|
18
|
+
...Array.from({ length: 8 }, (_, index) => ({ id: `bt-${index + 1}` })),
|
|
19
|
+
]);
|
|
20
|
+
assert.deepEqual(selection, { id: "bt-7", index: 7 });
|
|
21
|
+
|
|
22
|
+
reconcileDashboardSelection(selection, [
|
|
23
|
+
...Array.from({ length: 6 }, (_, index) => ({ id: `bt-${index + 1}` })),
|
|
24
|
+
{ id: "bt-8" },
|
|
25
|
+
{ id: "bt-9" },
|
|
26
|
+
]);
|
|
27
|
+
assert.deepEqual(selection, { id: "bt-9", index: 7 });
|
|
28
|
+
|
|
29
|
+
reconcileDashboardSelection(selection, [{ id: "bt-1" }, { id: "bt-2" }]);
|
|
30
|
+
assert.deepEqual(selection, { id: "bt-2", index: 1 });
|
|
31
|
+
|
|
32
|
+
reconcileDashboardSelection(selection, []);
|
|
33
|
+
assert.deepEqual(selection, { id: undefined, index: 0 });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("sanitizeText strips ANSI, tabs, and control characters", () => {
|
|
37
|
+
assert.equal(sanitizeText("\u001b[31mred\u001b[0m"), "red");
|
|
38
|
+
assert.equal(sanitizeText("\u001b[12345Cshifted"), "shifted");
|
|
39
|
+
assert.equal(sanitizeText("\u001b]0;window title\u0007output"), "output");
|
|
40
|
+
assert.equal(
|
|
41
|
+
sanitizeText("\u001b]8;;https://example.com\u001b\\link\u001b]8;;\u001b\\"),
|
|
42
|
+
"link",
|
|
43
|
+
);
|
|
44
|
+
assert.equal(sanitizeText("\u001b]0;title\u009coutput"), "output");
|
|
45
|
+
assert.equal(sanitizeText("\u009d0;title\u0007output"), "output");
|
|
46
|
+
assert.equal(sanitizeText("a\u0085b"), "ab");
|
|
47
|
+
assert.equal(sanitizeText("a\tb"), "a b");
|
|
48
|
+
assert.equal(sanitizeText("a\u0007b\u0000c"), "abc");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("output line cache reuses a version/width key and invalidates either dimension", () => {
|
|
52
|
+
const cache = createOutputLineCache();
|
|
53
|
+
const first = cache.get("first", 1, 80);
|
|
54
|
+
const sameKey = cache.get("different text is intentionally ignored", 1, 80);
|
|
55
|
+
assert.equal(sameKey, first);
|
|
56
|
+
assert.deepEqual(sameKey, ["first"]);
|
|
57
|
+
|
|
58
|
+
const newVersion = cache.get("second", 2, 80);
|
|
59
|
+
assert.notEqual(newVersion, first);
|
|
60
|
+
assert.deepEqual(newVersion, ["second"]);
|
|
61
|
+
|
|
62
|
+
const newWidth = cache.get("x".repeat(25), 2, 10);
|
|
63
|
+
assert.notEqual(newWidth, newVersion);
|
|
64
|
+
assert.ok(newWidth.length > 1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("buildOutputLines wraps long lines and keeps only the final CR segment", () => {
|
|
68
|
+
const lines = buildOutputLines("progress 1\rprogress 2\rdone\nnext", 80);
|
|
69
|
+
assert.deepEqual(lines, ["done", "next"]);
|
|
70
|
+
assert.deepEqual(buildOutputLines("progress 1\rprogress 2\r", 80), [
|
|
71
|
+
"progress 2",
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const wrapped = buildOutputLines("x".repeat(25), 10);
|
|
75
|
+
assert.ok(wrapped.length > 1);
|
|
76
|
+
assert.equal(wrapped.join(""), "x".repeat(25));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("buildOutputLines drops one trailing empty line from a trailing newline", () => {
|
|
80
|
+
assert.deepEqual(buildOutputLines("a\nb\n", 80), ["a", "b"]);
|
|
81
|
+
assert.deepEqual(buildOutputLines("a\n\n", 80), ["a", ""]);
|
|
82
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createDeferredResultDelivery } from "./src/result-delivery.ts";
|
|
4
|
+
|
|
5
|
+
test("a result consumed by a kill/status is not delivered", () => {
|
|
6
|
+
const delivery = createDeferredResultDelivery<{
|
|
7
|
+
id: string;
|
|
8
|
+
output: string;
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
delivery.defer({ id: "bt-1", output: "done" });
|
|
12
|
+
delivery.consume(["bt-1"]);
|
|
13
|
+
|
|
14
|
+
assert.deepEqual(delivery.drain(), []);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("unconsumed results are delivered once in settlement order", () => {
|
|
18
|
+
const delivery = createDeferredResultDelivery<{ id: string }>();
|
|
19
|
+
const first = { id: "bt-1" };
|
|
20
|
+
const second = { id: "bt-2" };
|
|
21
|
+
|
|
22
|
+
delivery.defer(first);
|
|
23
|
+
delivery.defer(second);
|
|
24
|
+
|
|
25
|
+
assert.deepEqual(delivery.drain(), [first, second]);
|
|
26
|
+
assert.deepEqual(delivery.drain(), []);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("re-deferring the same id replaces rather than duplicates", () => {
|
|
30
|
+
const delivery = createDeferredResultDelivery<{ id: string; n: number }>();
|
|
31
|
+
delivery.defer({ id: "bt-1", n: 1 });
|
|
32
|
+
delivery.defer({ id: "bt-1", n: 2 });
|
|
33
|
+
assert.deepEqual(delivery.drain(), [{ id: "bt-1", n: 2 }]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("a drained result can be retained for retry after delivery fails", () => {
|
|
37
|
+
const delivery = createDeferredResultDelivery<{ id: string }>();
|
|
38
|
+
const result = { id: "bt-1" };
|
|
39
|
+
delivery.defer(result);
|
|
40
|
+
|
|
41
|
+
for (const drained of delivery.drain()) delivery.defer(drained);
|
|
42
|
+
|
|
43
|
+
assert.deepEqual(delivery.drain(), [result]);
|
|
44
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain model for background terminals.
|
|
3
|
+
*
|
|
4
|
+
* A "terminal" is one long-running shell process started by the model. It
|
|
5
|
+
* receives no stdin (launched with stdin: "ignore"), captures stdout and
|
|
6
|
+
* stderr separately, and settles exactly once into a final state.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Data } from "effect";
|
|
10
|
+
|
|
11
|
+
export type TerminalStatus = "running" | "done" | "failed" | "killed";
|
|
12
|
+
// "done" = exited with code 0
|
|
13
|
+
// "failed" = exited non-zero, or a spawn-level runtime error after start
|
|
14
|
+
// "killed" = terminated by bg_kill, the /ps UI, or session teardown
|
|
15
|
+
|
|
16
|
+
/** Read-only view over one captured output stream (stdout or stderr). */
|
|
17
|
+
export interface OutputView {
|
|
18
|
+
/** Decoded, possibly head-trimmed text (bounded by the in-memory cap). */
|
|
19
|
+
readonly text: string;
|
|
20
|
+
/** True total bytes ever received on this stream. */
|
|
21
|
+
readonly totalBytes: number;
|
|
22
|
+
/** Bytes dropped from the head of the in-memory view (0 = complete). */
|
|
23
|
+
readonly truncatedBytes: number;
|
|
24
|
+
/** On-disk full capture; always the complete stream when spilling works. */
|
|
25
|
+
readonly spillPath?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TerminalSnapshot {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
/** Exactly the command line the model asked to run. */
|
|
31
|
+
readonly command: string;
|
|
32
|
+
/** Short model-provided name, shown in listings and the UI. */
|
|
33
|
+
readonly title: string;
|
|
34
|
+
/** Resolved absolute cwd the process runs in. */
|
|
35
|
+
readonly cwd: string;
|
|
36
|
+
/** Undefined only if spawn itself failed before a pid was assigned. */
|
|
37
|
+
readonly pid?: number;
|
|
38
|
+
readonly status: TerminalStatus;
|
|
39
|
+
/** Date.now() at spawn. */
|
|
40
|
+
readonly createdAt: number;
|
|
41
|
+
/** Date.now() at settle (exit/kill). */
|
|
42
|
+
readonly settledAt?: number;
|
|
43
|
+
/** Set when the process exited via exit code (exactly one of exitCode/signal). */
|
|
44
|
+
readonly exitCode?: number;
|
|
45
|
+
/** Set when the process was terminated by a signal, e.g. "SIGTERM". */
|
|
46
|
+
readonly signal?: string;
|
|
47
|
+
/** Spawn error / kill-escalation notes, bounded. */
|
|
48
|
+
readonly errorText?: string;
|
|
49
|
+
readonly stdout: OutputView;
|
|
50
|
+
readonly stderr: OutputView;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function formatElapsed(snap: TerminalSnapshot) {
|
|
54
|
+
const end = snap.settledAt ?? Date.now();
|
|
55
|
+
const totalSeconds = Math.max(0, Math.round((end - snap.createdAt) / 1000));
|
|
56
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
57
|
+
const seconds = totalSeconds % 60;
|
|
58
|
+
return minutes > 0
|
|
59
|
+
? `${minutes}m${seconds.toString().padStart(2, "0")}s`
|
|
60
|
+
: `${seconds}s`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** "exit 0", "exit 137", "SIGTERM", or "running". */
|
|
64
|
+
export function formatExit(snap: TerminalSnapshot) {
|
|
65
|
+
if (snap.status === "running") return "running";
|
|
66
|
+
if (snap.signal) return snap.signal;
|
|
67
|
+
if (snap.exitCode !== undefined) return `exit ${snap.exitCode}`;
|
|
68
|
+
return snap.status;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- Errors -------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
export class SpawnError extends Data.TaggedError("SpawnError")<{
|
|
74
|
+
readonly message: string;
|
|
75
|
+
}> {}
|
|
76
|
+
|
|
77
|
+
export class ConcurrencyLimitError extends Data.TaggedError(
|
|
78
|
+
"ConcurrencyLimitError",
|
|
79
|
+
)<{
|
|
80
|
+
readonly message: string;
|
|
81
|
+
}> {}
|
|
82
|
+
|
|
83
|
+
export class UnknownTerminalError extends Data.TaggedError(
|
|
84
|
+
"UnknownTerminalError",
|
|
85
|
+
)<{
|
|
86
|
+
readonly message: string;
|
|
87
|
+
}> {}
|