gsd-pi 2.37.1 → 2.38.0-dev.4d4d14a
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 +1 -1
- package/dist/app-paths.js +1 -1
- package/dist/cli.js +9 -0
- package/dist/extension-discovery.d.ts +5 -3
- package/dist/extension-discovery.js +14 -9
- package/dist/extension-registry.js +2 -2
- package/dist/onboarding.js +1 -0
- package/dist/remote-questions-config.js +2 -2
- package/dist/resources/extensions/browser-tools/package.json +3 -1
- package/dist/resources/extensions/cmux/index.js +55 -1
- package/dist/resources/extensions/context7/package.json +1 -1
- package/dist/resources/extensions/env-utils.js +29 -0
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/google-search/package.json +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +74 -9
- package/dist/resources/extensions/gsd/auto-loop.js +149 -170
- package/dist/resources/extensions/gsd/auto-post-unit.js +105 -68
- package/dist/resources/extensions/gsd/auto-prompts.js +98 -33
- package/dist/resources/extensions/gsd/auto-recovery.js +37 -1
- package/dist/resources/extensions/gsd/auto-start.js +13 -2
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/captures.js +9 -1
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +16 -3
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +22 -2
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
- package/dist/resources/extensions/gsd/doctor-format.js +15 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +62 -12
- package/dist/resources/extensions/gsd/doctor.js +184 -11
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +43 -2
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +8 -1
- package/dist/resources/extensions/gsd/index.js +24 -20
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/observability-validator.js +24 -0
- package/dist/resources/extensions/gsd/package.json +1 -1
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +3 -2
- package/dist/resources/extensions/gsd/preferences-validation.js +101 -11
- package/dist/resources/extensions/gsd/preferences.js +8 -5
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +44 -0
- package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/reactive-graph.js +227 -0
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/state.js +1 -1
- package/dist/resources/extensions/gsd/templates/task-plan.md +11 -3
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/gsd/worktree.js +35 -16
- package/dist/resources/extensions/remote-questions/status.js +2 -1
- package/dist/resources/extensions/remote-questions/store.js +2 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/subagent/index.js +12 -3
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/dist/resources/extensions/universal-config/package.json +1 -1
- package/dist/welcome-screen.d.ts +12 -0
- package/dist/welcome-screen.js +53 -0
- package/package.json +2 -1
- package/packages/pi-ai/dist/env-api-keys.js +13 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +172 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +172 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +64 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.js +668 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.d.ts +5 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.js +85 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts +4 -30
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +47 -764
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +6 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -2
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/package.json +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +14 -0
- package/packages/pi-ai/src/models.generated.ts +172 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +761 -0
- package/packages/pi-ai/src/providers/anthropic-vertex.ts +130 -0
- package/packages/pi-ai/src/providers/anthropic.ts +76 -868
- package/packages/pi-ai/src/providers/register-builtins.ts +7 -0
- package/packages/pi-ai/src/types.ts +2 -0
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cmux/index.ts +57 -1
- package/src/resources/extensions/env-utils.ts +31 -0
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dispatch.ts +99 -8
- package/src/resources/extensions/gsd/auto-loop.ts +207 -252
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -39
- package/src/resources/extensions/gsd/auto-prompts.ts +132 -36
- package/src/resources/extensions/gsd/auto-recovery.ts +42 -0
- package/src/resources/extensions/gsd/auto-start.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/captures.ts +10 -1
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +17 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +24 -2
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
- package/src/resources/extensions/gsd/doctor-format.ts +20 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +64 -10
- package/src/resources/extensions/gsd/doctor-types.ts +16 -1
- package/src/resources/extensions/gsd/doctor.ts +177 -13
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +47 -2
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +13 -1
- package/src/resources/extensions/gsd/index.ts +24 -17
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/observability-validator.ts +27 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +9 -5
- package/src/resources/extensions/gsd/preferences-validation.ts +92 -11
- package/src/resources/extensions/gsd/preferences.ts +8 -5
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +44 -0
- package/src/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/reactive-graph.ts +289 -0
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/state.ts +1 -1
- package/src/resources/extensions/gsd/templates/task-plan.md +11 -3
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +16 -37
- package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +191 -3
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +111 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +511 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +299 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +11 -3
- package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
- package/src/resources/extensions/gsd/types.ts +43 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/gsd/worktree.ts +35 -15
- package/src/resources/extensions/remote-questions/status.ts +3 -1
- package/src/resources/extensions/remote-questions/store.ts +3 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/subagent/index.ts +12 -3
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -47,6 +47,18 @@ function withEnv(vars: Record<string, string | undefined>, fn: () => void): void
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function withCwd(nextCwd: string, fn: () => void): void {
|
|
51
|
+
const saved = process.cwd();
|
|
52
|
+
process.chdir(nextCwd);
|
|
53
|
+
try {
|
|
54
|
+
fn();
|
|
55
|
+
} finally {
|
|
56
|
+
process.chdir(saved);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const PRESENT_TEST_VALUE = "configured";
|
|
61
|
+
|
|
50
62
|
// ─── formatProviderReport ─────────────────────────────────────────────────────
|
|
51
63
|
|
|
52
64
|
test("formatProviderReport returns fallback for empty results", () => {
|
|
@@ -184,7 +196,7 @@ test("runProviderChecks detects Anthropic key from ANTHROPIC_API_KEY env var", (
|
|
|
184
196
|
// Isolate from real HOME so loadEffectiveGSDPreferences returns null (default → anthropic)
|
|
185
197
|
// and auth.json lookups hit an empty directory.
|
|
186
198
|
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-env-test-")));
|
|
187
|
-
withEnv({ ANTHROPIC_API_KEY: "sk-ant-test-key", HOME: tmpHome }, () => {
|
|
199
|
+
withEnv({ ANTHROPIC_API_KEY: "sk-ant-test-key", ANTHROPIC_OAUTH_TOKEN: undefined, HOME: tmpHome }, () => {
|
|
188
200
|
try {
|
|
189
201
|
const results = runProviderChecks();
|
|
190
202
|
const anthropic = results.find(r => r.name === "anthropic");
|
|
@@ -199,7 +211,15 @@ test("runProviderChecks detects Anthropic key from ANTHROPIC_API_KEY env var", (
|
|
|
199
211
|
|
|
200
212
|
test("runProviderChecks returns error for Anthropic when no key present", () => {
|
|
201
213
|
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-test-")));
|
|
202
|
-
withEnv({
|
|
214
|
+
withEnv({
|
|
215
|
+
ANTHROPIC_API_KEY: undefined,
|
|
216
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
217
|
+
// Clear cross-provider routing env vars (GitHub Copilot can serve Claude models)
|
|
218
|
+
COPILOT_GITHUB_TOKEN: undefined,
|
|
219
|
+
GH_TOKEN: undefined,
|
|
220
|
+
GITHUB_TOKEN: undefined,
|
|
221
|
+
HOME: tmpHome,
|
|
222
|
+
}, () => {
|
|
203
223
|
try {
|
|
204
224
|
const results = runProviderChecks();
|
|
205
225
|
const anthropic = results.find(r => r.name === "anthropic");
|
|
@@ -275,7 +295,7 @@ test("runProviderChecks detects key from auth.json", () => {
|
|
|
275
295
|
});
|
|
276
296
|
|
|
277
297
|
test("runProviderChecks ignores empty placeholder keys in auth.json", () => {
|
|
278
|
-
withEnv({ ANTHROPIC_API_KEY: undefined }, () => {
|
|
298
|
+
withEnv({ ANTHROPIC_API_KEY: undefined, ANTHROPIC_OAUTH_TOKEN: undefined, COPILOT_GITHUB_TOKEN: undefined, GH_TOKEN: undefined, GITHUB_TOKEN: undefined }, () => {
|
|
279
299
|
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-test-")));
|
|
280
300
|
const agentDir = join(tmpHome, ".gsd", "agent");
|
|
281
301
|
mkdirSync(agentDir, { recursive: true });
|
|
@@ -296,3 +316,171 @@ test("runProviderChecks ignores empty placeholder keys in auth.json", () => {
|
|
|
296
316
|
rmSync(tmpHome, { recursive: true, force: true });
|
|
297
317
|
});
|
|
298
318
|
});
|
|
319
|
+
|
|
320
|
+
// ─── runProviderChecks — cross-provider routing ──────────────────────────────
|
|
321
|
+
|
|
322
|
+
test("runProviderChecks reports ok for Anthropic when GitHub Copilot env var is set", () => {
|
|
323
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-copilot-test-")));
|
|
324
|
+
withEnv({
|
|
325
|
+
ANTHROPIC_API_KEY: undefined,
|
|
326
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
327
|
+
COPILOT_GITHUB_TOKEN: PRESENT_TEST_VALUE,
|
|
328
|
+
GH_TOKEN: undefined,
|
|
329
|
+
GITHUB_TOKEN: undefined,
|
|
330
|
+
HOME: tmpHome,
|
|
331
|
+
}, () => {
|
|
332
|
+
try {
|
|
333
|
+
const results = runProviderChecks();
|
|
334
|
+
const anthropic = results.find(r => r.name === "anthropic");
|
|
335
|
+
assert.ok(anthropic, "anthropic result should exist");
|
|
336
|
+
assert.equal(anthropic!.status, "ok", "should be ok when Copilot auth is available");
|
|
337
|
+
assert.ok(anthropic!.message.includes("GitHub Copilot"), "should mention cross-provider source");
|
|
338
|
+
} finally {
|
|
339
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("runProviderChecks reports ok for Anthropic via GITHUB_TOKEN cross-provider routing", () => {
|
|
345
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-ghtoken-test-")));
|
|
346
|
+
withEnv({
|
|
347
|
+
ANTHROPIC_API_KEY: undefined,
|
|
348
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
349
|
+
COPILOT_GITHUB_TOKEN: undefined,
|
|
350
|
+
GH_TOKEN: undefined,
|
|
351
|
+
GITHUB_TOKEN: PRESENT_TEST_VALUE,
|
|
352
|
+
HOME: tmpHome,
|
|
353
|
+
}, () => {
|
|
354
|
+
try {
|
|
355
|
+
const results = runProviderChecks();
|
|
356
|
+
const anthropic = results.find(r => r.name === "anthropic");
|
|
357
|
+
assert.ok(anthropic, "anthropic result should exist");
|
|
358
|
+
assert.equal(anthropic!.status, "ok", "should be ok when GITHUB_TOKEN provides Copilot access");
|
|
359
|
+
} finally {
|
|
360
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("runProviderChecks detects ANTHROPIC_OAUTH_TOKEN as valid Anthropic auth", () => {
|
|
366
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-oauth-test-")));
|
|
367
|
+
withEnv({
|
|
368
|
+
ANTHROPIC_API_KEY: undefined,
|
|
369
|
+
ANTHROPIC_OAUTH_TOKEN: PRESENT_TEST_VALUE,
|
|
370
|
+
COPILOT_GITHUB_TOKEN: undefined,
|
|
371
|
+
GH_TOKEN: undefined,
|
|
372
|
+
GITHUB_TOKEN: undefined,
|
|
373
|
+
HOME: tmpHome,
|
|
374
|
+
}, () => {
|
|
375
|
+
try {
|
|
376
|
+
const results = runProviderChecks();
|
|
377
|
+
const anthropic = results.find(r => r.name === "anthropic");
|
|
378
|
+
assert.ok(anthropic, "anthropic result should exist");
|
|
379
|
+
assert.equal(anthropic!.status, "ok", "should be ok when ANTHROPIC_OAUTH_TOKEN is set");
|
|
380
|
+
assert.ok(anthropic!.message.includes("env"), "should report env source");
|
|
381
|
+
} finally {
|
|
382
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("runProviderChecks reports ok via Copilot auth.json for Anthropic", () => {
|
|
388
|
+
withEnv({
|
|
389
|
+
ANTHROPIC_API_KEY: undefined,
|
|
390
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
391
|
+
COPILOT_GITHUB_TOKEN: undefined,
|
|
392
|
+
GH_TOKEN: undefined,
|
|
393
|
+
GITHUB_TOKEN: undefined,
|
|
394
|
+
}, () => {
|
|
395
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-copilot-auth-test-")));
|
|
396
|
+
const agentDir = join(tmpHome, ".gsd", "agent");
|
|
397
|
+
mkdirSync(agentDir, { recursive: true });
|
|
398
|
+
|
|
399
|
+
// GitHub Copilot OAuth in auth.json
|
|
400
|
+
const authData = {
|
|
401
|
+
"github-copilot": { type: "oauth", apiKey: "ghu_copilot-key", expires: Date.now() + 3_600_000 },
|
|
402
|
+
};
|
|
403
|
+
writeFileSync(join(agentDir, "auth.json"), JSON.stringify(authData));
|
|
404
|
+
|
|
405
|
+
withEnv({ HOME: tmpHome }, () => {
|
|
406
|
+
const results = runProviderChecks();
|
|
407
|
+
const anthropic = results.find(r => r.name === "anthropic");
|
|
408
|
+
assert.ok(anthropic, "anthropic result should exist");
|
|
409
|
+
assert.equal(anthropic!.status, "ok", "should be ok when Copilot is authenticated in auth.json");
|
|
410
|
+
assert.ok(anthropic!.message.includes("GitHub Copilot"), "should mention Copilot as source");
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test("runProviderChecks uses provider-qualified anthropic-vertex model IDs", () => {
|
|
418
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-vertex-prefix-home-")));
|
|
419
|
+
const repo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-vertex-prefix-repo-")));
|
|
420
|
+
mkdirSync(join(repo, ".gsd"), { recursive: true });
|
|
421
|
+
writeFileSync(
|
|
422
|
+
join(repo, ".gsd", "preferences.md"),
|
|
423
|
+
[
|
|
424
|
+
"---",
|
|
425
|
+
"models:",
|
|
426
|
+
" execution: anthropic-vertex/claude-sonnet-4-6",
|
|
427
|
+
"---",
|
|
428
|
+
"",
|
|
429
|
+
].join("\n"),
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
withEnv({
|
|
433
|
+
HOME: tmpHome,
|
|
434
|
+
ANTHROPIC_API_KEY: undefined,
|
|
435
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
436
|
+
ANTHROPIC_VERTEX_PROJECT_ID: "vertex-project",
|
|
437
|
+
}, () => {
|
|
438
|
+
withCwd(repo, () => {
|
|
439
|
+
const results = runProviderChecks();
|
|
440
|
+
const vertex = results.find(r => r.name === "anthropic-vertex");
|
|
441
|
+
const anthropic = results.find(r => r.name === "anthropic");
|
|
442
|
+
assert.ok(vertex, "anthropic-vertex result should exist");
|
|
443
|
+
assert.equal(vertex!.status, "ok", "should accept ANTHROPIC_VERTEX_PROJECT_ID as configured");
|
|
444
|
+
assert.ok(!anthropic || !anthropic.required, "plain anthropic should not be required for anthropic-vertex config");
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
rmSync(repo, { recursive: true, force: true });
|
|
449
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test("runProviderChecks uses object provider field for anthropic-vertex models", () => {
|
|
453
|
+
const tmpHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-vertex-provider-home-")));
|
|
454
|
+
const repo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-providers-vertex-provider-repo-")));
|
|
455
|
+
mkdirSync(join(repo, ".gsd"), { recursive: true });
|
|
456
|
+
writeFileSync(
|
|
457
|
+
join(repo, ".gsd", "preferences.md"),
|
|
458
|
+
[
|
|
459
|
+
"---",
|
|
460
|
+
"models:",
|
|
461
|
+
" execution:",
|
|
462
|
+
" model: claude-sonnet-4-6",
|
|
463
|
+
" provider: anthropic-vertex",
|
|
464
|
+
"---",
|
|
465
|
+
"",
|
|
466
|
+
].join("\n"),
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
withEnv({
|
|
470
|
+
HOME: tmpHome,
|
|
471
|
+
ANTHROPIC_API_KEY: undefined,
|
|
472
|
+
ANTHROPIC_OAUTH_TOKEN: undefined,
|
|
473
|
+
ANTHROPIC_VERTEX_PROJECT_ID: undefined,
|
|
474
|
+
}, () => {
|
|
475
|
+
withCwd(repo, () => {
|
|
476
|
+
const results = runProviderChecks();
|
|
477
|
+
const vertex = results.find(r => r.name === "anthropic-vertex");
|
|
478
|
+
assert.ok(vertex, "anthropic-vertex result should exist");
|
|
479
|
+
assert.equal(vertex!.status, "error", "missing vertex config should be reported against anthropic-vertex");
|
|
480
|
+
assert.ok(vertex!.detail?.includes("ANTHROPIC_VERTEX_PROJECT_ID"), "should point to vertex setup");
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
rmSync(repo, { recursive: true, force: true });
|
|
485
|
+
rmSync(tmpHome, { recursive: true, force: true });
|
|
486
|
+
});
|
|
@@ -360,4 +360,115 @@ console.log('\n=== Clean slice plan: no plan-quality issues ===');
|
|
|
360
360
|
assertEq(planQualityIssues.length, 0, 'clean slice plan produces no empty_task_entry issues');
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
364
|
+
// validateTaskPlanContent — missing output file paths
|
|
365
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
366
|
+
|
|
367
|
+
console.log('\n=== validateTaskPlanContent: missing output file paths ===');
|
|
368
|
+
{
|
|
369
|
+
const content = `# T01: Some Task
|
|
370
|
+
|
|
371
|
+
## Description
|
|
372
|
+
|
|
373
|
+
Do something.
|
|
374
|
+
|
|
375
|
+
## Steps
|
|
376
|
+
|
|
377
|
+
1. Do the thing
|
|
378
|
+
|
|
379
|
+
## Verification
|
|
380
|
+
|
|
381
|
+
- Check it works
|
|
382
|
+
|
|
383
|
+
## Expected Output
|
|
384
|
+
|
|
385
|
+
This task produces the main output.
|
|
386
|
+
`;
|
|
387
|
+
|
|
388
|
+
const issues = validateTaskPlanContent('T01-PLAN.md', content);
|
|
389
|
+
const outputIssues = issues.filter(i => i.ruleId === 'missing_output_file_paths');
|
|
390
|
+
assertTrue(outputIssues.length >= 1, 'Expected Output without file paths triggers missing_output_file_paths');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
console.log('\n=== validateTaskPlanContent: valid output file paths ===');
|
|
394
|
+
{
|
|
395
|
+
const content = `# T01: Some Task
|
|
396
|
+
|
|
397
|
+
## Description
|
|
398
|
+
|
|
399
|
+
Do something.
|
|
400
|
+
|
|
401
|
+
## Steps
|
|
402
|
+
|
|
403
|
+
1. Do the thing
|
|
404
|
+
|
|
405
|
+
## Verification
|
|
406
|
+
|
|
407
|
+
- Check it works
|
|
408
|
+
|
|
409
|
+
## Expected Output
|
|
410
|
+
|
|
411
|
+
- \`src/types.ts\` — New type definitions
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
const issues = validateTaskPlanContent('T01-PLAN.md', content);
|
|
415
|
+
const outputIssues = issues.filter(i => i.ruleId === 'missing_output_file_paths');
|
|
416
|
+
assertEq(outputIssues.length, 0, 'Expected Output with file paths does not trigger warning');
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
console.log('\n=== validateTaskPlanContent: missing input file paths (info severity) ===');
|
|
420
|
+
{
|
|
421
|
+
const content = `# T01: Some Task
|
|
422
|
+
|
|
423
|
+
## Description
|
|
424
|
+
|
|
425
|
+
Do something.
|
|
426
|
+
|
|
427
|
+
## Steps
|
|
428
|
+
|
|
429
|
+
1. Do the thing
|
|
430
|
+
|
|
431
|
+
## Verification
|
|
432
|
+
|
|
433
|
+
- Check it works
|
|
434
|
+
|
|
435
|
+
## Inputs
|
|
436
|
+
|
|
437
|
+
Prior task summary insights about the architecture.
|
|
438
|
+
|
|
439
|
+
## Expected Output
|
|
440
|
+
|
|
441
|
+
- \`src/output.ts\` — Output file
|
|
442
|
+
`;
|
|
443
|
+
|
|
444
|
+
const issues = validateTaskPlanContent('T01-PLAN.md', content);
|
|
445
|
+
const inputIssues = issues.filter(i => i.ruleId === 'missing_input_file_paths');
|
|
446
|
+
assertTrue(inputIssues.length >= 1, 'Inputs without file paths triggers missing_input_file_paths');
|
|
447
|
+
if (inputIssues.length > 0) {
|
|
448
|
+
assertEq(inputIssues[0].severity, 'info', 'missing_input_file_paths is info severity (not warning)');
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.log('\n=== validateTaskPlanContent: no Expected Output section at all ===');
|
|
453
|
+
{
|
|
454
|
+
const content = `# T01: Some Task
|
|
455
|
+
|
|
456
|
+
## Description
|
|
457
|
+
|
|
458
|
+
Do something.
|
|
459
|
+
|
|
460
|
+
## Steps
|
|
461
|
+
|
|
462
|
+
1. Do the thing
|
|
463
|
+
|
|
464
|
+
## Verification
|
|
465
|
+
|
|
466
|
+
- Check it works
|
|
467
|
+
`;
|
|
468
|
+
|
|
469
|
+
const issues = validateTaskPlanContent('T01-PLAN.md', content);
|
|
470
|
+
const outputIssues = issues.filter(i => i.ruleId === 'missing_output_file_paths');
|
|
471
|
+
assertTrue(outputIssues.length >= 1, 'Missing Expected Output section triggers missing_output_file_paths');
|
|
472
|
+
}
|
|
473
|
+
|
|
363
474
|
report();
|
|
@@ -208,30 +208,25 @@ test("git fields comprehensive validation", () => {
|
|
|
208
208
|
assert.equal(preferences.git?.isolation, "branch");
|
|
209
209
|
});
|
|
210
210
|
|
|
211
|
-
test("auto_visualize, auto_report,
|
|
211
|
+
test("auto_visualize, auto_report, context_selection validate correctly", () => {
|
|
212
212
|
const { preferences, errors } = validatePreferences({
|
|
213
213
|
auto_visualize: true,
|
|
214
214
|
auto_report: false,
|
|
215
|
-
compression_strategy: "compress",
|
|
216
215
|
context_selection: "smart",
|
|
217
216
|
});
|
|
218
217
|
assert.equal(errors.length, 0);
|
|
219
218
|
assert.equal(preferences.auto_visualize, true);
|
|
220
219
|
assert.equal(preferences.auto_report, false);
|
|
221
|
-
assert.equal(preferences.compression_strategy, "compress");
|
|
222
220
|
assert.equal(preferences.context_selection, "smart");
|
|
223
221
|
});
|
|
224
222
|
|
|
225
|
-
test("auto_visualize, auto_report,
|
|
223
|
+
test("auto_visualize, auto_report, context_selection reject invalid values", () => {
|
|
226
224
|
const { errors: e1 } = validatePreferences({ auto_visualize: "yes" as never });
|
|
227
225
|
assert.ok(e1.some(e => e.includes("auto_visualize")));
|
|
228
226
|
|
|
229
227
|
const { errors: e2 } = validatePreferences({ auto_report: 1 as never });
|
|
230
228
|
assert.ok(e2.some(e => e.includes("auto_report")));
|
|
231
229
|
|
|
232
|
-
const { errors: e3 } = validatePreferences({ compression_strategy: "shrink" as never });
|
|
233
|
-
assert.ok(e3.some(e => e.includes("compression_strategy")));
|
|
234
|
-
|
|
235
230
|
const { errors: e4 } = validatePreferences({ context_selection: "partial" as never });
|
|
236
231
|
assert.ok(e4.some(e => e.includes("context_selection")));
|
|
237
232
|
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const promptsDir = join(process.cwd(), "src/resources/extensions/gsd/prompts");
|
|
7
|
+
|
|
8
|
+
function readPrompt(name: string): string {
|
|
9
|
+
return readFileSync(join(promptsDir, `${name}.md`), "utf-8");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test("reactive-execute prompt keeps task summaries with subagents and avoids batch commits", () => {
|
|
13
|
+
const prompt = readPrompt("reactive-execute");
|
|
14
|
+
assert.match(prompt, /subagent-written summary as authoritative/i);
|
|
15
|
+
assert.match(prompt, /Do NOT create a batch commit/i);
|
|
16
|
+
assert.doesNotMatch(prompt, /\*\*Write task summaries\*\*/i);
|
|
17
|
+
assert.doesNotMatch(prompt, /\*\*Commit\*\* all changes/i);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("run-uat prompt branches on dynamic UAT mode and supports runtime evidence", () => {
|
|
21
|
+
const prompt = readPrompt("run-uat");
|
|
22
|
+
assert.match(prompt, /\*\*Detected UAT mode:\*\*\s*`\{\{uatType\}\}`/);
|
|
23
|
+
assert.match(prompt, /uatType:\s*\{\{uatType\}\}/);
|
|
24
|
+
assert.match(prompt, /live-runtime/);
|
|
25
|
+
assert.match(prompt, /browser\/runtime\/network/i);
|
|
26
|
+
assert.match(prompt, /NEEDS-HUMAN/);
|
|
27
|
+
assert.doesNotMatch(prompt, /uatType:\s*artifact-driven/);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("workflow-start prompt defaults to autonomy instead of per-phase confirmation", () => {
|
|
31
|
+
const prompt = readPrompt("workflow-start");
|
|
32
|
+
assert.match(prompt, /Keep moving by default/i);
|
|
33
|
+
assert.match(prompt, /Decision gates, not ceremony/i);
|
|
34
|
+
assert.doesNotMatch(prompt, /confirm with the user before proceeding/i);
|
|
35
|
+
assert.doesNotMatch(prompt, /Gate between phases/i);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("discuss prompt allows implementation questions when they materially matter", () => {
|
|
39
|
+
const prompt = readPrompt("discuss");
|
|
40
|
+
assert.match(prompt, /Lead with experience, but ask implementation when it materially matters/i);
|
|
41
|
+
assert.match(prompt, /one gate, not two/i);
|
|
42
|
+
assert.doesNotMatch(prompt, /Questions must be about the experience, not the implementation/i);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("guided discussion prompts avoid wrap-up prompts after every round", () => {
|
|
46
|
+
const milestonePrompt = readPrompt("guided-discuss-milestone");
|
|
47
|
+
const slicePrompt = readPrompt("guided-discuss-slice");
|
|
48
|
+
assert.match(milestonePrompt, /Do \*\*not\*\* ask a meta "ready to wrap up\?" question after every round/i);
|
|
49
|
+
assert.match(slicePrompt, /Do \*\*not\*\* ask a meta "ready to wrap up\?" question after every round/i);
|
|
50
|
+
assert.doesNotMatch(milestonePrompt, /I think I have a solid picture of this milestone\. Ready to wrap up/i);
|
|
51
|
+
assert.doesNotMatch(slicePrompt, /I think I have a solid picture of this slice\. Ready to wrap up/i);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("guided-resume-task prompt preserves recovery state until work is superseded", () => {
|
|
55
|
+
const prompt = readPrompt("guided-resume-task");
|
|
56
|
+
assert.match(prompt, /Do \*\*not\*\* delete the continue file immediately/i);
|
|
57
|
+
assert.match(prompt, /successfully completed or you have written a newer summary\/continue artifact/i);
|
|
58
|
+
assert.doesNotMatch(prompt, /Delete the continue file after reading it/i);
|
|
59
|
+
});
|