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
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// GSD-2 — Tool Compatibility + Model Router Tool Filtering Tests (ADR-005 Phases 2-3)
|
|
2
|
+
import { describe, test, beforeEach } from "node:test";
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
registerToolCompatibility,
|
|
7
|
+
getToolCompatibility,
|
|
8
|
+
getAllToolCompatibility,
|
|
9
|
+
registerMcpToolCompatibility,
|
|
10
|
+
resetToolCompatibilityRegistry,
|
|
11
|
+
} from "@gsd/pi-coding-agent";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
isToolCompatibleWithProvider,
|
|
15
|
+
filterToolsForProvider,
|
|
16
|
+
adjustToolSet,
|
|
17
|
+
} from "../model-router.js";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
getProviderCapabilities,
|
|
21
|
+
} from "@gsd/pi-ai";
|
|
22
|
+
|
|
23
|
+
// ─── Tool Compatibility Registry ────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
describe("tool compatibility registry", () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
resetToolCompatibilityRegistry();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("built-in tools are pre-registered", () => {
|
|
31
|
+
const builtins = ["bash", "read", "write", "edit", "grep", "find", "ls", "lsp"];
|
|
32
|
+
for (const name of builtins) {
|
|
33
|
+
const compat = getToolCompatibility(name);
|
|
34
|
+
assert.ok(compat !== undefined, `${name} should be pre-registered`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("unknown tool returns undefined", () => {
|
|
39
|
+
assert.equal(getToolCompatibility("nonexistent_tool_xyz"), undefined);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("registerToolCompatibility stores and retrieves metadata", () => {
|
|
43
|
+
registerToolCompatibility("screenshot_tool", {
|
|
44
|
+
producesImages: true,
|
|
45
|
+
minCapabilityTier: "standard",
|
|
46
|
+
});
|
|
47
|
+
const compat = getToolCompatibility("screenshot_tool");
|
|
48
|
+
assert.ok(compat);
|
|
49
|
+
assert.equal(compat.producesImages, true);
|
|
50
|
+
assert.equal(compat.minCapabilityTier, "standard");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("registerMcpToolCompatibility sets default schema features", () => {
|
|
54
|
+
registerMcpToolCompatibility("mcp__test__tool");
|
|
55
|
+
const compat = getToolCompatibility("mcp__test__tool");
|
|
56
|
+
assert.ok(compat);
|
|
57
|
+
assert.ok(compat.schemaFeatures?.includes("patternProperties"));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("registerMcpToolCompatibility allows overrides", () => {
|
|
61
|
+
registerMcpToolCompatibility("mcp__test__override", { producesImages: true });
|
|
62
|
+
const compat = getToolCompatibility("mcp__test__override");
|
|
63
|
+
assert.ok(compat);
|
|
64
|
+
assert.equal(compat.producesImages, true);
|
|
65
|
+
assert.ok(compat.schemaFeatures?.includes("patternProperties"));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("getAllToolCompatibility returns all entries", () => {
|
|
69
|
+
const all = getAllToolCompatibility();
|
|
70
|
+
assert.ok(all.size >= 10); // at least built-in tools
|
|
71
|
+
assert.ok(all.has("bash"));
|
|
72
|
+
assert.ok(all.has("read"));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("resetToolCompatibilityRegistry clears custom entries but keeps builtins", () => {
|
|
76
|
+
registerToolCompatibility("custom_tool", { producesImages: true });
|
|
77
|
+
assert.ok(getToolCompatibility("custom_tool"));
|
|
78
|
+
resetToolCompatibilityRegistry();
|
|
79
|
+
assert.equal(getToolCompatibility("custom_tool"), undefined);
|
|
80
|
+
assert.ok(getToolCompatibility("bash")); // built-in preserved
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ─── isToolCompatibleWithProvider ───────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
describe("isToolCompatibleWithProvider", () => {
|
|
87
|
+
beforeEach(() => {
|
|
88
|
+
resetToolCompatibilityRegistry();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("tool without compatibility metadata is always compatible", () => {
|
|
92
|
+
const caps = getProviderCapabilities("anthropic-messages");
|
|
93
|
+
assert.equal(isToolCompatibleWithProvider("unknown_tool", caps), true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("built-in tools are compatible with all providers", () => {
|
|
97
|
+
const providers = ["anthropic-messages", "openai-responses", "google-generative-ai", "mistral-conversations"];
|
|
98
|
+
const tools = ["bash", "read", "write", "edit"];
|
|
99
|
+
for (const api of providers) {
|
|
100
|
+
const caps = getProviderCapabilities(api);
|
|
101
|
+
for (const tool of tools) {
|
|
102
|
+
assert.equal(
|
|
103
|
+
isToolCompatibleWithProvider(tool, caps),
|
|
104
|
+
true,
|
|
105
|
+
`${tool} should be compatible with ${api}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("image-producing tool filtered for providers without image support", () => {
|
|
112
|
+
registerToolCompatibility("screenshot", { producesImages: true });
|
|
113
|
+
const openaiCaps = getProviderCapabilities("openai-responses");
|
|
114
|
+
assert.equal(isToolCompatibleWithProvider("screenshot", openaiCaps), false);
|
|
115
|
+
|
|
116
|
+
const anthropicCaps = getProviderCapabilities("anthropic-messages");
|
|
117
|
+
assert.equal(isToolCompatibleWithProvider("screenshot", anthropicCaps), true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("tool with unsupported schema features filtered for Google", () => {
|
|
121
|
+
registerToolCompatibility("complex_schema_tool", {
|
|
122
|
+
schemaFeatures: ["patternProperties"],
|
|
123
|
+
});
|
|
124
|
+
const googleCaps = getProviderCapabilities("google-generative-ai");
|
|
125
|
+
assert.equal(isToolCompatibleWithProvider("complex_schema_tool", googleCaps), false);
|
|
126
|
+
|
|
127
|
+
const anthropicCaps = getProviderCapabilities("anthropic-messages");
|
|
128
|
+
assert.equal(isToolCompatibleWithProvider("complex_schema_tool", anthropicCaps), true);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// ─── filterToolsForProvider ─────────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
describe("filterToolsForProvider", () => {
|
|
135
|
+
beforeEach(() => {
|
|
136
|
+
resetToolCompatibilityRegistry();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("all built-in tools pass for any provider", () => {
|
|
140
|
+
const toolNames = ["bash", "read", "write", "edit", "grep", "find", "ls"];
|
|
141
|
+
const { compatible, filtered } = filterToolsForProvider(toolNames, "mistral-conversations");
|
|
142
|
+
assert.deepEqual(compatible, toolNames);
|
|
143
|
+
assert.deepEqual(filtered, []);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("image tool filtered for OpenAI Responses", () => {
|
|
147
|
+
registerToolCompatibility("browser_screenshot", { producesImages: true });
|
|
148
|
+
const toolNames = ["bash", "read", "browser_screenshot"];
|
|
149
|
+
const { compatible, filtered } = filterToolsForProvider(toolNames, "openai-responses");
|
|
150
|
+
assert.deepEqual(compatible, ["bash", "read"]);
|
|
151
|
+
assert.deepEqual(filtered, ["browser_screenshot"]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("MCP tool with patternProperties filtered for Google", () => {
|
|
155
|
+
registerMcpToolCompatibility("mcp__repowise__search");
|
|
156
|
+
const toolNames = ["bash", "read", "mcp__repowise__search"];
|
|
157
|
+
const { compatible, filtered } = filterToolsForProvider(toolNames, "google-generative-ai");
|
|
158
|
+
assert.deepEqual(compatible, ["bash", "read"]);
|
|
159
|
+
assert.deepEqual(filtered, ["mcp__repowise__search"]);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("unknown provider passes all tools (permissive default)", () => {
|
|
163
|
+
registerToolCompatibility("image_tool", { producesImages: true });
|
|
164
|
+
registerMcpToolCompatibility("mcp_tool");
|
|
165
|
+
const toolNames = ["bash", "image_tool", "mcp_tool"];
|
|
166
|
+
const { compatible, filtered } = filterToolsForProvider(toolNames, "unknown-provider-xyz");
|
|
167
|
+
assert.deepEqual(compatible, toolNames);
|
|
168
|
+
assert.deepEqual(filtered, []);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// ─── adjustToolSet ──────────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
describe("adjustToolSet", () => {
|
|
175
|
+
beforeEach(() => {
|
|
176
|
+
resetToolCompatibilityRegistry();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("returns all tools for Anthropic (most permissive)", () => {
|
|
180
|
+
registerToolCompatibility("screenshot", { producesImages: true });
|
|
181
|
+
const toolNames = ["bash", "read", "screenshot"];
|
|
182
|
+
const { toolNames: result, removedTools } = adjustToolSet(toolNames, "anthropic-messages");
|
|
183
|
+
assert.deepEqual(result, toolNames);
|
|
184
|
+
assert.deepEqual(removedTools, []);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("removes incompatible tools and reports them", () => {
|
|
188
|
+
registerToolCompatibility("screenshot", { producesImages: true });
|
|
189
|
+
registerMcpToolCompatibility("mcp_complex");
|
|
190
|
+
const toolNames = ["bash", "read", "screenshot", "mcp_complex"];
|
|
191
|
+
const { toolNames: result, removedTools } = adjustToolSet(toolNames, "google-generative-ai");
|
|
192
|
+
// Google supports images but not patternProperties
|
|
193
|
+
assert.ok(result.includes("bash"));
|
|
194
|
+
assert.ok(result.includes("read"));
|
|
195
|
+
assert.ok(result.includes("screenshot")); // Google supports images
|
|
196
|
+
assert.ok(!result.includes("mcp_complex")); // patternProperties not supported
|
|
197
|
+
assert.deepEqual(removedTools, ["mcp_complex"]);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -230,16 +230,13 @@ import {
|
|
|
230
230
|
// ─── Scenario 19: isGateQuestionId recognizes all gate patterns ──
|
|
231
231
|
|
|
232
232
|
test('write-gate: isGateQuestionId recognizes all gate patterns', () => {
|
|
233
|
-
assert.strictEqual(isGateQuestionId('layer1_scope_gate'), true);
|
|
234
|
-
assert.strictEqual(isGateQuestionId('layer2_architecture_gate'), true);
|
|
235
|
-
assert.strictEqual(isGateQuestionId('layer3_error_gate'), true);
|
|
236
|
-
assert.strictEqual(isGateQuestionId('layer4_quality_gate'), true);
|
|
237
233
|
assert.strictEqual(isGateQuestionId('depth_verification'), true);
|
|
238
234
|
assert.strictEqual(isGateQuestionId('depth_verification_M002'), true);
|
|
239
|
-
assert.strictEqual(isGateQuestionId('
|
|
235
|
+
assert.strictEqual(isGateQuestionId('depth_verification_confirm'), true);
|
|
240
236
|
// Non-gate question IDs
|
|
241
237
|
assert.strictEqual(isGateQuestionId('project_intent'), false);
|
|
242
238
|
assert.strictEqual(isGateQuestionId('feature_priority'), false);
|
|
239
|
+
assert.strictEqual(isGateQuestionId('layer1_scope_gate'), false);
|
|
243
240
|
assert.strictEqual(isGateQuestionId(''), false);
|
|
244
241
|
});
|
|
245
242
|
|
|
@@ -249,14 +246,14 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
|
|
|
249
246
|
clearDiscussionFlowState();
|
|
250
247
|
assert.strictEqual(getPendingGate(), null, 'starts null');
|
|
251
248
|
|
|
252
|
-
setPendingGate('
|
|
253
|
-
assert.strictEqual(getPendingGate(), '
|
|
249
|
+
setPendingGate('depth_verification');
|
|
250
|
+
assert.strictEqual(getPendingGate(), 'depth_verification', 'set correctly');
|
|
254
251
|
|
|
255
252
|
clearPendingGate();
|
|
256
253
|
assert.strictEqual(getPendingGate(), null, 'cleared correctly');
|
|
257
254
|
|
|
258
255
|
// clearDiscussionFlowState also clears pending gate
|
|
259
|
-
setPendingGate('
|
|
256
|
+
setPendingGate('depth_verification_M002');
|
|
260
257
|
clearDiscussionFlowState();
|
|
261
258
|
assert.strictEqual(getPendingGate(), null, 'clearDiscussionFlowState clears pending gate');
|
|
262
259
|
});
|
|
@@ -265,12 +262,12 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
|
|
|
265
262
|
|
|
266
263
|
test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate', () => {
|
|
267
264
|
clearDiscussionFlowState();
|
|
268
|
-
setPendingGate('
|
|
265
|
+
setPendingGate('depth_verification');
|
|
269
266
|
|
|
270
267
|
// write should be blocked during discussion
|
|
271
268
|
const writeResult = shouldBlockPendingGate('write', 'M001', false);
|
|
272
269
|
assert.strictEqual(writeResult.block, true, 'write should be blocked');
|
|
273
|
-
assert.ok(writeResult.reason!.includes('
|
|
270
|
+
assert.ok(writeResult.reason!.includes('depth_verification'), 'reason mentions the gate');
|
|
274
271
|
|
|
275
272
|
// edit should be blocked
|
|
276
273
|
const editResult = shouldBlockPendingGate('edit', 'M001', false);
|
|
@@ -287,7 +284,7 @@ test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate',
|
|
|
287
284
|
|
|
288
285
|
test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions during pending gate', () => {
|
|
289
286
|
clearDiscussionFlowState();
|
|
290
|
-
setPendingGate('
|
|
287
|
+
setPendingGate('depth_verification');
|
|
291
288
|
|
|
292
289
|
// ask_user_questions is always safe (model needs to re-ask)
|
|
293
290
|
assert.strictEqual(shouldBlockPendingGate('ask_user_questions', 'M001').block, false);
|
|
@@ -304,7 +301,7 @@ test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions
|
|
|
304
301
|
|
|
305
302
|
test('write-gate: shouldBlockPendingGate blocks outside discussion when a gate is pending', () => {
|
|
306
303
|
clearDiscussionFlowState();
|
|
307
|
-
setPendingGate('
|
|
304
|
+
setPendingGate('depth_verification');
|
|
308
305
|
|
|
309
306
|
// No milestoneId and no queue phase — still block because the gate is pending
|
|
310
307
|
const result = shouldBlockPendingGate('write', null, false);
|
|
@@ -330,7 +327,7 @@ test('write-gate: shouldBlockPendingGate blocks in queue mode when gate is pendi
|
|
|
330
327
|
|
|
331
328
|
test('write-gate: shouldBlockPendingGateBash allows read-only commands during pending gate', () => {
|
|
332
329
|
clearDiscussionFlowState();
|
|
333
|
-
setPendingGate('
|
|
330
|
+
setPendingGate('depth_verification');
|
|
334
331
|
|
|
335
332
|
assert.strictEqual(shouldBlockPendingGateBash('cat file.txt', 'M001').block, false);
|
|
336
333
|
assert.strictEqual(shouldBlockPendingGateBash('git log --oneline', 'M001').block, false);
|
|
@@ -344,11 +341,11 @@ test('write-gate: shouldBlockPendingGateBash allows read-only commands during pe
|
|
|
344
341
|
|
|
345
342
|
test('write-gate: shouldBlockPendingGateBash blocks mutating commands during pending gate', () => {
|
|
346
343
|
clearDiscussionFlowState();
|
|
347
|
-
setPendingGate('
|
|
344
|
+
setPendingGate('depth_verification');
|
|
348
345
|
|
|
349
346
|
const result = shouldBlockPendingGateBash('npm run build', 'M001');
|
|
350
347
|
assert.strictEqual(result.block, true, 'mutating bash should be blocked');
|
|
351
|
-
assert.ok(result.reason!.includes('
|
|
348
|
+
assert.ok(result.reason!.includes('depth_verification'));
|
|
352
349
|
|
|
353
350
|
clearDiscussionFlowState();
|
|
354
351
|
});
|
|
@@ -365,7 +362,7 @@ test('write-gate: no pending gate means no blocking', () => {
|
|
|
365
362
|
// ─── Scenario 28: resetWriteGateState clears pending gate ──
|
|
366
363
|
|
|
367
364
|
test('write-gate: resetWriteGateState clears pending gate', () => {
|
|
368
|
-
setPendingGate('
|
|
365
|
+
setPendingGate('depth_verification');
|
|
369
366
|
resetWriteGateState();
|
|
370
367
|
assert.strictEqual(getPendingGate(), null);
|
|
371
368
|
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GSD Prompt Validation — Validates enhanced context output before writing.
|
|
3
|
-
*
|
|
4
|
-
* Implements R109 validation requirement: CONTEXT.md must have required sections
|
|
5
|
-
* before being written to disk.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Validate that enhanced context content has all required sections.
|
|
9
|
-
*
|
|
10
|
-
* Required sections per R109:
|
|
11
|
-
* - Scope section (## Scope, ## Milestone Scope, or ## Why This Milestone)
|
|
12
|
-
* - Architectural Decisions section (## Architectural Decisions)
|
|
13
|
-
* - Acceptance Criteria section (## Acceptance Criteria or ## Final Integrated Acceptance)
|
|
14
|
-
*
|
|
15
|
-
* Additionally validates that the Architectural Decisions section contains
|
|
16
|
-
* at least one decision entry (### heading or **Decision marker).
|
|
17
|
-
*
|
|
18
|
-
* @param content - The enhanced context markdown content
|
|
19
|
-
* @returns ValidationResult with valid flag and list of missing sections
|
|
20
|
-
*/
|
|
21
|
-
export function validateEnhancedContext(content) {
|
|
22
|
-
const missing = [];
|
|
23
|
-
// Required section 1: Scope (multiple acceptable header variants)
|
|
24
|
-
const hasScopeSection = /^## Scope\b/m.test(content) ||
|
|
25
|
-
/^## Milestone Scope\b/m.test(content) ||
|
|
26
|
-
/^## Why This Milestone\b/m.test(content);
|
|
27
|
-
if (!hasScopeSection) {
|
|
28
|
-
missing.push("Milestone Scope or Why This Milestone");
|
|
29
|
-
}
|
|
30
|
-
// Required section 2: Architectural Decisions
|
|
31
|
-
const hasArchitecturalDecisions = /^## Architectural Decisions\b/m.test(content);
|
|
32
|
-
if (!hasArchitecturalDecisions) {
|
|
33
|
-
missing.push("Architectural Decisions");
|
|
34
|
-
}
|
|
35
|
-
// Required section 3: Acceptance Criteria (multiple acceptable header variants)
|
|
36
|
-
const hasAcceptanceCriteria = /^## Acceptance Criteria\b/m.test(content) ||
|
|
37
|
-
/^## Final Integrated Acceptance\b/m.test(content);
|
|
38
|
-
if (!hasAcceptanceCriteria) {
|
|
39
|
-
missing.push("Acceptance Criteria");
|
|
40
|
-
}
|
|
41
|
-
// Additional validation: Architectural Decisions must have at least one entry
|
|
42
|
-
if (hasArchitecturalDecisions) {
|
|
43
|
-
// Extract the section content between ## Architectural Decisions and the next ## heading.
|
|
44
|
-
// Uses indexOf-based extraction instead of regex with \z (which is invalid in JavaScript
|
|
45
|
-
// regex — it's PCRE/Ruby syntax and JS treats it as literal 'z').
|
|
46
|
-
const sectionStart = content.indexOf("## Architectural Decisions");
|
|
47
|
-
if (sectionStart === -1) {
|
|
48
|
-
missing.push("Architectural Decisions");
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
const afterHeading = content.slice(sectionStart + "## Architectural Decisions".length);
|
|
52
|
-
const nextSection = afterHeading.search(/^## /m);
|
|
53
|
-
const sectionContent = nextSection === -1 ? afterHeading : afterHeading.slice(0, nextSection);
|
|
54
|
-
// Check for actual decision entries:
|
|
55
|
-
// - ### heading (subsection per decision)
|
|
56
|
-
// - **Decision marker (inline decision format)
|
|
57
|
-
const hasDecisionEntry = /^### /m.test(sectionContent) || /^\*\*Decision/m.test(sectionContent);
|
|
58
|
-
if (!hasDecisionEntry) {
|
|
59
|
-
missing.push("At least one architectural decision entry");
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
valid: missing.length === 0,
|
|
65
|
-
missing,
|
|
66
|
-
};
|
|
67
|
-
}
|