@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,146 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_MAX_BYTES,
|
|
4
|
+
DEFAULT_MAX_LINES,
|
|
5
|
+
truncateHead,
|
|
6
|
+
} from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { Effect, FileSystem, Stream } from "effect";
|
|
8
|
+
import { ChildProcess } from "effect/unstable/process";
|
|
9
|
+
import type { CapturedOutput } from "./output.ts";
|
|
10
|
+
|
|
11
|
+
const STDERR_MAX_BYTES = 64 * 1024;
|
|
12
|
+
|
|
13
|
+
interface PreviewState {
|
|
14
|
+
readonly decoder: TextDecoder;
|
|
15
|
+
preview: string;
|
|
16
|
+
totalBytes: number;
|
|
17
|
+
lineBreaks: number;
|
|
18
|
+
trailingLineBreaks: number;
|
|
19
|
+
truncated: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function makePreviewState(): PreviewState {
|
|
23
|
+
return {
|
|
24
|
+
decoder: new TextDecoder(),
|
|
25
|
+
preview: "",
|
|
26
|
+
totalBytes: 0,
|
|
27
|
+
lineBreaks: 0,
|
|
28
|
+
trailingLineBreaks: 0,
|
|
29
|
+
truncated: false,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function observeStdout(state: PreviewState, chunk: Uint8Array) {
|
|
34
|
+
state.totalBytes += chunk.byteLength;
|
|
35
|
+
for (const byte of chunk) {
|
|
36
|
+
if (byte === 0x0a) {
|
|
37
|
+
state.lineBreaks++;
|
|
38
|
+
state.trailingLineBreaks++;
|
|
39
|
+
} else {
|
|
40
|
+
state.trailingLineBreaks = 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (state.truncated) return;
|
|
45
|
+
state.preview += state.decoder.decode(chunk, { stream: true });
|
|
46
|
+
const truncation = truncateHead(state.preview, {
|
|
47
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
48
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
49
|
+
});
|
|
50
|
+
if (truncation.truncated) {
|
|
51
|
+
state.preview = truncation.content;
|
|
52
|
+
state.truncated = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function finishStdout(state: PreviewState, fullOutputPath: string) {
|
|
57
|
+
if (!state.truncated) state.preview += state.decoder.decode();
|
|
58
|
+
const totalBytes = state.totalBytes - state.trailingLineBreaks;
|
|
59
|
+
const lineCount =
|
|
60
|
+
totalBytes === 0 ? 0 : state.lineBreaks - state.trailingLineBreaks + 1;
|
|
61
|
+
return {
|
|
62
|
+
preview: state.preview,
|
|
63
|
+
lineCount,
|
|
64
|
+
totalBytes,
|
|
65
|
+
truncated: state.truncated,
|
|
66
|
+
fullOutputPath: state.truncated ? fullOutputPath : undefined,
|
|
67
|
+
} satisfies CapturedOutput;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function collectStderr<E, R>(stream: Stream.Stream<Uint8Array, E, R>) {
|
|
71
|
+
return Stream.runFold(
|
|
72
|
+
stream,
|
|
73
|
+
() => Buffer.alloc(0),
|
|
74
|
+
(captured, chunk) => {
|
|
75
|
+
if (captured.byteLength >= STDERR_MAX_BYTES) return captured;
|
|
76
|
+
const remaining = STDERR_MAX_BYTES - captured.byteLength;
|
|
77
|
+
return Buffer.concat([captured, chunk.subarray(0, remaining)]);
|
|
78
|
+
},
|
|
79
|
+
).pipe(Effect.map((bytes) => bytes.toString("utf8")));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function executeSearchProcess(options: {
|
|
83
|
+
readonly command: string;
|
|
84
|
+
readonly args: readonly string[];
|
|
85
|
+
readonly cwd: string;
|
|
86
|
+
readonly tempPrefix: string;
|
|
87
|
+
}) {
|
|
88
|
+
return Effect.gen(function* () {
|
|
89
|
+
const fs = yield* FileSystem.FileSystem;
|
|
90
|
+
const directory = yield* fs.makeTempDirectory({
|
|
91
|
+
prefix: options.tempPrefix,
|
|
92
|
+
});
|
|
93
|
+
const fullOutputPath = join(directory, "output.txt");
|
|
94
|
+
let retainDirectory = false;
|
|
95
|
+
|
|
96
|
+
return yield* Effect.gen(function* () {
|
|
97
|
+
const preview = makePreviewState();
|
|
98
|
+
const process = yield* ChildProcess.make(options.command, options.args, {
|
|
99
|
+
cwd: options.cwd,
|
|
100
|
+
stdin: "ignore",
|
|
101
|
+
stdout: "pipe",
|
|
102
|
+
stderr: "pipe",
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const result = yield* Effect.all(
|
|
106
|
+
{
|
|
107
|
+
exitCode: process.exitCode,
|
|
108
|
+
stdout: process.stdout.pipe(
|
|
109
|
+
Stream.tap((chunk) =>
|
|
110
|
+
Effect.sync(() => observeStdout(preview, chunk)),
|
|
111
|
+
),
|
|
112
|
+
Stream.run(fs.sink(fullOutputPath)),
|
|
113
|
+
),
|
|
114
|
+
stderr: collectStderr(process.stderr),
|
|
115
|
+
},
|
|
116
|
+
{ concurrency: "unbounded" },
|
|
117
|
+
);
|
|
118
|
+
const output = finishStdout(preview, fullOutputPath);
|
|
119
|
+
retainDirectory = output.truncated;
|
|
120
|
+
return {
|
|
121
|
+
code: Number(result.exitCode),
|
|
122
|
+
stderr: result.stderr,
|
|
123
|
+
output,
|
|
124
|
+
};
|
|
125
|
+
}).pipe(
|
|
126
|
+
Effect.ensuring(
|
|
127
|
+
Effect.suspend(() =>
|
|
128
|
+
retainDirectory
|
|
129
|
+
? Effect.void
|
|
130
|
+
: fs
|
|
131
|
+
.remove(directory, { recursive: true, force: true })
|
|
132
|
+
.pipe(Effect.orDie),
|
|
133
|
+
),
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
}).pipe(Effect.scoped);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function discardCapturedOutput(output: CapturedOutput) {
|
|
140
|
+
if (!output.fullOutputPath) return Effect.void;
|
|
141
|
+
const directory = dirname(output.fullOutputPath);
|
|
142
|
+
return Effect.gen(function* () {
|
|
143
|
+
const fs = yield* FileSystem.FileSystem;
|
|
144
|
+
yield* fs.remove(directory, { recursive: true, force: true });
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Model-facing text for the fd and rg tools. */
|
|
2
|
+
|
|
3
|
+
export const FD_TOOL_DESCRIPTION =
|
|
4
|
+
"Find files and directories by name with fd. Respects .gitignore by default. Results are limited to 1000 entries unless a higher limit is given; output is limited to 2000 lines or 50KB, and complete truncated output is saved to a temporary file.";
|
|
5
|
+
|
|
6
|
+
export const FD_PROMPT_SNIPPET =
|
|
7
|
+
"Find files and directories by name with fd (fast, gitignore-aware).";
|
|
8
|
+
|
|
9
|
+
export const FD_PROMPT_GUIDELINES = [
|
|
10
|
+
"Use fd as the primary tool for discovering files and directories by name, extension, or glob instead of bash with find or ls -R.",
|
|
11
|
+
"Use rg instead of fd when searching file contents rather than file names.",
|
|
12
|
+
"Keep using bash for complex multi-step workflows that pipe or post-process file listings.",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const FD_PARAMETER_DESCRIPTIONS = {
|
|
16
|
+
pattern:
|
|
17
|
+
"Regex matched against file names (or a glob when glob is true). Omit to list everything under path.",
|
|
18
|
+
path: "Directory to search. Defaults to the current working directory.",
|
|
19
|
+
type: "Only return entries of this type: file, directory, or symlink.",
|
|
20
|
+
extension: "Only return files with this extension, e.g. 'ts' or 'md'.",
|
|
21
|
+
glob: "Treat pattern as a glob (e.g. '*.test.ts') instead of a regex.",
|
|
22
|
+
hidden: "Include hidden files and directories. Defaults to false.",
|
|
23
|
+
max_depth: "Maximum directory depth to descend (1-64).",
|
|
24
|
+
limit: "Maximum number of results (1-10000). Defaults to 1000.",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const RG_TOOL_DESCRIPTION =
|
|
28
|
+
"Search file contents with ripgrep. Uses smart-case matching, respects .gitignore by default, and returns at most 100 matches per file unless a different limit is given. Output is limited to 2000 lines or 50KB; complete truncated output is saved to a temporary file.";
|
|
29
|
+
|
|
30
|
+
export const RG_PROMPT_SNIPPET =
|
|
31
|
+
"Search file contents with ripgrep (fast regex content search).";
|
|
32
|
+
|
|
33
|
+
export const RG_PROMPT_GUIDELINES = [
|
|
34
|
+
"Use rg as the primary tool for searching file contents instead of bash with grep.",
|
|
35
|
+
"Use fd instead of rg when looking for files by name rather than content.",
|
|
36
|
+
"Set fixed_strings on rg when searching for literal code snippets containing regex metacharacters.",
|
|
37
|
+
"Keep using bash for complex multi-step workflows that combine searching with other commands.",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
export const RG_PARAMETER_DESCRIPTIONS = {
|
|
41
|
+
pattern: "Regex to search for (literal text when fixed_strings is true).",
|
|
42
|
+
path: "File or directory to search. Defaults to the current working directory.",
|
|
43
|
+
glob: "Only search files matching this glob, e.g. '*.ts' or 'src/**'.",
|
|
44
|
+
file_type:
|
|
45
|
+
"Only search files of this ripgrep type, e.g. 'ts', 'js', 'py', 'rust'.",
|
|
46
|
+
case_sensitive:
|
|
47
|
+
"true forces case-sensitive matching, false forces case-insensitive. Defaults to smart-case.",
|
|
48
|
+
fixed_strings: "Treat pattern as a literal string instead of a regex.",
|
|
49
|
+
hidden: "Search hidden files and directories. Defaults to false.",
|
|
50
|
+
context: "Lines of context to show around each match (0-20).",
|
|
51
|
+
limit: "Maximum matches per file (1-1000). Defaults to 100.",
|
|
52
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# goal
|
|
2
|
+
|
|
3
|
+
Keep the agent working until a goal is achieved.
|
|
4
|
+
|
|
5
|
+
## Command
|
|
6
|
+
|
|
7
|
+
| Command | Action |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `/goal <prompt>` | Runs the workflow below, looping until you confirm the goal is achieved |
|
|
10
|
+
| `/goal` | Prompts for the goal interactively, then runs the same workflow |
|
|
11
|
+
|
|
12
|
+
`/goal` with no argument opens an input dialog; if the dialog is cancelled or
|
|
13
|
+
left empty, nothing runs.
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
|
|
17
|
+
`/goal <prompt>` injects an instruction into the main agent that runs four
|
|
18
|
+
phases in order:
|
|
19
|
+
|
|
20
|
+
1. **Research** — web-search the goal to ground the design.
|
|
21
|
+
2. **Design** — follow the `brainstorming` skill; present the design for
|
|
22
|
+
approval, then save the design doc to `docs/superpowers/specs/`.
|
|
23
|
+
3. **Plan** — follow the `writing-plans` skill; save a bite-sized plan to
|
|
24
|
+
`docs/superpowers/plans/`.
|
|
25
|
+
4. **Implement and verify** — write the code, tests, and docs; run them and
|
|
26
|
+
fix failures until the goal actually works.
|
|
27
|
+
|
|
28
|
+
### The loop
|
|
29
|
+
|
|
30
|
+
After the agent settles, `/goal` asks you what to do next:
|
|
31
|
+
|
|
32
|
+
- **Continue working toward the goal** — re-engages the agent to keep going,
|
|
33
|
+
respecting the phase gates (it won't skip design approval).
|
|
34
|
+
- **Goal achieved - stop** — ends the loop.
|
|
35
|
+
- **Pause - stop checking** — ends the loop and leaves you to take over
|
|
36
|
+
manually.
|
|
37
|
+
|
|
38
|
+
The loop runs in the interactive TUI (it needs to ask you). In RPC and
|
|
39
|
+
print/JSON modes there is no dialog, so the agent works a single pass and the
|
|
40
|
+
loop ends. The workflow always stops after Phase 2 and waits for you to approve
|
|
41
|
+
the design doc before planning and implementing.
|
|
42
|
+
|
|
43
|
+
## Files
|
|
44
|
+
|
|
45
|
+
- `index.ts` — registers the `/goal` command, builds the phase instruction,
|
|
46
|
+
and re-engages the agent on `agent_settled`
|
|
47
|
+
- `README.md` — this file
|
|
48
|
+
|
|
49
|
+
Nothing is written into the extension folder; the design and plan land in the
|
|
50
|
+
project's `docs/superpowers/` tree (the skills' default locations).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* goal — keep the agent working until the goal is achieved.
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* /goal <prompt> Research → design → plan → implement → verify, looping
|
|
6
|
+
* until you confirm the goal is achieved.
|
|
7
|
+
* /goal Prompts for the goal interactively.
|
|
8
|
+
*
|
|
9
|
+
* After the agent settles, this extension asks whether to keep working, mark
|
|
10
|
+
* the goal achieved, or pause. "Keep working" re-engages the agent until the
|
|
11
|
+
* goal is done. See README.md for the phase-by-phase workflow.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
|
|
17
|
+
const HOME = homedir().replace(/\\/g, "/");
|
|
18
|
+
const BRAINSTORMING_SKILL = `${HOME}/.agents/skills/brainstorming/SKILL.md`;
|
|
19
|
+
const WRITING_PLANS_SKILL = `${HOME}/.agents/skills/writing-plans/SKILL.md`;
|
|
20
|
+
|
|
21
|
+
/** Shared closing instruction for every /goal pass. */
|
|
22
|
+
const REPORT_TAIL = "When you finish a pass, report what is done, what remains, and whether the goal is achieved.";
|
|
23
|
+
|
|
24
|
+
/** The goal the agent is currently working toward, or null when idle. */
|
|
25
|
+
let activeGoal: string | null = null;
|
|
26
|
+
|
|
27
|
+
function shortGoal(goal: string): string {
|
|
28
|
+
const s = goal.replace(/\s+/g, " ").trim();
|
|
29
|
+
return s.length > 60 ? `${s.slice(0, 60)}…` : s;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function buildInstruction(goal: string): string {
|
|
33
|
+
return [
|
|
34
|
+
"You are executing a /goal workflow: research, then design, then plan, then implement and verify — working until the goal is achieved.",
|
|
35
|
+
"",
|
|
36
|
+
"GOAL:",
|
|
37
|
+
goal,
|
|
38
|
+
"",
|
|
39
|
+
"Work through the phases in order.",
|
|
40
|
+
"",
|
|
41
|
+
"PHASE 1 — RESEARCH",
|
|
42
|
+
"- Use web_search to research the goal: relevant technologies, existing libraries and approaches, best practices, constraints, and open questions.",
|
|
43
|
+
"- Gather grounded facts to inform the design; cite what you learn in the design doc.",
|
|
44
|
+
"",
|
|
45
|
+
"PHASE 2 — DESIGN",
|
|
46
|
+
`- First read the brainstorming skill: ${BRAINSTORMING_SKILL}. Follow it.`,
|
|
47
|
+
"- Ask clarifying questions one at a time (use ask_user when a choice can be enumerated) to pin down purpose, constraints, and success criteria.",
|
|
48
|
+
"- Propose 2-3 approaches with trade-offs and a recommendation; present the design in sections and get approval after each section.",
|
|
49
|
+
"- When the design is approved, save it to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md and ask the user to review it.",
|
|
50
|
+
"- STOP here and wait for the user to approve the design doc. Do not begin later phases until the user explicitly approves.",
|
|
51
|
+
"",
|
|
52
|
+
"PHASE 3 — PLAN",
|
|
53
|
+
`- First read the writing-plans skill: ${WRITING_PLANS_SKILL}. Follow it.`,
|
|
54
|
+
"- Write a detailed, bite-sized implementation plan with no placeholders and save it to docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md.",
|
|
55
|
+
"",
|
|
56
|
+
"PHASE 4 — IMPLEMENT AND VERIFY",
|
|
57
|
+
"- Implement the plan: write the actual code, tests, and docs.",
|
|
58
|
+
"- Run the tests and any verification; fix failures until everything passes.",
|
|
59
|
+
"- Verify the goal is actually achieved and working, not just that code was written.",
|
|
60
|
+
"",
|
|
61
|
+
REPORT_TAIL,
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function buildContinueInstruction(goal: string): string {
|
|
66
|
+
return [
|
|
67
|
+
`Continue working toward the goal: ${goal}`,
|
|
68
|
+
"",
|
|
69
|
+
"Review the current state and resume the /goal workflow from where you left off, respecting the phase gates:",
|
|
70
|
+
"- If the design has not been approved yet: present the design and STOP for approval. Do not plan or implement until the user approves.",
|
|
71
|
+
"- If the design is approved but the plan is not written: follow the writing-plans skill and write the plan.",
|
|
72
|
+
"- Otherwise: implement and verify, fixing failures until everything passes.",
|
|
73
|
+
"If you are blocked or need a decision, ask the user.",
|
|
74
|
+
REPORT_TAIL,
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function runGoal(pi: ExtensionAPI, ctx: ExtensionCommandContext, goal: string): Promise<void> {
|
|
79
|
+
activeGoal = goal;
|
|
80
|
+
if (ctx.isIdle()) {
|
|
81
|
+
await pi.sendUserMessage(buildInstruction(goal));
|
|
82
|
+
} else {
|
|
83
|
+
await pi.sendUserMessage(buildInstruction(goal), { deliverAs: "followUp" });
|
|
84
|
+
}
|
|
85
|
+
ctx.ui.notify("goal: working until achieved", "info");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default function (pi: ExtensionAPI) {
|
|
89
|
+
pi.registerCommand("goal", {
|
|
90
|
+
description:
|
|
91
|
+
"Keep the agent working until a goal is achieved: web research, brainstorming design, writing-plans plan, implement and verify",
|
|
92
|
+
handler: async (args, ctx) => {
|
|
93
|
+
let goal = (args ?? "").trim();
|
|
94
|
+
if (!goal) {
|
|
95
|
+
if (!ctx.hasUI) {
|
|
96
|
+
console.error("Usage: /goal <goal> - work on it until it is achieved");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const typed = await ctx.ui.input("What goal would you like to achieve?", "e.g. add a /goal extension to pi");
|
|
100
|
+
goal = (typed ?? "").trim();
|
|
101
|
+
if (!goal) return;
|
|
102
|
+
}
|
|
103
|
+
await runGoal(pi, ctx, goal);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Re-engage the agent after each settle until the goal is achieved.
|
|
108
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
109
|
+
if (!activeGoal) return;
|
|
110
|
+
|
|
111
|
+
// The interactive loop needs the TUI: awaiting a dialog from inside
|
|
112
|
+
// the settle handler can deadlock RPC clients, and print/JSON modes
|
|
113
|
+
// can't prompt at all. Stop the loop rather than spin.
|
|
114
|
+
if (ctx.mode !== "tui") {
|
|
115
|
+
activeGoal = null;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const choice = await ctx.ui.select(`Goal: ${shortGoal(activeGoal)}`, [
|
|
120
|
+
"Continue working toward the goal",
|
|
121
|
+
"Goal achieved - stop",
|
|
122
|
+
"Pause - stop checking",
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
// Esc / cancel → pause, so the loop never runs away.
|
|
126
|
+
if (!choice || choice === "Pause - stop checking") {
|
|
127
|
+
activeGoal = null;
|
|
128
|
+
ctx.ui.notify("goal: paused - take over manually", "info");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (choice === "Goal achieved - stop") {
|
|
133
|
+
activeGoal = null;
|
|
134
|
+
ctx.ui.notify("goal: marked achieved", "info");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// "Continue working toward the goal"
|
|
139
|
+
if (ctx.isIdle()) {
|
|
140
|
+
await pi.sendUserMessage(buildContinueInstruction(activeGoal));
|
|
141
|
+
} else {
|
|
142
|
+
await pi.sendUserMessage(buildContinueInstruction(activeGoal), { deliverAs: "followUp" });
|
|
143
|
+
}
|
|
144
|
+
ctx.ui.notify("goal: continuing...", "info");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Reset state on session boundaries so a stale goal never leaks into a
|
|
148
|
+
// fresh session (or across /reload).
|
|
149
|
+
pi.on("session_start", () => {
|
|
150
|
+
activeGoal = null;
|
|
151
|
+
});
|
|
152
|
+
pi.on("session_shutdown", () => {
|
|
153
|
+
activeGoal = null;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
# Per-extension installer — Windows / PowerShell
|
|
3
|
+
# Installs npm dependencies for this extension. No-op if no package.json.
|
|
4
|
+
$ErrorActionPreference = "Stop"
|
|
5
|
+
$extDir = $PSScriptRoot
|
|
6
|
+
if (-not $extDir) { $extDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
|
|
7
|
+
if (-not (Test-Path "$extDir/package.json")) {
|
|
8
|
+
Write-Host " - no package.json — skipping" -ForegroundColor DarkGray
|
|
9
|
+
exit 0
|
|
10
|
+
}
|
|
11
|
+
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
|
|
12
|
+
Write-Host " x npm not found — install Node.js 22+" -ForegroundColor Red
|
|
13
|
+
exit 1
|
|
14
|
+
}
|
|
15
|
+
if (Test-Path "$extDir/package-lock.json") {
|
|
16
|
+
Write-Host " - npm ci" -ForegroundColor DarkGray
|
|
17
|
+
npm --prefix $extDir ci --no-audit --no-fund
|
|
18
|
+
} else {
|
|
19
|
+
Write-Host " - npm install" -ForegroundColor DarkGray
|
|
20
|
+
npm --prefix $extDir install --no-audit --no-fund
|
|
21
|
+
}
|
|
22
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
23
|
+
Write-Host " + done" -ForegroundColor Green
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Per-extension installer — macOS / Linux
|
|
3
|
+
# Installs npm dependencies for this extension. No-op if no package.json.
|
|
4
|
+
set -eu
|
|
5
|
+
EXT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
if [ ! -f "$EXT_DIR/package.json" ]; then
|
|
7
|
+
echo " · no package.json — skipping"
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
11
|
+
echo " ✖ npm not found — install Node.js 22+" >&2
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
if [ -f "$EXT_DIR/package-lock.json" ]; then
|
|
15
|
+
echo " · npm ci"
|
|
16
|
+
npm --prefix "$EXT_DIR" ci --no-audit --no-fund
|
|
17
|
+
else
|
|
18
|
+
echo " · npm install"
|
|
19
|
+
npm --prefix "$EXT_DIR" install --no-audit --no-fund
|
|
20
|
+
fi
|
|
21
|
+
echo " ✓ done"
|