gsd-pi 2.36.0-dev.d612764 → 2.36.0-dev.f887f4e

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.
Files changed (46) hide show
  1. package/dist/resources/extensions/gsd/auto-dashboard.js +104 -334
  2. package/dist/resources/extensions/gsd/auto-loop.js +0 -11
  3. package/dist/resources/extensions/gsd/auto.js +0 -16
  4. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  5. package/dist/resources/extensions/gsd/commands.js +1 -51
  6. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -25
  7. package/dist/resources/extensions/gsd/index.js +0 -5
  8. package/dist/resources/extensions/gsd/notifications.js +1 -10
  9. package/dist/resources/extensions/gsd/preferences-types.js +0 -2
  10. package/dist/resources/extensions/gsd/preferences-validation.js +0 -29
  11. package/dist/resources/extensions/gsd/preferences.js +0 -3
  12. package/dist/resources/extensions/gsd/prompts/research-milestone.md +3 -4
  13. package/dist/resources/extensions/gsd/prompts/research-slice.md +2 -3
  14. package/dist/resources/extensions/gsd/templates/preferences.md +0 -6
  15. package/dist/resources/extensions/search-the-web/native-search.js +4 -45
  16. package/dist/resources/extensions/shared/terminal.js +0 -5
  17. package/dist/resources/extensions/subagent/index.js +60 -180
  18. package/package.json +1 -1
  19. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  20. package/packages/pi-tui/dist/terminal-image.js +0 -4
  21. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  22. package/packages/pi-tui/src/terminal-image.ts +0 -5
  23. package/src/resources/extensions/gsd/auto-dashboard.ts +116 -363
  24. package/src/resources/extensions/gsd/auto-loop.ts +0 -42
  25. package/src/resources/extensions/gsd/auto.ts +0 -21
  26. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  27. package/src/resources/extensions/gsd/commands.ts +1 -54
  28. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -25
  29. package/src/resources/extensions/gsd/index.ts +0 -8
  30. package/src/resources/extensions/gsd/notifications.ts +1 -10
  31. package/src/resources/extensions/gsd/preferences-types.ts +0 -13
  32. package/src/resources/extensions/gsd/preferences-validation.ts +0 -26
  33. package/src/resources/extensions/gsd/preferences.ts +0 -4
  34. package/src/resources/extensions/gsd/prompts/research-milestone.md +3 -4
  35. package/src/resources/extensions/gsd/prompts/research-slice.md +2 -3
  36. package/src/resources/extensions/gsd/templates/preferences.md +0 -6
  37. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -2
  38. package/src/resources/extensions/gsd/tests/preferences.test.ts +0 -23
  39. package/src/resources/extensions/search-the-web/native-search.ts +4 -50
  40. package/src/resources/extensions/shared/terminal.ts +0 -5
  41. package/src/resources/extensions/subagent/index.ts +79 -236
  42. package/dist/resources/extensions/cmux/index.js +0 -321
  43. package/dist/resources/extensions/gsd/commands-cmux.js +0 -120
  44. package/src/resources/extensions/cmux/index.ts +0 -384
  45. package/src/resources/extensions/gsd/commands-cmux.ts +0 -143
  46. package/src/resources/extensions/gsd/tests/cmux.test.ts +0 -98
@@ -1,321 +0,0 @@
1
- import { execFile, execFileSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { promisify } from "node:util";
4
- const execFileAsync = promisify(execFile);
5
- const DEFAULT_SOCKET_PATH = "/tmp/cmux.sock";
6
- const STATUS_KEY = "gsd";
7
- const lastSidebarSnapshots = new Map();
8
- let cmuxPromptedThisSession = false;
9
- let cachedCliAvailability = null;
10
- export function detectCmuxEnvironment(env = process.env, socketExists = existsSync, cliAvailable = isCmuxCliAvailable) {
11
- const socketPath = env.CMUX_SOCKET_PATH ?? DEFAULT_SOCKET_PATH;
12
- const workspaceId = env.CMUX_WORKSPACE_ID?.trim() || undefined;
13
- const surfaceId = env.CMUX_SURFACE_ID?.trim() || undefined;
14
- const available = Boolean(workspaceId && surfaceId && socketExists(socketPath));
15
- return {
16
- available,
17
- cliAvailable: cliAvailable(),
18
- socketPath,
19
- workspaceId,
20
- surfaceId,
21
- };
22
- }
23
- export function resolveCmuxConfig(preferences, env = process.env, socketExists = existsSync, cliAvailable = isCmuxCliAvailable) {
24
- const detected = detectCmuxEnvironment(env, socketExists, cliAvailable);
25
- const cmux = preferences?.cmux ?? {};
26
- const enabled = detected.available && cmux.enabled === true;
27
- return {
28
- ...detected,
29
- enabled,
30
- notifications: enabled && cmux.notifications !== false,
31
- sidebar: enabled && cmux.sidebar !== false,
32
- splits: enabled && cmux.splits === true,
33
- browser: enabled && cmux.browser === true,
34
- };
35
- }
36
- export function shouldPromptToEnableCmux(preferences, env = process.env, socketExists = existsSync, cliAvailable = isCmuxCliAvailable) {
37
- if (cmuxPromptedThisSession)
38
- return false;
39
- const detected = detectCmuxEnvironment(env, socketExists, cliAvailable);
40
- if (!detected.available)
41
- return false;
42
- return preferences?.cmux?.enabled === undefined;
43
- }
44
- export function markCmuxPromptShown() {
45
- cmuxPromptedThisSession = true;
46
- }
47
- export function resetCmuxPromptState() {
48
- cmuxPromptedThisSession = false;
49
- }
50
- export function isCmuxCliAvailable() {
51
- if (cachedCliAvailability !== null)
52
- return cachedCliAvailability;
53
- try {
54
- execFileSync("cmux", ["--help"], { stdio: "ignore", timeout: 1000 });
55
- cachedCliAvailability = true;
56
- }
57
- catch {
58
- cachedCliAvailability = false;
59
- }
60
- return cachedCliAvailability;
61
- }
62
- export function supportsOsc777Notifications(env = process.env) {
63
- const termProgram = env.TERM_PROGRAM?.toLowerCase() ?? "";
64
- return termProgram === "ghostty" || termProgram === "wezterm" || termProgram === "iterm.app";
65
- }
66
- export function emitOsc777Notification(title, body) {
67
- if (!supportsOsc777Notifications())
68
- return;
69
- const safeTitle = normalizeNotificationText(title).replace(/;/g, ",");
70
- const safeBody = normalizeNotificationText(body).replace(/;/g, ",");
71
- process.stdout.write(`\x1b]777;notify;${safeTitle};${safeBody}\x07`);
72
- }
73
- export function buildCmuxStatusLabel(state) {
74
- const parts = [];
75
- if (state.activeMilestone)
76
- parts.push(state.activeMilestone.id);
77
- if (state.activeSlice)
78
- parts.push(state.activeSlice.id);
79
- if (state.activeTask) {
80
- const prev = parts.pop();
81
- parts.push(prev ? `${prev}/${state.activeTask.id}` : state.activeTask.id);
82
- }
83
- if (parts.length === 0)
84
- return state.phase;
85
- return `${parts.join(" ")} · ${state.phase}`;
86
- }
87
- export function buildCmuxProgress(state) {
88
- const progress = state.progress;
89
- if (!progress)
90
- return null;
91
- const choose = (done, total, label) => {
92
- if (total <= 0)
93
- return null;
94
- return { value: Math.max(0, Math.min(1, done / total)), label: `${done}/${total} ${label}` };
95
- };
96
- return choose(progress.tasks?.done ?? 0, progress.tasks?.total ?? 0, "tasks")
97
- ?? choose(progress.slices?.done ?? 0, progress.slices?.total ?? 0, "slices")
98
- ?? choose(progress.milestones.done, progress.milestones.total, "milestones");
99
- }
100
- function phaseVisuals(phase) {
101
- switch (phase) {
102
- case "blocked":
103
- return { icon: "triangle-alert", color: "#ef4444" };
104
- case "paused":
105
- return { icon: "pause", color: "#f59e0b" };
106
- case "complete":
107
- case "completing-milestone":
108
- return { icon: "check", color: "#22c55e" };
109
- case "planning":
110
- case "researching":
111
- case "replanning-slice":
112
- return { icon: "compass", color: "#3b82f6" };
113
- case "validating-milestone":
114
- case "verifying":
115
- return { icon: "shield-check", color: "#06b6d4" };
116
- default:
117
- return { icon: "rocket", color: "#4ade80" };
118
- }
119
- }
120
- function sidebarSnapshotKey(config) {
121
- return config.workspaceId ?? "default";
122
- }
123
- export class CmuxClient {
124
- config;
125
- constructor(config) {
126
- this.config = config;
127
- }
128
- static fromPreferences(preferences) {
129
- return new CmuxClient(resolveCmuxConfig(preferences));
130
- }
131
- getConfig() {
132
- return this.config;
133
- }
134
- canRun() {
135
- return this.config.available && this.config.cliAvailable;
136
- }
137
- appendWorkspace(args) {
138
- return this.config.workspaceId ? [...args, "--workspace", this.config.workspaceId] : args;
139
- }
140
- appendSurface(args, surfaceId) {
141
- return surfaceId ? [...args, "--surface", surfaceId] : args;
142
- }
143
- runSync(args) {
144
- if (!this.canRun())
145
- return null;
146
- try {
147
- return execFileSync("cmux", args, {
148
- encoding: "utf-8",
149
- timeout: 3000,
150
- env: process.env,
151
- });
152
- }
153
- catch {
154
- return null;
155
- }
156
- }
157
- async runAsync(args) {
158
- if (!this.canRun())
159
- return null;
160
- try {
161
- const result = await execFileAsync("cmux", args, {
162
- encoding: "utf-8",
163
- timeout: 5000,
164
- env: process.env,
165
- });
166
- return result.stdout;
167
- }
168
- catch {
169
- return null;
170
- }
171
- }
172
- getCapabilities() {
173
- const stdout = this.runSync(["capabilities", "--json"]);
174
- return stdout ? parseJson(stdout) : null;
175
- }
176
- identify() {
177
- const stdout = this.runSync(["identify", "--json"]);
178
- return stdout ? parseJson(stdout) : null;
179
- }
180
- setStatus(label, phase) {
181
- if (!this.config.sidebar)
182
- return;
183
- const visuals = phaseVisuals(phase);
184
- this.runSync(this.appendWorkspace([
185
- "set-status",
186
- STATUS_KEY,
187
- label,
188
- "--icon",
189
- visuals.icon,
190
- "--color",
191
- visuals.color,
192
- ]));
193
- }
194
- clearStatus() {
195
- if (!this.config.sidebar)
196
- return;
197
- this.runSync(this.appendWorkspace(["clear-status", STATUS_KEY]));
198
- }
199
- setProgress(progress) {
200
- if (!this.config.sidebar)
201
- return;
202
- if (!progress) {
203
- this.runSync(this.appendWorkspace(["clear-progress"]));
204
- return;
205
- }
206
- this.runSync(this.appendWorkspace([
207
- "set-progress",
208
- progress.value.toFixed(3),
209
- "--label",
210
- progress.label,
211
- ]));
212
- }
213
- log(message, level = "info", source = "gsd") {
214
- if (!this.config.sidebar)
215
- return;
216
- this.runSync(this.appendWorkspace([
217
- "log",
218
- "--level",
219
- level,
220
- "--source",
221
- source,
222
- "--",
223
- message,
224
- ]));
225
- }
226
- notify(title, body, subtitle) {
227
- if (!this.config.notifications)
228
- return false;
229
- const args = ["notify", "--title", title, "--body", body];
230
- if (subtitle)
231
- args.push("--subtitle", subtitle);
232
- return this.runSync(args) !== null;
233
- }
234
- async listSurfaceIds() {
235
- const stdout = await this.runAsync(this.appendWorkspace(["list-surfaces", "--json", "--id-format", "both"]));
236
- const parsed = stdout ? parseJson(stdout) : null;
237
- return extractSurfaceIds(parsed);
238
- }
239
- async createSplit(direction) {
240
- if (!this.config.splits)
241
- return null;
242
- const before = new Set(await this.listSurfaceIds());
243
- const args = ["new-split", direction];
244
- const scopedArgs = this.appendSurface(this.appendWorkspace(args), this.config.surfaceId);
245
- await this.runAsync(scopedArgs);
246
- const after = await this.listSurfaceIds();
247
- for (const id of after) {
248
- if (!before.has(id))
249
- return id;
250
- }
251
- return null;
252
- }
253
- async sendSurface(surfaceId, text) {
254
- const payload = text.endsWith("\n") ? text : `${text}\n`;
255
- const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, payload]);
256
- return stdout !== null;
257
- }
258
- }
259
- export function syncCmuxSidebar(preferences, state) {
260
- const client = CmuxClient.fromPreferences(preferences);
261
- const config = client.getConfig();
262
- if (!config.sidebar)
263
- return;
264
- const label = buildCmuxStatusLabel(state);
265
- const progress = buildCmuxProgress(state);
266
- const snapshot = JSON.stringify({ label, progress, phase: state.phase });
267
- const key = sidebarSnapshotKey(config);
268
- if (lastSidebarSnapshots.get(key) === snapshot)
269
- return;
270
- client.setStatus(label, state.phase);
271
- client.setProgress(progress);
272
- lastSidebarSnapshots.set(key, snapshot);
273
- }
274
- export function clearCmuxSidebar(preferences) {
275
- const config = resolveCmuxConfig(preferences);
276
- if (!config.available || !config.cliAvailable)
277
- return;
278
- const client = new CmuxClient({ ...config, enabled: true, sidebar: true });
279
- const key = sidebarSnapshotKey(config);
280
- client.clearStatus();
281
- client.setProgress(null);
282
- lastSidebarSnapshots.delete(key);
283
- }
284
- export function logCmuxEvent(preferences, message, level = "info") {
285
- CmuxClient.fromPreferences(preferences).log(message, level);
286
- }
287
- export function shellEscape(value) {
288
- return `'${value.replace(/'/g, `'\\''`)}'`;
289
- }
290
- function normalizeNotificationText(value) {
291
- return value.replace(/\r?\n/g, " ").trim();
292
- }
293
- function parseJson(text) {
294
- try {
295
- return JSON.parse(text);
296
- }
297
- catch {
298
- return null;
299
- }
300
- }
301
- function extractSurfaceIds(value) {
302
- const found = new Set();
303
- const visit = (node) => {
304
- if (Array.isArray(node)) {
305
- for (const item of node)
306
- visit(item);
307
- return;
308
- }
309
- if (!node || typeof node !== "object")
310
- return;
311
- for (const [key, child] of Object.entries(node)) {
312
- if (typeof child === "string"
313
- && (key === "surface_id" || key === "surface" || (key === "id" && child.includes("surface")))) {
314
- found.add(child);
315
- }
316
- visit(child);
317
- }
318
- };
319
- visit(value);
320
- return Array.from(found);
321
- }
@@ -1,120 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { clearCmuxSidebar, CmuxClient, detectCmuxEnvironment, resolveCmuxConfig } from "../cmux/index.js";
3
- import { saveFile } from "./files.js";
4
- import { getProjectGSDPreferencesPath, loadEffectiveGSDPreferences, loadProjectGSDPreferences, } from "./preferences.js";
5
- import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
6
- function extractBodyAfterFrontmatter(content) {
7
- const start = content.startsWith("---\n") ? 4 : content.startsWith("---\r\n") ? 5 : -1;
8
- if (start === -1)
9
- return null;
10
- const closingIdx = content.indexOf("\n---", start);
11
- if (closingIdx === -1)
12
- return null;
13
- const after = content.slice(closingIdx + 4);
14
- return after.trim() ? after : null;
15
- }
16
- async function writeProjectCmuxPreferences(ctx, updater) {
17
- const path = getProjectGSDPreferencesPath();
18
- await ensurePreferencesFile(path, ctx, "project");
19
- const existing = loadProjectGSDPreferences();
20
- const prefs = existing?.preferences ? { ...existing.preferences } : { version: 1 };
21
- updater(prefs);
22
- prefs.version = prefs.version || 1;
23
- const frontmatter = serializePreferencesToFrontmatter(prefs);
24
- let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
25
- if (existsSync(path)) {
26
- const preserved = extractBodyAfterFrontmatter(readFileSync(path, "utf-8"));
27
- if (preserved)
28
- body = preserved;
29
- }
30
- await saveFile(path, `---\n${frontmatter}---${body}`);
31
- await ctx.waitForIdle();
32
- await ctx.reload();
33
- }
34
- function formatCmuxStatus() {
35
- const loaded = loadEffectiveGSDPreferences();
36
- const detected = detectCmuxEnvironment();
37
- const resolved = resolveCmuxConfig(loaded?.preferences);
38
- const capabilities = new CmuxClient(resolved).getCapabilities();
39
- const accessMode = typeof capabilities?.mode === "string"
40
- ? capabilities.mode
41
- : typeof capabilities?.access_mode === "string"
42
- ? capabilities.access_mode
43
- : "unknown";
44
- const methods = Array.isArray(capabilities?.methods) ? capabilities.methods.length : 0;
45
- return [
46
- "cmux status",
47
- "",
48
- `Detected: ${detected.available ? "yes" : "no"}`,
49
- `Enabled: ${resolved.enabled ? "yes" : "no"}`,
50
- `CLI available: ${detected.cliAvailable ? "yes" : "no"}`,
51
- `Socket: ${detected.socketPath}`,
52
- `Workspace: ${detected.workspaceId ?? "(none)"}`,
53
- `Surface: ${detected.surfaceId ?? "(none)"}`,
54
- `Features: notifications=${resolved.notifications ? "on" : "off"}, sidebar=${resolved.sidebar ? "on" : "off"}, splits=${resolved.splits ? "on" : "off"}, browser=${resolved.browser ? "on" : "off"}`,
55
- `Capabilities: access=${accessMode}, methods=${methods}`,
56
- ].join("\n");
57
- }
58
- function ensureCmuxAvailableForEnable(ctx) {
59
- const detected = detectCmuxEnvironment();
60
- if (detected.available)
61
- return true;
62
- ctx.ui.notify("cmux not detected. Install it from https://cmux.com and run gsd inside a cmux terminal.", "warning");
63
- return false;
64
- }
65
- export async function handleCmux(args, ctx) {
66
- const trimmed = args.trim();
67
- if (!trimmed || trimmed === "status") {
68
- ctx.ui.notify(formatCmuxStatus(), "info");
69
- return;
70
- }
71
- if (trimmed === "on") {
72
- if (!ensureCmuxAvailableForEnable(ctx))
73
- return;
74
- await writeProjectCmuxPreferences(ctx, (prefs) => {
75
- prefs.cmux = {
76
- enabled: true,
77
- notifications: true,
78
- sidebar: true,
79
- splits: false,
80
- browser: false,
81
- ...(prefs.cmux ?? {}),
82
- };
83
- prefs.cmux.enabled = true;
84
- });
85
- ctx.ui.notify("cmux integration enabled in project preferences.", "info");
86
- return;
87
- }
88
- if (trimmed === "off") {
89
- const effective = loadEffectiveGSDPreferences()?.preferences;
90
- await writeProjectCmuxPreferences(ctx, (prefs) => {
91
- prefs.cmux = { ...(prefs.cmux ?? {}), enabled: false };
92
- });
93
- clearCmuxSidebar(effective);
94
- ctx.ui.notify("cmux integration disabled in project preferences.", "info");
95
- return;
96
- }
97
- const parts = trimmed.split(/\s+/);
98
- if (parts.length === 2 && ["notifications", "sidebar", "splits", "browser"].includes(parts[0]) && ["on", "off"].includes(parts[1])) {
99
- const feature = parts[0];
100
- const enabled = parts[1] === "on";
101
- if (enabled && !ensureCmuxAvailableForEnable(ctx))
102
- return;
103
- await writeProjectCmuxPreferences(ctx, (prefs) => {
104
- const next = { ...(prefs.cmux ?? {}) };
105
- next[feature] = enabled;
106
- if (enabled)
107
- next.enabled = true;
108
- prefs.cmux = next;
109
- });
110
- if (!enabled && feature === "sidebar") {
111
- clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
112
- }
113
- const note = feature === "browser" && enabled
114
- ? " Browser surfaces are still a follow-up path."
115
- : "";
116
- ctx.ui.notify(`cmux ${feature} ${enabled ? "enabled" : "disabled"}.${note}`, "info");
117
- return;
118
- }
119
- ctx.ui.notify("Usage: /gsd cmux <status|on|off|notifications on|notifications off|sidebar on|sidebar off|splits on|splits off|browser on|browser off>", "info");
120
- }