@esso0428/pi-subagents 0.17.5 → 0.17.7
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/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +4 -0
- package/README.md +1 -1
- package/dist/abortable.d.ts +13 -0
- package/dist/abortable.d.ts.map +1 -0
- package/dist/abortable.js +43 -0
- package/dist/abortable.js.map +1 -0
- package/dist/agent-color.d.ts +36 -0
- package/dist/agent-color.d.ts.map +1 -0
- package/dist/agent-color.js +124 -0
- package/dist/agent-color.js.map +1 -0
- package/dist/agent-file-toggle.d.ts +126 -0
- package/dist/agent-file-toggle.d.ts.map +1 -0
- package/dist/agent-file-toggle.js +259 -0
- package/dist/agent-file-toggle.js.map +1 -0
- package/dist/agent-history.d.ts +4 -0
- package/dist/agent-history.d.ts.map +1 -1
- package/dist/agent-history.js +47 -1
- package/dist/agent-history.js.map +1 -1
- package/dist/agent-manager.d.ts +370 -56
- package/dist/agent-manager.d.ts.map +1 -1
- package/dist/agent-manager.js +1123 -409
- package/dist/agent-manager.js.map +1 -1
- package/dist/agent-runner.d.ts +100 -10
- package/dist/agent-runner.d.ts.map +1 -1
- package/dist/agent-runner.js +166 -21
- package/dist/agent-runner.js.map +1 -1
- package/dist/agent-types.d.ts +57 -5
- package/dist/agent-types.d.ts.map +1 -1
- package/dist/agent-types.js +164 -32
- package/dist/agent-types.js.map +1 -1
- package/dist/child-context.d.ts +3 -0
- package/dist/child-context.d.ts.map +1 -0
- package/dist/child-context.js +13 -0
- package/dist/child-context.js.map +1 -0
- package/dist/cross-extension-rpc.d.ts +23 -3
- package/dist/cross-extension-rpc.d.ts.map +1 -1
- package/dist/cross-extension-rpc.js +79 -17
- package/dist/cross-extension-rpc.js.map +1 -1
- package/dist/custom-agents.d.ts +38 -1
- package/dist/custom-agents.d.ts.map +1 -1
- package/dist/custom-agents.js +164 -12
- package/dist/custom-agents.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1908 -495
- package/dist/index.js.map +1 -1
- package/dist/invocation-config.d.ts +87 -2
- package/dist/invocation-config.d.ts.map +1 -1
- package/dist/invocation-config.js +71 -3
- package/dist/invocation-config.js.map +1 -1
- package/dist/mention-clone.d.ts +88 -0
- package/dist/mention-clone.d.ts.map +1 -0
- package/dist/mention-clone.js +154 -0
- package/dist/mention-clone.js.map +1 -0
- package/dist/mention.d.ts +82 -0
- package/dist/mention.d.ts.map +1 -0
- package/dist/mention.js +132 -0
- package/dist/mention.js.map +1 -0
- package/dist/model-resolver.d.ts +17 -0
- package/dist/model-resolver.d.ts.map +1 -1
- package/dist/model-resolver.js +15 -0
- package/dist/model-resolver.js.map +1 -1
- package/dist/model-scope.d.ts +50 -0
- package/dist/model-scope.d.ts.map +1 -0
- package/dist/model-scope.js +49 -0
- package/dist/model-scope.js.map +1 -0
- package/dist/nested-tools.d.ts +57 -0
- package/dist/nested-tools.d.ts.map +1 -0
- package/dist/nested-tools.js +301 -0
- package/dist/nested-tools.js.map +1 -0
- package/dist/output-file.d.ts +22 -3
- package/dist/output-file.d.ts.map +1 -1
- package/dist/output-file.js +58 -7
- package/dist/output-file.js.map +1 -1
- package/dist/prompts.d.ts +23 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +20 -2
- package/dist/prompts.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +36 -15
- package/dist/schedule.js.map +1 -1
- package/dist/settings.d.ts +228 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +94 -0
- package/dist/settings.js.map +1 -1
- package/dist/status-note.d.ts +49 -1
- package/dist/status-note.d.ts.map +1 -1
- package/dist/status-note.js +62 -1
- package/dist/status-note.js.map +1 -1
- package/dist/structured-output.d.ts +62 -0
- package/dist/structured-output.d.ts.map +1 -0
- package/dist/structured-output.js +113 -0
- package/dist/structured-output.js.map +1 -0
- package/dist/types.d.ts +176 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/agent-mention.d.ts +83 -0
- package/dist/ui/agent-mention.d.ts.map +1 -0
- package/dist/ui/agent-mention.js +188 -0
- package/dist/ui/agent-mention.js.map +1 -0
- package/dist/ui/agent-widget.d.ts +96 -75
- package/dist/ui/agent-widget.d.ts.map +1 -1
- package/dist/ui/agent-widget.js +397 -420
- package/dist/ui/agent-widget.js.map +1 -1
- package/dist/ui/conversation-blocks.d.ts.map +1 -1
- package/dist/ui/conversation-blocks.js +6 -0
- package/dist/ui/conversation-blocks.js.map +1 -1
- package/dist/ui/conversation-timeline.d.ts +10 -2
- package/dist/ui/conversation-timeline.d.ts.map +1 -1
- package/dist/ui/conversation-timeline.js +130 -23
- package/dist/ui/conversation-timeline.js.map +1 -1
- package/dist/ui/conversation-viewer.d.ts +20 -5
- package/dist/ui/conversation-viewer.d.ts.map +1 -1
- package/dist/ui/conversation-viewer.js +274 -73
- package/dist/ui/conversation-viewer.js.map +1 -1
- package/dist/ui/fleet-list.d.ts +198 -0
- package/dist/ui/fleet-list.d.ts.map +1 -0
- package/dist/ui/fleet-list.js +487 -0
- package/dist/ui/fleet-list.js.map +1 -0
- package/dist/ui/schedule-menu.d.ts.map +1 -1
- package/dist/ui/schedule-menu.js +6 -7
- package/dist/ui/schedule-menu.js.map +1 -1
- package/dist/ui/select-item.d.ts +28 -0
- package/dist/ui/select-item.d.ts.map +1 -0
- package/dist/ui/select-item.js +35 -0
- package/dist/ui/select-item.js.map +1 -0
- package/dist/ui/workflow-card.d.ts +176 -0
- package/dist/ui/workflow-card.d.ts.map +1 -0
- package/dist/ui/workflow-card.js +333 -0
- package/dist/ui/workflow-card.js.map +1 -0
- package/dist/ui/workflow-dialog.d.ts +306 -0
- package/dist/ui/workflow-dialog.d.ts.map +1 -0
- package/dist/ui/workflow-dialog.js +844 -0
- package/dist/ui/workflow-dialog.js.map +1 -0
- package/dist/ui/workflow-menu.d.ts +61 -0
- package/dist/ui/workflow-menu.d.ts.map +1 -0
- package/dist/ui/workflow-menu.js +148 -0
- package/dist/ui/workflow-menu.js.map +1 -0
- package/dist/usage.d.ts +86 -1
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +72 -1
- package/dist/usage.js.map +1 -1
- package/dist/workflow/collisions.d.ts +96 -0
- package/dist/workflow/collisions.d.ts.map +1 -0
- package/dist/workflow/collisions.js +89 -0
- package/dist/workflow/collisions.js.map +1 -0
- package/dist/workflow/entry.d.ts +33 -0
- package/dist/workflow/entry.d.ts.map +1 -0
- package/dist/workflow/entry.js +30 -0
- package/dist/workflow/entry.js.map +1 -0
- package/dist/workflow/host.d.ts +63 -0
- package/dist/workflow/host.d.ts.map +1 -0
- package/dist/workflow/host.js +363 -0
- package/dist/workflow/host.js.map +1 -0
- package/dist/workflow/journal.d.ts +98 -0
- package/dist/workflow/journal.d.ts.map +1 -0
- package/dist/workflow/journal.js +121 -0
- package/dist/workflow/journal.js.map +1 -0
- package/dist/workflow/json-schema.d.ts +52 -0
- package/dist/workflow/json-schema.d.ts.map +1 -0
- package/dist/workflow/json-schema.js +112 -0
- package/dist/workflow/json-schema.js.map +1 -0
- package/dist/workflow/meta.d.ts +68 -0
- package/dist/workflow/meta.d.ts.map +1 -0
- package/dist/workflow/meta.js +318 -0
- package/dist/workflow/meta.js.map +1 -0
- package/dist/workflow/progress.d.ts +225 -0
- package/dist/workflow/progress.d.ts.map +1 -0
- package/dist/workflow/progress.js +362 -0
- package/dist/workflow/progress.js.map +1 -0
- package/dist/workflow/runtime.d.ts +335 -0
- package/dist/workflow/runtime.d.ts.map +1 -0
- package/dist/workflow/runtime.js +831 -0
- package/dist/workflow/runtime.js.map +1 -0
- package/dist/workflow/saved.d.ts +91 -0
- package/dist/workflow/saved.d.ts.map +1 -0
- package/dist/workflow/saved.js +204 -0
- package/dist/workflow/saved.js.map +1 -0
- package/dist/workflow/task.d.ts +137 -0
- package/dist/workflow/task.d.ts.map +1 -0
- package/dist/workflow/task.js +208 -0
- package/dist/workflow/task.js.map +1 -0
- package/dist/workflow/tool-description.d.ts +39 -0
- package/dist/workflow/tool-description.d.ts.map +1 -0
- package/dist/workflow/tool-description.js +200 -0
- package/dist/workflow/tool-description.js.map +1 -0
- package/dist/workflow/worker-source.d.ts +48 -0
- package/dist/workflow/worker-source.d.ts.map +1 -0
- package/dist/workflow/worker-source.js +779 -0
- package/dist/workflow/worker-source.js.map +1 -0
- package/dist/worktree.d.ts +10 -3
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +58 -54
- package/dist/worktree.js.map +1 -1
- package/dist/xml.d.ts +11 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +13 -0
- package/dist/xml.js.map +1 -0
- package/docs/rpc.md +183 -0
- package/docs/superpowers/plans/2026-09-30-conversation-viewer-scrollbar.md +216 -0
- package/docs/superpowers/plans/2026-09-30-upstream-event-workflow-partial-history.md +195 -0
- package/docs/superpowers/specs/2026-09-30-conversation-viewer-scrollbar-design.md +82 -0
- package/docs/superpowers/specs/2026-09-30-upstream-event-workflow-partial-history-design.md +49 -0
- package/docs/workflows.md +437 -0
- package/examples/agent-tool-description.md +7 -7
- package/examples/workflows/compose.js +51 -0
- package/examples/workflows/fan-out-audit.js +47 -0
- package/examples/workflows/gated-fix.js +60 -0
- package/examples/workflows/lib/count-child.js +27 -0
- package/examples/workflows/review-panel.js +63 -0
- package/examples/workflows/structured-findings.js +78 -0
- package/package.json +1 -1
- package/src/abortable.ts +43 -0
- package/src/agent-color.ts +161 -0
- package/src/agent-file-toggle.ts +269 -0
- package/src/agent-history.ts +54 -2
- package/src/agent-manager.ts +1263 -402
- package/src/agent-runner.ts +251 -27
- package/src/agent-types.ts +188 -32
- package/src/child-context.ts +15 -0
- package/src/cross-extension-rpc.ts +96 -20
- package/src/custom-agents.ts +170 -13
- package/src/index.ts +2024 -537
- package/src/invocation-config.ts +118 -3
- package/src/mention-clone.ts +196 -0
- package/src/mention.ts +141 -0
- package/src/model-resolver.ts +18 -0
- package/src/model-scope.ts +70 -0
- package/src/nested-tools.ts +424 -0
- package/src/output-file.ts +61 -6
- package/src/prompts.ts +45 -2
- package/src/schedule.ts +35 -14
- package/src/settings.ts +312 -2
- package/src/status-note.ts +66 -1
- package/src/structured-output.ts +130 -0
- package/src/types.ts +177 -10
- package/src/ui/agent-mention.ts +216 -0
- package/src/ui/agent-widget.ts +389 -441
- package/src/ui/conversation-blocks.ts +6 -0
- package/src/ui/conversation-timeline.ts +139 -25
- package/src/ui/conversation-viewer.ts +284 -69
- package/src/ui/fleet-list.ts +558 -0
- package/src/ui/schedule-menu.ts +9 -8
- package/src/ui/select-item.ts +45 -0
- package/src/ui/workflow-card.ts +470 -0
- package/src/ui/workflow-dialog.ts +1115 -0
- package/src/ui/workflow-menu.ts +193 -0
- package/src/usage.ts +109 -2
- package/src/workflow/collisions.ts +123 -0
- package/src/workflow/entry.ts +47 -0
- package/src/workflow/host.ts +403 -0
- package/src/workflow/journal.ts +164 -0
- package/src/workflow/json-schema.ts +128 -0
- package/src/workflow/meta.ts +325 -0
- package/src/workflow/progress.ts +550 -0
- package/src/workflow/runtime.ts +1219 -0
- package/src/workflow/saved.ts +217 -0
- package/src/workflow/task.ts +302 -0
- package/src/workflow/tool-description.ts +200 -0
- package/src/workflow/worker-source.ts +781 -0
- package/src/worktree.ts +69 -55
- package/src/xml.ts +13 -0
- package/vitest.config.ts +0 -18
package/src/worktree.ts
CHANGED
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
* Creates a temporary git worktree so the agent works on an isolated copy of the repo.
|
|
5
5
|
* On completion, if no changes were made, the worktree is cleaned up.
|
|
6
6
|
* If changes exist, a branch is created and returned in the result.
|
|
7
|
+
*
|
|
8
|
+
* Every git call goes through `pi.exec` (async) rather than `execFileSync`: a
|
|
9
|
+
* worktree copy can take seconds, and a session that spawns several isolated
|
|
10
|
+
* agents at once would otherwise serialize them all on the TUI's event loop.
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
|
-
import { execFileSync } from "node:child_process";
|
|
10
13
|
import { randomUUID } from "node:crypto";
|
|
11
14
|
import { existsSync, realpathSync } from "node:fs";
|
|
12
15
|
import { tmpdir } from "node:os";
|
|
13
16
|
import { join, relative } from "node:path";
|
|
17
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
14
18
|
|
|
15
19
|
export interface WorktreeInfo {
|
|
16
20
|
/** Absolute path to the worktree directory (the copied repo's root). */
|
|
@@ -28,6 +32,26 @@ export interface WorktreeInfo {
|
|
|
28
32
|
workPath: string;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Project-wide switch for worktree isolation (`worktreeIsolation` in
|
|
37
|
+
* subagents.json). Default `true` — unchanged behaviour.
|
|
38
|
+
*
|
|
39
|
+
* The `"off"` isolation value gives a model a legal way to decline a worktree,
|
|
40
|
+
* but it still depends on the model choosing it. This is the deterministic half
|
|
41
|
+
* of the same fix: on a large repo where every worktree costs real time and
|
|
42
|
+
* disk (#184), turning it off means no caller can create one, whatever it
|
|
43
|
+
* passes.
|
|
44
|
+
*/
|
|
45
|
+
let worktreeIsolationEnabled = true;
|
|
46
|
+
|
|
47
|
+
export function setWorktreeIsolationEnabled(enabled: boolean): void {
|
|
48
|
+
worktreeIsolationEnabled = enabled;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isWorktreeIsolationEnabled(): boolean {
|
|
52
|
+
return worktreeIsolationEnabled;
|
|
53
|
+
}
|
|
54
|
+
|
|
31
55
|
export interface WorktreeCleanupResult {
|
|
32
56
|
/** Whether changes were found in the worktree. */
|
|
33
57
|
hasChanges: boolean;
|
|
@@ -37,26 +61,43 @@ export interface WorktreeCleanupResult {
|
|
|
37
61
|
path?: string;
|
|
38
62
|
}
|
|
39
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Run git and return its trimmed stdout, throwing on failure so callers keep
|
|
66
|
+
* the try/catch control flow `execFileSync` gave them.
|
|
67
|
+
*
|
|
68
|
+
* `pi.exec` never rejects — it reports failure in the result — and a command
|
|
69
|
+
* killed by its timeout comes back as `killed` with an exit code of 0, so both
|
|
70
|
+
* have to be checked to reproduce `execFileSync`'s "throws on anything but a
|
|
71
|
+
* clean exit".
|
|
72
|
+
*/
|
|
73
|
+
async function git(pi: ExtensionAPI, cwd: string, args: string[], timeout: number): Promise<string> {
|
|
74
|
+
const result = await pi.exec("git", args, { cwd, timeout });
|
|
75
|
+
if (result.killed || result.code !== 0) {
|
|
76
|
+
throw new Error(result.stderr.trim() || `git ${args.join(" ")} failed (exit ${result.code})`);
|
|
77
|
+
}
|
|
78
|
+
return result.stdout.trim();
|
|
79
|
+
}
|
|
80
|
+
|
|
40
81
|
/**
|
|
41
82
|
* Create a temporary git worktree for an agent.
|
|
42
83
|
* Returns the worktree path, or undefined if not in a git repo.
|
|
43
84
|
*/
|
|
44
|
-
export function createWorktree(
|
|
85
|
+
export async function createWorktree(
|
|
86
|
+
pi: ExtensionAPI,
|
|
87
|
+
cwd: string,
|
|
88
|
+
agentId: string,
|
|
89
|
+
): Promise<WorktreeInfo | undefined> {
|
|
45
90
|
// Verify we're in a git repo with at least one commit (HEAD must exist)
|
|
46
91
|
let baseSha: string;
|
|
47
92
|
let subdir: string;
|
|
48
93
|
try {
|
|
49
|
-
|
|
50
|
-
baseSha =
|
|
51
|
-
.toString()
|
|
52
|
-
.trim();
|
|
94
|
+
await git(pi, cwd, ["rev-parse", "--is-inside-work-tree"], 5000);
|
|
95
|
+
baseSha = await git(pi, cwd, ["rev-parse", "HEAD"], 5000);
|
|
53
96
|
// Where cwd sits inside the repo ("" at the root): the agent must work at
|
|
54
97
|
// the same subdirectory inside the copy, or a monorepo-package cwd would
|
|
55
98
|
// silently widen to the whole repo. realpath both sides — git emits
|
|
56
99
|
// resolved paths while cwd may arrive through a symlink (macOS /tmp).
|
|
57
|
-
const topLevel =
|
|
58
|
-
.toString()
|
|
59
|
-
.trim();
|
|
100
|
+
const topLevel = await git(pi, cwd, ["rev-parse", "--show-toplevel"], 5000);
|
|
60
101
|
subdir = relative(realpathSync(topLevel), realpathSync(cwd));
|
|
61
102
|
} catch {
|
|
62
103
|
return undefined;
|
|
@@ -68,11 +109,7 @@ export function createWorktree(cwd: string, agentId: string): WorktreeInfo | und
|
|
|
68
109
|
|
|
69
110
|
try {
|
|
70
111
|
// Create detached worktree at HEAD
|
|
71
|
-
|
|
72
|
-
cwd,
|
|
73
|
-
stdio: "pipe",
|
|
74
|
-
timeout: 30000,
|
|
75
|
-
});
|
|
112
|
+
await git(pi, cwd, ["worktree", "add", "--detach", worktreePath, "HEAD"], 30000);
|
|
76
113
|
return { path: worktreePath, branch, baseSha, workPath: subdir ? join(worktreePath, subdir) : worktreePath };
|
|
77
114
|
} catch {
|
|
78
115
|
// If worktree creation fails, return undefined (agent runs in normal cwd)
|
|
@@ -85,44 +122,33 @@ export function createWorktree(cwd: string, agentId: string): WorktreeInfo | und
|
|
|
85
122
|
* - If no changes: remove worktree entirely.
|
|
86
123
|
* - If changes exist: create a branch, commit changes, return branch info.
|
|
87
124
|
*/
|
|
88
|
-
export function cleanupWorktree(
|
|
125
|
+
export async function cleanupWorktree(
|
|
126
|
+
pi: ExtensionAPI,
|
|
89
127
|
cwd: string,
|
|
90
128
|
worktree: WorktreeInfo,
|
|
91
129
|
agentDescription: string,
|
|
92
|
-
): WorktreeCleanupResult {
|
|
130
|
+
): Promise<WorktreeCleanupResult> {
|
|
93
131
|
if (!existsSync(worktree.path)) {
|
|
94
132
|
return { hasChanges: false };
|
|
95
133
|
}
|
|
96
134
|
|
|
97
135
|
try {
|
|
98
136
|
// Check for uncommitted changes in the worktree
|
|
99
|
-
const status =
|
|
100
|
-
cwd: worktree.path,
|
|
101
|
-
stdio: "pipe",
|
|
102
|
-
timeout: 10000,
|
|
103
|
-
}).toString().trim();
|
|
137
|
+
const status = await git(pi, worktree.path, ["status", "--porcelain"], 10000);
|
|
104
138
|
|
|
105
139
|
if (status) {
|
|
106
140
|
// Changes exist — stage, commit, and create a branch
|
|
107
|
-
|
|
108
|
-
// Truncate description for commit message (no shell sanitization needed —
|
|
141
|
+
await git(pi, worktree.path, ["add", "-A"], 10000);
|
|
142
|
+
// Truncate description for commit message (no shell sanitization needed — pi.exec uses argv)
|
|
109
143
|
const safeDesc = agentDescription.slice(0, 200);
|
|
110
144
|
const commitMsg = `pi-agent: ${safeDesc}`;
|
|
111
|
-
|
|
112
|
-
cwd: worktree.path,
|
|
113
|
-
stdio: "pipe",
|
|
114
|
-
timeout: 10000,
|
|
115
|
-
});
|
|
145
|
+
await git(pi, worktree.path, ["commit", "--no-verify", "-m", commitMsg], 10000);
|
|
116
146
|
} else {
|
|
117
|
-
const currentSha =
|
|
118
|
-
cwd: worktree.path,
|
|
119
|
-
stdio: "pipe",
|
|
120
|
-
timeout: 5000,
|
|
121
|
-
}).toString().trim();
|
|
147
|
+
const currentSha = await git(pi, worktree.path, ["rev-parse", "HEAD"], 5000);
|
|
122
148
|
|
|
123
149
|
if (currentSha === worktree.baseSha) {
|
|
124
150
|
// No changes — remove worktree
|
|
125
|
-
removeWorktree(cwd, worktree.path);
|
|
151
|
+
await removeWorktree(pi, cwd, worktree.path);
|
|
126
152
|
return { hasChanges: false };
|
|
127
153
|
}
|
|
128
154
|
}
|
|
@@ -131,25 +157,17 @@ export function cleanupWorktree(
|
|
|
131
157
|
// If the branch already exists, append a suffix to avoid overwriting previous work.
|
|
132
158
|
let branchName = worktree.branch;
|
|
133
159
|
try {
|
|
134
|
-
|
|
135
|
-
cwd: worktree.path,
|
|
136
|
-
stdio: "pipe",
|
|
137
|
-
timeout: 5000,
|
|
138
|
-
});
|
|
160
|
+
await git(pi, worktree.path, ["branch", branchName], 5000);
|
|
139
161
|
} catch {
|
|
140
162
|
// Branch already exists — use a unique suffix
|
|
141
163
|
branchName = `${worktree.branch}-${Date.now()}`;
|
|
142
|
-
|
|
143
|
-
cwd: worktree.path,
|
|
144
|
-
stdio: "pipe",
|
|
145
|
-
timeout: 5000,
|
|
146
|
-
});
|
|
164
|
+
await git(pi, worktree.path, ["branch", branchName], 5000);
|
|
147
165
|
}
|
|
148
166
|
// Update branch name in worktree info for the caller
|
|
149
167
|
worktree.branch = branchName;
|
|
150
168
|
|
|
151
169
|
// Remove the worktree (branch persists in main repo)
|
|
152
|
-
removeWorktree(cwd, worktree.path);
|
|
170
|
+
await removeWorktree(pi, cwd, worktree.path);
|
|
153
171
|
|
|
154
172
|
return {
|
|
155
173
|
hasChanges: true,
|
|
@@ -158,7 +176,7 @@ export function cleanupWorktree(
|
|
|
158
176
|
};
|
|
159
177
|
} catch {
|
|
160
178
|
// Best effort cleanup on error
|
|
161
|
-
try { removeWorktree(cwd, worktree.path); } catch { /* ignore */ }
|
|
179
|
+
try { await removeWorktree(pi, cwd, worktree.path); } catch { /* ignore */ }
|
|
162
180
|
return { hasChanges: false };
|
|
163
181
|
}
|
|
164
182
|
}
|
|
@@ -166,17 +184,13 @@ export function cleanupWorktree(
|
|
|
166
184
|
/**
|
|
167
185
|
* Force-remove a worktree.
|
|
168
186
|
*/
|
|
169
|
-
function removeWorktree(cwd: string, worktreePath: string): void {
|
|
187
|
+
async function removeWorktree(pi: ExtensionAPI, cwd: string, worktreePath: string): Promise<void> {
|
|
170
188
|
try {
|
|
171
|
-
|
|
172
|
-
cwd,
|
|
173
|
-
stdio: "pipe",
|
|
174
|
-
timeout: 10000,
|
|
175
|
-
});
|
|
189
|
+
await git(pi, cwd, ["worktree", "remove", "--force", worktreePath], 10000);
|
|
176
190
|
} catch {
|
|
177
191
|
// If git worktree remove fails, try pruning
|
|
178
192
|
try {
|
|
179
|
-
|
|
193
|
+
await git(pi, cwd, ["worktree", "prune"], 5000);
|
|
180
194
|
} catch { /* ignore */ }
|
|
181
195
|
}
|
|
182
196
|
}
|
|
@@ -184,8 +198,8 @@ function removeWorktree(cwd: string, worktreePath: string): void {
|
|
|
184
198
|
/**
|
|
185
199
|
* Prune any orphaned worktrees (crash recovery).
|
|
186
200
|
*/
|
|
187
|
-
export function pruneWorktrees(cwd: string): void {
|
|
201
|
+
export async function pruneWorktrees(pi: ExtensionAPI, cwd: string): Promise<void> {
|
|
188
202
|
try {
|
|
189
|
-
|
|
203
|
+
await git(pi, cwd, ["worktree", "prune"], 5000);
|
|
190
204
|
} catch { /* ignore */ }
|
|
191
205
|
}
|
package/src/xml.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xml.ts — escaping for the `<task-notification>` payloads.
|
|
3
|
+
*
|
|
4
|
+
* A module of its own because both notification builders need it and they sit
|
|
5
|
+
* on opposite sides of a dependency edge: the agent one lives in `index.ts`,
|
|
6
|
+
* which imports `workflow/task.ts`, so the workflow one cannot reach back for
|
|
7
|
+
* it without a cycle.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Escape XML special characters to prevent injection in structured notifications. */
|
|
11
|
+
export function escapeXml(s: string): string {
|
|
12
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
13
|
+
}
|
package/vitest.config.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vitest/config";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
// The print-mode e2e suite (test/subagents-print-mode-e2e.test.ts) drives REAL
|
|
5
|
-
// faux-model turns through pi-coding-agent + pi-agent-core. That requires ONE
|
|
6
|
-
// shared @earendil-works/pi-ai instance so the faux provider the test registers
|
|
7
|
-
// lands in the same api-registry the session streams through. npm physically
|
|
8
|
-
// duplicates pi-ai (a top-level copy and one nested under pi-coding-agent), which
|
|
9
|
-
// otherwise yields two registries and "No API provider registered" errors.
|
|
10
|
-
// Inlining the @earendil-works packages routes them through Vite's resolver so
|
|
11
|
-
// dedupe can collapse pi-ai to a single instance — for the parent AND for every
|
|
12
|
-
// subagent session the extension spawns. dedupe alone is insufficient (it only
|
|
13
|
-
// affects modules Vite resolves; without inline the runtime stays externalized).
|
|
14
|
-
test: {
|
|
15
|
-
server: { deps: { inline: [/@earendil-works\/pi-/] } },
|
|
16
|
-
},
|
|
17
|
-
resolve: { dedupe: ["@earendil-works/pi-ai"] },
|
|
18
|
-
});
|