gsd-pi 2.71.0-dev.e17e0ce → 2.72.0-dev.de4c4b3
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/README.md +34 -1
- package/dist/cli.js +17 -0
- package/dist/mcp-server.js +37 -14
- package/dist/resources/agents/debugger.md +58 -0
- package/dist/resources/agents/doc-writer.md +43 -0
- package/dist/resources/agents/git-ops.md +56 -0
- package/dist/resources/agents/javascript-pro.md +46 -271
- package/dist/resources/agents/planner.md +55 -0
- package/dist/resources/agents/refactorer.md +47 -0
- package/dist/resources/agents/reviewer.md +48 -0
- package/dist/resources/agents/security.md +59 -0
- package/dist/resources/agents/tester.md +50 -0
- package/dist/resources/agents/typescript-pro.md +41 -235
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +103 -6
- package/dist/resources/extensions/gsd/auto/phases.js +4 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +88 -33
- package/dist/resources/extensions/gsd/auto-start.js +24 -4
- package/dist/resources/extensions/gsd/auto.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +2 -5
- package/dist/resources/extensions/gsd/doctor-providers.js +23 -0
- package/dist/resources/extensions/gsd/error-classifier.js +4 -1
- package/dist/resources/extensions/gsd/gate-registry.js +208 -0
- package/dist/resources/extensions/gsd/gsd-db.js +41 -0
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +11 -12
- package/dist/resources/extensions/gsd/notification-overlay.js +26 -12
- package/dist/resources/extensions/gsd/notification-store.js +5 -4
- package/dist/resources/extensions/gsd/prompt-validation.js +126 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/shortcut-defs.js +7 -1
- package/dist/resources/extensions/gsd/state.js +9 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +52 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +51 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +4 -1
- package/dist/resources/extensions/ollama/index.js +13 -5
- package/dist/resources/extensions/shared/gsd-phase-state.js +35 -0
- package/dist/resources/extensions/subagent/agents.js +8 -0
- package/dist/resources/extensions/subagent/index.js +17 -0
- package/dist/startup-model-validation.d.ts +0 -1
- package/dist/startup-model-validation.js +6 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- 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 +8 -8
- 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/package.json +1 -1
- package/packages/mcp-server/dist/server.d.ts +12 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +90 -42
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/server.ts +110 -38
- package/packages/mcp-server/src/workflow-tools.ts +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +55 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +57 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +83 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +60 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
- package/pkg/package.json +1 -1
- package/src/resources/agents/debugger.md +58 -0
- package/src/resources/agents/doc-writer.md +43 -0
- package/src/resources/agents/git-ops.md +56 -0
- package/src/resources/agents/javascript-pro.md +46 -271
- package/src/resources/agents/planner.md +55 -0
- package/src/resources/agents/refactorer.md +47 -0
- package/src/resources/agents/reviewer.md +48 -0
- package/src/resources/agents/security.md +59 -0
- package/src/resources/agents/tester.md +50 -0
- package/src/resources/agents/typescript-pro.md +41 -235
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +109 -3
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +133 -2
- package/src/resources/extensions/gsd/auto/phases.ts +4 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +111 -33
- package/src/resources/extensions/gsd/auto-start.ts +31 -4
- package/src/resources/extensions/gsd/auto.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +2 -5
- package/src/resources/extensions/gsd/doctor-providers.ts +24 -0
- package/src/resources/extensions/gsd/error-classifier.ts +4 -1
- package/src/resources/extensions/gsd/gate-registry.ts +251 -0
- package/src/resources/extensions/gsd/gsd-db.ts +51 -0
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +11 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +27 -11
- package/src/resources/extensions/gsd/notification-store.ts +5 -4
- package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/shortcut-defs.ts +8 -1
- package/src/resources/extensions/gsd/state.ts +13 -2
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/complete-slice-gate-closure.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/prompt-system-gate-coverage.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +63 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +4 -1
- package/src/resources/extensions/gsd/types.ts +26 -0
- package/src/resources/extensions/ollama/index.ts +13 -3
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
- package/src/resources/extensions/shared/gsd-phase-state.ts +42 -0
- package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +48 -0
- package/src/resources/extensions/subagent/agents.ts +10 -0
- package/src/resources/extensions/subagent/index.ts +18 -0
- package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
- /package/dist/web/standalone/.next/static/{cYPZv_bAhZk2ms-Pz6vsY → f-Gremw0nLxxFUySaHRPw}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{cYPZv_bAhZk2ms-Pz6vsY → f-Gremw0nLxxFUySaHRPw}/_ssgManifest.js +0 -0
|
@@ -536,6 +536,24 @@ export interface CompleteTaskParams {
|
|
|
536
536
|
verdict: string;
|
|
537
537
|
durationMs: number;
|
|
538
538
|
}>;
|
|
539
|
+
/**
|
|
540
|
+
* Q5 failure-modes section content (what breaks when dependencies fail).
|
|
541
|
+
* Populated → `pass`; omitted/empty → `omitted`.
|
|
542
|
+
* @optional
|
|
543
|
+
*/
|
|
544
|
+
failureModes?: string;
|
|
545
|
+
/**
|
|
546
|
+
* Q6 load-profile section content (10x breakpoint + protection).
|
|
547
|
+
* Populated → `pass`; omitted/empty → `omitted`.
|
|
548
|
+
* @optional
|
|
549
|
+
*/
|
|
550
|
+
loadProfile?: string;
|
|
551
|
+
/**
|
|
552
|
+
* Q7 negative-tests section content (malformed inputs, error paths,
|
|
553
|
+
* boundaries). Populated → `pass`; omitted/empty → `omitted`.
|
|
554
|
+
* @optional
|
|
555
|
+
*/
|
|
556
|
+
negativeTests?: string;
|
|
539
557
|
/** Optional caller-provided identity for audit trail */
|
|
540
558
|
actorName?: string;
|
|
541
559
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -584,6 +602,14 @@ export interface CompleteSliceParams {
|
|
|
584
602
|
affects?: string[];
|
|
585
603
|
/** @optional — defaults to [] when omitted */
|
|
586
604
|
drillDownPaths?: string[];
|
|
605
|
+
/**
|
|
606
|
+
* Q8 operational readiness section content (health signal, failure signal,
|
|
607
|
+
* recovery, monitoring gaps). When populated, the complete-slice handler
|
|
608
|
+
* records Q8 as `pass`; when omitted or empty, Q8 is recorded as `omitted`.
|
|
609
|
+
* See gate-registry.ts.
|
|
610
|
+
* @optional
|
|
611
|
+
*/
|
|
612
|
+
operationalReadiness?: string;
|
|
587
613
|
/** Optional caller-provided identity for audit trail */
|
|
588
614
|
actorName?: string;
|
|
589
615
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -57,7 +57,15 @@ async function probeAndRegister(pi: ExtensionAPI): Promise<boolean> {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
const models = await discoverModels();
|
|
60
|
-
if (models.length === 0)
|
|
60
|
+
if (models.length === 0) {
|
|
61
|
+
// No local models means there's nothing usable to register in GSD.
|
|
62
|
+
// Keep the footer/status clean instead of advertising Ollama availability.
|
|
63
|
+
if (providerRegistered) {
|
|
64
|
+
pi.unregisterProvider("ollama");
|
|
65
|
+
providerRegistered = false;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
61
69
|
|
|
62
70
|
const baseUrl = client.getOllamaHost();
|
|
63
71
|
|
|
@@ -115,9 +123,11 @@ export default function ollama(pi: ExtensionAPI) {
|
|
|
115
123
|
} else {
|
|
116
124
|
probeAndRegister(pi)
|
|
117
125
|
.then((found) => {
|
|
118
|
-
|
|
126
|
+
ctx.ui.setStatus("ollama", found ? "Ollama" : undefined);
|
|
119
127
|
})
|
|
120
|
-
.catch(() => {
|
|
128
|
+
.catch(() => {
|
|
129
|
+
ctx.ui.setStatus("ollama", undefined);
|
|
130
|
+
});
|
|
121
131
|
}
|
|
122
132
|
});
|
|
123
133
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test: don't show an Ollama footer status unless Ollama is
|
|
3
|
+
* actually usable (running with at least one discovered model).
|
|
4
|
+
*/
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const src = readFileSync(join(__dirname, "index.ts"), "utf-8");
|
|
13
|
+
|
|
14
|
+
test("probeAndRegister returns false when no Ollama models are discovered", () => {
|
|
15
|
+
assert.match(
|
|
16
|
+
src,
|
|
17
|
+
/if \(models\.length === 0\)[\s\S]*return false;/,
|
|
18
|
+
"running-without-models should not be treated as available",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("interactive session clears ollama footer status when unavailable", () => {
|
|
23
|
+
assert.match(
|
|
24
|
+
src,
|
|
25
|
+
/ctx\.ui\.setStatus\("ollama", found \? "Ollama" : undefined\)/,
|
|
26
|
+
"status should be cleared when probeAndRegister reports unavailable",
|
|
27
|
+
);
|
|
28
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Phase State — cross-extension coordination
|
|
3
|
+
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
4
|
+
*
|
|
5
|
+
* Lightweight module-level state that GSD auto-mode writes to and the
|
|
6
|
+
* subagent tool reads from. Both extensions run in the same process so
|
|
7
|
+
* a module variable is sufficient — no file I/O needed.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let _active = false;
|
|
11
|
+
let _currentPhase: string | null = null;
|
|
12
|
+
|
|
13
|
+
/** Mark GSD auto-mode as active. */
|
|
14
|
+
export function activateGSD(): void {
|
|
15
|
+
_active = true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Mark GSD auto-mode as inactive and clear the current phase. */
|
|
19
|
+
export function deactivateGSD(): void {
|
|
20
|
+
_active = false;
|
|
21
|
+
_currentPhase = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Set the currently dispatched GSD phase (e.g. "plan-milestone"). */
|
|
25
|
+
export function setCurrentPhase(phase: string): void {
|
|
26
|
+
_currentPhase = phase;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Clear the current phase (unit completed or aborted). */
|
|
30
|
+
export function clearCurrentPhase(): void {
|
|
31
|
+
_currentPhase = null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Returns true if GSD auto-mode is currently active. */
|
|
35
|
+
export function isGSDActive(): boolean {
|
|
36
|
+
return _active;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Returns the current GSD phase, or null if none is active. */
|
|
40
|
+
export function getCurrentPhase(): string | null {
|
|
41
|
+
return _active ? _currentPhase : null;
|
|
42
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, beforeEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import {
|
|
4
|
+
activateGSD,
|
|
5
|
+
deactivateGSD,
|
|
6
|
+
setCurrentPhase,
|
|
7
|
+
clearCurrentPhase,
|
|
8
|
+
isGSDActive,
|
|
9
|
+
getCurrentPhase,
|
|
10
|
+
} from "../gsd-phase-state.js";
|
|
11
|
+
|
|
12
|
+
describe("gsd-phase-state", () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
deactivateGSD();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("tracks active/inactive state", () => {
|
|
18
|
+
assert.equal(isGSDActive(), false);
|
|
19
|
+
activateGSD();
|
|
20
|
+
assert.equal(isGSDActive(), true);
|
|
21
|
+
deactivateGSD();
|
|
22
|
+
assert.equal(isGSDActive(), false);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("tracks the current phase when active", () => {
|
|
26
|
+
activateGSD();
|
|
27
|
+
assert.equal(getCurrentPhase(), null);
|
|
28
|
+
setCurrentPhase("plan-milestone");
|
|
29
|
+
assert.equal(getCurrentPhase(), "plan-milestone");
|
|
30
|
+
clearCurrentPhase();
|
|
31
|
+
assert.equal(getCurrentPhase(), null);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("returns null phase when inactive even if phase was set", () => {
|
|
35
|
+
activateGSD();
|
|
36
|
+
setCurrentPhase("plan-milestone");
|
|
37
|
+
deactivateGSD();
|
|
38
|
+
assert.equal(getCurrentPhase(), null);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("deactivation clears the current phase", () => {
|
|
42
|
+
activateGSD();
|
|
43
|
+
setCurrentPhase("execute-task");
|
|
44
|
+
deactivateGSD();
|
|
45
|
+
activateGSD();
|
|
46
|
+
assert.equal(getCurrentPhase(), null);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -15,6 +15,7 @@ export interface AgentConfig {
|
|
|
15
15
|
description: string;
|
|
16
16
|
tools?: string[];
|
|
17
17
|
model?: string;
|
|
18
|
+
conflictsWith?: string[];
|
|
18
19
|
systemPrompt: string;
|
|
19
20
|
source: "user" | "project";
|
|
20
21
|
filePath: string;
|
|
@@ -30,6 +31,13 @@ interface AgentFrontmatter extends Record<string, unknown> {
|
|
|
30
31
|
description?: string;
|
|
31
32
|
tools?: string | string[];
|
|
32
33
|
model?: string;
|
|
34
|
+
conflicts_with?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function parseConflictsWith(value: string | undefined): string[] | undefined {
|
|
38
|
+
if (typeof value !== "string") return undefined;
|
|
39
|
+
const conflicts = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
40
|
+
return conflicts.length > 0 ? conflicts : undefined;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
function parseAgentTools(value: string | string[] | undefined): string[] | undefined {
|
|
@@ -85,12 +93,14 @@ function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig
|
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
const tools = parseAgentTools(frontmatter.tools);
|
|
96
|
+
const conflictsWith = parseConflictsWith(frontmatter.conflicts_with);
|
|
88
97
|
|
|
89
98
|
agents.push({
|
|
90
99
|
name: frontmatter.name,
|
|
91
100
|
description: frontmatter.description,
|
|
92
101
|
tools: tools && tools.length > 0 ? tools : undefined,
|
|
93
102
|
model: frontmatter.model,
|
|
103
|
+
conflictsWith,
|
|
94
104
|
systemPrompt: body,
|
|
95
105
|
source,
|
|
96
106
|
filePath,
|
|
@@ -24,6 +24,7 @@ import { type ExtensionAPI, getMarkdownTheme } from "@gsd/pi-coding-agent";
|
|
|
24
24
|
import { Container, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
25
25
|
import { Type } from "@sinclair/typebox";
|
|
26
26
|
import { formatTokenCount } from "../shared/mod.js";
|
|
27
|
+
import { getCurrentPhase } from "../shared/gsd-phase-state.js";
|
|
27
28
|
import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js";
|
|
28
29
|
import {
|
|
29
30
|
type IsolationEnvironment,
|
|
@@ -352,6 +353,23 @@ async function runSingleAgent(
|
|
|
352
353
|
};
|
|
353
354
|
}
|
|
354
355
|
|
|
356
|
+
// GSD phase guard: block agents that conflict with the active GSD phase
|
|
357
|
+
if (agent.conflictsWith && agent.conflictsWith.length > 0) {
|
|
358
|
+
const activePhase = getCurrentPhase();
|
|
359
|
+
if (activePhase && agent.conflictsWith.includes(activePhase)) {
|
|
360
|
+
return {
|
|
361
|
+
agent: agentName,
|
|
362
|
+
agentSource: agent.source,
|
|
363
|
+
task,
|
|
364
|
+
exitCode: 1,
|
|
365
|
+
messages: [],
|
|
366
|
+
stderr: `Agent "${agentName}" is blocked: it conflicts with the active GSD phase "${activePhase}". Use the built-in GSD workflow instead.`,
|
|
367
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
368
|
+
step,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
355
373
|
let tmpPromptDir: string | null = null;
|
|
356
374
|
let tmpPromptPath: string | null = null;
|
|
357
375
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { parseConflictsWith } from "../agents.js";
|
|
4
|
+
|
|
5
|
+
describe("parseConflictsWith", () => {
|
|
6
|
+
it("parses comma-separated conflict list", () => {
|
|
7
|
+
const result = parseConflictsWith("plan-milestone, plan-slice, research-milestone");
|
|
8
|
+
assert.deepEqual(result, ["plan-milestone", "plan-slice", "research-milestone"]);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("returns undefined for undefined input", () => {
|
|
12
|
+
assert.equal(parseConflictsWith(undefined), undefined);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("returns undefined for empty string", () => {
|
|
16
|
+
assert.equal(parseConflictsWith(""), undefined);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("handles single value without commas", () => {
|
|
20
|
+
const result = parseConflictsWith("plan-milestone");
|
|
21
|
+
assert.deepEqual(result, ["plan-milestone"]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("trims whitespace from values", () => {
|
|
25
|
+
const result = parseConflictsWith(" plan-milestone , plan-slice ");
|
|
26
|
+
assert.deepEqual(result, ["plan-milestone", "plan-slice"]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("filters out empty entries from trailing commas", () => {
|
|
30
|
+
const result = parseConflictsWith("plan-milestone,,plan-slice,");
|
|
31
|
+
assert.deepEqual(result, ["plan-milestone", "plan-slice"]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
File without changes
|
|
File without changes
|