@specship/specship-win32-arm64 0.25.0 → 0.29.0

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.
Files changed (305) hide show
  1. package/bin/specship.cmd +31 -1
  2. package/lib/dist/activation/cheatsheet.d.ts +17 -1
  3. package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
  4. package/lib/dist/activation/cheatsheet.js +47 -3
  5. package/lib/dist/activation/cheatsheet.js.map +1 -1
  6. package/lib/dist/activation/hook-output.d.ts +80 -0
  7. package/lib/dist/activation/hook-output.d.ts.map +1 -0
  8. package/lib/dist/activation/hook-output.js +103 -0
  9. package/lib/dist/activation/hook-output.js.map +1 -0
  10. package/lib/dist/activation/search-intercept.d.ts +60 -29
  11. package/lib/dist/activation/search-intercept.d.ts.map +1 -1
  12. package/lib/dist/activation/search-intercept.js +159 -55
  13. package/lib/dist/activation/search-intercept.js.map +1 -1
  14. package/lib/dist/activation/steering.d.ts +8 -10
  15. package/lib/dist/activation/steering.d.ts.map +1 -1
  16. package/lib/dist/activation/steering.js +21 -6
  17. package/lib/dist/activation/steering.js.map +1 -1
  18. package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
  19. package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
  20. package/lib/dist/behaviour/behaviour-surface.js +108 -2
  21. package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
  22. package/lib/dist/bin/node-version-check.d.ts +22 -7
  23. package/lib/dist/bin/node-version-check.d.ts.map +1 -1
  24. package/lib/dist/bin/node-version-check.js +39 -9
  25. package/lib/dist/bin/node-version-check.js.map +1 -1
  26. package/lib/dist/bin/specship.js +799 -81
  27. package/lib/dist/bin/specship.js.map +1 -1
  28. package/lib/dist/commands/specship/learn.md +22 -0
  29. package/lib/dist/commands/specship/spec.md +19 -1
  30. package/lib/dist/db/sqlite-adapter.d.ts +7 -5
  31. package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
  32. package/lib/dist/db/sqlite-adapter.js +11 -9
  33. package/lib/dist/db/sqlite-adapter.js.map +1 -1
  34. package/lib/dist/design-md/check.d.ts +51 -0
  35. package/lib/dist/design-md/check.d.ts.map +1 -0
  36. package/lib/dist/design-md/check.js +335 -0
  37. package/lib/dist/design-md/check.js.map +1 -0
  38. package/lib/dist/design-md/css.d.ts +40 -0
  39. package/lib/dist/design-md/css.d.ts.map +1 -0
  40. package/lib/dist/design-md/css.js +224 -0
  41. package/lib/dist/design-md/css.js.map +1 -0
  42. package/lib/dist/design-md/extract.d.ts +84 -0
  43. package/lib/dist/design-md/extract.d.ts.map +1 -0
  44. package/lib/dist/design-md/extract.js +595 -0
  45. package/lib/dist/design-md/extract.js.map +1 -0
  46. package/lib/dist/design-md/maintain.d.ts +45 -0
  47. package/lib/dist/design-md/maintain.d.ts.map +1 -0
  48. package/lib/dist/design-md/maintain.js +127 -0
  49. package/lib/dist/design-md/maintain.js.map +1 -0
  50. package/lib/dist/design-md/render.d.ts +28 -0
  51. package/lib/dist/design-md/render.d.ts.map +1 -0
  52. package/lib/dist/design-md/render.js +178 -0
  53. package/lib/dist/design-md/render.js.map +1 -0
  54. package/lib/dist/design-md/upkeep.d.ts +48 -0
  55. package/lib/dist/design-md/upkeep.d.ts.map +1 -0
  56. package/lib/dist/design-md/upkeep.js +169 -0
  57. package/lib/dist/design-md/upkeep.js.map +1 -0
  58. package/lib/dist/design-md/verify.d.ts +65 -0
  59. package/lib/dist/design-md/verify.d.ts.map +1 -0
  60. package/lib/dist/design-md/verify.js +311 -0
  61. package/lib/dist/design-md/verify.js.map +1 -0
  62. package/lib/dist/enforce/changed-files.d.ts +11 -0
  63. package/lib/dist/enforce/changed-files.d.ts.map +1 -1
  64. package/lib/dist/enforce/changed-files.js +42 -0
  65. package/lib/dist/enforce/changed-files.js.map +1 -1
  66. package/lib/dist/enforce/enforce.d.ts +25 -1
  67. package/lib/dist/enforce/enforce.d.ts.map +1 -1
  68. package/lib/dist/enforce/enforce.js +58 -3
  69. package/lib/dist/enforce/enforce.js.map +1 -1
  70. package/lib/dist/enforce/mutation.d.ts +46 -0
  71. package/lib/dist/enforce/mutation.d.ts.map +1 -0
  72. package/lib/dist/enforce/mutation.js +104 -0
  73. package/lib/dist/enforce/mutation.js.map +1 -0
  74. package/lib/dist/enforce/suppressions.d.ts +33 -0
  75. package/lib/dist/enforce/suppressions.d.ts.map +1 -0
  76. package/lib/dist/enforce/suppressions.js +159 -0
  77. package/lib/dist/enforce/suppressions.js.map +1 -0
  78. package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
  79. package/lib/dist/extraction/specs/markdown-spec-extractor.js +16 -2
  80. package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
  81. package/lib/dist/graph/spec-coverage.d.ts +57 -1
  82. package/lib/dist/graph/spec-coverage.d.ts.map +1 -1
  83. package/lib/dist/graph/spec-coverage.js +129 -5
  84. package/lib/dist/graph/spec-coverage.js.map +1 -1
  85. package/lib/dist/health/smoke-check.js +2 -2
  86. package/lib/dist/health/smoke-check.js.map +1 -1
  87. package/lib/dist/index.d.ts +8 -3
  88. package/lib/dist/index.d.ts.map +1 -1
  89. package/lib/dist/index.js +65 -9
  90. package/lib/dist/index.js.map +1 -1
  91. package/lib/dist/installer/gemini-commands.d.ts +107 -0
  92. package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
  93. package/lib/dist/installer/gemini-commands.js +271 -0
  94. package/lib/dist/installer/gemini-commands.js.map +1 -0
  95. package/lib/dist/installer/index.d.ts +23 -1
  96. package/lib/dist/installer/index.d.ts.map +1 -1
  97. package/lib/dist/installer/index.js +22 -3
  98. package/lib/dist/installer/index.js.map +1 -1
  99. package/lib/dist/installer/install-defaults.d.ts +19 -0
  100. package/lib/dist/installer/install-defaults.d.ts.map +1 -1
  101. package/lib/dist/installer/install-defaults.js +28 -0
  102. package/lib/dist/installer/install-defaults.js.map +1 -1
  103. package/lib/dist/installer/instructions-template.d.ts +22 -0
  104. package/lib/dist/installer/instructions-template.d.ts.map +1 -1
  105. package/lib/dist/installer/instructions-template.js +37 -1
  106. package/lib/dist/installer/instructions-template.js.map +1 -1
  107. package/lib/dist/installer/targets/claude.d.ts +5 -1
  108. package/lib/dist/installer/targets/claude.d.ts.map +1 -1
  109. package/lib/dist/installer/targets/claude.js +15 -27
  110. package/lib/dist/installer/targets/claude.js.map +1 -1
  111. package/lib/dist/installer/targets/gemini.d.ts +85 -12
  112. package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
  113. package/lib/dist/installer/targets/gemini.js +527 -30
  114. package/lib/dist/installer/targets/gemini.js.map +1 -1
  115. package/lib/dist/installer/targets/shared.d.ts +13 -0
  116. package/lib/dist/installer/targets/shared.d.ts.map +1 -1
  117. package/lib/dist/installer/targets/shared.js +18 -0
  118. package/lib/dist/installer/targets/shared.js.map +1 -1
  119. package/lib/dist/installer/targets/types.d.ts +12 -0
  120. package/lib/dist/installer/targets/types.d.ts.map +1 -1
  121. package/lib/dist/jira/auto-publish.d.ts +71 -4
  122. package/lib/dist/jira/auto-publish.d.ts.map +1 -1
  123. package/lib/dist/jira/auto-publish.js +186 -17
  124. package/lib/dist/jira/auto-publish.js.map +1 -1
  125. package/lib/dist/jira/reconcile.d.ts +24 -1
  126. package/lib/dist/jira/reconcile.d.ts.map +1 -1
  127. package/lib/dist/jira/reconcile.js +46 -2
  128. package/lib/dist/jira/reconcile.js.map +1 -1
  129. package/lib/dist/jira/repo-config.d.ts +9 -0
  130. package/lib/dist/jira/repo-config.d.ts.map +1 -1
  131. package/lib/dist/jira/repo-config.js +11 -0
  132. package/lib/dist/jira/repo-config.js.map +1 -1
  133. package/lib/dist/jira/types.d.ts +7 -0
  134. package/lib/dist/jira/types.d.ts.map +1 -1
  135. package/lib/dist/jira/types.js.map +1 -1
  136. package/lib/dist/knowledge/enforce.d.ts +75 -0
  137. package/lib/dist/knowledge/enforce.d.ts.map +1 -0
  138. package/lib/dist/knowledge/enforce.js +250 -0
  139. package/lib/dist/knowledge/enforce.js.map +1 -0
  140. package/lib/dist/knowledge/facts.d.ts +33 -0
  141. package/lib/dist/knowledge/facts.d.ts.map +1 -0
  142. package/lib/dist/knowledge/facts.js +117 -0
  143. package/lib/dist/knowledge/facts.js.map +1 -0
  144. package/lib/dist/knowledge/proposals.d.ts +88 -0
  145. package/lib/dist/knowledge/proposals.d.ts.map +1 -0
  146. package/lib/dist/knowledge/proposals.js +360 -0
  147. package/lib/dist/knowledge/proposals.js.map +1 -0
  148. package/lib/dist/knowledge/stale.d.ts +64 -0
  149. package/lib/dist/knowledge/stale.d.ts.map +1 -0
  150. package/lib/dist/knowledge/stale.js +174 -0
  151. package/lib/dist/knowledge/stale.js.map +1 -0
  152. package/lib/dist/mcp/gemini-session.d.ts +50 -0
  153. package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
  154. package/lib/dist/mcp/gemini-session.js +159 -0
  155. package/lib/dist/mcp/gemini-session.js.map +1 -0
  156. package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
  157. package/lib/dist/mcp/jira-tools.js +25 -0
  158. package/lib/dist/mcp/jira-tools.js.map +1 -1
  159. package/lib/dist/mcp/model-context.d.ts +22 -9
  160. package/lib/dist/mcp/model-context.d.ts.map +1 -1
  161. package/lib/dist/mcp/model-context.js +35 -13
  162. package/lib/dist/mcp/model-context.js.map +1 -1
  163. package/lib/dist/mcp/proxy.js +1 -1
  164. package/lib/dist/mcp/proxy.js.map +1 -1
  165. package/lib/dist/mcp/server-instructions.d.ts +16 -15
  166. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  167. package/lib/dist/mcp/server-instructions.js +67 -1
  168. package/lib/dist/mcp/server-instructions.js.map +1 -1
  169. package/lib/dist/mcp/session.js +1 -1
  170. package/lib/dist/mcp/session.js.map +1 -1
  171. package/lib/dist/mcp/spec-tools.d.ts +9 -1
  172. package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
  173. package/lib/dist/mcp/spec-tools.js +69 -21
  174. package/lib/dist/mcp/spec-tools.js.map +1 -1
  175. package/lib/dist/mcp/tools.d.ts +37 -1
  176. package/lib/dist/mcp/tools.d.ts.map +1 -1
  177. package/lib/dist/mcp/tools.js +120 -9
  178. package/lib/dist/mcp/tools.js.map +1 -1
  179. package/lib/dist/pulse/pulse.d.ts +93 -0
  180. package/lib/dist/pulse/pulse.d.ts.map +1 -0
  181. package/lib/dist/pulse/pulse.js +401 -0
  182. package/lib/dist/pulse/pulse.js.map +1 -0
  183. package/lib/dist/reflect/apply.d.ts.map +1 -1
  184. package/lib/dist/reflect/apply.js +38 -3
  185. package/lib/dist/reflect/apply.js.map +1 -1
  186. package/lib/dist/reflect/auto-sweep.d.ts +26 -0
  187. package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
  188. package/lib/dist/reflect/auto-sweep.js +90 -0
  189. package/lib/dist/reflect/auto-sweep.js.map +1 -0
  190. package/lib/dist/reflect/cli.d.ts +62 -0
  191. package/lib/dist/reflect/cli.d.ts.map +1 -0
  192. package/lib/dist/reflect/cli.js +163 -0
  193. package/lib/dist/reflect/cli.js.map +1 -0
  194. package/lib/dist/reflect/miner.d.ts.map +1 -1
  195. package/lib/dist/reflect/miner.js +119 -0
  196. package/lib/dist/reflect/miner.js.map +1 -1
  197. package/lib/dist/reflect/sweep.d.ts +1 -0
  198. package/lib/dist/reflect/sweep.d.ts.map +1 -1
  199. package/lib/dist/reflect/sweep.js +62 -13
  200. package/lib/dist/reflect/sweep.js.map +1 -1
  201. package/lib/dist/reflect/targets.d.ts +2 -0
  202. package/lib/dist/reflect/targets.d.ts.map +1 -1
  203. package/lib/dist/reflect/targets.js +33 -0
  204. package/lib/dist/reflect/targets.js.map +1 -1
  205. package/lib/dist/reflect/types.d.ts +19 -2
  206. package/lib/dist/reflect/types.d.ts.map +1 -1
  207. package/lib/dist/resolution/test-title-links.d.ts.map +1 -1
  208. package/lib/dist/resolution/test-title-links.js +3 -14
  209. package/lib/dist/resolution/test-title-links.js.map +1 -1
  210. package/lib/dist/server/routes/claude.js +15 -7
  211. package/lib/dist/server/routes/knowledge.js +118 -0
  212. package/lib/dist/server/server.js +2 -0
  213. package/lib/dist/skills/design-md/SKILL.md +172 -0
  214. package/lib/dist/skills/design-md/references/authored-sections.md +90 -0
  215. package/lib/dist/skills/design-md/references/sources.md +71 -0
  216. package/lib/dist/spec-lint/lint.d.ts +1 -1
  217. package/lib/dist/spec-lint/lint.d.ts.map +1 -1
  218. package/lib/dist/spec-lint/lint.js +63 -2
  219. package/lib/dist/spec-lint/lint.js.map +1 -1
  220. package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
  221. package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
  222. package/lib/dist/spec-quality/criterion-ids.js +38 -0
  223. package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
  224. package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
  225. package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
  226. package/lib/dist/spec-quality/evidence-kind.js +183 -0
  227. package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
  228. package/lib/dist/spec-quality/link-persist.d.ts +65 -0
  229. package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
  230. package/lib/dist/spec-quality/link-persist.js +249 -0
  231. package/lib/dist/spec-quality/link-persist.js.map +1 -0
  232. package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
  233. package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
  234. package/lib/dist/spec-quality/plan-scope.js +129 -0
  235. package/lib/dist/spec-quality/plan-scope.js.map +1 -0
  236. package/lib/dist/spec-quality/postcheck.d.ts +91 -0
  237. package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
  238. package/lib/dist/spec-quality/postcheck.js +421 -0
  239. package/lib/dist/spec-quality/postcheck.js.map +1 -0
  240. package/lib/dist/spec-quality/readiness.d.ts +72 -0
  241. package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
  242. package/lib/dist/spec-quality/readiness.js +226 -0
  243. package/lib/dist/spec-quality/readiness.js.map +1 -0
  244. package/lib/dist/workflows/agents/claude.d.ts +16 -0
  245. package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
  246. package/lib/dist/workflows/agents/claude.js +82 -0
  247. package/lib/dist/workflows/agents/claude.js.map +1 -0
  248. package/lib/dist/workflows/agents/gemini.d.ts +21 -0
  249. package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
  250. package/lib/dist/workflows/agents/gemini.js +124 -0
  251. package/lib/dist/workflows/agents/gemini.js.map +1 -0
  252. package/lib/dist/workflows/agents/index.d.ts +28 -0
  253. package/lib/dist/workflows/agents/index.d.ts.map +1 -0
  254. package/lib/dist/workflows/agents/index.js +104 -0
  255. package/lib/dist/workflows/agents/index.js.map +1 -0
  256. package/lib/dist/workflows/agents/types.d.ts +55 -0
  257. package/lib/dist/workflows/agents/types.d.ts.map +1 -0
  258. package/lib/dist/workflows/agents/types.js +46 -0
  259. package/lib/dist/workflows/agents/types.js.map +1 -0
  260. package/lib/dist/workflows/batch.d.ts +63 -0
  261. package/lib/dist/workflows/batch.d.ts.map +1 -0
  262. package/lib/dist/workflows/batch.js +151 -0
  263. package/lib/dist/workflows/batch.js.map +1 -0
  264. package/lib/dist/workflows/defaults/claude-design-implement.yaml +37 -9
  265. package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
  266. package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -436
  267. package/lib/dist/workflows/defaults/spec-implement.yaml +481 -46
  268. package/lib/dist/workflows/discovery.d.ts +13 -0
  269. package/lib/dist/workflows/discovery.d.ts.map +1 -1
  270. package/lib/dist/workflows/discovery.js +79 -17
  271. package/lib/dist/workflows/discovery.js.map +1 -1
  272. package/lib/dist/workflows/executor.d.ts +18 -0
  273. package/lib/dist/workflows/executor.d.ts.map +1 -1
  274. package/lib/dist/workflows/executor.js +130 -33
  275. package/lib/dist/workflows/executor.js.map +1 -1
  276. package/lib/dist/workflows/gc.d.ts +50 -0
  277. package/lib/dist/workflows/gc.d.ts.map +1 -0
  278. package/lib/dist/workflows/gc.js +120 -0
  279. package/lib/dist/workflows/gc.js.map +1 -0
  280. package/lib/dist/workflows/merge-queue.d.ts +64 -0
  281. package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
  282. package/lib/dist/workflows/merge-queue.js +162 -0
  283. package/lib/dist/workflows/merge-queue.js.map +1 -0
  284. package/lib/dist/workflows/runners/approval.d.ts +1 -1
  285. package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
  286. package/lib/dist/workflows/runners/approval.js +11 -2
  287. package/lib/dist/workflows/runners/approval.js.map +1 -1
  288. package/lib/dist/workflows/runners/bash.d.ts +15 -0
  289. package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
  290. package/lib/dist/workflows/runners/bash.js +50 -1
  291. package/lib/dist/workflows/runners/bash.js.map +1 -1
  292. package/lib/dist/workflows/runners/prompt.d.ts +16 -41
  293. package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
  294. package/lib/dist/workflows/runners/prompt.js +55 -120
  295. package/lib/dist/workflows/runners/prompt.js.map +1 -1
  296. package/lib/dist/workflows/runners/types.d.ts +12 -0
  297. package/lib/dist/workflows/runners/types.d.ts.map +1 -1
  298. package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
  299. package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
  300. package/lib/dist/workflows/schemas/workflow.js +27 -0
  301. package/lib/dist/workflows/schemas/workflow.js.map +1 -1
  302. package/lib/node_modules/.package-lock.json +1 -1
  303. package/lib/package.json +2 -2
  304. package/package.json +5 -3
  305. package/node.exe +0 -4
@@ -1,24 +1,32 @@
1
1
  "use strict";
2
2
  /**
3
- * Point-of-use search interceptor (STEER-HOOK-DOC, REQ-STEER-004/005).
3
+ * Point-of-use search interceptor (STEER-HOOK-DOC, REQ-STEER-004/005,
4
+ * REQ-GEMINI-011).
4
5
  *
5
6
  * The prompt-level nudge (steering.ts) fires once, at prompt submit, and its
6
7
  * pull decays across a long turn — the observed failure is a search-shaped
7
8
  * tool call made many tool-calls after the nudge. This module is the decision
8
- * logic for the `PreToolUse` hook the installer writes on search tools
9
- * (`specship search-intercept`): deliver the same guidance at the moment of
10
- * the wrong choice.
9
+ * logic for the hook the installer writes on each host's search tools
10
+ * (Claude: PreToolUse on Grep/Glob; Gemini: BeforeTool on grep_search / glob /
11
+ * run_shell_command): deliver the same guidance at the moment of the wrong
12
+ * choice.
11
13
  *
12
- * Two properties are non-negotiable:
14
+ * Two modes exist:
13
15
  *
14
- * - ADVISORY (REQ-STEER-004): the emitted text is `additionalContext`,
15
- * never a permission decision. A search the index cannot answer is a
16
- * legitimate search; a wrong denial costs the agent a turn — the very
17
- * failure this feature exists to reduce.
18
- * - SELF-SILENCING (REQ-STEER-005): at most one line per session, and only
19
- * when the session has made zero specship tool calls. Firing on every
20
- * search would make the hook noise, and noise is what taught the agent to
21
- * ignore the prompt-level nudge.
16
+ * - ADVISORY (default, both hosts, REQ-STEER-004/005): emit a one-line
17
+ * `additionalContext` redirect. At most once per session, silent once the
18
+ * session has used specship. The search still runs.
19
+ * - STRICT (Gemini-only opt-in, REQ-GEMINI-011): for a built-in search tool
20
+ * (`grep_search`, `glob`) in an indexed project, emit a top-level
21
+ * `{decision:'deny'}` with a reason naming `specship_explore`. A
22
+ * search-shaped `run_shell_command` NEVER denies — Gemini's hook runs
23
+ * after the user's shell confirmation, so denying it would make the user
24
+ * approve a command and then see it blocked. Parse-failure / unindexed
25
+ * project / already-using-specship → ALLOW.
26
+ *
27
+ * Shared code stays agent-agnostic: this file never sniffs `hook_event_name`
28
+ * or tool-name prefixes. The caller (bin/specship) hands in host traits
29
+ * derived in the hook I/O adapter (`activation/hook-output.ts`).
22
30
  */
23
31
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
32
  if (k2 === undefined) k2 = k;
@@ -56,16 +64,18 @@ var __importStar = (this && this.__importStar) || (function () {
56
64
  Object.defineProperty(exports, "__esModule", { value: true });
57
65
  exports.SEARCH_INTERCEPT_TEXT = void 0;
58
66
  exports.interceptStatePath = interceptStatePath;
67
+ exports.classifyShellCommand = classifyShellCommand;
59
68
  exports.buildSearchIntercept = buildSearchIntercept;
60
69
  const fs = __importStar(require("fs"));
61
70
  const path = __importStar(require("path"));
62
71
  const runtime_settings_1 = require("../config/runtime-settings");
72
+ const hook_output_1 = require("./hook-output");
63
73
  /**
64
74
  * The one redirect line. Explicitly advisory ("your search still runs") so
65
75
  * the model doesn't treat it as a rejection of the call it just made.
66
76
  */
67
77
  exports.SEARCH_INTERCEPT_TEXT = 'SpecShip: this project has an indexed code graph. For finding or understanding code, ' +
68
- 'mcp__specship__specship_explore with the relevant symbol/file names usually answers in ' +
78
+ 'specship_explore with the relevant symbol/file names usually answers in ' +
69
79
  'ONE call and returns the verbatim source. Your search still runs — reach for explore ' +
70
80
  'on the next lookup.';
71
81
  /** Per-session tracking file, kept inside the project's own `.specship/`. */
@@ -91,7 +101,6 @@ function readState(file) {
91
101
  return {};
92
102
  }
93
103
  }
94
- /** Best-effort write with TTL pruning; a failed write must never fail the hook. */
95
104
  function writeState(file, state, now) {
96
105
  try {
97
106
  const pruned = {};
@@ -106,18 +115,7 @@ function writeState(file, state, now) {
106
115
  /* state is an optimization; losing it only risks one extra advisory line */
107
116
  }
108
117
  }
109
- /**
110
- * Whether the session's transcript shows any specship tool USE. A transcript
111
- * record must be an actual `tool_use` naming a specship tool — a bare
112
- * mention of a tool name is NOT use: transcripts routinely carry the full
113
- * tool listing (`deferred_tools_delta` attachments, skill listings), so a
114
- * substring test alone silences the hook in every session where specship is
115
- * merely INSTALLED (found live in the REQ-STEER-006 A/B — the interceptor
116
- * never fired). Reads at most the trailing 4 MB — usage anywhere counts, but
117
- * a huge transcript must not blow the hook's latency budget, and a false
118
- * negative costs one harmless advisory line.
119
- */
120
- function transcriptUsedSpecship(transcriptPath) {
118
+ function scanTranscript(transcriptPath, markers, format) {
121
119
  const MAX_SCAN_BYTES = 4 * 1024 * 1024;
122
120
  let text;
123
121
  try {
@@ -125,7 +123,7 @@ function transcriptUsedSpecship(transcriptPath) {
125
123
  if (stat.size <= MAX_SCAN_BYTES) {
126
124
  text = fs.readFileSync(transcriptPath, 'utf-8');
127
125
  }
128
- else {
126
+ else if (format === 'jsonl') {
129
127
  const fd = fs.openSync(transcriptPath, 'r');
130
128
  try {
131
129
  const buf = Buffer.alloc(MAX_SCAN_BYTES);
@@ -136,38 +134,120 @@ function transcriptUsedSpecship(transcriptPath) {
136
134
  fs.closeSync(fd);
137
135
  }
138
136
  }
137
+ else {
138
+ // single-json needs a full read to parse; a huge transcript can't be
139
+ // reliably scanned → treat as parse-failure (ALLOW in strict).
140
+ return 'parse-failure';
141
+ }
139
142
  }
140
143
  catch {
141
- return false;
144
+ return format === 'single-json' ? 'parse-failure' : 'not-used';
142
145
  }
143
- // One JSONL record per line; a specship tool_use block puts both markers on
144
- // the same record. Cheap two-substring test — no JSON.parse per line.
145
- for (const line of text.split('\n')) {
146
- if (line.includes('"type":"tool_use"') && line.includes('"name":"mcp__specship__')) {
147
- return true;
146
+ if (format === 'jsonl') {
147
+ for (const line of text.split('\n')) {
148
+ if (line.includes('"type":"tool_use"') && markers.some((m) => line.includes(m))) {
149
+ return 'used';
150
+ }
148
151
  }
152
+ return 'not-used';
153
+ }
154
+ // single-json: Gemini CLI's ChatRecordingService writes one pretty-printed
155
+ // JSON doc with `messages[].toolCalls[].name`. Parse once, iterate names.
156
+ let doc;
157
+ try {
158
+ doc = JSON.parse(text);
149
159
  }
150
- return false;
160
+ catch {
161
+ return 'parse-failure';
162
+ }
163
+ const messages = doc?.messages;
164
+ if (!Array.isArray(messages))
165
+ return 'not-used';
166
+ for (const m of messages) {
167
+ const calls = m?.toolCalls;
168
+ if (!Array.isArray(calls))
169
+ continue;
170
+ for (const c of calls) {
171
+ const name = c?.name;
172
+ if (typeof name === 'string') {
173
+ // Gemini records the function name the model called, which for an
174
+ // MCP tool is its bare name (`specship_explore`); the composite
175
+ // `specship__<tool>` form appears only when a name collision forces
176
+ // qualification (verified in 0.28.0 DiscoveredMCPTool). `specship_`
177
+ // covers both; tolerate the Claude form if a transcript carries it.
178
+ if (name.startsWith('specship_') || name.startsWith(hook_output_1.CLAUDE_CODE_TRAITS.toolPrefix)) {
179
+ return 'used';
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return 'not-used';
151
185
  }
152
186
  /**
153
- * Decide whether to emit the redirect line for one intercepted search call.
154
- *
155
- * Silence gates, in order (all REQ-STEER-004.A3 / REQ-STEER-005):
156
- * 1. `SPECSHIP_NO_STEERING=1` (env > project > install settings) — same
157
- * opt-out as the prompt nudge.
158
- * 2. No `.specship/` directory at cwd — uninitialized projects get zero
159
- * noise.
160
- * 3. No session id — nothing to key the once-per-session guarantee on, so
161
- * silence beats repeat-firing.
162
- * 4. The session is already recorded — it fired before, or was seen using
163
- * specship.
164
- * 5. The transcript shows specship use — the agent doesn't need redirecting;
165
- * record the session so later calls skip the scan.
187
+ * Classify a shell command string for intercept purposes. We ONLY look at the
188
+ * first pipeline segment: `npm test | grep FAIL` uses grep as a FILTER on
189
+ * another command's output and must not be nudged, while `rg "renderScene"
190
+ * src/` is the lookup we care about. Read-shaped programs (`cat`, `head`,
191
+ * `tail`, `sed -n`, …) are never classified `search` — reading a config or
192
+ * log is legitimate.
193
+ */
194
+ function classifyShellCommand(cmd) {
195
+ const first = firstPipelineSegment(cmd).trim();
196
+ if (!first)
197
+ return 'other';
198
+ const tokens = first.split(/\s+/);
199
+ const t0 = tokens[0] ?? '';
200
+ const t1 = tokens[1] ?? '';
201
+ const SEARCH_TOOLS = new Set(['grep', 'rg', 'ag', 'ack', 'fd', 'find']);
202
+ if (SEARCH_TOOLS.has(t0))
203
+ return 'search';
204
+ if (t0 === 'git' && t1 === 'grep')
205
+ return 'search';
206
+ return 'other';
207
+ }
208
+ /** Return the first `|`/`&&`/`;` separated segment, respecting simple quotes. */
209
+ function firstPipelineSegment(cmd) {
210
+ let quote = null;
211
+ for (let i = 0; i < cmd.length; i++) {
212
+ const c = cmd[i];
213
+ if (quote) {
214
+ if (c === quote && cmd[i - 1] !== '\\')
215
+ quote = null;
216
+ continue;
217
+ }
218
+ if (c === '"' || c === "'") {
219
+ quote = c;
220
+ continue;
221
+ }
222
+ if (c === '|' || c === ';')
223
+ return cmd.slice(0, i);
224
+ if (c === '&' && cmd[i + 1] === '&')
225
+ return cmd.slice(0, i);
226
+ }
227
+ return cmd;
228
+ }
229
+ function denyReason(pattern) {
230
+ const trimmed = pattern ? pattern.trim() : '';
231
+ const named = trimmed ? ` naming ${JSON.stringify(trimmed.slice(0, 80))}` : '';
232
+ return (`SpecShip: this project has an indexed code graph. Call specship_explore${named} ` +
233
+ 'instead — it returns the verbatim source in one call. If the index cannot ' +
234
+ 'answer the question, ask the user and retry.');
235
+ }
236
+ /**
237
+ * Decide what to emit for one intercepted search call.
166
238
  *
167
- * Otherwise: record the session and return the line (fires exactly once).
239
+ * Order:
240
+ * 1. `SPECSHIP_NO_STEERING=1` → ALLOW (silent).
241
+ * 2. No `.specship/` at cwd → ALLOW.
242
+ * 3. Shell runner: classify; `other` → ALLOW; `search` → advisory path
243
+ * only (never deny, REQ-GEMINI-011.A3).
244
+ * 4. Strict + denyEligible: parse transcript; `used` or `parse-failure` or
245
+ * no transcript path → ALLOW; `not-used` → DENY with reason.
246
+ * 5. Otherwise advisory: once-per-session, silent in sessions already using
247
+ * specship (REQ-STEER-005).
168
248
  */
169
249
  function buildSearchIntercept(input) {
170
- const { cwd, sessionId, transcriptPath, env = process.env, homedir, now = new Date() } = input;
250
+ const { cwd, sessionId, transcriptPath, env = process.env, homedir, now = new Date(), specshipToolMarkers = hook_output_1.CLAUDE_CODE_TRAITS.specshipToolMarkers, transcriptFormat = 'jsonl', strict = false, denyEligible = false, shellCommand = null, searchPattern = null, } = input;
171
251
  if ((0, runtime_settings_1.resolveSetting)('SPECSHIP_NO_STEERING', cwd, env, homedir) === '1')
172
252
  return null;
173
253
  try {
@@ -177,6 +257,22 @@ function buildSearchIntercept(input) {
177
257
  catch {
178
258
  return null;
179
259
  }
260
+ // Shell runner — strict is NEVER applied here. Non-search shell commands
261
+ // pass through silently; search-shaped ones fall into the advisory path.
262
+ if (shellCommand !== null) {
263
+ if (classifyShellCommand(shellCommand) !== 'search')
264
+ return null;
265
+ }
266
+ // Strict deny path: built-in search tools only, never shell.
267
+ if (strict && denyEligible && shellCommand === null) {
268
+ if (!transcriptPath)
269
+ return null;
270
+ const scan = scanTranscript(transcriptPath, specshipToolMarkers, transcriptFormat);
271
+ if (scan !== 'not-used')
272
+ return null;
273
+ return { decision: 'deny', reason: denyReason(searchPattern) };
274
+ }
275
+ // Advisory path.
180
276
  if (!sessionId)
181
277
  return null;
182
278
  const stateFile = interceptStatePath(cwd);
@@ -184,12 +280,20 @@ function buildSearchIntercept(input) {
184
280
  if (state[sessionId])
185
281
  return null;
186
282
  state[sessionId] = { at: now.toISOString() };
187
- if (transcriptPath && transcriptUsedSpecship(transcriptPath)) {
188
- // Already an index user — silence, but remember so we don't rescan.
189
- writeState(stateFile, state, now);
190
- return null;
283
+ if (transcriptPath) {
284
+ const scan = scanTranscript(transcriptPath, specshipToolMarkers, transcriptFormat);
285
+ if (scan === 'used') {
286
+ writeState(stateFile, state, now);
287
+ return null;
288
+ }
289
+ // Gemini parse-failure fails toward silence in advisory mode (spec
290
+ // REQ-GEMINI-011); Claude JSONL never returns parse-failure.
291
+ if (scan === 'parse-failure' && transcriptFormat === 'single-json') {
292
+ writeState(stateFile, state, now);
293
+ return null;
294
+ }
191
295
  }
192
296
  writeState(stateFile, state, now);
193
- return exports.SEARCH_INTERCEPT_TEXT;
297
+ return { additionalContext: exports.SEARCH_INTERCEPT_TEXT };
194
298
  }
195
299
  //# sourceMappingURL=search-intercept.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-intercept.js","sourceRoot":"","sources":["../../src/activation/search-intercept.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-intercept.js","sourceRoot":"","sources":["../../src/activation/search-intercept.ts"],"names":[],"mappings":"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"}
@@ -11,17 +11,15 @@
11
11
  * hook (REQ-STEER-001) whose command is `specship steer-nudge`.
12
12
  */
13
13
  /**
14
- * The one steering line injected per prompt. Kept short (~40 tokens) — it is
15
- * added to EVERY prompt in an initialized project, so brevity is the cost
16
- * ceiling. Wording is A/B-gated before default-on release (REQ-STEER-003).
14
+ * Render a steering template with the calling host's tool-name form
15
+ * (AGENTADAPT-DOC, REQ-AGENTADAPT-001): Claude Code calls the tool
16
+ * `mcp__specship__specship_explore`, Gemini CLI calls it `specship_explore`.
17
+ * The prefix comes from the hook adapter — this module never names a host.
17
18
  */
19
+ export declare function renderSteering(template: string, toolPrefix: string): string;
20
+ /** The standard line as Claude Code (the legacy default host) receives it. */
18
21
  export declare const STEERING_TEXT: string;
19
- /**
20
- * The lite-tier template (LOWMODEL-DOC, REQ-LOWMODEL-002): small models
21
- * follow prescriptive templates far better than principles, and fan-out
22
- * (subagents) multiplies their cost and confusion. Kept under ~80 tokens
23
- * (REQ-LOWMODEL-002.A2).
24
- */
22
+ /** The lite line as Claude Code (the legacy default host) receives it. */
25
23
  export declare const STEERING_TEXT_LITE: string;
26
24
  /**
27
25
  * Decide whether to emit the steering line (REQ-STEER-002): silent unless the
@@ -31,5 +29,5 @@ export declare const STEERING_TEXT_LITE: string;
31
29
  * lite-tier sessions get the prescriptive template; standard and frontier keep
32
30
  * the standard line.
33
31
  */
34
- export declare function buildSteeringNudge(cwd: string, env?: NodeJS.ProcessEnv, homedir?: string): string | null;
32
+ export declare function buildSteeringNudge(cwd: string, env?: NodeJS.ProcessEnv, homedir?: string, toolPrefix?: string): string | null;
35
33
  //# sourceMappingURL=steering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"steering.d.ts","sourceRoot":"","sources":["../../src/activation/steering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH;;;;GAIG;AACH,eAAO,MAAM,aAAa,QAKJ,CAAC;AAEvB;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAIsC,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAUf"}
1
+ {"version":3,"file":"steering.d.ts","sourceRoot":"","sources":["../../src/activation/steering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,8EAA8E;AAC9E,eAAO,MAAM,aAAa,QAAmE,CAAC;AAc9F,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,QAAwE,CAAC;AAExG;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,GAAE,MAAsC,GACjD,MAAM,GAAG,IAAI,CAaf"}
@@ -46,31 +46,46 @@ var __importStar = (this && this.__importStar) || (function () {
46
46
  })();
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.STEERING_TEXT_LITE = exports.STEERING_TEXT = void 0;
49
+ exports.renderSteering = renderSteering;
49
50
  exports.buildSteeringNudge = buildSteeringNudge;
50
51
  const fs = __importStar(require("fs"));
51
52
  const path = __importStar(require("path"));
52
53
  const model_context_1 = require("../mcp/model-context");
53
54
  const runtime_settings_1 = require("../config/runtime-settings");
55
+ const hook_output_1 = require("./hook-output");
54
56
  /**
55
57
  * The one steering line injected per prompt. Kept short (~40 tokens) — it is
56
58
  * added to EVERY prompt in an initialized project, so brevity is the cost
57
59
  * ceiling. Wording is A/B-gated before default-on release (REQ-STEER-003).
58
60
  */
59
- exports.STEERING_TEXT = 'This project has a SpecShip code-graph index. Before reading or editing ANY ' +
61
+ const STEERING_TEMPLATE = 'This project has a SpecShip code-graph index. Before reading or editing ANY ' +
60
62
  'code for a task — understanding, implementing, fixing, refactoring — call ' +
61
- 'mcp__specship__specship_explore with the relevant symbol/file names FIRST. ' +
63
+ '{explore} with the relevant symbol/file names FIRST. ' +
62
64
  'Treat the source it returns as already read; use Read/Grep only for content ' +
63
65
  'it did not return.';
66
+ /**
67
+ * Render a steering template with the calling host's tool-name form
68
+ * (AGENTADAPT-DOC, REQ-AGENTADAPT-001): Claude Code calls the tool
69
+ * `mcp__specship__specship_explore`, Gemini CLI calls it `specship_explore`.
70
+ * The prefix comes from the hook adapter — this module never names a host.
71
+ */
72
+ function renderSteering(template, toolPrefix) {
73
+ return template.replace('{explore}', `${toolPrefix}specship_explore`);
74
+ }
75
+ /** The standard line as Claude Code (the legacy default host) receives it. */
76
+ exports.STEERING_TEXT = renderSteering(STEERING_TEMPLATE, hook_output_1.CLAUDE_CODE_TRAITS.toolPrefix);
64
77
  /**
65
78
  * The lite-tier template (LOWMODEL-DOC, REQ-LOWMODEL-002): small models
66
79
  * follow prescriptive templates far better than principles, and fan-out
67
80
  * (subagents) multiplies their cost and confusion. Kept under ~80 tokens
68
81
  * (REQ-LOWMODEL-002.A2).
69
82
  */
70
- exports.STEERING_TEXT_LITE = 'This project has a SpecShip index. For any code question, call exactly: ' +
71
- 'mcp__specship__specship_explore with the symbol/file names from the question. ' +
83
+ const STEERING_TEMPLATE_LITE = 'This project has a SpecShip index. For any code question, call exactly: ' +
84
+ '{explore} with the symbol/file names from the question. ' +
72
85
  'ONE call, then answer from its output — the source it returns is already read. ' +
73
86
  'Do not spawn subagents. Do not Read/Grep files the tool returned.';
87
+ /** The lite line as Claude Code (the legacy default host) receives it. */
88
+ exports.STEERING_TEXT_LITE = renderSteering(STEERING_TEMPLATE_LITE, hook_output_1.CLAUDE_CODE_TRAITS.toolPrefix);
74
89
  /**
75
90
  * Decide whether to emit the steering line (REQ-STEER-002): silent unless the
76
91
  * project is initialized (`.specship/` exists at cwd), and silent when the
@@ -79,7 +94,7 @@ exports.STEERING_TEXT_LITE = 'This project has a SpecShip index. For any code qu
79
94
  * lite-tier sessions get the prescriptive template; standard and frontier keep
80
95
  * the standard line.
81
96
  */
82
- function buildSteeringNudge(cwd, env = process.env, homedir) {
97
+ function buildSteeringNudge(cwd, env = process.env, homedir, toolPrefix = hook_output_1.CLAUDE_CODE_TRAITS.toolPrefix) {
83
98
  // RUNSET-DOC: the opt-out resolves env > project .specship/settings.json >
84
99
  // ~/.specship/settings.json, so a repo can silence steering durably.
85
100
  if ((0, runtime_settings_1.resolveSetting)('SPECSHIP_NO_STEERING', cwd, env, homedir) === '1')
@@ -91,6 +106,6 @@ function buildSteeringNudge(cwd, env = process.env, homedir) {
91
106
  catch {
92
107
  return null;
93
108
  }
94
- return (0, model_context_1.detectModelTier)(cwd, env, homedir) === 'lite' ? exports.STEERING_TEXT_LITE : exports.STEERING_TEXT;
109
+ return renderSteering((0, model_context_1.detectModelTier)(cwd, env, homedir) === 'lite' ? STEERING_TEMPLATE_LITE : STEERING_TEMPLATE, toolPrefix);
95
110
  }
96
111
  //# sourceMappingURL=steering.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"steering.js","sourceRoot":"","sources":["../../src/activation/steering.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCH,gDAcC;AAnDD,uCAAyB;AACzB,2CAA6B;AAC7B,wDAAuD;AACvD,iEAA4D;AAE5D;;;;GAIG;AACU,QAAA,aAAa,GACxB,8EAA8E;IAC9E,4EAA4E;IAC5E,6EAA6E;IAC7E,8EAA8E;IAC9E,oBAAoB,CAAC;AAEvB;;;;;GAKG;AACU,QAAA,kBAAkB,GAC7B,0EAA0E;IAC1E,gFAAgF;IAChF,iFAAiF;IACjF,mEAAmE,CAAC;AAEtE;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,GAAW,EACX,MAAyB,OAAO,CAAC,GAAG,EACpC,OAAgB;IAEhB,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,IAAA,iCAAc,EAAC,sBAAsB,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAA,+BAAe,EAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,0BAAkB,CAAC,CAAC,CAAC,qBAAa,CAAC;AAC5F,CAAC"}
1
+ {"version":3,"file":"steering.js","sourceRoot":"","sources":["../../src/activation/steering.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,wCAEC;AA4BD,gDAkBC;AAxED,uCAAyB;AACzB,2CAA6B;AAC7B,wDAAuD;AACvD,iEAA4D;AAC5D,+CAAmD;AAEnD;;;;GAIG;AACH,MAAM,iBAAiB,GACrB,8EAA8E;IAC9E,4EAA4E;IAC5E,uDAAuD;IACvD,8EAA8E;IAC9E,oBAAoB,CAAC;AAEvB;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,QAAgB,EAAE,UAAkB;IACjE,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,UAAU,kBAAkB,CAAC,CAAC;AACxE,CAAC;AAED,8EAA8E;AACjE,QAAA,aAAa,GAAG,cAAc,CAAC,iBAAiB,EAAE,gCAAkB,CAAC,UAAU,CAAC,CAAC;AAE9F;;;;;GAKG;AACH,MAAM,sBAAsB,GAC1B,0EAA0E;IAC1E,0DAA0D;IAC1D,iFAAiF;IACjF,mEAAmE,CAAC;AAEtE,0EAA0E;AAC7D,QAAA,kBAAkB,GAAG,cAAc,CAAC,sBAAsB,EAAE,gCAAkB,CAAC,UAAU,CAAC,CAAC;AAExG;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,GAAW,EACX,MAAyB,OAAO,CAAC,GAAG,EACpC,OAAgB,EAChB,aAAqB,gCAAkB,CAAC,UAAU;IAElD,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,IAAA,iCAAc,EAAC,sBAAsB,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,cAAc,CACnB,IAAA,+BAAe,EAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,iBAAiB,EAC1F,UAAU,CACX,CAAC;AACJ,CAAC"}
@@ -25,6 +25,13 @@ export interface BehaviourFlowElement {
25
25
  /** True when the requirement links to this node directly (vs a neighbour). */
26
26
  linkedDirectly: boolean;
27
27
  }
28
+ /** How an acceptance criterion is best tested (REQ-QGATE-001). */
29
+ export type CriterionTestShape = 'example' | 'invariant';
30
+ export interface ClassifiedCriterion {
31
+ id: string;
32
+ text: string;
33
+ testShape: CriterionTestShape;
34
+ }
28
35
  export interface BehaviourSurface {
29
36
  requirementId: string;
30
37
  /** False when the requirement id resolves to no spec (REQ-BEHAVIOUR-001.A4). */
@@ -33,6 +40,18 @@ export interface BehaviourSurface {
33
40
  ui: BehaviourFlowElement[];
34
41
  /** Backend / batch flows — API / job test targets. */
35
42
  backend: BehaviourFlowElement[];
43
+ /** Acceptance criteria classified example|invariant (REQ-QGATE-001.A1). */
44
+ criteria: ClassifiedCriterion[];
45
+ /**
46
+ * Contract-fuzz eligibility (REQ-QGATE-003.A1): a spec whose DIRECT links
47
+ * include `route`-kind nodes describes an API contract and can be fuzzed
48
+ * from the OpenAPI schema. Neighbour routes don't qualify — the fuzz run
49
+ * must target only what the requirement actually links to (A2).
50
+ */
51
+ contractFuzz: {
52
+ eligible: boolean;
53
+ routes: BehaviourFlowElement[];
54
+ };
36
55
  }
37
56
  export interface BehaviourSurfaceDeps {
38
57
  requirementId: string;
@@ -42,7 +61,28 @@ export interface BehaviourSurfaceDeps {
42
61
  linkedNodes: Node[];
43
62
  /** 1-hop caller/callee neighbours of the linked nodes. */
44
63
  neighbourNodes: Node[];
64
+ /** Acceptance criteria (id + bullet text) for shape classification. */
65
+ criteria?: Array<{
66
+ id: string;
67
+ text: string;
68
+ }>;
45
69
  }
70
+ /**
71
+ * Classify a criterion's test shape (REQ-QGATE-001.A1) — deterministic
72
+ * keyword/shape heuristic, no LLM. Invariant cues are universal quantifiers
73
+ * and negative universals ("for all", "every", "never", "always", "MUST
74
+ * NOT"), plus the classic property shapes (round-trip, idempotence,
75
+ * input-independence). Everything else is an example: a concrete
76
+ * stimulus→response pair.
77
+ */
78
+ export declare function classifyCriterionShape(text: string): CriterionTestShape;
79
+ /**
80
+ * The property-testing framework the generated skeleton should use
81
+ * (REQ-QGATE-001.A2), picked from the linked implementation's file types:
82
+ * Python → Hypothesis, everything else (this tool's world is JS/TS) →
83
+ * fast-check.
84
+ */
85
+ export declare function propertyFramework(linkedNodes: Node[]): string;
46
86
  /** A node is UI when it's a component or lives in a front-end file. */
47
87
  export declare function isUiNode(node: Node): boolean;
48
88
  /**
@@ -54,6 +94,13 @@ export declare function isUiNode(node: Node): boolean;
54
94
  * tier rather than an error (A3).
55
95
  */
56
96
  export declare function computeBehaviourSurface(deps: BehaviourSurfaceDeps): BehaviourSurface;
97
+ /**
98
+ * The reviewable Schemathesis invocation for a route-backed spec
99
+ * (REQ-QGATE-003.A2) — scoped to the linked routes via a path regex, never
100
+ * the whole API. Emitted as text for a human/agent to review and run; this
101
+ * module executes nothing.
102
+ */
103
+ export declare function renderContractFuzzCommand(routes: BehaviourFlowElement[], schemaRef: string): string;
57
104
  /** Render a behaviour surface as markdown for the `specship_spec` response. */
58
105
  export declare function renderBehaviourSurface(surface: BehaviourSurface): string;
59
106
  //# sourceMappingURL=behaviour-surface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"behaviour-surface.d.ts","sourceRoot":"","sources":["../../src/behaviour/behaviour-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAa1C,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,KAAK,EAAE,OAAO,CAAC;IACf,4EAA4E;IAC5E,EAAE,EAAE,oBAAoB,EAAE,CAAC;IAC3B,sDAAsD;IACtD,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,4EAA4E;IAC5E,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,0DAA0D;IAC1D,cAAc,EAAE,IAAI,EAAE,CAAC;CACxB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAE5C;AAYD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAgCpF;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CA+BxE"}
1
+ {"version":3,"file":"behaviour-surface.d.ts","sourceRoot":"","sources":["../../src/behaviour/behaviour-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAa1C,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,WAAW,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,KAAK,EAAE,OAAO,CAAC;IACf,4EAA4E;IAC5E,EAAE,EAAE,oBAAoB,EAAE,CAAC;IAC3B,sDAAsD;IACtD,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;;;OAKG;IACH,YAAY,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,oBAAoB,EAAE,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,4EAA4E;IAC5E,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,0DAA0D;IAC1D,cAAc,EAAE,IAAI,EAAE,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAevE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,MAAM,CAG7D;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAE5C;AAYD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CA6CpF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAanG;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CA0ExE"}