gsd-pi 2.68.0 → 2.68.1-dev.abc8f2b
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 +66 -70
- package/dist/resources/extensions/gsd/auto-model-selection.js +27 -1
- package/dist/resources/extensions/gsd/auto.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -5
- package/dist/resources/extensions/gsd/guided-flow.js +25 -70
- package/dist/resources/extensions/gsd/model-router.js +85 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/templates/context.md +34 -2
- 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 +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/index.d.ts +3 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +2 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +2 -2
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/mistral.js +2 -2
- package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +2 -2
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +2 -2
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/provider-capabilities.d.ts +59 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.js +173 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.js.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.js +132 -0
- package/packages/pi-ai/dist/providers/provider-capabilities.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.js +172 -0
- package/packages/pi-ai/dist/providers/transform-messages-report.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +34 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +73 -2
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/src/index.ts +3 -0
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +2 -2
- package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -2
- package/packages/pi-ai/src/providers/google-shared.ts +2 -2
- package/packages/pi-ai/src/providers/mistral.ts +2 -2
- package/packages/pi-ai/src/providers/openai-completions.ts +2 -2
- package/packages/pi-ai/src/providers/openai-responses-shared.ts +2 -2
- package/packages/pi-ai/src/providers/provider-capabilities.test.ts +174 -0
- package/packages/pi-ai/src/providers/provider-capabilities.ts +215 -0
- package/packages/pi-ai/src/providers/transform-messages-report.test.ts +189 -0
- package/packages/pi-ai/src/providers/transform-messages.ts +94 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.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 +10 -1
- 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 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +15 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +41 -0
- 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/tools/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts +27 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js +69 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +3 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +11 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +18 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +45 -0
- package/packages/pi-coding-agent/src/core/tools/index.ts +7 -0
- package/packages/pi-coding-agent/src/core/tools/tool-compatibility-registry.ts +83 -0
- package/packages/pi-coding-agent/src/index.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -4
- package/src/resources/extensions/gsd/auto.ts +8 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -5
- package/src/resources/extensions/gsd/guided-flow.ts +22 -84
- package/src/resources/extensions/gsd/model-router.ts +117 -10
- package/src/resources/extensions/gsd/preferences-types.ts +3 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/templates/context.md +34 -2
- package/src/resources/extensions/gsd/tests/capability-router.test.ts +31 -7
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +13 -16
- package/dist/resources/extensions/gsd/prompt-validation.js +0 -67
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +0 -138
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/src/resources/extensions/gsd/prompt-validation.ts +0 -88
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
- package/src/resources/extensions/gsd/templates/context-enhanced.md +0 -138
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +0 -223
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +0 -53
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +0 -525
- package/src/resources/extensions/gsd/tests/preparation.test.ts +0 -1211
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +0 -669
- /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → 3HMOXcBoys84RYd2F8a79}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ka3ShQTakcliYL-EXRRb6 → 3HMOXcBoys84RYd2F8a79}/_ssgManifest.js +0 -0
|
@@ -1,669 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Builder Tests — Comprehensive tests for S02 components.
|
|
3
|
-
*
|
|
4
|
-
* Tests cover:
|
|
5
|
-
* 1. Template validation (context-enhanced.md, discuss-prepared.md)
|
|
6
|
-
* 2. Prompt loading and variable substitution
|
|
7
|
-
* 3. Enhanced context validation (R109)
|
|
8
|
-
* 4. Integration tests for format functions and prompt injection
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import test, { describe } from "node:test";
|
|
12
|
-
import assert from "node:assert/strict";
|
|
13
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
14
|
-
import { join } from "node:path";
|
|
15
|
-
|
|
16
|
-
// ─── Template Paths ─────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
const templatesDir = join(process.cwd(), "src/resources/extensions/gsd/templates");
|
|
19
|
-
const promptsDir = join(process.cwd(), "src/resources/extensions/gsd/prompts");
|
|
20
|
-
|
|
21
|
-
const contextEnhancedPath = join(templatesDir, "context-enhanced.md");
|
|
22
|
-
const contextPath = join(templatesDir, "context.md");
|
|
23
|
-
const discussPreparedPath = join(promptsDir, "discuss-prepared.md");
|
|
24
|
-
|
|
25
|
-
// ─── Template Tests ─────────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
describe("Template: context-enhanced.md", () => {
|
|
28
|
-
test("file exists", () => {
|
|
29
|
-
assert.ok(existsSync(contextEnhancedPath), "context-enhanced.md should exist");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("contains all original context.md sections", () => {
|
|
33
|
-
const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
|
|
34
|
-
const originalContext = readFileSync(contextPath, "utf-8");
|
|
35
|
-
|
|
36
|
-
// Extract section headers from original context.md
|
|
37
|
-
const originalSections = originalContext.match(/^## .+$/gm) ?? [];
|
|
38
|
-
|
|
39
|
-
// Each original section should be present in context-enhanced.md
|
|
40
|
-
for (const section of originalSections) {
|
|
41
|
-
assert.ok(
|
|
42
|
-
contextEnhanced.includes(section),
|
|
43
|
-
`context-enhanced.md should contain original section: ${section}`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("contains new structured sections for prepared discussions", () => {
|
|
49
|
-
const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
|
|
50
|
-
|
|
51
|
-
// New sections required by R108
|
|
52
|
-
const newSections = [
|
|
53
|
-
"## Codebase Brief",
|
|
54
|
-
"## Architectural Decisions",
|
|
55
|
-
"## Interface Contracts",
|
|
56
|
-
"## Error Handling Strategy",
|
|
57
|
-
"## Testing Requirements",
|
|
58
|
-
"## Acceptance Criteria",
|
|
59
|
-
"## Ecosystem Notes",
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
for (const section of newSections) {
|
|
63
|
-
assert.ok(
|
|
64
|
-
contextEnhanced.includes(section),
|
|
65
|
-
`context-enhanced.md should contain new section: ${section}`,
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("Codebase Brief has sub-sections", () => {
|
|
71
|
-
const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
|
|
72
|
-
|
|
73
|
-
assert.ok(
|
|
74
|
-
contextEnhanced.includes("### Technology Stack"),
|
|
75
|
-
"Codebase Brief should have Technology Stack sub-section",
|
|
76
|
-
);
|
|
77
|
-
assert.ok(
|
|
78
|
-
contextEnhanced.includes("### Key Modules"),
|
|
79
|
-
"Codebase Brief should have Key Modules sub-section",
|
|
80
|
-
);
|
|
81
|
-
assert.ok(
|
|
82
|
-
contextEnhanced.includes("### Patterns in Use"),
|
|
83
|
-
"Codebase Brief should have Patterns in Use sub-section",
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("Architectural Decisions has structured format guidance", () => {
|
|
88
|
-
const contextEnhanced = readFileSync(contextEnhancedPath, "utf-8");
|
|
89
|
-
|
|
90
|
-
// Check for decision structure markers
|
|
91
|
-
assert.ok(
|
|
92
|
-
contextEnhanced.includes("**Decision:**"),
|
|
93
|
-
"Architectural Decisions should have Decision marker",
|
|
94
|
-
);
|
|
95
|
-
assert.ok(
|
|
96
|
-
contextEnhanced.includes("**Rationale:**"),
|
|
97
|
-
"Architectural Decisions should have Rationale marker",
|
|
98
|
-
);
|
|
99
|
-
assert.ok(
|
|
100
|
-
contextEnhanced.includes("**Evidence:**"),
|
|
101
|
-
"Architectural Decisions should have Evidence marker",
|
|
102
|
-
);
|
|
103
|
-
assert.ok(
|
|
104
|
-
contextEnhanced.includes("**Alternatives Considered:**"),
|
|
105
|
-
"Architectural Decisions should have Alternatives Considered marker",
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe("Template: discuss-prepared.md", () => {
|
|
111
|
-
test("file exists", () => {
|
|
112
|
-
assert.ok(existsSync(discussPreparedPath), "discuss-prepared.md should exist");
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("contains all three brief placeholders", () => {
|
|
116
|
-
const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
|
|
117
|
-
|
|
118
|
-
assert.ok(
|
|
119
|
-
discussPrepared.includes("{{codebaseBrief}}"),
|
|
120
|
-
"discuss-prepared.md should contain {{codebaseBrief}} placeholder",
|
|
121
|
-
);
|
|
122
|
-
assert.ok(
|
|
123
|
-
discussPrepared.includes("{{priorContextBrief}}"),
|
|
124
|
-
"discuss-prepared.md should contain {{priorContextBrief}} placeholder",
|
|
125
|
-
);
|
|
126
|
-
assert.ok(
|
|
127
|
-
discussPrepared.includes("{{ecosystemBrief}}"),
|
|
128
|
-
"discuss-prepared.md should contain {{ecosystemBrief}} placeholder",
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test("contains 4-layer protocol markers", () => {
|
|
133
|
-
const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
|
|
134
|
-
|
|
135
|
-
// Check for all four layer headings
|
|
136
|
-
assert.ok(
|
|
137
|
-
discussPrepared.includes("## Layer 1 — Scope"),
|
|
138
|
-
"discuss-prepared.md should contain Layer 1 (Scope)",
|
|
139
|
-
);
|
|
140
|
-
assert.ok(
|
|
141
|
-
discussPrepared.includes("## Layer 2 — Architecture"),
|
|
142
|
-
"discuss-prepared.md should contain Layer 2 (Architecture)",
|
|
143
|
-
);
|
|
144
|
-
assert.ok(
|
|
145
|
-
discussPrepared.includes("## Layer 3 — Error States"),
|
|
146
|
-
"discuss-prepared.md should contain Layer 3 (Error States)",
|
|
147
|
-
);
|
|
148
|
-
assert.ok(
|
|
149
|
-
discussPrepared.includes("## Layer 4 — Quality Bar"),
|
|
150
|
-
"discuss-prepared.md should contain Layer 4 (Quality Bar)",
|
|
151
|
-
);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test("contains gate question IDs for all layers", () => {
|
|
155
|
-
const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
|
|
156
|
-
|
|
157
|
-
assert.ok(
|
|
158
|
-
discussPrepared.includes("layer1_scope_gate"),
|
|
159
|
-
"discuss-prepared.md should contain layer1_scope_gate question ID",
|
|
160
|
-
);
|
|
161
|
-
assert.ok(
|
|
162
|
-
discussPrepared.includes("layer2_architecture_gate"),
|
|
163
|
-
"discuss-prepared.md should contain layer2_architecture_gate question ID",
|
|
164
|
-
);
|
|
165
|
-
assert.ok(
|
|
166
|
-
discussPrepared.includes("layer3_error_gate"),
|
|
167
|
-
"discuss-prepared.md should contain layer3_error_gate question ID",
|
|
168
|
-
);
|
|
169
|
-
assert.ok(
|
|
170
|
-
discussPrepared.includes("layer4_quality_gate"),
|
|
171
|
-
"discuss-prepared.md should contain layer4_quality_gate question ID",
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
test("contains context-enhanced template guidance", () => {
|
|
176
|
-
const discussPrepared = readFileSync(discussPreparedPath, "utf-8");
|
|
177
|
-
|
|
178
|
-
assert.ok(
|
|
179
|
-
discussPrepared.includes("context-enhanced"),
|
|
180
|
-
"discuss-prepared.md should reference context-enhanced template",
|
|
181
|
-
);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// ─── Prompt Loading Tests ───────────────────────────────────────────────────────
|
|
186
|
-
|
|
187
|
-
describe("Prompt Loading", () => {
|
|
188
|
-
// Dynamic import to work with the module's warm cache
|
|
189
|
-
test("loadPrompt substitutes all variables correctly", async () => {
|
|
190
|
-
const { loadPrompt } = await import("../prompt-loader.ts");
|
|
191
|
-
|
|
192
|
-
const result = loadPrompt("discuss-prepared", {
|
|
193
|
-
preamble: "Test preamble",
|
|
194
|
-
codebaseBrief: "Test codebase brief content",
|
|
195
|
-
priorContextBrief: "Test prior context brief content",
|
|
196
|
-
ecosystemBrief: "Test ecosystem brief content",
|
|
197
|
-
milestoneId: "M001",
|
|
198
|
-
contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
|
|
199
|
-
roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
|
|
200
|
-
inlinedTemplates: "Test templates",
|
|
201
|
-
commitInstruction: "Test commit instruction",
|
|
202
|
-
multiMilestoneCommitInstruction: "Test multi-milestone commit",
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
assert.ok(result.includes("Test codebase brief content"), "codebaseBrief should be substituted");
|
|
206
|
-
assert.ok(result.includes("Test prior context brief content"), "priorContextBrief should be substituted");
|
|
207
|
-
assert.ok(result.includes("Test ecosystem brief content"), "ecosystemBrief should be substituted");
|
|
208
|
-
assert.ok(!result.includes("{{codebaseBrief}}"), "placeholder should not remain");
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test("loadPrompt throws GSDError for missing variables", async () => {
|
|
212
|
-
const { loadPrompt } = await import("../prompt-loader.ts");
|
|
213
|
-
const { GSDError, GSD_PARSE_ERROR } = await import("../errors.ts");
|
|
214
|
-
|
|
215
|
-
assert.throws(
|
|
216
|
-
() => loadPrompt("discuss-prepared", {}), // Missing required variables
|
|
217
|
-
(err: unknown) => {
|
|
218
|
-
assert.ok(err instanceof GSDError, "should throw GSDError");
|
|
219
|
-
assert.equal((err as InstanceType<typeof GSDError>).code, GSD_PARSE_ERROR, "should have GSD_PARSE_ERROR code");
|
|
220
|
-
return true;
|
|
221
|
-
},
|
|
222
|
-
);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("brief content with {{...}} patterns does not cause false variable errors", async () => {
|
|
226
|
-
const { loadPrompt } = await import("../prompt-loader.ts");
|
|
227
|
-
|
|
228
|
-
// Content that contains template-like patterns but should not be treated as variables
|
|
229
|
-
const briefWithPatterns = `
|
|
230
|
-
## Tech Stack
|
|
231
|
-
- Framework: Uses \`{{slot}}\` placeholder syntax in templates
|
|
232
|
-
- Pattern: The codebase has \`{{variableName}}\` markers
|
|
233
|
-
`;
|
|
234
|
-
|
|
235
|
-
// This should NOT throw, because {{slot}} and {{variableName}} are inside
|
|
236
|
-
// the brief value, not undeclared placeholders in the template itself.
|
|
237
|
-
const result = loadPrompt("discuss-prepared", {
|
|
238
|
-
preamble: "Test",
|
|
239
|
-
codebaseBrief: briefWithPatterns,
|
|
240
|
-
priorContextBrief: "Test brief",
|
|
241
|
-
ecosystemBrief: "Test brief",
|
|
242
|
-
milestoneId: "M001",
|
|
243
|
-
contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
|
|
244
|
-
roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
|
|
245
|
-
inlinedTemplates: "Test templates",
|
|
246
|
-
commitInstruction: "Test commit instruction",
|
|
247
|
-
multiMilestoneCommitInstruction: "Test multi-milestone commit",
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
assert.ok(result.includes("{{slot}}"), "template-like patterns in content should be preserved");
|
|
251
|
-
assert.ok(result.includes("{{variableName}}"), "template-like patterns in content should be preserved");
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// ─── Validation Tests ───────────────────────────────────────────────────────────
|
|
256
|
-
|
|
257
|
-
describe("Enhanced Context Validation", () => {
|
|
258
|
-
test("valid enhanced context passes validation", async () => {
|
|
259
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
260
|
-
|
|
261
|
-
const validContent = `
|
|
262
|
-
# M001: Test Milestone
|
|
263
|
-
|
|
264
|
-
## Why This Milestone
|
|
265
|
-
|
|
266
|
-
This is why we need this milestone.
|
|
267
|
-
|
|
268
|
-
## Architectural Decisions
|
|
269
|
-
|
|
270
|
-
### Decision 1
|
|
271
|
-
|
|
272
|
-
**Decision:** Use TypeScript
|
|
273
|
-
**Rationale:** Type safety
|
|
274
|
-
|
|
275
|
-
## Acceptance Criteria
|
|
276
|
-
|
|
277
|
-
- Criterion 1
|
|
278
|
-
- Criterion 2
|
|
279
|
-
`;
|
|
280
|
-
|
|
281
|
-
const result = validateEnhancedContext(validContent);
|
|
282
|
-
assert.equal(result.valid, true, "valid content should pass validation");
|
|
283
|
-
assert.equal(result.missing.length, 0, "no missing sections");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("missing scope section fails", async () => {
|
|
287
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
288
|
-
|
|
289
|
-
const contentMissingScope = `
|
|
290
|
-
# M001: Test Milestone
|
|
291
|
-
|
|
292
|
-
## Architectural Decisions
|
|
293
|
-
|
|
294
|
-
### Decision 1
|
|
295
|
-
|
|
296
|
-
**Decision:** Use TypeScript
|
|
297
|
-
|
|
298
|
-
## Acceptance Criteria
|
|
299
|
-
|
|
300
|
-
- Criterion 1
|
|
301
|
-
`;
|
|
302
|
-
|
|
303
|
-
const result = validateEnhancedContext(contentMissingScope);
|
|
304
|
-
assert.equal(result.valid, false, "should fail validation");
|
|
305
|
-
assert.ok(
|
|
306
|
-
result.missing.some((m) => m.includes("Scope") || m.includes("Why This Milestone")),
|
|
307
|
-
"should report missing scope section",
|
|
308
|
-
);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
test("missing architectural decisions section fails", async () => {
|
|
312
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
313
|
-
|
|
314
|
-
const contentMissingDecisions = `
|
|
315
|
-
# M001: Test Milestone
|
|
316
|
-
|
|
317
|
-
## Why This Milestone
|
|
318
|
-
|
|
319
|
-
This is why we need this milestone.
|
|
320
|
-
|
|
321
|
-
## Acceptance Criteria
|
|
322
|
-
|
|
323
|
-
- Criterion 1
|
|
324
|
-
`;
|
|
325
|
-
|
|
326
|
-
const result = validateEnhancedContext(contentMissingDecisions);
|
|
327
|
-
assert.equal(result.valid, false, "should fail validation");
|
|
328
|
-
assert.ok(
|
|
329
|
-
result.missing.includes("Architectural Decisions"),
|
|
330
|
-
"should report missing architectural decisions section",
|
|
331
|
-
);
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
test("missing acceptance criteria section fails", async () => {
|
|
335
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
336
|
-
|
|
337
|
-
const contentMissingCriteria = `
|
|
338
|
-
# M001: Test Milestone
|
|
339
|
-
|
|
340
|
-
## Why This Milestone
|
|
341
|
-
|
|
342
|
-
This is why we need this milestone.
|
|
343
|
-
|
|
344
|
-
## Architectural Decisions
|
|
345
|
-
|
|
346
|
-
### Decision 1
|
|
347
|
-
|
|
348
|
-
**Decision:** Use TypeScript
|
|
349
|
-
`;
|
|
350
|
-
|
|
351
|
-
const result = validateEnhancedContext(contentMissingCriteria);
|
|
352
|
-
assert.equal(result.valid, false, "should fail validation");
|
|
353
|
-
assert.ok(
|
|
354
|
-
result.missing.includes("Acceptance Criteria"),
|
|
355
|
-
"should report missing acceptance criteria section",
|
|
356
|
-
);
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
test("empty architectural decisions section (no entries) fails", async () => {
|
|
360
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
361
|
-
|
|
362
|
-
const contentEmptyDecisions = `
|
|
363
|
-
# M001: Test Milestone
|
|
364
|
-
|
|
365
|
-
## Why This Milestone
|
|
366
|
-
|
|
367
|
-
This is why we need this milestone.
|
|
368
|
-
|
|
369
|
-
## Architectural Decisions
|
|
370
|
-
|
|
371
|
-
No decisions yet.
|
|
372
|
-
|
|
373
|
-
## Acceptance Criteria
|
|
374
|
-
|
|
375
|
-
- Criterion 1
|
|
376
|
-
`;
|
|
377
|
-
|
|
378
|
-
const result = validateEnhancedContext(contentEmptyDecisions);
|
|
379
|
-
assert.equal(result.valid, false, "should fail validation");
|
|
380
|
-
assert.ok(
|
|
381
|
-
result.missing.some((m) => m.includes("decision entry")),
|
|
382
|
-
"should report missing decision entry",
|
|
383
|
-
);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
test("alternative scope headers are accepted", async () => {
|
|
387
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
388
|
-
|
|
389
|
-
// Test with ## Scope
|
|
390
|
-
const withScope = `
|
|
391
|
-
## Scope
|
|
392
|
-
|
|
393
|
-
### In Scope
|
|
394
|
-
- Item 1
|
|
395
|
-
|
|
396
|
-
## Architectural Decisions
|
|
397
|
-
|
|
398
|
-
### Decision 1
|
|
399
|
-
**Decision:** Test
|
|
400
|
-
|
|
401
|
-
## Acceptance Criteria
|
|
402
|
-
|
|
403
|
-
- Criterion 1
|
|
404
|
-
`;
|
|
405
|
-
assert.equal(validateEnhancedContext(withScope).valid, true, "## Scope should be accepted");
|
|
406
|
-
|
|
407
|
-
// Test with ## Milestone Scope
|
|
408
|
-
const withMilestoneScope = `
|
|
409
|
-
## Milestone Scope
|
|
410
|
-
|
|
411
|
-
This is the scope.
|
|
412
|
-
|
|
413
|
-
## Architectural Decisions
|
|
414
|
-
|
|
415
|
-
### Decision 1
|
|
416
|
-
**Decision:** Test
|
|
417
|
-
|
|
418
|
-
## Acceptance Criteria
|
|
419
|
-
|
|
420
|
-
- Criterion 1
|
|
421
|
-
`;
|
|
422
|
-
assert.equal(
|
|
423
|
-
validateEnhancedContext(withMilestoneScope).valid,
|
|
424
|
-
true,
|
|
425
|
-
"## Milestone Scope should be accepted",
|
|
426
|
-
);
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
test("alternative acceptance criteria headers are accepted", async () => {
|
|
430
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
431
|
-
|
|
432
|
-
const withFinalIntegrated = `
|
|
433
|
-
## Why This Milestone
|
|
434
|
-
|
|
435
|
-
Test
|
|
436
|
-
|
|
437
|
-
## Architectural Decisions
|
|
438
|
-
|
|
439
|
-
### Decision 1
|
|
440
|
-
**Decision:** Test
|
|
441
|
-
|
|
442
|
-
## Final Integrated Acceptance
|
|
443
|
-
|
|
444
|
-
- Criterion 1
|
|
445
|
-
`;
|
|
446
|
-
assert.equal(
|
|
447
|
-
validateEnhancedContext(withFinalIntegrated).valid,
|
|
448
|
-
true,
|
|
449
|
-
"## Final Integrated Acceptance should be accepted",
|
|
450
|
-
);
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
test("inline decision format is accepted", async () => {
|
|
454
|
-
const { validateEnhancedContext } = await import("../prompt-validation.ts");
|
|
455
|
-
|
|
456
|
-
const withInlineDecision = `
|
|
457
|
-
## Why This Milestone
|
|
458
|
-
|
|
459
|
-
Test
|
|
460
|
-
|
|
461
|
-
## Architectural Decisions
|
|
462
|
-
|
|
463
|
-
**Decision:** Use React for the frontend
|
|
464
|
-
|
|
465
|
-
## Acceptance Criteria
|
|
466
|
-
|
|
467
|
-
- Criterion 1
|
|
468
|
-
`;
|
|
469
|
-
assert.equal(
|
|
470
|
-
validateEnhancedContext(withInlineDecision).valid,
|
|
471
|
-
true,
|
|
472
|
-
"**Decision marker format should be accepted",
|
|
473
|
-
);
|
|
474
|
-
});
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
// ─── Integration Tests ──────────────────────────────────────────────────────────
|
|
478
|
-
|
|
479
|
-
describe("Integration: Format Functions", () => {
|
|
480
|
-
test("formatCodebaseBrief produces non-empty output", async () => {
|
|
481
|
-
const { formatCodebaseBrief } = await import("../preparation.ts");
|
|
482
|
-
|
|
483
|
-
const brief = {
|
|
484
|
-
techStack: {
|
|
485
|
-
primaryLanguage: "TypeScript",
|
|
486
|
-
detectedFiles: ["package.json", "tsconfig.json"],
|
|
487
|
-
packageManager: "npm",
|
|
488
|
-
isMonorepo: false,
|
|
489
|
-
hasTests: true,
|
|
490
|
-
hasCI: true,
|
|
491
|
-
},
|
|
492
|
-
moduleStructure: {
|
|
493
|
-
topLevelDirs: ["src", "tests"],
|
|
494
|
-
srcSubdirs: ["components", "utils"],
|
|
495
|
-
totalFilesSampled: 5,
|
|
496
|
-
},
|
|
497
|
-
patterns: {
|
|
498
|
-
asyncStyle: "async/await" as const,
|
|
499
|
-
errorHandling: "try/catch" as const,
|
|
500
|
-
namingConvention: "camelCase" as const,
|
|
501
|
-
evidence: {
|
|
502
|
-
asyncStyle: ["src/foo.ts: async/await (5 occurrences)"],
|
|
503
|
-
errorHandling: ["src/bar.ts: try/catch (3 occurrences)"],
|
|
504
|
-
namingConvention: ["camelCase: 50 occurrences"],
|
|
505
|
-
},
|
|
506
|
-
fileCounts: {
|
|
507
|
-
asyncAwait: 3,
|
|
508
|
-
promises: 0,
|
|
509
|
-
callbacks: 0,
|
|
510
|
-
tryCatch: 2,
|
|
511
|
-
errorCallbacks: 0,
|
|
512
|
-
resultTypes: 0,
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
sampledFiles: ["src/index.ts", "src/utils.ts"],
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
const formatted = formatCodebaseBrief(brief);
|
|
519
|
-
assert.ok(formatted.length > 0, "formatted brief should not be empty");
|
|
520
|
-
assert.ok(formatted.includes("TypeScript"), "should include primary language");
|
|
521
|
-
assert.ok(formatted.includes("async/await"), "should include async style");
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
test("formatPriorContextBrief produces non-empty output", async () => {
|
|
525
|
-
const { formatPriorContextBrief } = await import("../preparation.ts");
|
|
526
|
-
|
|
527
|
-
const brief = {
|
|
528
|
-
decisions: {
|
|
529
|
-
byScope: new Map([
|
|
530
|
-
["architecture", [{ id: "D001", scope: "architecture", decision: "Use SQLite", choice: "SQLite", rationale: "Simplicity" }]],
|
|
531
|
-
]),
|
|
532
|
-
totalCount: 1,
|
|
533
|
-
},
|
|
534
|
-
requirements: {
|
|
535
|
-
active: [{ id: "R001", description: "Test requirement", status: "active" as const }],
|
|
536
|
-
validated: [],
|
|
537
|
-
deferred: [],
|
|
538
|
-
totalCount: 1,
|
|
539
|
-
},
|
|
540
|
-
knowledge: "Some knowledge entry",
|
|
541
|
-
summaries: "M001 completed X and Y",
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
const formatted = formatPriorContextBrief(brief);
|
|
545
|
-
assert.ok(formatted.length > 0, "formatted brief should not be empty");
|
|
546
|
-
assert.ok(formatted.includes("Prior Decisions"), "should include decisions section");
|
|
547
|
-
assert.ok(formatted.includes("D001"), "should include decision ID");
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
test("formatEcosystemBrief returns simplified message (research happens during discussion)", async () => {
|
|
551
|
-
const { formatEcosystemBrief } = await import("../preparation.ts");
|
|
552
|
-
|
|
553
|
-
// formatEcosystemBrief now returns a fixed message regardless of brief content
|
|
554
|
-
// because ecosystem research happens during the discussion, not preparation
|
|
555
|
-
const briefWithFindings = {
|
|
556
|
-
available: true,
|
|
557
|
-
queries: ["Next.js best practices 2024"],
|
|
558
|
-
findings: [
|
|
559
|
-
{
|
|
560
|
-
query: "Next.js best practices 2024",
|
|
561
|
-
title: "Server Components Guide",
|
|
562
|
-
url: "https://example.com/guide",
|
|
563
|
-
snippet: "Use Server Components for data fetching",
|
|
564
|
-
},
|
|
565
|
-
],
|
|
566
|
-
provider: "tavily",
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
const formatted = formatEcosystemBrief(briefWithFindings);
|
|
570
|
-
assert.ok(formatted.length > 0, "formatted brief should not be empty");
|
|
571
|
-
assert.ok(formatted.includes("Ecosystem Research"), "should include research heading");
|
|
572
|
-
assert.ok(formatted.includes("during the discussion"), "should mention research happens during discussion");
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
test("formatEcosystemBrief returns same output for any brief state", async () => {
|
|
576
|
-
const { formatEcosystemBrief } = await import("../preparation.ts");
|
|
577
|
-
|
|
578
|
-
const briefUnavailable = {
|
|
579
|
-
available: false,
|
|
580
|
-
queries: [],
|
|
581
|
-
findings: [],
|
|
582
|
-
skippedReason: "No API key configured",
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
const briefAvailable = {
|
|
586
|
-
available: true,
|
|
587
|
-
queries: ["test"],
|
|
588
|
-
findings: [],
|
|
589
|
-
provider: "tavily",
|
|
590
|
-
};
|
|
591
|
-
|
|
592
|
-
const formatted1 = formatEcosystemBrief(briefUnavailable);
|
|
593
|
-
const formatted2 = formatEcosystemBrief(briefAvailable);
|
|
594
|
-
|
|
595
|
-
// Both should return the same simplified message
|
|
596
|
-
assert.equal(formatted1, formatted2, "should return consistent output regardless of brief state");
|
|
597
|
-
assert.ok(formatted1.includes("web search tools"), "should mention web search tools");
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
test("formatted briefs can be injected into prompt without errors", async () => {
|
|
601
|
-
const { loadPrompt } = await import("../prompt-loader.ts");
|
|
602
|
-
const { formatCodebaseBrief, formatPriorContextBrief, formatEcosystemBrief } = await import("../preparation.ts");
|
|
603
|
-
|
|
604
|
-
// Create realistic briefs
|
|
605
|
-
const codebaseBrief = formatCodebaseBrief({
|
|
606
|
-
techStack: {
|
|
607
|
-
primaryLanguage: "TypeScript",
|
|
608
|
-
detectedFiles: ["package.json"],
|
|
609
|
-
packageManager: "npm",
|
|
610
|
-
isMonorepo: false,
|
|
611
|
-
hasTests: true,
|
|
612
|
-
hasCI: false,
|
|
613
|
-
},
|
|
614
|
-
moduleStructure: {
|
|
615
|
-
topLevelDirs: ["src"],
|
|
616
|
-
srcSubdirs: [],
|
|
617
|
-
totalFilesSampled: 1,
|
|
618
|
-
},
|
|
619
|
-
patterns: {
|
|
620
|
-
asyncStyle: "async/await" as const,
|
|
621
|
-
errorHandling: "try/catch" as const,
|
|
622
|
-
namingConvention: "camelCase" as const,
|
|
623
|
-
evidence: { asyncStyle: [], errorHandling: [], namingConvention: [] },
|
|
624
|
-
fileCounts: {
|
|
625
|
-
asyncAwait: 0,
|
|
626
|
-
promises: 0,
|
|
627
|
-
callbacks: 0,
|
|
628
|
-
tryCatch: 0,
|
|
629
|
-
errorCallbacks: 0,
|
|
630
|
-
resultTypes: 0,
|
|
631
|
-
},
|
|
632
|
-
},
|
|
633
|
-
sampledFiles: [],
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
const priorContextBrief = formatPriorContextBrief({
|
|
637
|
-
decisions: { byScope: new Map(), totalCount: 0 },
|
|
638
|
-
requirements: { active: [], validated: [], deferred: [], totalCount: 0 },
|
|
639
|
-
knowledge: "No prior knowledge recorded.",
|
|
640
|
-
summaries: "No prior milestone summaries.",
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
const ecosystemBrief = formatEcosystemBrief({
|
|
644
|
-
available: false,
|
|
645
|
-
queries: [],
|
|
646
|
-
findings: [],
|
|
647
|
-
skippedReason: "Preparation disabled",
|
|
648
|
-
});
|
|
649
|
-
|
|
650
|
-
// Should not throw when injecting formatted briefs
|
|
651
|
-
const result = loadPrompt("discuss-prepared", {
|
|
652
|
-
preamble: "Test preamble",
|
|
653
|
-
codebaseBrief,
|
|
654
|
-
priorContextBrief,
|
|
655
|
-
ecosystemBrief,
|
|
656
|
-
milestoneId: "M001",
|
|
657
|
-
contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
|
|
658
|
-
roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
|
|
659
|
-
inlinedTemplates: "Test templates",
|
|
660
|
-
commitInstruction: "Do not commit",
|
|
661
|
-
multiMilestoneCommitInstruction: "Do not commit",
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
assert.ok(result.includes("TypeScript"), "codebase brief should be present");
|
|
665
|
-
assert.ok(result.includes("Prior Decisions"), "prior context brief should be present");
|
|
666
|
-
// formatEcosystemBrief now returns a fixed message about research during discussion
|
|
667
|
-
assert.ok(result.includes("during the discussion"), "ecosystem brief should be present");
|
|
668
|
-
});
|
|
669
|
-
});
|
|
File without changes
|
|
File without changes
|