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.
- package/dist/resources/extensions/gsd/auto-dashboard.js +104 -334
- package/dist/resources/extensions/gsd/auto-loop.js +0 -11
- package/dist/resources/extensions/gsd/auto.js +0 -16
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +1 -51
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -25
- package/dist/resources/extensions/gsd/index.js +0 -5
- package/dist/resources/extensions/gsd/notifications.js +1 -10
- package/dist/resources/extensions/gsd/preferences-types.js +0 -2
- package/dist/resources/extensions/gsd/preferences-validation.js +0 -29
- package/dist/resources/extensions/gsd/preferences.js +0 -3
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +3 -4
- package/dist/resources/extensions/gsd/prompts/research-slice.md +2 -3
- package/dist/resources/extensions/gsd/templates/preferences.md +0 -6
- package/dist/resources/extensions/search-the-web/native-search.js +4 -45
- package/dist/resources/extensions/shared/terminal.js +0 -5
- package/dist/resources/extensions/subagent/index.js +60 -180
- package/package.json +1 -1
- package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal-image.js +0 -4
- package/packages/pi-tui/dist/terminal-image.js.map +1 -1
- package/packages/pi-tui/src/terminal-image.ts +0 -5
- package/src/resources/extensions/gsd/auto-dashboard.ts +116 -363
- package/src/resources/extensions/gsd/auto-loop.ts +0 -42
- package/src/resources/extensions/gsd/auto.ts +0 -21
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +1 -54
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -25
- package/src/resources/extensions/gsd/index.ts +0 -8
- package/src/resources/extensions/gsd/notifications.ts +1 -10
- package/src/resources/extensions/gsd/preferences-types.ts +0 -13
- package/src/resources/extensions/gsd/preferences-validation.ts +0 -26
- package/src/resources/extensions/gsd/preferences.ts +0 -4
- package/src/resources/extensions/gsd/prompts/research-milestone.md +3 -4
- package/src/resources/extensions/gsd/prompts/research-slice.md +2 -3
- package/src/resources/extensions/gsd/templates/preferences.md +0 -6
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -2
- package/src/resources/extensions/gsd/tests/preferences.test.ts +0 -23
- package/src/resources/extensions/search-the-web/native-search.ts +4 -50
- package/src/resources/extensions/shared/terminal.ts +0 -5
- package/src/resources/extensions/subagent/index.ts +79 -236
- package/dist/resources/extensions/cmux/index.js +0 -321
- package/dist/resources/extensions/gsd/commands-cmux.js +0 -120
- package/src/resources/extensions/cmux/index.ts +0 -384
- package/src/resources/extensions/gsd/commands-cmux.ts +0 -143
- package/src/resources/extensions/gsd/tests/cmux.test.ts +0 -98
|
@@ -50,7 +50,6 @@ import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache
|
|
|
50
50
|
import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
|
|
51
51
|
import { isDbAvailable } from "./gsd-db.js";
|
|
52
52
|
import { countPendingCaptures } from "./captures.js";
|
|
53
|
-
import { clearCmuxSidebar, logCmuxEvent, syncCmuxSidebar } from "../cmux/index.js";
|
|
54
53
|
// ── Extracted modules ──────────────────────────────────────────────────────
|
|
55
54
|
import { startUnitSupervision } from "./auto-timers.js";
|
|
56
55
|
import { runPostUnitVerification } from "./auto-verification.js";
|
|
@@ -249,7 +248,6 @@ function handleLostSessionLock(ctx) {
|
|
|
249
248
|
s.paused = false;
|
|
250
249
|
clearUnitTimeout();
|
|
251
250
|
deregisterSigtermHandler();
|
|
252
|
-
clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
|
|
253
251
|
ctx?.ui.notify("Session lock lost — another GSD process appears to have taken over. Stopping gracefully.", "error");
|
|
254
252
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
255
253
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
@@ -258,7 +256,6 @@ function handleLostSessionLock(ctx) {
|
|
|
258
256
|
export async function stopAuto(ctx, pi, reason) {
|
|
259
257
|
if (!s.active && !s.paused)
|
|
260
258
|
return;
|
|
261
|
-
const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
|
|
262
259
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
263
260
|
clearUnitTimeout();
|
|
264
261
|
if (lockBase())
|
|
@@ -317,8 +314,6 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
317
314
|
});
|
|
318
315
|
}
|
|
319
316
|
}
|
|
320
|
-
clearCmuxSidebar(loadedPreferences);
|
|
321
|
-
logCmuxEvent(loadedPreferences, `Auto-mode stopped${reasonSuffix || ""}.`, reason?.startsWith("Blocked:") ? "warning" : "info");
|
|
322
317
|
if (isDebugEnabled()) {
|
|
323
318
|
const logPath = writeDebugSummary();
|
|
324
319
|
if (logPath) {
|
|
@@ -460,8 +455,6 @@ function buildLoopDeps() {
|
|
|
460
455
|
pauseAuto,
|
|
461
456
|
clearUnitTimeout,
|
|
462
457
|
updateProgressWidget,
|
|
463
|
-
syncCmuxSidebar,
|
|
464
|
-
logCmuxEvent,
|
|
465
458
|
// State and cache
|
|
466
459
|
invalidateAllCaches,
|
|
467
460
|
deriveState,
|
|
@@ -612,7 +605,6 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
612
605
|
restoreHookState(s.basePath);
|
|
613
606
|
try {
|
|
614
607
|
await rebuildState(s.basePath);
|
|
615
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
616
608
|
}
|
|
617
609
|
catch (e) {
|
|
618
610
|
debugLog("resume-rebuild-state-failed", {
|
|
@@ -642,7 +634,6 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
642
634
|
}
|
|
643
635
|
updateSessionLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown", s.completedUnits.length);
|
|
644
636
|
writeLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown", s.completedUnits.length);
|
|
645
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
646
637
|
await autoLoop(ctx, pi, s, buildLoopDeps());
|
|
647
638
|
return;
|
|
648
639
|
}
|
|
@@ -656,13 +647,6 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
656
647
|
const ready = await bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, bootstrapDeps);
|
|
657
648
|
if (!ready)
|
|
658
649
|
return;
|
|
659
|
-
try {
|
|
660
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
661
|
-
}
|
|
662
|
-
catch {
|
|
663
|
-
// Best-effort only — sidebar sync must never block auto-mode startup
|
|
664
|
-
}
|
|
665
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
666
650
|
// Dispatch the first unit
|
|
667
651
|
await autoLoop(ctx, pi, s, buildLoopDeps());
|
|
668
652
|
}
|
|
@@ -626,7 +626,7 @@ export function serializePreferencesToFrontmatter(prefs) {
|
|
|
626
626
|
"skill_rules", "custom_instructions", "models", "skill_discovery",
|
|
627
627
|
"skill_staleness_days", "auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
|
628
628
|
"budget_ceiling", "budget_enforcement", "context_pause_threshold",
|
|
629
|
-
"notifications", "
|
|
629
|
+
"notifications", "remote_questions", "git",
|
|
630
630
|
"post_unit_hooks", "pre_dispatch_hooks",
|
|
631
631
|
"dynamic_routing", "token_profile", "phases", "parallel",
|
|
632
632
|
"auto_visualize", "auto_report",
|
|
@@ -37,7 +37,6 @@ import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
|
37
37
|
import { handleLogs } from "./commands-logs.js";
|
|
38
38
|
import { handleStart, handleTemplates, getTemplateCompletions } from "./commands-workflow-templates.js";
|
|
39
39
|
import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.js";
|
|
40
|
-
import { handleCmux } from "./commands-cmux.js";
|
|
41
40
|
/** Resolve the effective project root, accounting for worktree paths. */
|
|
42
41
|
export function projectRoot() {
|
|
43
42
|
const cwd = process.cwd();
|
|
@@ -90,7 +89,7 @@ function notifyRemoteAutoActive(ctx, basePath) {
|
|
|
90
89
|
}
|
|
91
90
|
export function registerGSDCommand(pi) {
|
|
92
91
|
pi.registerCommand("gsd", {
|
|
93
|
-
description: "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|
|
|
92
|
+
description: "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|update",
|
|
94
93
|
getArgumentCompletions: (prefix) => {
|
|
95
94
|
const subcommands = [
|
|
96
95
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -99,7 +98,6 @@ export function registerGSDCommand(pi) {
|
|
|
99
98
|
{ cmd: "stop", desc: "Stop auto mode gracefully" },
|
|
100
99
|
{ cmd: "pause", desc: "Pause auto-mode (preserves state, /gsd auto to resume)" },
|
|
101
100
|
{ cmd: "status", desc: "Progress dashboard" },
|
|
102
|
-
{ cmd: "widget", desc: "Cycle widget: full → small → min → off" },
|
|
103
101
|
{ cmd: "visualize", desc: "Open 10-tab workflow visualizer (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)" },
|
|
104
102
|
{ cmd: "queue", desc: "Queue and reorder future milestones" },
|
|
105
103
|
{ cmd: "quick", desc: "Execute a quick task without full planning overhead" },
|
|
@@ -133,7 +131,6 @@ export function registerGSDCommand(pi) {
|
|
|
133
131
|
{ cmd: "knowledge", desc: "Add persistent project knowledge (rule, pattern, or lesson)" },
|
|
134
132
|
{ cmd: "new-milestone", desc: "Create a milestone from a specification document (headless)" },
|
|
135
133
|
{ cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge)" },
|
|
136
|
-
{ cmd: "cmux", desc: "Manage cmux integration (status, sidebar, notifications, splits)" },
|
|
137
134
|
{ cmd: "park", desc: "Park a milestone — skip without deleting" },
|
|
138
135
|
{ cmd: "unpark", desc: "Reactivate a parked milestone" },
|
|
139
136
|
{ cmd: "update", desc: "Update GSD to the latest version" },
|
|
@@ -185,36 +182,6 @@ export function registerGSDCommand(pi) {
|
|
|
185
182
|
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
186
183
|
.map((s) => ({ value: `parallel ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
187
184
|
}
|
|
188
|
-
if (parts[0] === "cmux") {
|
|
189
|
-
if (parts.length <= 2) {
|
|
190
|
-
const subPrefix = parts[1] ?? "";
|
|
191
|
-
const subs = [
|
|
192
|
-
{ cmd: "status", desc: "Show cmux detection, prefs, and capabilities" },
|
|
193
|
-
{ cmd: "on", desc: "Enable cmux integration" },
|
|
194
|
-
{ cmd: "off", desc: "Disable cmux integration" },
|
|
195
|
-
{ cmd: "notifications", desc: "Toggle cmux desktop notifications" },
|
|
196
|
-
{ cmd: "sidebar", desc: "Toggle cmux sidebar metadata" },
|
|
197
|
-
{ cmd: "splits", desc: "Toggle cmux visual subagent splits" },
|
|
198
|
-
{ cmd: "browser", desc: "Toggle future browser integration flag" },
|
|
199
|
-
];
|
|
200
|
-
return subs
|
|
201
|
-
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
202
|
-
.map((s) => ({ value: `cmux ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
203
|
-
}
|
|
204
|
-
if (parts.length <= 3 && ["notifications", "sidebar", "splits", "browser"].includes(parts[1])) {
|
|
205
|
-
const togglePrefix = parts[2] ?? "";
|
|
206
|
-
return [
|
|
207
|
-
{ cmd: "on", desc: "Enable this cmux area" },
|
|
208
|
-
{ cmd: "off", desc: "Disable this cmux area" },
|
|
209
|
-
]
|
|
210
|
-
.filter((item) => item.cmd.startsWith(togglePrefix))
|
|
211
|
-
.map((item) => ({
|
|
212
|
-
value: `cmux ${parts[1]} ${item.cmd}`,
|
|
213
|
-
label: item.cmd,
|
|
214
|
-
description: item.desc,
|
|
215
|
-
}));
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
185
|
if (parts[0] === "setup" && parts.length <= 2) {
|
|
219
186
|
const subPrefix = parts[1] ?? "";
|
|
220
187
|
const subs = [
|
|
@@ -463,18 +430,6 @@ export async function handleGSDCommand(args, ctx, pi) {
|
|
|
463
430
|
await handleStatus(ctx);
|
|
464
431
|
return;
|
|
465
432
|
}
|
|
466
|
-
if (trimmed === "widget" || trimmed.startsWith("widget ")) {
|
|
467
|
-
const { cycleWidgetMode, setWidgetMode, getWidgetMode } = await import("./auto-dashboard.js");
|
|
468
|
-
const arg = trimmed.replace(/^widget\s*/, "").trim();
|
|
469
|
-
if (arg === "full" || arg === "small" || arg === "min" || arg === "off") {
|
|
470
|
-
setWidgetMode(arg);
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
cycleWidgetMode();
|
|
474
|
-
}
|
|
475
|
-
ctx.ui.notify(`Widget: ${getWidgetMode()}`, "info");
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
433
|
if (trimmed === "visualize") {
|
|
479
434
|
await handleVisualize(ctx);
|
|
480
435
|
return;
|
|
@@ -491,10 +446,6 @@ export async function handleGSDCommand(args, ctx, pi) {
|
|
|
491
446
|
await handlePrefs(trimmed.replace(/^prefs\s*/, "").trim(), ctx);
|
|
492
447
|
return;
|
|
493
448
|
}
|
|
494
|
-
if (trimmed === "cmux" || trimmed.startsWith("cmux ")) {
|
|
495
|
-
await handleCmux(trimmed.replace(/^cmux\s*/, "").trim(), ctx);
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
449
|
if (trimmed === "init") {
|
|
499
450
|
const { detectProjectState } = await import("./detection.js");
|
|
500
451
|
const { showProjectInit, handleReinit } = await import("./init-wizard.js");
|
|
@@ -949,7 +900,6 @@ function showHelp(ctx) {
|
|
|
949
900
|
" /gsd setup Global setup status [llm|search|remote|keys|prefs]",
|
|
950
901
|
" /gsd mode Set workflow mode (solo/team) [global|project]",
|
|
951
902
|
" /gsd prefs Manage preferences [global|project|status|wizard|setup|import-claude]",
|
|
952
|
-
" /gsd cmux Manage cmux integration [status|on|off|notifications|sidebar|splits|browser]",
|
|
953
903
|
" /gsd config Set API keys for external tools",
|
|
954
904
|
" /gsd keys API key manager [list|add|remove|test|rotate|doctor]",
|
|
955
905
|
" /gsd hooks Show post-unit hook configuration",
|
|
@@ -173,13 +173,6 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
173
173
|
- `on_milestone`: boolean — notify when a milestone finishes. Default: `true`.
|
|
174
174
|
- `on_attention`: boolean — notify when manual attention is needed. Default: `true`.
|
|
175
175
|
|
|
176
|
-
- `cmux`: configures cmux terminal integration when GSD is running inside a cmux workspace. Keys:
|
|
177
|
-
- `enabled`: boolean — master toggle for cmux integration. Default: `false`.
|
|
178
|
-
- `notifications`: boolean — route desktop notifications through cmux. Default: `true` when enabled.
|
|
179
|
-
- `sidebar`: boolean — publish status, progress, and log metadata to the cmux sidebar. Default: `true` when enabled.
|
|
180
|
-
- `splits`: boolean — run supported subagent work in visible cmux splits. Default: `false`.
|
|
181
|
-
- `browser`: boolean — reserve the future browser integration flag. Default: `false`.
|
|
182
|
-
|
|
183
176
|
- `dynamic_routing`: configures the dynamic model router that adjusts model selection based on task complexity. Keys:
|
|
184
177
|
- `enabled`: boolean — enable dynamic routing. Default: `false`.
|
|
185
178
|
- `tier_models`: object — model overrides per complexity tier. Keys: `light`, `standard`, `heavy`. Values are model ID strings.
|
|
@@ -484,24 +477,6 @@ Disables per-unit completion notifications (noisy in long runs) while keeping er
|
|
|
484
477
|
|
|
485
478
|
---
|
|
486
479
|
|
|
487
|
-
## cmux Example
|
|
488
|
-
|
|
489
|
-
```yaml
|
|
490
|
-
---
|
|
491
|
-
version: 1
|
|
492
|
-
cmux:
|
|
493
|
-
enabled: true
|
|
494
|
-
notifications: true
|
|
495
|
-
sidebar: true
|
|
496
|
-
splits: true
|
|
497
|
-
browser: false
|
|
498
|
-
---
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
Enables cmux-aware notifications, sidebar metadata, and visible subagent splits when GSD is running inside a cmux terminal.
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
480
|
## Post-Unit Hooks Example
|
|
506
481
|
|
|
507
482
|
```yaml
|
|
@@ -46,7 +46,6 @@ import { pauseAutoForProviderError, classifyProviderError } from "./provider-err
|
|
|
46
46
|
import { toPosixPath } from "../shared/mod.js";
|
|
47
47
|
import { isParallelActive, shutdownParallel } from "./parallel-orchestrator.js";
|
|
48
48
|
import { DEFAULT_BASH_TIMEOUT_SECS } from "./constants.js";
|
|
49
|
-
import { markCmuxPromptShown, shouldPromptToEnableCmux } from "../cmux/index.js";
|
|
50
49
|
// ── Agent Instructions (DEPRECATED) ──────────────────────────────────────
|
|
51
50
|
// agent-instructions.md is deprecated. Use AGENTS.md or CLAUDE.md instead.
|
|
52
51
|
// Pi core natively supports AGENTS.md (with CLAUDE.md fallback) per directory.
|
|
@@ -533,10 +532,6 @@ export default function (pi) {
|
|
|
533
532
|
const stopContextTimer = debugTime("context-inject");
|
|
534
533
|
const systemContent = loadPrompt("system");
|
|
535
534
|
const loadedPreferences = loadEffectiveGSDPreferences();
|
|
536
|
-
if (shouldPromptToEnableCmux(loadedPreferences?.preferences)) {
|
|
537
|
-
markCmuxPromptShown();
|
|
538
|
-
ctx.ui.notify("cmux detected. Run /gsd cmux on to enable sidebar metadata, notifications, and visual subagent splits for this project.", "info");
|
|
539
|
-
}
|
|
540
535
|
let preferenceBlock = "";
|
|
541
536
|
if (loadedPreferences) {
|
|
542
537
|
const cwd = process.cwd();
|
|
@@ -2,22 +2,13 @@
|
|
|
2
2
|
// Cross-platform desktop notifications for auto-mode events.
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
5
|
-
import { CmuxClient, emitOsc777Notification, resolveCmuxConfig } from "../cmux/index.js";
|
|
6
5
|
/**
|
|
7
6
|
* Send a native desktop notification. Non-blocking, non-fatal.
|
|
8
7
|
* macOS: osascript, Linux: notify-send, Windows: skipped.
|
|
9
8
|
*/
|
|
10
9
|
export function sendDesktopNotification(title, message, level = "info", kind = "complete") {
|
|
11
|
-
|
|
12
|
-
if (!shouldSendDesktopNotification(kind, loaded?.notifications))
|
|
10
|
+
if (!shouldSendDesktopNotification(kind))
|
|
13
11
|
return;
|
|
14
|
-
const cmux = resolveCmuxConfig(loaded);
|
|
15
|
-
if (cmux.notifications) {
|
|
16
|
-
const delivered = CmuxClient.fromPreferences(loaded).notify(title, message);
|
|
17
|
-
if (delivered)
|
|
18
|
-
return;
|
|
19
|
-
emitOsc777Notification(title, message);
|
|
20
|
-
}
|
|
21
12
|
try {
|
|
22
13
|
const command = buildDesktopNotificationCommand(process.platform, title, message, level);
|
|
23
14
|
if (!command)
|
|
@@ -47,7 +47,6 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
47
47
|
"budget_enforcement",
|
|
48
48
|
"context_pause_threshold",
|
|
49
49
|
"notifications",
|
|
50
|
-
"cmux",
|
|
51
50
|
"remote_questions",
|
|
52
51
|
"git",
|
|
53
52
|
"post_unit_hooks",
|
|
@@ -64,7 +63,6 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
64
63
|
"search_provider",
|
|
65
64
|
"compression_strategy",
|
|
66
65
|
"context_selection",
|
|
67
|
-
"widget_mode",
|
|
68
66
|
]);
|
|
69
67
|
/** Canonical list of all dispatch unit types. */
|
|
70
68
|
export const KNOWN_UNIT_TYPES = [
|
|
@@ -225,35 +225,6 @@ export function validatePreferences(preferences) {
|
|
|
225
225
|
errors.push("notifications must be an object");
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
-
// ─── Cmux ───────────────────────────────────────────────────────────────
|
|
229
|
-
if (preferences.cmux !== undefined) {
|
|
230
|
-
if (preferences.cmux && typeof preferences.cmux === "object") {
|
|
231
|
-
const cmux = preferences.cmux;
|
|
232
|
-
const validatedCmux = {};
|
|
233
|
-
if (cmux.enabled !== undefined)
|
|
234
|
-
validatedCmux.enabled = !!cmux.enabled;
|
|
235
|
-
if (cmux.notifications !== undefined)
|
|
236
|
-
validatedCmux.notifications = !!cmux.notifications;
|
|
237
|
-
if (cmux.sidebar !== undefined)
|
|
238
|
-
validatedCmux.sidebar = !!cmux.sidebar;
|
|
239
|
-
if (cmux.splits !== undefined)
|
|
240
|
-
validatedCmux.splits = !!cmux.splits;
|
|
241
|
-
if (cmux.browser !== undefined)
|
|
242
|
-
validatedCmux.browser = !!cmux.browser;
|
|
243
|
-
const knownCmuxKeys = new Set(["enabled", "notifications", "sidebar", "splits", "browser"]);
|
|
244
|
-
for (const key of Object.keys(cmux)) {
|
|
245
|
-
if (!knownCmuxKeys.has(key)) {
|
|
246
|
-
warnings.push(`unknown cmux key "${key}" — ignored`);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
if (Object.keys(validatedCmux).length > 0) {
|
|
250
|
-
validated.cmux = validatedCmux;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
errors.push("cmux must be an object");
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
228
|
// ─── Remote Questions ───────────────────────────────────────────────
|
|
258
229
|
if (preferences.remote_questions !== undefined) {
|
|
259
230
|
if (preferences.remote_questions && typeof preferences.remote_questions === "object") {
|
|
@@ -174,9 +174,6 @@ function mergePreferences(base, override) {
|
|
|
174
174
|
notifications: (base.notifications || override.notifications)
|
|
175
175
|
? { ...(base.notifications ?? {}), ...(override.notifications ?? {}) }
|
|
176
176
|
: undefined,
|
|
177
|
-
cmux: (base.cmux || override.cmux)
|
|
178
|
-
? { ...(base.cmux ?? {}), ...(override.cmux ?? {}) }
|
|
179
|
-
: undefined,
|
|
180
177
|
remote_questions: override.remote_questions
|
|
181
178
|
? { ...(base.remote_questions ?? {}), ...override.remote_questions }
|
|
182
179
|
: base.remote_questions,
|
|
@@ -25,10 +25,9 @@ Then research the codebase and relevant technologies. Narrate key findings and s
|
|
|
25
25
|
2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
|
|
26
26
|
3. Explore relevant code. For small/familiar codebases, use `rg`, `find`, and targeted reads. For large or unfamiliar codebases, use `scout` to build a broad map efficiently before diving in.
|
|
27
27
|
4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase
|
|
28
|
-
5.
|
|
29
|
-
6.
|
|
30
|
-
7.
|
|
31
|
-
8. Write `{{outputPath}}`
|
|
28
|
+
5. Use the **Research** output template from the inlined context above — include only sections that have real content
|
|
29
|
+
6. If `.gsd/REQUIREMENTS.md` exists, research against it. Identify which Active requirements are table stakes, likely omissions, overbuilt risks, or domain-standard behaviors the user may or may not want.
|
|
30
|
+
7. Write `{{outputPath}}`
|
|
32
31
|
|
|
33
32
|
## Strategic Questions to Answer
|
|
34
33
|
|
|
@@ -46,9 +46,8 @@ Research what this slice needs. Narrate key findings and surprises as you go —
|
|
|
46
46
|
2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
|
|
47
47
|
3. Explore relevant code for this slice's scope. For targeted exploration, use `rg`, `find`, and reads. For broad or unfamiliar subsystems, use `scout` to map the relevant area first.
|
|
48
48
|
4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase
|
|
49
|
-
5.
|
|
50
|
-
6.
|
|
51
|
-
7. Write `{{outputPath}}`
|
|
49
|
+
5. Use the **Research** output template from the inlined context above — include only sections that have real content. The template is already inlined above; do NOT attempt to read any template file from disk (there is no `templates/SLICE-RESEARCH.md` — the correct template is already present in this prompt).
|
|
50
|
+
6. Write `{{outputPath}}`
|
|
52
51
|
|
|
53
52
|
The slice directory already exists at `{{slicePath}}/`. Do NOT mkdir — just write the file.
|
|
54
53
|
|
|
@@ -11,15 +11,6 @@ export const BRAVE_TOOL_NAMES = ["search-the-web", "search_and_read"];
|
|
|
11
11
|
export const CUSTOM_SEARCH_TOOL_NAMES = ["search-the-web", "search_and_read", "google_search"];
|
|
12
12
|
/** Thinking block types that require signature validation by the API */
|
|
13
13
|
const THINKING_TYPES = new Set(["thinking", "redacted_thinking"]);
|
|
14
|
-
/**
|
|
15
|
-
* Maximum number of native web searches allowed per session (agent unit).
|
|
16
|
-
* The Anthropic API's `max_uses` is per-request — it resets on each API call.
|
|
17
|
-
* When `pause_turn` triggers a resubmit, the model gets a fresh budget.
|
|
18
|
-
* This session-level cap prevents unbounded search accumulation (#1309).
|
|
19
|
-
*
|
|
20
|
-
* 15 = 3 full turns of 5 searches each — generous for research, but bounded.
|
|
21
|
-
*/
|
|
22
|
-
export const MAX_NATIVE_SEARCHES_PER_SESSION = 15;
|
|
23
14
|
/** When true, skip native web search injection and keep Brave/custom tools active on Anthropic. */
|
|
24
15
|
export function preferBraveSearch() {
|
|
25
16
|
// preferences.md takes priority over env var
|
|
@@ -66,10 +57,6 @@ export function stripThinkingFromHistory(messages) {
|
|
|
66
57
|
export function registerNativeSearchHooks(pi) {
|
|
67
58
|
let isAnthropicProvider = false;
|
|
68
59
|
let modelSelectFired = false;
|
|
69
|
-
// Session-level native search counter (#1309).
|
|
70
|
-
// Tracks cumulative web_search_tool_result blocks across all turns in a session.
|
|
71
|
-
// Reset on session_start. Used to compute remaining budget for max_uses.
|
|
72
|
-
let sessionSearchCount = 0;
|
|
73
60
|
// Track provider changes via model selection — also handles diagnostics
|
|
74
61
|
// since model_select fires AFTER session_start and knows the provider.
|
|
75
62
|
pi.on("model_select", async (event, ctx) => {
|
|
@@ -148,46 +135,18 @@ export function registerNativeSearchHooks(pi) {
|
|
|
148
135
|
// the model and causes it to pick custom tools which can fail with network errors.
|
|
149
136
|
tools = tools.filter((t) => !CUSTOM_SEARCH_TOOL_NAMES.includes(t.name));
|
|
150
137
|
payload.tools = tools;
|
|
151
|
-
// ── Session-level search budget (#1309) ──────────────────────────────
|
|
152
|
-
// Count web_search_tool_result blocks in the conversation history to
|
|
153
|
-
// determine how many native searches have already been used this session.
|
|
154
|
-
// The Anthropic API's max_uses resets per request, so without this guard,
|
|
155
|
-
// pause_turn → resubmit cycles allow unlimited total searches.
|
|
156
|
-
if (Array.isArray(messages)) {
|
|
157
|
-
let historySearchCount = 0;
|
|
158
|
-
for (const msg of messages) {
|
|
159
|
-
const content = msg.content;
|
|
160
|
-
if (!Array.isArray(content))
|
|
161
|
-
continue;
|
|
162
|
-
for (const block of content) {
|
|
163
|
-
if (block?.type === "web_search_tool_result") {
|
|
164
|
-
historySearchCount++;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
// Sync counter from history (handles session restore / context replay)
|
|
169
|
-
sessionSearchCount = historySearchCount;
|
|
170
|
-
}
|
|
171
|
-
const remaining = Math.max(0, MAX_NATIVE_SEARCHES_PER_SESSION - sessionSearchCount);
|
|
172
|
-
if (remaining <= 0) {
|
|
173
|
-
// Budget exhausted — don't inject the search tool at all.
|
|
174
|
-
// The model will proceed without web search capability.
|
|
175
|
-
return payload;
|
|
176
|
-
}
|
|
177
138
|
tools.push({
|
|
178
139
|
type: "web_search_20250305",
|
|
179
140
|
name: "web_search",
|
|
180
|
-
// Cap
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
max_uses:
|
|
141
|
+
// Cap server-side searches per response to prevent the model from
|
|
142
|
+
// looping on web_search without synthesizing results (#817).
|
|
143
|
+
// 5 searches is generous — most queries need 1-2.
|
|
144
|
+
max_uses: 5,
|
|
184
145
|
});
|
|
185
146
|
return payload;
|
|
186
147
|
});
|
|
187
148
|
// Basic startup diagnostics — provider-specific info comes from model_select
|
|
188
149
|
pi.on("session_start", async (_event, ctx) => {
|
|
189
|
-
// Reset session-level search budget (#1309)
|
|
190
|
-
sessionSearchCount = 0;
|
|
191
150
|
const hasBrave = !!process.env.BRAVE_API_KEY;
|
|
192
151
|
const hasJina = !!process.env.JINA_API_KEY;
|
|
193
152
|
const hasAnswers = !!process.env.BRAVE_ANSWERS_KEY;
|
|
@@ -5,14 +5,9 @@
|
|
|
5
5
|
* Terminals that lack this support silently swallow the key combos.
|
|
6
6
|
*/
|
|
7
7
|
const UNSUPPORTED_TERMS = ["apple_terminal", "warpterm"];
|
|
8
|
-
export function isCmuxTerminal(env = process.env) {
|
|
9
|
-
return Boolean(env.CMUX_WORKSPACE_ID && env.CMUX_SURFACE_ID);
|
|
10
|
-
}
|
|
11
8
|
export function supportsCtrlAltShortcuts() {
|
|
12
9
|
const term = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
13
10
|
const jetbrains = (process.env.TERMINAL_EMULATOR || "").toLowerCase().includes("jetbrains");
|
|
14
|
-
if (isCmuxTerminal())
|
|
15
|
-
return true;
|
|
16
11
|
return !UNSUPPORTED_TERMS.some((t) => term.includes(t)) && !jetbrains;
|
|
17
12
|
}
|
|
18
13
|
/**
|