gsd-pi 2.80.0-dev.cf9433f56 → 2.80.0-dev.d4fc28e6b
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/cli.js +0 -19
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
- package/dist/resources/extensions/gsd/auto/loop.js +71 -8
- package/dist/resources/extensions/gsd/auto/phases.js +150 -94
- package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -30
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
- package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +90 -15
- package/dist/resources/extensions/gsd/auto-start.js +197 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +18 -22
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +86 -19
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +298 -54
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
- package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
- package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
- package/dist/resources/extensions/gsd/guided-flow.js +47 -28
- package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +15 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +35 -4
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/welcome-screen.d.ts +2 -0
- package/dist/welcome-screen.js +9 -7
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +2 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
- package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
- package/packages/pi-agent-core/dist/token-audit.js +221 -0
- package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
- package/packages/pi-agent-core/dist/types.d.ts +9 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-agent-core/src/agent.ts +8 -0
- package/packages/pi-agent-core/src/index.ts +2 -0
- package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
- package/packages/pi-agent-core/src/token-audit.ts +287 -0
- package/packages/pi-agent-core/src/types.ts +14 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +36 -7
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -6
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +3 -3
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +32 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +40 -7
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +3 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +5 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +35 -1
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
- package/src/resources/extensions/gsd/auto/loop.ts +84 -8
- package/src/resources/extensions/gsd/auto/phases.ts +218 -154
- package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -29
- package/src/resources/extensions/gsd/auto/session.ts +8 -0
- package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
- package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +95 -14
- package/src/resources/extensions/gsd/auto-start.ts +230 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
- package/src/resources/extensions/gsd/auto.ts +18 -18
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +100 -18
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +10 -3
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +347 -54
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
- package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
- package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +52 -35
- package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
- package/src/resources/extensions/gsd/pre-execution-checks.ts +16 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +361 -10
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
- package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +166 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +104 -3
- package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +49 -4
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
- /package/dist/web/standalone/.next/static/{-5nHJWzSdG-WkPMul_khA → cWaxzf-sdbSSbbwYu8q7a}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-5nHJWzSdG-WkPMul_khA → cWaxzf-sdbSSbbwYu8q7a}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Registers GSD extension runtime hooks and token-saving tool policies.
|
|
3
|
+
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
2
7
|
|
|
3
8
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
4
9
|
import { isToolCallEventType } from "@gsd/pi-coding-agent";
|
|
@@ -25,12 +30,245 @@ import { initNotificationWidget } from "../notification-widget.js";
|
|
|
25
30
|
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
26
31
|
import { extractSubagentAgentClasses } from "./subagent-input.js";
|
|
27
32
|
import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
|
|
33
|
+
import { resolveSkillManifest } from "../skill-manifest.js";
|
|
28
34
|
|
|
29
|
-
// Skip the welcome screen on the very first session_start — cli.ts already
|
|
30
|
-
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
|
|
31
|
-
let isFirstSession = true;
|
|
32
35
|
let approvalQuestionAbortInFlight = false;
|
|
33
36
|
|
|
37
|
+
interface DeferredApprovalGate {
|
|
38
|
+
gateId: string;
|
|
39
|
+
basePath: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type WelcomeScreenModule = {
|
|
43
|
+
buildWelcomeScreenLines(opts: { version: string; remoteChannel?: string; width?: number }): string[];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
async function loadWelcomeScreenModule(): Promise<WelcomeScreenModule | undefined> {
|
|
47
|
+
const candidates: string[] = [];
|
|
48
|
+
const gsdBinPath = process.env.GSD_BIN_PATH;
|
|
49
|
+
if (gsdBinPath) {
|
|
50
|
+
candidates.push(join(dirname(gsdBinPath), "welcome-screen.js"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const packageRoot = process.env.GSD_PKG_ROOT;
|
|
54
|
+
if (packageRoot) {
|
|
55
|
+
candidates.push(join(packageRoot, "dist", "welcome-screen.js"));
|
|
56
|
+
candidates.push(join(packageRoot, "src", "welcome-screen.ts"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (const candidate of candidates) {
|
|
60
|
+
try {
|
|
61
|
+
if (!existsSync(candidate)) continue;
|
|
62
|
+
const mod = await import(pathToFileURL(candidate).href) as Partial<WelcomeScreenModule>;
|
|
63
|
+
if (typeof mod.buildWelcomeScreenLines === "function") {
|
|
64
|
+
return mod as WelcomeScreenModule;
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
// Try the next package layout.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function installWelcomeHeader(ctx: ExtensionContext): Promise<void> {
|
|
74
|
+
if (!ctx.hasUI || typeof ctx.ui?.setHeader !== "function") return;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const welcome = await loadWelcomeScreenModule();
|
|
78
|
+
if (!welcome) return;
|
|
79
|
+
|
|
80
|
+
let remoteChannel: string | undefined;
|
|
81
|
+
try {
|
|
82
|
+
const { resolveRemoteConfig } = await import("../../remote-questions/config.js");
|
|
83
|
+
const rc = resolveRemoteConfig();
|
|
84
|
+
if (rc) remoteChannel = rc.channel;
|
|
85
|
+
} catch { /* non-fatal */ }
|
|
86
|
+
|
|
87
|
+
ctx.ui.setHeader(() => ({
|
|
88
|
+
render(width: number): string[] {
|
|
89
|
+
return welcome.buildWelcomeScreenLines({
|
|
90
|
+
version: process.env.GSD_VERSION || "0.0.0",
|
|
91
|
+
remoteChannel,
|
|
92
|
+
width,
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
invalidate(): void {},
|
|
96
|
+
}));
|
|
97
|
+
} catch {
|
|
98
|
+
/* non-fatal */
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let deferredApprovalGate: DeferredApprovalGate | null = null;
|
|
103
|
+
|
|
104
|
+
export const MINIMAL_GSD_TOOL_NAMES = [
|
|
105
|
+
"gsd_exec",
|
|
106
|
+
"gsd_exec_search",
|
|
107
|
+
"gsd_resume",
|
|
108
|
+
"gsd_milestone_status",
|
|
109
|
+
"gsd_checkpoint_db",
|
|
110
|
+
"memory_query",
|
|
111
|
+
"capture_thought",
|
|
112
|
+
] as const;
|
|
113
|
+
|
|
114
|
+
export const MINIMAL_AUTO_BASE_TOOL_NAMES = [
|
|
115
|
+
"ask_user_questions",
|
|
116
|
+
"bash",
|
|
117
|
+
"bg_shell",
|
|
118
|
+
"edit",
|
|
119
|
+
"glob",
|
|
120
|
+
"grep",
|
|
121
|
+
"ls",
|
|
122
|
+
"read",
|
|
123
|
+
"write",
|
|
124
|
+
] as const;
|
|
125
|
+
|
|
126
|
+
const AUTO_UNIT_SCOPED_TOOLS: Record<string, readonly string[]> = {
|
|
127
|
+
"research-milestone": ["gsd_summary_save", "gsd_decision_save"],
|
|
128
|
+
"plan-milestone": ["gsd_plan_milestone", "gsd_decision_save", "gsd_requirement_update"],
|
|
129
|
+
"discuss-milestone": ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
|
|
130
|
+
"validate-milestone": ["gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
|
|
131
|
+
"complete-milestone": ["gsd_complete_milestone", "subagent"],
|
|
132
|
+
"research-slice": ["gsd_summary_save", "gsd_decision_save"],
|
|
133
|
+
"plan-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
134
|
+
"refine-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
135
|
+
"replan-slice": ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
136
|
+
"complete-slice": ["gsd_slice_complete", "gsd_decision_save", "gsd_requirement_update", "subagent"],
|
|
137
|
+
"reassess-roadmap": ["gsd_reassess_roadmap"],
|
|
138
|
+
"execute-task": ["gsd_task_complete", "gsd_decision_save"],
|
|
139
|
+
"execute-task-simple": ["gsd_task_complete", "gsd_decision_save"],
|
|
140
|
+
"reactive-execute": ["gsd_task_complete", "gsd_decision_save"],
|
|
141
|
+
"run-uat": ["gsd_summary_save"],
|
|
142
|
+
"gate-evaluate": ["gsd_save_gate_result"],
|
|
143
|
+
"rewrite-docs": ["gsd_summary_save", "gsd_decision_save"],
|
|
144
|
+
"workflow-preferences": ["gsd_summary_save"],
|
|
145
|
+
"discuss-project": ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
|
|
146
|
+
"discuss-requirements": ["gsd_requirement_save", "gsd_summary_save"],
|
|
147
|
+
"research-decision": ["gsd_summary_save"],
|
|
148
|
+
"research-project": ["gsd_summary_save", "gsd_decision_save"],
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const WORKFLOW_GSD_TOOL_NAMES = [
|
|
152
|
+
...MINIMAL_GSD_TOOL_NAMES,
|
|
153
|
+
...Object.values(AUTO_UNIT_SCOPED_TOOLS).flat(),
|
|
154
|
+
].filter(isGsdManagedTool);
|
|
155
|
+
|
|
156
|
+
function isGsdManagedTool(name: string): boolean {
|
|
157
|
+
return name.startsWith("gsd_") || name === "memory_query" || name === "capture_thought" || name === "gsd_graph";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function buildMinimalGsdToolSet(activeToolNames: readonly string[]): string[] {
|
|
161
|
+
const active = new Set(activeToolNames);
|
|
162
|
+
const preserved = activeToolNames.filter((name) => !isGsdManagedTool(name));
|
|
163
|
+
const minimal = MINIMAL_GSD_TOOL_NAMES.filter((name) => active.has(name));
|
|
164
|
+
return [...new Set([...preserved, ...minimal])];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function buildMinimalAutoGsdToolSet(
|
|
168
|
+
activeToolNames: readonly string[],
|
|
169
|
+
unitType: string | undefined,
|
|
170
|
+
): string[] {
|
|
171
|
+
const active = new Set(activeToolNames);
|
|
172
|
+
const unitTools = unitType ? AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [] : [];
|
|
173
|
+
const autoBaseTools = new Set<string>(MINIMAL_AUTO_BASE_TOOL_NAMES);
|
|
174
|
+
const preserved = activeToolNames.filter((name) => autoBaseTools.has(name));
|
|
175
|
+
const scoped = [...MINIMAL_GSD_TOOL_NAMES, ...unitTools].filter((name) => active.has(name));
|
|
176
|
+
return [...new Set([...preserved, ...scoped])];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function buildMinimalGsdWorkflowToolSet(activeToolNames: readonly string[]): string[] {
|
|
180
|
+
const active = new Set(activeToolNames);
|
|
181
|
+
const autoBaseTools = new Set<string>(MINIMAL_AUTO_BASE_TOOL_NAMES);
|
|
182
|
+
const preserved = activeToolNames.filter((name) => autoBaseTools.has(name));
|
|
183
|
+
const scoped = WORKFLOW_GSD_TOOL_NAMES.filter((name) => active.has(name));
|
|
184
|
+
return [...new Set([...preserved, ...scoped])];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function buildRequestScopedGsdToolSet(
|
|
188
|
+
activeToolNames: readonly string[],
|
|
189
|
+
requestCustomMessages: readonly { customType?: string }[] | undefined,
|
|
190
|
+
): string[] | undefined {
|
|
191
|
+
for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
|
|
192
|
+
const currentCustomType = requestCustomMessages?.[index]?.customType;
|
|
193
|
+
if (
|
|
194
|
+
currentCustomType === "gsd-run" ||
|
|
195
|
+
currentCustomType === "gsd-discuss" ||
|
|
196
|
+
currentCustomType === "gsd-doctor-heal" ||
|
|
197
|
+
currentCustomType === "gsd-triage"
|
|
198
|
+
) {
|
|
199
|
+
return buildMinimalGsdWorkflowToolSet(activeToolNames);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function isFullGsdToolSurfaceRequested(): boolean {
|
|
206
|
+
return process.env.PI_GSD_FULL_TOOLS === "1";
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function isGeneralGsdToolScopingRequested(): boolean {
|
|
210
|
+
return process.env.PI_GSD_MINIMAL_TOOLS === "1";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface ScopedGsdWorkflowState {
|
|
214
|
+
tools: string[] | null;
|
|
215
|
+
visibleSkills: string[] | undefined;
|
|
216
|
+
restoreVisibleSkills: boolean;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
type GsdWorkflowScopeApi = Pick<ExtensionAPI, "getActiveTools" | "setActiveTools"> & Partial<Pick<ExtensionAPI, "getVisibleSkills" | "setVisibleSkills">>;
|
|
220
|
+
|
|
221
|
+
function applyMinimalGsdToolSurface(pi: ExtensionAPI): void {
|
|
222
|
+
if (isFullGsdToolSurfaceRequested()) return;
|
|
223
|
+
const dash = getAutoRuntimeSnapshot();
|
|
224
|
+
if (dash.active && dash.currentUnit) {
|
|
225
|
+
pi.setActiveTools(buildMinimalAutoGsdToolSet(pi.getActiveTools(), dash.currentUnit.type));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (!isGeneralGsdToolScopingRequested()) return;
|
|
229
|
+
pi.setActiveTools(buildMinimalGsdToolSet(pi.getActiveTools()));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function scopeGsdWorkflowToolsForDispatch(
|
|
233
|
+
pi: GsdWorkflowScopeApi,
|
|
234
|
+
unitType?: string,
|
|
235
|
+
): ScopedGsdWorkflowState | null {
|
|
236
|
+
if (isFullGsdToolSurfaceRequested()) return null;
|
|
237
|
+
const current = pi.getActiveTools();
|
|
238
|
+
const scoped = unitType
|
|
239
|
+
? buildMinimalAutoGsdToolSet(current, unitType)
|
|
240
|
+
: buildMinimalGsdWorkflowToolSet(current);
|
|
241
|
+
const toolsChanged = !(scoped.length === current.length && scoped.every((name, index) => name === current[index]));
|
|
242
|
+
const skillManifest = resolveSkillManifest(unitType);
|
|
243
|
+
const canScopeSkills = skillManifest !== null && pi.getVisibleSkills && pi.setVisibleSkills;
|
|
244
|
+
if (!toolsChanged && !canScopeSkills) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (toolsChanged) {
|
|
248
|
+
pi.setActiveTools(scoped);
|
|
249
|
+
}
|
|
250
|
+
const visibleSkills = canScopeSkills ? pi.getVisibleSkills!() : undefined;
|
|
251
|
+
if (canScopeSkills) {
|
|
252
|
+
pi.setVisibleSkills!(skillManifest);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
tools: toolsChanged ? current : null,
|
|
256
|
+
visibleSkills,
|
|
257
|
+
restoreVisibleSkills: Boolean(canScopeSkills),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function restoreGsdWorkflowTools(
|
|
262
|
+
pi: Pick<ExtensionAPI, "setActiveTools"> & Partial<Pick<ExtensionAPI, "setVisibleSkills">>,
|
|
263
|
+
savedState: ScopedGsdWorkflowState | null,
|
|
264
|
+
): void {
|
|
265
|
+
if (!savedState) return;
|
|
266
|
+
if (savedState.tools) pi.setActiveTools(savedState.tools);
|
|
267
|
+
if (savedState.restoreVisibleSkills && pi.setVisibleSkills) {
|
|
268
|
+
pi.setVisibleSkills(savedState.visibleSkills);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
34
272
|
async function deriveGsdState(basePath: string) {
|
|
35
273
|
const { deriveState } = await import("../state.js");
|
|
36
274
|
return deriveState(basePath);
|
|
@@ -85,12 +323,56 @@ async function applyCompactionThresholdOverride(ctx: ExtensionContext): Promise<
|
|
|
85
323
|
}
|
|
86
324
|
}
|
|
87
325
|
|
|
88
|
-
|
|
89
|
-
|
|
326
|
+
function clearDeferredApprovalGate(basePath?: string): void {
|
|
327
|
+
if (!basePath || deferredApprovalGate?.basePath === basePath) {
|
|
328
|
+
deferredApprovalGate = null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function deferApprovalGate(gateId: string, basePath: string): void {
|
|
333
|
+
deferredApprovalGate = { gateId, basePath };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function contextBasePath(ctx?: { cwd?: string }): string {
|
|
337
|
+
return typeof ctx?.cwd === "string" ? ctx.cwd : process.cwd();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function activateDeferredApprovalGate(basePath: string): void {
|
|
341
|
+
if (deferredApprovalGate?.basePath !== basePath) return;
|
|
342
|
+
setPendingGate(deferredApprovalGate.gateId, basePath);
|
|
343
|
+
deferredApprovalGate = null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
|
|
347
|
+
if (toolName !== "gsd_summary_save" && toolName !== "summary_save") return false;
|
|
348
|
+
if (!input || typeof input !== "object") return false;
|
|
349
|
+
return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function shouldBlockDeferredApprovalTool(
|
|
353
|
+
toolName: string,
|
|
354
|
+
input: unknown,
|
|
355
|
+
basePath: string,
|
|
356
|
+
): { block: boolean; reason?: string } {
|
|
357
|
+
if (deferredApprovalGate?.basePath !== basePath) return { block: false };
|
|
358
|
+
if (toolName === "ask_user_questions") return { block: false };
|
|
359
|
+
if (isContextDraftSummarySave(toolName, input)) return { block: false };
|
|
360
|
+
return {
|
|
361
|
+
block: true,
|
|
362
|
+
reason: [
|
|
363
|
+
`HARD BLOCK: Approval question "${deferredApprovalGate.gateId}" has been shown to the user.`,
|
|
364
|
+
`Only CONTEXT-DRAFT persistence may finish in this same assistant turn.`,
|
|
365
|
+
`Wait for the user's answer before calling additional tools.`,
|
|
366
|
+
].join(" "),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function resolveNotificationStoreBasePath(basePath: string): string {
|
|
371
|
+
return resolveWorktreeProjectRoot(basePath);
|
|
90
372
|
}
|
|
91
373
|
|
|
92
374
|
function initSessionNotifications(ctx: ExtensionContext): void {
|
|
93
|
-
initNotificationStore(resolveNotificationStoreBasePath());
|
|
375
|
+
initNotificationStore(resolveNotificationStoreBasePath(contextBasePath(ctx)));
|
|
94
376
|
installNotifyInterceptor(ctx);
|
|
95
377
|
initNotificationWidget(ctx);
|
|
96
378
|
}
|
|
@@ -132,53 +414,34 @@ export function registerHooks(
|
|
|
132
414
|
ecosystemHandlers: GSDEcosystemBeforeAgentStartHandler[],
|
|
133
415
|
): void {
|
|
134
416
|
pi.on("session_start", async (_event, ctx) => {
|
|
417
|
+
const basePath = contextBasePath(ctx);
|
|
135
418
|
initSessionNotifications(ctx);
|
|
136
419
|
if (!isAutoActive()) {
|
|
137
420
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
138
421
|
initHealthWidget(ctx);
|
|
139
422
|
}
|
|
140
|
-
resetWriteGateState(
|
|
423
|
+
resetWriteGateState(basePath);
|
|
141
424
|
resetToolCallLoopGuard();
|
|
142
425
|
approvalQuestionAbortInFlight = false;
|
|
426
|
+
clearDeferredApprovalGate();
|
|
143
427
|
await resetAskUserQuestionsTurnCache();
|
|
144
428
|
await syncServiceTierStatus(ctx);
|
|
145
429
|
await applyDisabledModelProviderPolicy(ctx);
|
|
146
430
|
await applyCompactionThresholdOverride(ctx);
|
|
147
431
|
// Skip MCP auto-prep when running inside an auto-worktree (see session_switch below).
|
|
148
432
|
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
149
|
-
if (!isInAutoWorktree(
|
|
433
|
+
if (!isInAutoWorktree(basePath)) {
|
|
150
434
|
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
151
|
-
prepareWorkflowMcpForProject(ctx,
|
|
435
|
+
prepareWorkflowMcpForProject(ctx, basePath);
|
|
152
436
|
}
|
|
153
437
|
|
|
154
438
|
// Apply show_token_cost preference (#1515)
|
|
155
439
|
try {
|
|
156
440
|
const { loadEffectiveGSDPreferences } = await import("../preferences.js");
|
|
157
|
-
const prefs = loadEffectiveGSDPreferences();
|
|
441
|
+
const prefs = loadEffectiveGSDPreferences(basePath);
|
|
158
442
|
process.env.GSD_SHOW_TOKEN_COST = prefs?.preferences.show_token_cost ? "1" : "";
|
|
159
443
|
} catch { /* non-fatal */ }
|
|
160
|
-
|
|
161
|
-
isFirstSession = false;
|
|
162
|
-
} else {
|
|
163
|
-
try {
|
|
164
|
-
const gsdBinPath = process.env.GSD_BIN_PATH;
|
|
165
|
-
if (gsdBinPath) {
|
|
166
|
-
const { dirname } = await import("node:path");
|
|
167
|
-
const { printWelcomeScreen } = await import(
|
|
168
|
-
join(dirname(gsdBinPath), "welcome-screen.js")
|
|
169
|
-
) as { printWelcomeScreen: (opts: { version: string; modelName?: string; provider?: string; remoteChannel?: string }) => void };
|
|
170
|
-
|
|
171
|
-
let remoteChannel: string | undefined;
|
|
172
|
-
try {
|
|
173
|
-
const { resolveRemoteConfig } = await import("../../remote-questions/config.js");
|
|
174
|
-
const rc = resolveRemoteConfig();
|
|
175
|
-
if (rc) remoteChannel = rc.channel;
|
|
176
|
-
} catch { /* non-fatal */ }
|
|
177
|
-
|
|
178
|
-
printWelcomeScreen({ version: process.env.GSD_VERSION || "0.0.0", remoteChannel });
|
|
179
|
-
}
|
|
180
|
-
} catch { /* non-fatal */ }
|
|
181
|
-
}
|
|
444
|
+
await installWelcomeHeader(ctx);
|
|
182
445
|
await loadToolApiKeysForSession();
|
|
183
446
|
if (isAutoActive()) {
|
|
184
447
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
@@ -186,11 +449,13 @@ export function registerHooks(
|
|
|
186
449
|
});
|
|
187
450
|
|
|
188
451
|
pi.on("session_switch", async (_event, ctx) => {
|
|
452
|
+
const basePath = contextBasePath(ctx);
|
|
189
453
|
initSessionNotifications(ctx);
|
|
190
|
-
resetWriteGateState(
|
|
454
|
+
resetWriteGateState(basePath);
|
|
191
455
|
resetToolCallLoopGuard();
|
|
456
|
+
clearDeferredApprovalGate();
|
|
192
457
|
await resetAskUserQuestionsTurnCache();
|
|
193
|
-
clearDiscussionFlowState(
|
|
458
|
+
clearDiscussionFlowState(basePath);
|
|
194
459
|
await syncServiceTierStatus(ctx);
|
|
195
460
|
await applyDisabledModelProviderPolicy(ctx);
|
|
196
461
|
await applyCompactionThresholdOverride(ctx);
|
|
@@ -199,9 +464,9 @@ export function registerHooks(
|
|
|
199
464
|
// post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
|
|
200
465
|
// CLI path resolution), dirtying the tree and breaking the milestone merge.
|
|
201
466
|
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
202
|
-
if (!isInAutoWorktree(
|
|
467
|
+
if (!isInAutoWorktree(basePath)) {
|
|
203
468
|
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
204
|
-
prepareWorkflowMcpForProject(ctx,
|
|
469
|
+
prepareWorkflowMcpForProject(ctx, basePath);
|
|
205
470
|
}
|
|
206
471
|
await loadToolApiKeysForSession();
|
|
207
472
|
if (!isAutoActive()) {
|
|
@@ -213,11 +478,13 @@ export function registerHooks(
|
|
|
213
478
|
});
|
|
214
479
|
|
|
215
480
|
pi.on("before_agent_start", async (event, ctx: ExtensionContext) => {
|
|
481
|
+
applyMinimalGsdToolSurface(pi);
|
|
482
|
+
|
|
216
483
|
// Wait for ecosystem loader to finish (no-op after first turn).
|
|
217
484
|
const { getEcosystemReadyPromise } = await import("../ecosystem/loader.js");
|
|
218
485
|
await getEcosystemReadyPromise();
|
|
219
486
|
|
|
220
|
-
const beforeAgentBasePath =
|
|
487
|
+
const beforeAgentBasePath = contextBasePath(ctx);
|
|
221
488
|
const pendingApprovalGate = getPendingGate(beforeAgentBasePath);
|
|
222
489
|
if (pendingApprovalGate && isExplicitApprovalResponse(event.prompt, pendingApprovalGate)) {
|
|
223
490
|
markApprovalGateVerified(pendingApprovalGate, beforeAgentBasePath);
|
|
@@ -225,6 +492,7 @@ export function registerHooks(
|
|
|
225
492
|
if (milestoneId) markDepthVerified(milestoneId, beforeAgentBasePath);
|
|
226
493
|
clearPendingGate(beforeAgentBasePath);
|
|
227
494
|
}
|
|
495
|
+
clearDeferredApprovalGate(beforeAgentBasePath);
|
|
228
496
|
|
|
229
497
|
// GSD's own context injection (existing behavior — unchanged).
|
|
230
498
|
const { buildBeforeAgentStartResult } = await import("./system-context.js");
|
|
@@ -233,7 +501,7 @@ export function registerHooks(
|
|
|
233
501
|
// Refresh the snapshot used by ecosystem getPhase()/getActiveUnit().
|
|
234
502
|
// deriveState has its own ~100ms cache so this is cheap on repeat calls.
|
|
235
503
|
try {
|
|
236
|
-
const state = await deriveGsdState(
|
|
504
|
+
const state = await deriveGsdState(beforeAgentBasePath);
|
|
237
505
|
updateSnapshot(state);
|
|
238
506
|
} catch {
|
|
239
507
|
updateSnapshot(null);
|
|
@@ -275,7 +543,11 @@ export function registerHooks(
|
|
|
275
543
|
resetToolCallLoopGuard();
|
|
276
544
|
await resetAskUserQuestionsTurnCache();
|
|
277
545
|
const { handleAgentEnd } = await import("./agent-end-recovery.js");
|
|
278
|
-
|
|
546
|
+
try {
|
|
547
|
+
await handleAgentEnd(pi, event, ctx);
|
|
548
|
+
} finally {
|
|
549
|
+
activateDeferredApprovalGate(contextBasePath(ctx));
|
|
550
|
+
}
|
|
279
551
|
});
|
|
280
552
|
|
|
281
553
|
// Squash-merge quick-task branch back to the original branch after the
|
|
@@ -290,8 +562,8 @@ export function registerHooks(
|
|
|
290
562
|
}
|
|
291
563
|
});
|
|
292
564
|
|
|
293
|
-
pi.on("session_before_compact", async () => {
|
|
294
|
-
const basePath =
|
|
565
|
+
pi.on("session_before_compact", async (_event, ctx) => {
|
|
566
|
+
const basePath = contextBasePath(ctx);
|
|
295
567
|
// Context Mode is default-on. Write the resumable snapshot before any
|
|
296
568
|
// active-auto cancel return so auto sessions still leave re-entry context.
|
|
297
569
|
await writeContextModeCompactionSnapshot(basePath);
|
|
@@ -358,7 +630,7 @@ export function registerHooks(
|
|
|
358
630
|
if (!unitType) {
|
|
359
631
|
try {
|
|
360
632
|
const { getPendingDeepProjectSetupUnitForContext } = await import("../guided-flow.js");
|
|
361
|
-
const pending = getPendingDeepProjectSetupUnitForContext(ctx,
|
|
633
|
+
const pending = getPendingDeepProjectSetupUnitForContext(ctx, contextBasePath(ctx));
|
|
362
634
|
unitType = pending?.unitType;
|
|
363
635
|
unitId = pending?.unitId;
|
|
364
636
|
} catch {
|
|
@@ -367,7 +639,7 @@ export function registerHooks(
|
|
|
367
639
|
}
|
|
368
640
|
|
|
369
641
|
if (!unitType) {
|
|
370
|
-
const milestoneId = await getDiscussionMilestoneIdFor(
|
|
642
|
+
const milestoneId = await getDiscussionMilestoneIdFor(contextBasePath(ctx));
|
|
371
643
|
if (milestoneId) {
|
|
372
644
|
unitType = "discuss-milestone";
|
|
373
645
|
unitId = milestoneId;
|
|
@@ -377,15 +649,16 @@ export function registerHooks(
|
|
|
377
649
|
if (!shouldPauseForUserApprovalQuestion(unitType, [event.message])) return;
|
|
378
650
|
|
|
379
651
|
const gateId = approvalGateIdForUnit(unitType, unitId);
|
|
380
|
-
if (gateId)
|
|
652
|
+
if (gateId) deferApprovalGate(gateId, contextBasePath(ctx));
|
|
381
653
|
|
|
382
654
|
approvalQuestionAbortInFlight = true;
|
|
383
655
|
ctx.ui.notify(
|
|
384
656
|
`${unitType}${unitId ? ` ${unitId}` : ""} is waiting for your approval - pausing before more tool calls run.`,
|
|
385
657
|
"info",
|
|
386
658
|
);
|
|
387
|
-
// The pending gate
|
|
388
|
-
//
|
|
659
|
+
// The durable pending gate is activated at agent_end so same-turn
|
|
660
|
+
// CONTEXT-DRAFT persistence can finish after the text boundary streams.
|
|
661
|
+
// The tool_call hook below still blocks non-draft tools in this turn.
|
|
389
662
|
// Aborting mid-stream eats the model's question text on external CLI
|
|
390
663
|
// providers (Claude Code SDK) because lastTextContent isn't populated
|
|
391
664
|
// from in-flight builder state — the user only ever sees "Claude Code
|
|
@@ -396,7 +669,7 @@ export function registerHooks(
|
|
|
396
669
|
const { isParallelActive, shutdownParallel } = await import("../parallel-orchestrator.js");
|
|
397
670
|
if (isParallelActive()) {
|
|
398
671
|
try {
|
|
399
|
-
await shutdownParallel(
|
|
672
|
+
await shutdownParallel(contextBasePath(ctx));
|
|
400
673
|
} catch {
|
|
401
674
|
// best-effort
|
|
402
675
|
}
|
|
@@ -408,8 +681,8 @@ export function registerHooks(
|
|
|
408
681
|
}
|
|
409
682
|
});
|
|
410
683
|
|
|
411
|
-
pi.on("tool_call", async (event) => {
|
|
412
|
-
const discussionBasePath =
|
|
684
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
685
|
+
const discussionBasePath = contextBasePath(ctx);
|
|
413
686
|
const toolName = canonicalToolName(event.toolName);
|
|
414
687
|
// ── Loop guard: block repeated identical tool calls ──
|
|
415
688
|
const loopCheck = checkToolCallLoop(toolName, event.input as Record<string, unknown>);
|
|
@@ -417,6 +690,13 @@ export function registerHooks(
|
|
|
417
690
|
return { block: true, reason: loopCheck.reason };
|
|
418
691
|
}
|
|
419
692
|
|
|
693
|
+
const deferredGateGuard = shouldBlockDeferredApprovalTool(
|
|
694
|
+
toolName,
|
|
695
|
+
event.input,
|
|
696
|
+
discussionBasePath,
|
|
697
|
+
);
|
|
698
|
+
if (deferredGateGuard.block) return deferredGateGuard;
|
|
699
|
+
|
|
420
700
|
// ── Discussion gate enforcement: track pending gate questions ─────────
|
|
421
701
|
// Only gate-shaped ask_user_questions calls should block execution.
|
|
422
702
|
// The gate stays pending until the user selects the approval option.
|
|
@@ -586,7 +866,7 @@ export function registerHooks(
|
|
|
586
866
|
}
|
|
587
867
|
});
|
|
588
868
|
|
|
589
|
-
pi.on("tool_result", async (event) => {
|
|
869
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
590
870
|
if (isAutoActive() && typeof event.toolCallId === "string") {
|
|
591
871
|
markToolEnd(event.toolCallId);
|
|
592
872
|
}
|
|
@@ -605,7 +885,7 @@ export function registerHooks(
|
|
|
605
885
|
}
|
|
606
886
|
const toolName = canonicalToolName(event.toolName);
|
|
607
887
|
if (toolName !== "ask_user_questions") return;
|
|
608
|
-
const basePath =
|
|
888
|
+
const basePath = contextBasePath(ctx);
|
|
609
889
|
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
610
890
|
const queueActive = isQueuePhaseActive(basePath);
|
|
611
891
|
|
|
@@ -811,8 +1091,21 @@ export function registerHooks(
|
|
|
811
1091
|
// Tool set adaptation hook (ADR-005 Phase 4)
|
|
812
1092
|
// Extensions can override tool set after model selection by returning { toolNames: [...] }
|
|
813
1093
|
// Return undefined to let the built-in provider compatibility filtering proceed.
|
|
814
|
-
pi.on("adjust_tool_set", async (
|
|
815
|
-
|
|
1094
|
+
pi.on("adjust_tool_set", async (event) => {
|
|
1095
|
+
if (isFullGsdToolSurfaceRequested()) return undefined;
|
|
1096
|
+
const removed = new Set(event.filteredTools);
|
|
1097
|
+
const providerCompatible = event.activeToolNames.filter((name) => !removed.has(name));
|
|
1098
|
+
const requestScoped = buildRequestScopedGsdToolSet(providerCompatible, event.requestCustomMessages);
|
|
1099
|
+
if (requestScoped) {
|
|
1100
|
+
return { toolNames: requestScoped };
|
|
1101
|
+
}
|
|
1102
|
+
const dash = getAutoRuntimeSnapshot();
|
|
1103
|
+
if (dash.active && dash.currentUnit) {
|
|
1104
|
+
return { toolNames: buildMinimalAutoGsdToolSet(providerCompatible, dash.currentUnit.type) };
|
|
1105
|
+
}
|
|
1106
|
+
if (isGeneralGsdToolScopingRequested()) {
|
|
1107
|
+
return { toolNames: buildMinimalGsdToolSet(providerCompatible) };
|
|
1108
|
+
}
|
|
816
1109
|
return undefined;
|
|
817
1110
|
});
|
|
818
1111
|
}
|