@pencil-agent/nano-pencil 1.11.37 → 1.11.38
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/dist/builtin-extensions.js +21 -11
- package/dist/core/config/settings-manager.d.ts +6 -0
- package/dist/core/config/settings-manager.js +11 -0
- package/dist/core/i18n/messages.d.ts +4 -0
- package/dist/core/i18n/messages.js +17 -0
- package/dist/core/i18n/messages.zh.d.ts +4 -0
- package/dist/core/i18n/messages.zh.js +17 -0
- package/dist/core/package-manager.js +3 -1
- package/dist/core/sub-agent/index.d.ts +2 -0
- package/dist/core/sub-agent/index.js +1 -0
- package/dist/core/sub-agent/subprocess-backend.d.ts +36 -0
- package/dist/core/sub-agent/subprocess-backend.js +105 -0
- package/dist/core/sub-agent/subprocess-worker.d.ts +13 -0
- package/dist/core/sub-agent/subprocess-worker.js +41 -0
- package/dist/core/workspace/worktree-manager.d.ts +23 -2
- package/dist/core/workspace/worktree-manager.js +248 -16
- package/dist/extensions/defaults/CLAUDE.md +24 -12
- package/dist/extensions/defaults/grub/README.md +25 -0
- package/dist/extensions/defaults/grub/grub-controller.d.ts +32 -0
- package/dist/extensions/defaults/{loop/loop-controller.js → grub/grub-controller.js} +19 -19
- package/dist/extensions/defaults/grub/grub-parser.d.ts +10 -0
- package/dist/extensions/defaults/{loop/loop-parser.js → grub/grub-parser.js} +6 -6
- package/dist/extensions/defaults/grub/grub-types.d.ts +54 -0
- package/dist/extensions/defaults/grub/grub-types.js +2 -0
- package/dist/extensions/defaults/grub/index.d.ts +9 -0
- package/dist/extensions/defaults/grub/index.js +310 -0
- package/dist/extensions/defaults/loop/README.md +47 -24
- package/dist/extensions/defaults/loop/index.d.ts +4 -4
- package/dist/extensions/defaults/loop/index.js +165 -346
- package/dist/extensions/defaults/loop/scheduler-controller.d.ts +13 -7
- package/dist/extensions/defaults/loop/scheduler-controller.js +84 -19
- package/dist/extensions/defaults/loop/scheduler-parser.d.ts +5 -5
- package/dist/extensions/defaults/loop/scheduler-parser.js +126 -49
- package/dist/extensions/defaults/loop/scheduler-types.d.ts +34 -9
- package/dist/extensions/defaults/loop/scheduler-types.js +3 -3
- package/dist/extensions/defaults/presence/index.d.ts +3 -3
- package/dist/extensions/defaults/presence/index.js +479 -30
- package/dist/extensions/defaults/subagent/index.js +138 -66
- package/dist/extensions/defaults/subagent/subagent-parser.d.ts +11 -6
- package/dist/extensions/defaults/subagent/subagent-parser.js +64 -41
- package/dist/extensions/defaults/subagent/subagent-runner.d.ts +7 -0
- package/dist/extensions/defaults/subagent/subagent-runner.js +123 -19
- package/dist/extensions/defaults/subagent/subagent-types.d.ts +5 -0
- package/dist/extensions/defaults/team/CLAUDE.md +87 -0
- package/dist/extensions/defaults/team/TESTING.md +247 -0
- package/dist/extensions/defaults/team/index.d.ts +14 -4
- package/dist/extensions/defaults/team/index.js +342 -1036
- package/dist/extensions/defaults/team/team-mailbox.d.ts +47 -0
- package/dist/extensions/defaults/team/team-mailbox.js +65 -0
- package/dist/extensions/defaults/team/team-parser.d.ts +39 -19
- package/dist/extensions/defaults/team/team-parser.js +134 -43
- package/dist/extensions/defaults/team/team-permissions.d.ts +64 -0
- package/dist/extensions/defaults/team/team-permissions.js +117 -0
- package/dist/extensions/defaults/team/team-runtime.d.ts +116 -0
- package/dist/extensions/defaults/team/team-runtime.js +503 -0
- package/dist/extensions/defaults/team/team-state-store.d.ts +25 -0
- package/dist/extensions/defaults/team/team-state-store.js +78 -0
- package/dist/extensions/defaults/team/team-transcript.d.ts +32 -0
- package/dist/extensions/defaults/team/team-transcript.js +59 -0
- package/dist/extensions/defaults/team/team-types.d.ts +91 -51
- package/dist/extensions/defaults/team/team-types.js +6 -0
- package/dist/modes/acp/acp-mode.js +18 -4
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.js +12 -0
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/docs/AgentTeam/351/207/215/346/236/204/346/226/271/346/241/210.md +6 -9
- package/node_modules/@pencil-agent/ai/dist/models.generated.d.ts +166 -57
- package/node_modules/@pencil-agent/ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@pencil-agent/ai/dist/models.generated.js +203 -99
- package/node_modules/@pencil-agent/ai/dist/models.generated.js.map +1 -1
- package/package.json +2 -1
- package/dist/extensions/defaults/loop/loop-controller.d.ts +0 -32
- package/dist/extensions/defaults/loop/loop-parser.d.ts +0 -10
- package/dist/extensions/defaults/loop/loop-types.d.ts +0 -54
- package/dist/extensions/defaults/loop/loop-types.js +0 -2
- package/dist/extensions/defaults/team/team-controller.d.ts +0 -24
- package/dist/extensions/defaults/team/team-controller.js +0 -98
|
@@ -19,8 +19,9 @@ const BUNDLED_SOUL_EXTENSION = join(__dirname, "extensions", "defaults", "soul",
|
|
|
19
19
|
const BUNDLED_PRESENCE_EXTENSION = join(__dirname, "extensions", "defaults", "presence", "index.js");
|
|
20
20
|
const BUNDLED_INTERVIEW_EXTENSION = join(__dirname, "extensions", "defaults", "interview", "index.js");
|
|
21
21
|
const BUNDLED_LOOP_EXTENSION = join(__dirname, "extensions", "defaults", "loop", "index.js");
|
|
22
|
-
const
|
|
22
|
+
const BUNDLED_GRUB_EXTENSION = join(__dirname, "extensions", "defaults", "grub", "index.js");
|
|
23
23
|
const BUNDLED_SUBAGENT_EXTENSION = join(__dirname, "extensions", "defaults", "subagent", "index.js");
|
|
24
|
+
const BUNDLED_TEAM_EXTENSION = join(__dirname, "extensions", "defaults", "team", "index.js");
|
|
24
25
|
const BUNDLED_MCP_EXTENSION = join(__dirname, "extensions", "defaults", "mcp", "index.js");
|
|
25
26
|
const BUNDLED_EXPORT_HTML_EXTENSION = join(__dirname, "extensions", "optional", "export-html", "index.js");
|
|
26
27
|
/** Find package root from current module location (containing package.json with nano-pencil related name) */
|
|
@@ -139,7 +140,16 @@ export function getBuiltinExtensionPaths() {
|
|
|
139
140
|
if (existsSync(interviewTs))
|
|
140
141
|
paths.push(interviewTs);
|
|
141
142
|
}
|
|
142
|
-
// ===
|
|
143
|
+
// === Grub extension (/grub autonomous iterative task) ===
|
|
144
|
+
if (existsSync(BUNDLED_GRUB_EXTENSION)) {
|
|
145
|
+
paths.push(BUNDLED_GRUB_EXTENSION);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const grubTs = join(__dirname, "extensions", "defaults", "grub", "index.ts");
|
|
149
|
+
if (existsSync(grubTs))
|
|
150
|
+
paths.push(grubTs);
|
|
151
|
+
}
|
|
152
|
+
// === Loop extension (/loop recurring scheduler) ===
|
|
143
153
|
if (existsSync(BUNDLED_LOOP_EXTENSION)) {
|
|
144
154
|
paths.push(BUNDLED_LOOP_EXTENSION);
|
|
145
155
|
}
|
|
@@ -149,15 +159,6 @@ export function getBuiltinExtensionPaths() {
|
|
|
149
159
|
paths.push(loopTs);
|
|
150
160
|
}
|
|
151
161
|
// === MCP extension (MCP tool protocol adapter) ===
|
|
152
|
-
// Built-in team extension
|
|
153
|
-
if (existsSync(BUNDLED_TEAM_EXTENSION)) {
|
|
154
|
-
paths.push(BUNDLED_TEAM_EXTENSION);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
const teamTs = join(__dirname, "extensions", "defaults", "team", "index.ts");
|
|
158
|
-
if (existsSync(teamTs))
|
|
159
|
-
paths.push(teamTs);
|
|
160
|
-
}
|
|
161
162
|
// Built-in SubAgent extension
|
|
162
163
|
if (existsSync(BUNDLED_SUBAGENT_EXTENSION)) {
|
|
163
164
|
paths.push(BUNDLED_SUBAGENT_EXTENSION);
|
|
@@ -167,6 +168,15 @@ export function getBuiltinExtensionPaths() {
|
|
|
167
168
|
if (existsSync(subagentTs))
|
|
168
169
|
paths.push(subagentTs);
|
|
169
170
|
}
|
|
171
|
+
// Built-in AgentTeam extension (Phase B - persistent teammates)
|
|
172
|
+
if (existsSync(BUNDLED_TEAM_EXTENSION)) {
|
|
173
|
+
paths.push(BUNDLED_TEAM_EXTENSION);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const teamTs = join(__dirname, "extensions", "defaults", "team", "index.ts");
|
|
177
|
+
if (existsSync(teamTs))
|
|
178
|
+
paths.push(teamTs);
|
|
179
|
+
}
|
|
170
180
|
// Built-in MCP extension
|
|
171
181
|
if (existsSync(BUNDLED_MCP_EXTENSION)) {
|
|
172
182
|
paths.push(BUNDLED_MCP_EXTENSION);
|
|
@@ -97,6 +97,10 @@ export interface Settings {
|
|
|
97
97
|
lockStaleMinutes?: number;
|
|
98
98
|
};
|
|
99
99
|
};
|
|
100
|
+
/** Presence extension settings - AI greeting and idle messages */
|
|
101
|
+
presence?: {
|
|
102
|
+
enabled?: boolean;
|
|
103
|
+
};
|
|
100
104
|
/** Auto-update setting: 'always' = auto-update on startup, 'prompt' = ask user (default), 'never' = never check */
|
|
101
105
|
autoUpdate?: "always" | "prompt" | "never";
|
|
102
106
|
/** Last skipped version for update prompts */
|
|
@@ -240,6 +244,8 @@ export declare class SettingsManager {
|
|
|
240
244
|
setShowWorkingTrace(enabled: boolean): void;
|
|
241
245
|
getShowMemoryTrace(): boolean;
|
|
242
246
|
setShowMemoryTrace(enabled: boolean): void;
|
|
247
|
+
getPresenceEnabled(): boolean;
|
|
248
|
+
setPresenceEnabled(enabled: boolean): void;
|
|
243
249
|
getImageAutoResize(): boolean;
|
|
244
250
|
setImageAutoResize(enabled: boolean): void;
|
|
245
251
|
getBlockImages(): boolean;
|
|
@@ -624,6 +624,17 @@ export class SettingsManager {
|
|
|
624
624
|
this.markModified("terminal", "showMemoryTrace");
|
|
625
625
|
this.save();
|
|
626
626
|
}
|
|
627
|
+
getPresenceEnabled() {
|
|
628
|
+
return this.settings.presence?.enabled ?? true;
|
|
629
|
+
}
|
|
630
|
+
setPresenceEnabled(enabled) {
|
|
631
|
+
if (!this.globalSettings.presence) {
|
|
632
|
+
this.globalSettings.presence = {};
|
|
633
|
+
}
|
|
634
|
+
this.globalSettings.presence.enabled = enabled;
|
|
635
|
+
this.markModified("presence", "enabled");
|
|
636
|
+
this.save();
|
|
637
|
+
}
|
|
627
638
|
getImageAutoResize() {
|
|
628
639
|
return this.settings.images?.autoResize ?? true;
|
|
629
640
|
}
|
|
@@ -58,5 +58,22 @@ export const messages = {
|
|
|
58
58
|
confirmQuit: "Are you sure you want to quit?",
|
|
59
59
|
confirmNewSession: "Start a new session? Current session will be saved.",
|
|
60
60
|
confirmDelete: "Are you sure you want to delete?",
|
|
61
|
+
// Presence (AI generation fails or memory is empty - fallback messages)
|
|
62
|
+
presence: {
|
|
63
|
+
opening: [
|
|
64
|
+
"Hey, what's up?",
|
|
65
|
+
"Ready when you are.",
|
|
66
|
+
"What do you want to work on?",
|
|
67
|
+
"Any ideas?",
|
|
68
|
+
"Let's do this.",
|
|
69
|
+
],
|
|
70
|
+
idle: [
|
|
71
|
+
"Still here when you need me.",
|
|
72
|
+
"No rush, take your time.",
|
|
73
|
+
"Ready when you are.",
|
|
74
|
+
"I'll be here.",
|
|
75
|
+
"Whenever you're ready.",
|
|
76
|
+
],
|
|
77
|
+
},
|
|
61
78
|
};
|
|
62
79
|
//# sourceMappingURL=messages.js.map
|
|
@@ -58,5 +58,22 @@ export const messages = {
|
|
|
58
58
|
confirmQuit: "确定要退出吗?",
|
|
59
59
|
confirmNewSession: "开始新会话?当前会话将被保存。",
|
|
60
60
|
confirmDelete: "确定要删除吗?",
|
|
61
|
+
// Presence (AI生成失败或记忆为空时的备用消息)
|
|
62
|
+
presence: {
|
|
63
|
+
opening: [
|
|
64
|
+
"来了啊。",
|
|
65
|
+
"嘿,有什么想做的吗?",
|
|
66
|
+
"准备开始吧。",
|
|
67
|
+
"随时可以开始。",
|
|
68
|
+
"有什么要聊聊的吗?",
|
|
69
|
+
],
|
|
70
|
+
idle: [
|
|
71
|
+
"还在,有需要随时说。",
|
|
72
|
+
"不急,慢慢来。",
|
|
73
|
+
"我在,随时继续。",
|
|
74
|
+
"有空了就继续吧。",
|
|
75
|
+
"没关系的,想什么时候继续都行。",
|
|
76
|
+
],
|
|
77
|
+
},
|
|
61
78
|
};
|
|
62
79
|
//# sourceMappingURL=messages.zh.js.map
|
|
@@ -3,5 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { SubAgentRuntime, subAgentRuntime } from "./sub-agent-runtime.js";
|
|
5
5
|
export { InProcessSubAgentBackend } from "./sub-agent-backend.js";
|
|
6
|
+
export { SubprocessSubAgentBackend } from "./subprocess-backend.js";
|
|
7
|
+
export type { SubprocessBackendOptions } from "./subprocess-backend.js";
|
|
6
8
|
export type { SubAgentSpec, SubAgentResult, SubAgentHandle, SubAgentBackend, } from "./sub-agent-types.js";
|
|
7
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [WHO]: SubprocessSubAgentBackend
|
|
3
|
+
* [FROM]: Depends on node:worker_threads, ./sub-agent-types
|
|
4
|
+
* [TO]: Consumed by SubAgentRuntime when caller wants crash isolation
|
|
5
|
+
* [HERE]: core/sub-agent/subprocess-backend.ts - Phase B B.6 multi-backend
|
|
6
|
+
*
|
|
7
|
+
* Crash-isolated SubAgent backend built on top of node:worker_threads.
|
|
8
|
+
*
|
|
9
|
+
* The worker thread runs the in-process backend in its own V8 isolate, so
|
|
10
|
+
* an unhandled error inside a teammate cannot tear down the main session.
|
|
11
|
+
* The Tool[] surface in `SubAgentSpec` is NOT serializable across the
|
|
12
|
+
* worker boundary, so the caller must pre-stage tools by name and resolve
|
|
13
|
+
* them inside the worker via `toolFactoryName`. For v1 we accept the same
|
|
14
|
+
* profiles the team extension already uses ("read-only" / "sandboxed").
|
|
15
|
+
*
|
|
16
|
+
* Status: SHIPPED with the worker harness in place; the worker entry
|
|
17
|
+
* itself is intentionally minimal (echo + abort) so the interface is real
|
|
18
|
+
* and exercisable. The full agent loop inside the worker is deferred to a
|
|
19
|
+
* follow-up because it requires re-creating the model registry inside the
|
|
20
|
+
* isolate, which is out of scope for the AgentTeam Phase B milestone.
|
|
21
|
+
*
|
|
22
|
+
* The backend therefore documents itself honestly: callers that need real
|
|
23
|
+
* LLM execution should keep using `InProcessSubAgentBackend`; callers that
|
|
24
|
+
* just need an isolated bash/echo worker can use this one today.
|
|
25
|
+
*/
|
|
26
|
+
import type { SubAgentBackend, SubAgentHandle, SubAgentSpec } from "./sub-agent-types.js";
|
|
27
|
+
export interface SubprocessBackendOptions {
|
|
28
|
+
/** Override the worker entry path (for tests). */
|
|
29
|
+
workerEntry?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare class SubprocessSubAgentBackend implements SubAgentBackend {
|
|
32
|
+
private readonly workerEntry;
|
|
33
|
+
constructor(options?: SubprocessBackendOptions);
|
|
34
|
+
spawn(spec: SubAgentSpec): Promise<SubAgentHandle>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=subprocess-backend.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [WHO]: SubprocessSubAgentBackend
|
|
3
|
+
* [FROM]: Depends on node:worker_threads, ./sub-agent-types
|
|
4
|
+
* [TO]: Consumed by SubAgentRuntime when caller wants crash isolation
|
|
5
|
+
* [HERE]: core/sub-agent/subprocess-backend.ts - Phase B B.6 multi-backend
|
|
6
|
+
*
|
|
7
|
+
* Crash-isolated SubAgent backend built on top of node:worker_threads.
|
|
8
|
+
*
|
|
9
|
+
* The worker thread runs the in-process backend in its own V8 isolate, so
|
|
10
|
+
* an unhandled error inside a teammate cannot tear down the main session.
|
|
11
|
+
* The Tool[] surface in `SubAgentSpec` is NOT serializable across the
|
|
12
|
+
* worker boundary, so the caller must pre-stage tools by name and resolve
|
|
13
|
+
* them inside the worker via `toolFactoryName`. For v1 we accept the same
|
|
14
|
+
* profiles the team extension already uses ("read-only" / "sandboxed").
|
|
15
|
+
*
|
|
16
|
+
* Status: SHIPPED with the worker harness in place; the worker entry
|
|
17
|
+
* itself is intentionally minimal (echo + abort) so the interface is real
|
|
18
|
+
* and exercisable. The full agent loop inside the worker is deferred to a
|
|
19
|
+
* follow-up because it requires re-creating the model registry inside the
|
|
20
|
+
* isolate, which is out of scope for the AgentTeam Phase B milestone.
|
|
21
|
+
*
|
|
22
|
+
* The backend therefore documents itself honestly: callers that need real
|
|
23
|
+
* LLM execution should keep using `InProcessSubAgentBackend`; callers that
|
|
24
|
+
* just need an isolated bash/echo worker can use this one today.
|
|
25
|
+
*/
|
|
26
|
+
import { Worker } from "node:worker_threads";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
|
+
import { dirname, join } from "node:path";
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
export class SubprocessSubAgentBackend {
|
|
31
|
+
workerEntry;
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.workerEntry = options.workerEntry ?? join(__dirname, "subprocess-worker.js");
|
|
34
|
+
}
|
|
35
|
+
async spawn(spec) {
|
|
36
|
+
const id = crypto.randomUUID();
|
|
37
|
+
const workerSpec = {
|
|
38
|
+
id,
|
|
39
|
+
prompt: spec.prompt,
|
|
40
|
+
cwd: spec.cwd,
|
|
41
|
+
timeoutMs: spec.timeoutMs,
|
|
42
|
+
};
|
|
43
|
+
const worker = new Worker(this.workerEntry, { workerData: workerSpec });
|
|
44
|
+
let status = "running";
|
|
45
|
+
let resolved;
|
|
46
|
+
const donePromise = new Promise((resolve) => {
|
|
47
|
+
const finish = (r, nextStatus) => {
|
|
48
|
+
if (resolved)
|
|
49
|
+
return;
|
|
50
|
+
resolved = r;
|
|
51
|
+
status = nextStatus;
|
|
52
|
+
resolve(r);
|
|
53
|
+
};
|
|
54
|
+
worker.on("message", (msg) => {
|
|
55
|
+
if (msg.type === "result") {
|
|
56
|
+
finish(msg.payload ?? { success: true }, "done");
|
|
57
|
+
}
|
|
58
|
+
else if (msg.type === "error") {
|
|
59
|
+
finish({ success: false, error: String(msg.payload?.error ?? "Worker error") }, "error");
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
worker.on("error", (err) => {
|
|
63
|
+
finish({ success: false, error: err.message }, "error");
|
|
64
|
+
});
|
|
65
|
+
worker.on("exit", (code) => {
|
|
66
|
+
if (!resolved) {
|
|
67
|
+
finish({
|
|
68
|
+
success: false,
|
|
69
|
+
error: code === 0 ? "Worker exited without result" : `Worker exited with code ${code}`,
|
|
70
|
+
}, "error");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
const onAbort = () => {
|
|
74
|
+
if (!resolved) {
|
|
75
|
+
worker.postMessage({ type: "abort" });
|
|
76
|
+
finish({ success: false, error: "Aborted" }, "aborted");
|
|
77
|
+
worker.terminate().catch(() => { });
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
if (spec.signal.aborted)
|
|
81
|
+
onAbort();
|
|
82
|
+
else
|
|
83
|
+
spec.signal.addEventListener("abort", onAbort, { once: true });
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
id,
|
|
87
|
+
get status() {
|
|
88
|
+
return status;
|
|
89
|
+
},
|
|
90
|
+
async result() {
|
|
91
|
+
return donePromise;
|
|
92
|
+
},
|
|
93
|
+
async abort() {
|
|
94
|
+
if (!resolved) {
|
|
95
|
+
worker.postMessage({ type: "abort" });
|
|
96
|
+
await worker.terminate().catch(() => { });
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
async terminate() {
|
|
100
|
+
await worker.terminate().catch(() => { });
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=subprocess-backend.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [WHO]: Worker entry for SubprocessSubAgentBackend
|
|
3
|
+
* [FROM]: Depends on node:worker_threads
|
|
4
|
+
* [TO]: Spawned by SubprocessSubAgentBackend
|
|
5
|
+
* [HERE]: core/sub-agent/subprocess-worker.ts
|
|
6
|
+
*
|
|
7
|
+
* Minimal isolated worker. Receives a `WorkerSpec` via workerData, runs
|
|
8
|
+
* a trivial echo loop, and posts a `result` message back. This is the
|
|
9
|
+
* harness that proves the channel + abort + lifecycle wiring; full agent
|
|
10
|
+
* execution inside the worker is intentionally deferred (see backend doc).
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=subprocess-worker.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [WHO]: Worker entry for SubprocessSubAgentBackend
|
|
3
|
+
* [FROM]: Depends on node:worker_threads
|
|
4
|
+
* [TO]: Spawned by SubprocessSubAgentBackend
|
|
5
|
+
* [HERE]: core/sub-agent/subprocess-worker.ts
|
|
6
|
+
*
|
|
7
|
+
* Minimal isolated worker. Receives a `WorkerSpec` via workerData, runs
|
|
8
|
+
* a trivial echo loop, and posts a `result` message back. This is the
|
|
9
|
+
* harness that proves the channel + abort + lifecycle wiring; full agent
|
|
10
|
+
* execution inside the worker is intentionally deferred (see backend doc).
|
|
11
|
+
*/
|
|
12
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
13
|
+
const spec = workerData;
|
|
14
|
+
let aborted = false;
|
|
15
|
+
parentPort?.on("message", (msg) => {
|
|
16
|
+
if (msg.type === "abort") {
|
|
17
|
+
aborted = true;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
async function run() {
|
|
21
|
+
// Simulate a tiny amount of work so abort has a window to fire.
|
|
22
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
23
|
+
if (aborted) {
|
|
24
|
+
parentPort?.postMessage({ type: "error", payload: { error: "Aborted" } });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
parentPort?.postMessage({
|
|
28
|
+
type: "result",
|
|
29
|
+
payload: {
|
|
30
|
+
success: true,
|
|
31
|
+
response: `[subprocess-worker:${spec.id}] received prompt of ${spec.prompt.length} chars in cwd ${spec.cwd}`,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
run().catch((err) => {
|
|
36
|
+
parentPort?.postMessage({
|
|
37
|
+
type: "error",
|
|
38
|
+
payload: { error: err instanceof Error ? err.message : String(err) },
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=subprocess-worker.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [UPSTREAM]: Depends on node:fs/promises, node:path
|
|
2
|
+
* [UPSTREAM]: Depends on node:fs/promises, node:path, node:child_process
|
|
3
3
|
* [SURFACE]: WorktreeManager - temporary workspace management
|
|
4
4
|
* [LOCUS]: core/workspace/worktree-manager.ts
|
|
5
5
|
*/
|
|
@@ -9,6 +9,10 @@ export interface WorkspacePath {
|
|
|
9
9
|
/** Type of workspace */
|
|
10
10
|
readonly type: "temp" | "worktree";
|
|
11
11
|
}
|
|
12
|
+
export interface WorkspaceChange {
|
|
13
|
+
path: string;
|
|
14
|
+
status: "added" | "modified" | "deleted";
|
|
15
|
+
}
|
|
12
16
|
/**
|
|
13
17
|
* Manager for creating and disposing workspaces for SubAgents.
|
|
14
18
|
* Provides temporary directories and git worktrees.
|
|
@@ -16,19 +20,32 @@ export interface WorkspacePath {
|
|
|
16
20
|
export declare class WorktreeManager {
|
|
17
21
|
private tempDirs;
|
|
18
22
|
private worktrees;
|
|
23
|
+
private snapshots;
|
|
19
24
|
/**
|
|
20
25
|
* Create a temporary workspace.
|
|
21
26
|
* Copies seed files to a new temp directory.
|
|
22
27
|
* @param seedFiles Files to copy to the temp workspace
|
|
23
28
|
* @param prefix Prefix for the temp directory name
|
|
24
29
|
*/
|
|
25
|
-
createTempWorkspace(seedFiles?: string[], prefix?: string): Promise<WorkspacePath>;
|
|
30
|
+
createTempWorkspace(seedFiles?: string[], prefix?: string, sourceCwd?: string): Promise<WorkspacePath>;
|
|
31
|
+
/**
|
|
32
|
+
* Create a temporary snapshot workspace by copying the current project tree.
|
|
33
|
+
* Used as a fallback when git worktree is unavailable.
|
|
34
|
+
*/
|
|
35
|
+
createSnapshotWorkspace(sourceCwd: string, prefix?: string): Promise<WorkspacePath>;
|
|
26
36
|
/**
|
|
27
37
|
* Create a git worktree for the given branch.
|
|
28
38
|
* @param branch Branch name for the worktree
|
|
29
39
|
* @param cwd Working directory for git operations
|
|
30
40
|
*/
|
|
31
41
|
createGitWorktree(branch?: string, cwd?: string): Promise<WorkspacePath>;
|
|
42
|
+
/**
|
|
43
|
+
* List changed files inside a workspace.
|
|
44
|
+
*/
|
|
45
|
+
listChangedFiles(workspace: WorkspacePath): Promise<string[]>;
|
|
46
|
+
listChanges(workspace: WorkspacePath): Promise<WorkspaceChange[]>;
|
|
47
|
+
writePatch(workspace: WorkspacePath, outputPath: string): Promise<boolean>;
|
|
48
|
+
applyChanges(workspace: WorkspacePath, targetCwd: string): Promise<WorkspaceChange[]>;
|
|
32
49
|
/**
|
|
33
50
|
* Dispose of a workspace.
|
|
34
51
|
* Removes temp directories and worktrees.
|
|
@@ -43,6 +60,10 @@ export declare class WorktreeManager {
|
|
|
43
60
|
* Clean up all temp directories.
|
|
44
61
|
*/
|
|
45
62
|
disposeAll(): Promise<void>;
|
|
63
|
+
private parseGitStatusLine;
|
|
64
|
+
private collectSnapshotChanges;
|
|
65
|
+
private collectWorkspaceFiles;
|
|
66
|
+
private shouldIgnoreRelativePath;
|
|
46
67
|
}
|
|
47
68
|
/**
|
|
48
69
|
* Default global worktree manager instance.
|