@khoavu882/doflow 2.0.0-beta.4 → 2.0.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 (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -11,7 +11,7 @@ const path = require('node:path');
11
11
  * @param {{ k?: number }} [options]
12
12
  * @returns {Array<{ id: string, rrfScore: number }>}
13
13
  */
14
- function reciprocalRankFusion(rankedLists , { k = 60 } = {}) {
14
+ function reciprocalRankFusion(rankedLists , { k = 60, fullPrecision = false } = {}) {
15
15
  const scores = new Map ();
16
16
  const items = new Map ();
17
17
 
@@ -26,9 +26,7 @@ function reciprocalRankFusion(rankedLists , { k = 60 } =
26
26
  if (!id) continue;
27
27
  const rrf = 1 / (k + rank + 1);
28
28
  scores.set(id, (scores.get(id) || 0) + rrf);
29
- if (!items.has(id)) {
30
- items.set(id, item);
31
- }
29
+ if (!items.has(id)) items.set(id, item);
32
30
  }
33
31
  }
34
32
 
@@ -37,7 +35,7 @@ function reciprocalRankFusion(rankedLists , { k = 60 } =
37
35
  fused.push({
38
36
  ...items.get(id),
39
37
  id,
40
- rrfScore: Number(rrfScore.toFixed(6)),
38
+ rrfScore: fullPrecision ? rrfScore : Number(rrfScore.toFixed(6)),
41
39
  });
42
40
  }
43
41
 
@@ -51,21 +49,22 @@ function reciprocalRankFusion(rankedLists , { k = 60 } =
51
49
  * @param {string} [projectRoot]
52
50
  * @returns {{ file: string, line?: number, endLine?: number }}
53
51
  */
52
+ const slashed = (p ) => p.split(path.sep).join('/');
54
53
  function normalizeLocator(raw , projectRoot = process.cwd()) {
55
54
  if (!raw) return { file: '' };
56
55
  if (typeof raw === 'string') {
57
56
  const match = raw.match(/^([^:]+)(?::(\d+))?(?::(\d+))?$/);
58
57
  if (match) {
59
- const relFile = path.isAbsolute(match[1]) ? path.relative(projectRoot, match[1]) : match[1];
58
+ const relFile = slashed(path.isAbsolute(match[1]) ? path.relative(projectRoot, match[1]) : match[1]);
60
59
  return {
61
60
  file: relFile,
62
61
  ...(match[2] ? { line: parseInt(match[2], 10) } : {}),
63
62
  };
64
63
  }
65
- return { file: path.isAbsolute(raw) ? path.relative(projectRoot, raw) : raw };
64
+ return { file: slashed(path.isAbsolute(raw) ? path.relative(projectRoot, raw) : raw) };
66
65
  }
67
66
  if (typeof raw === 'object' && raw.file) {
68
- const relFile = path.isAbsolute(raw.file) ? path.relative(projectRoot, raw.file) : raw.file;
67
+ const relFile = slashed(path.isAbsolute(raw.file) ? path.relative(projectRoot, raw.file) : raw.file);
69
68
  return {
70
69
  file: relFile,
71
70
  ...(raw.line ? { line: raw.line } : {}),
@@ -142,8 +141,137 @@ function fuseHybridResults({
142
141
  return candidates;
143
142
  }
144
143
 
144
+ /** Strict code candidates are separate from the legacy guidance locator string convention. */
145
+ function normalizeCodeCandidates(items , { projectRoot = process.cwd(), provider, capability, corpusIdentity = '', queryRef = null, retrievalAttemptRef = null } = {}) {
146
+ const { relativeCodePath } = require('./code-corpus.js');
147
+ const candidates = [];
148
+ const rejected = [];
149
+ for (const item of Array.isArray(items) ? items : []) {
150
+ let raw = item?.locator || item?.path || item?.file;
151
+ let loc ;
152
+ if (typeof raw === 'string') {
153
+ const match = /^(.*?):(\d+)(?::(\d+))?$/.exec(raw);
154
+ if (match) loc = { file: match[1], line: Number(match[2]), endLine: Number(match[3] || match[2]) };
155
+ else loc = { file: raw, line: item.startLine ?? item.line ?? 1, endLine: item.endLine ?? item.startLine ?? item.line ?? 1 };
156
+ } else if (raw && typeof raw === 'object') {
157
+ loc = { file: raw.file, line: raw.line ?? raw.startLine ?? 1, endLine: raw.endLine ?? raw.line ?? raw.startLine ?? 1 };
158
+ }
159
+ if (loc && typeof loc.file === 'string' && path.isAbsolute(loc.file)) loc.file = path.relative(projectRoot, loc.file);
160
+ const file = relativeCodePath(loc?.file);
161
+ if (!file || !Number.isInteger(loc.line) || !Number.isInteger(loc.endLine) || loc.line < 1 || loc.endLine < loc.line) {
162
+ rejected.push({ locator: raw ?? null, reason: 'invalid-locator' }); continue;
163
+ }
164
+ loc.file = file;
165
+ const id = JSON.stringify([corpusIdentity, file, loc.line, loc.endLine]);
166
+ const actualProvider = item.provider || provider;
167
+ const actualCapability = item.capability || capability;
168
+ const origin = { provider: actualProvider, capability: actualCapability, queryRef: item.queryRef ?? queryRef,
169
+ retrievalAttemptRef: item.retrievalAttemptRef ?? retrievalAttemptRef,
170
+ originalRank: candidates.length + 1, sourceVersion: item.sourceVersion ?? null };
171
+ const origins = item.origins?.length ? item.origins.map((o ) => ({ ...origin, ...o })) : [origin];
172
+ candidates.push({ ...item, schemaVersion: 1, id, locator: loc, provider: actualProvider, capability: actualCapability, origins });
173
+ }
174
+ return { candidates, rejected };
175
+ }
176
+
177
+ function addOrigins(bucket , origins ) {
178
+ for (const origin of origins) {
179
+ const serialized = JSON.stringify(origin);
180
+ if (!bucket.some((o ) => JSON.stringify(o) === serialized)) bucket.push(origin);
181
+ }
182
+ }
183
+
184
+ /** RRF terms summed in ascending-rank order, so equal rank multisets give bit-identical scores (DEC-016). */
185
+ function rrfSum(ranks , k ) {
186
+ return [...ranks].sort((a, b) => a - b).reduce((sum, rank) => sum + 1 / (k + rank), 0);
187
+ }
188
+
189
+ /**
190
+ * File-grain fusion for conceptual requests with more than one voting provider (IC-006, DEC-025). A provider's
191
+ * rank for a file is its dense rank over distinct files; it votes only within its first `depth` files. Voted
192
+ * files order by capped RRF, then full-depth RRF, then path; files outside every provider's depth form an
193
+ * unscored tail ordered by smallest provider rank, then path. The delivered locator is the widest of each
194
+ * provider's first-ranked span on the file (ties: better provider rank, smaller line, endLine, provider id),
195
+ * always a span some provider returned.
196
+ */
197
+ function fuseByFile(providerLists , { corpusIdentity, k, depth, compareText } ) {
198
+ const files = new Map ();
199
+ for (const [provider, list] of providerLists) {
200
+ let rank = 0;
201
+ for (const item of list) {
202
+ const file = item.locator.file;
203
+ if (!files.has(file)) files.set(file, { votes: [], origins: [] });
204
+ const entry = files.get(file) ;
205
+ if (!entry.votes.some((vote ) => vote.provider === provider)) { rank += 1; entry.votes.push({ provider, rank, item }); }
206
+ const locator = { file, line: item.locator.line, endLine: item.locator.endLine };
207
+ addOrigins(entry.origins, item.origins.map((origin ) => ({ ...origin, locator })));
208
+ }
209
+ }
210
+ const width = (vote ) => vote.item.locator.endLine - vote.item.locator.line;
211
+ const fused = [...files.entries()].map(([file, { votes, origins }]) => {
212
+ const ranks = votes.map((vote ) => vote.rank);
213
+ const [delivered] = [...votes].sort((a , b ) => width(b) - width(a) || a.rank - b.rank
214
+ || a.item.locator.line - b.item.locator.line || a.item.locator.endLine - b.item.locator.endLine || compareText(a.provider, b.provider));
215
+ return { candidate: { ...delivered.item, id: JSON.stringify([corpusIdentity, file]), locator: { ...delivered.item.locator }, origins,
216
+ rrfScore: rrfSum(ranks.filter((rank ) => rank <= depth), k) },
217
+ file, full: rrfSum(ranks, k), best: Math.min(...ranks) };
218
+ });
219
+ fused.sort((a , b ) => {
220
+ const voted = Number(b.candidate.rrfScore > 0) - Number(a.candidate.rrfScore > 0);
221
+ if (voted) return voted;
222
+ if (a.candidate.rrfScore > 0) return b.candidate.rrfScore - a.candidate.rrfScore || b.full - a.full || compareText(a.file, b.file);
223
+ return a.best - b.best || compareText(a.file, b.file);
224
+ });
225
+ return fused.map((entry ) => entry.candidate);
226
+ }
227
+
228
+ /**
229
+ * One vote per provider and identity, all origins retained, full precision until presentation. Span grain
230
+ * (exact requests, single-provider lists) keeps `(corpus identity, file, line, endLine)`; `grain: 'file'`
231
+ * with two or more voting providers fuses by file with vote depth `depth` (IC-006, DEC-025).
232
+ */
233
+ function fuseRankedCandidates({ rankedLists, projectRoot = process.cwd(), corpusIdentity = '', k = 60, grain = 'span', depth = Infinity } ) {
234
+ const { compareText } = require('./code-corpus.js');
235
+ const providerLists = new Map ();
236
+ const items = [];
237
+ const rejected = [];
238
+ for (let listIndex = 0; listIndex < rankedLists.length; listIndex += 1) {
239
+ const list = rankedLists[listIndex];
240
+ const normalized = normalizeCodeCandidates(Array.isArray(list) ? list : list.candidates,
241
+ { projectRoot, corpusIdentity, provider: list.provider || 'list-' + listIndex, capability: list.capability,
242
+ queryRef: list.queryRef, retrievalAttemptRef: list.retrievalAttemptRef });
243
+ rejected.push(...normalized.rejected);
244
+ for (const item of normalized.candidates) {
245
+ if (!providerLists.has(item.provider)) providerLists.set(item.provider, []);
246
+ providerLists.get(item.provider) .push(item);
247
+ items.push(item);
248
+ }
249
+ }
250
+ if (grain === 'file' && providerLists.size > 1) {
251
+ const candidates = fuseByFile(providerLists, { corpusIdentity, k, depth, compareText });
252
+ candidates.forEach((candidate , index ) => { candidate.rank = index + 1; });
253
+ return { candidates, rejected };
254
+ }
255
+ const origins = new Map ();
256
+ for (const item of items) {
257
+ if (!origins.has(item.id)) origins.set(item.id, []);
258
+ addOrigins(origins.get(item.id) , item.origins);
259
+ }
260
+ const uniqueProviderLists = [...providerLists.values()].map((list ) => {
261
+ const seen = new Set ();
262
+ return list.filter((item ) => { if (seen.has(item.id)) return false; seen.add(item.id); return true; });
263
+ });
264
+ const candidates = reciprocalRankFusion(uniqueProviderLists, { k, fullPrecision: true }).map((item ) => ({ ...item, origins: origins.get(item.id) }));
265
+ candidates.sort((a , b ) => b.rrfScore - a.rrfScore || compareText(a.locator.file, b.locator.file)
266
+ || a.locator.line - b.locator.line || a.locator.endLine - b.locator.endLine);
267
+ candidates.forEach((candidate , index ) => { candidate.rank = index + 1; });
268
+ return { candidates, rejected };
269
+ }
270
+
145
271
  module.exports = {
146
272
  reciprocalRankFusion,
147
273
  normalizeLocator,
274
+ normalizeCodeCandidates,
275
+ fuseRankedCandidates,
148
276
  fuseHybridResults,
149
277
  };
@@ -145,7 +145,15 @@ function searchGuidance({ corpusDir, indexDir, query, k = 5, fsImpl = fs }
145
145
  * code from this install, knowledge from the project being worked on. The `.doflow` root is
146
146
  * $DOFLOW_CONFIG_DIR, else the nearest one above `stateRoot` that holds a guidance tree, else the
147
147
  * home install; the index is kept beside the corpus chosen. */
148
- function handleRetrieveCommand({ query, top, json = false, stateRoot } = {}) {
148
+ function handleRetrieveCommand(options = {}) {
149
+ const { query, top, json = false, stateRoot } = options;
150
+ if (options.scope !== undefined && options.scope !== 'guidance' && options.scope !== 'code') {
151
+ return usageError('retrieve', `--scope must be guidance or code, got '${options.scope}'`, json);
152
+ }
153
+ if (options.scope === 'code' || options.indexAction !== undefined) {
154
+ if (options.scope !== 'code') return usageError('retrieve', '--index-action requires --scope code', json);
155
+ return handleCodeRetrieveCommand(options);
156
+ }
149
157
  const { configDir } = resolveRunsLocation({ start: stateRoot, containing: 'guidance' });
150
158
  const corpusDir = path.join(configDir, 'guidance');
151
159
  const indexDir = path.join(configDir, 'index', 'guidance');
@@ -174,6 +182,30 @@ function handleRetrieveCommand({ query, top, json = false, stateRoot }
174
182
  }
175
183
  }
176
184
 
185
+ /** Additive code path. The guidance branch above retains its existing output and exit behavior. The search root is
186
+ * `root` or cwd, never `stateRoot`: in a linked worktree the state root is the main checkout's feature store. */
187
+ function handleCodeRetrieveCommand(options ) {
188
+ const { executeCodeRetrieval } = require('./code-retrieval.js');
189
+ return executeCodeRetrieval({ ...options, root: options.root || process.cwd() }).then((outcome ) => {
190
+ const response = outcome.response;
191
+ if (options.json) console.log(JSON.stringify(response, null, 2));
192
+ else if (!response.ok) console.error(`[ERROR] retrieve: ${response.error}${response.cause ? ` (${response.cause})` : ''}${response.summary ? ` — ${response.summary}` : ''}`);
193
+ else if (response.action) console.log(`${response.complete ? '[OK]' : '[ERROR]'} ${response.action} code index${response.generation ? ` ${response.generation}` : ''}`);
194
+ else if (!response.results.length) console.log('[OK] No matching code found in the attempted scope. absenceEstablished=false');
195
+ else response.results.forEach((candidate , index ) => {
196
+ console.log(`${index + 1}. ${candidate.locator.file}:${candidate.locator.line}-${candidate.locator.endLine}`);
197
+ if (candidate.snippet) console.log(` ${candidate.snippet}`);
198
+ });
199
+ if (!options.json && response.gaps?.length) for (const gap of response.gaps) console.error(`[INFO] retrieve gap: ${gap.provider || gap.source || 'retrieval'} ${gap.reason}`);
200
+ return finishRuntime(outcome.exit);
201
+ }).catch((error ) => {
202
+ captureCaught(error, 'retrieve', 1);
203
+ if (options.json) console.log(JSON.stringify({ ok: false, schemaVersion: 1, scope: 'code', error: 'retrieval-failed', cause: error.message }, null, 2));
204
+ else console.error(`[ERROR] retrieve: ${error.message}`);
205
+ return finishRuntime(1);
206
+ });
207
+ }
208
+
177
209
  const {
178
210
  reciprocalRankFusion,
179
211
  normalizeLocator,
@@ -187,6 +219,7 @@ module.exports = {
187
219
  buildImportGraph,
188
220
  expandViaGraph,
189
221
  handleRetrieveCommand,
222
+ handleCodeRetrieveCommand,
190
223
  STOPWORDS,
191
224
  reciprocalRankFusion,
192
225
  normalizeLocator,
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ function formatWithRTK(
12
+ resolution ,
13
+ options
14
+ ) {
15
+ const rawJson = JSON.stringify(resolution, null, 2);
16
+ const rawChars = rawJson.length;
17
+
18
+ const lines = [];
19
+ const statusMark = resolution.status === 'HEALTHY' ? '✓' : resolution.status === 'FALLBACK' ? '▲' : '✗';
20
+ lines.push(`${statusMark} [${resolution.provider}] query: "${resolution.query}" (status: ${resolution.status}, freshness: ${resolution.freshness})`);
21
+
22
+ if (resolution.fallbackReason) {
23
+ lines.push(` fallback-reason: ${resolution.fallbackReason}`);
24
+ }
25
+
26
+ if (resolution.isAbsence) {
27
+ lines.push(` absence: true (${resolution.absenceReason || 'zero occurrences'})`);
28
+ }
29
+
30
+ const maxLines = options?.maxLines ?? 50;
31
+ const candidates = Array.isArray(resolution.candidates) ? resolution.candidates : [];
32
+ const totalCandidates = candidates.length;
33
+ const displayedCandidates = candidates.slice(0, maxLines);
34
+
35
+ for (const cand of displayedCandidates) {
36
+ const loc = cand.locator || {};
37
+ const fileLine = loc.line !== undefined ? `${loc.file}:${loc.line}` : loc.file;
38
+ const relStr = cand.relation ? ` [${cand.relation}]` : '';
39
+ const symStr = loc.symbol ? ` ${loc.symbol}` : '';
40
+ const scoreStr = typeof cand.score === 'number' ? ` (${cand.score.toFixed(2)})` : '';
41
+ lines.push(` #${cand.rank ?? 0} ${fileLine}${symStr}${relStr}${scoreStr}`);
42
+ }
43
+
44
+ if (totalCandidates > maxLines) {
45
+ lines.push(` ... (${totalCandidates - maxLines} more candidates truncated)`);
46
+ }
47
+
48
+ const formattedOutput = lines.join('\n');
49
+ const compressedChars = formattedOutput.length;
50
+ const ratio = rawChars > 0 ? Number((compressedChars / rawChars).toFixed(3)) : 1.0;
51
+
52
+ let locatorsPreserved = true;
53
+ for (const cand of displayedCandidates) {
54
+ const loc = cand.locator;
55
+ if (!loc || !loc.file) continue;
56
+ if (!formattedOutput.includes(loc.file)) {
57
+ locatorsPreserved = false;
58
+ break;
59
+ }
60
+ if (loc.line !== undefined && !formattedOutput.includes(`${loc.file}:${loc.line}`)) {
61
+ locatorsPreserved = false;
62
+ break;
63
+ }
64
+ }
65
+
66
+ return {
67
+ rawChars,
68
+ compressedChars,
69
+ ratio,
70
+ formattedOutput,
71
+ locatorsPreserved,
72
+ };
73
+ }
74
+
75
+ module.exports = {
76
+ formatWithRTK,
77
+ };
@@ -0,0 +1,106 @@
1
+ """Semble 0.7.0 public API adapter. One bounded JSON request per process.
2
+
3
+ The audit policy denies network and child processes even on model loader retry paths.
4
+ It also confines Python writes to the invocation's declared project-local cache/staging.
5
+ No library function or private provider implementation is patched.
6
+ """
7
+ import importlib.metadata
8
+ import json
9
+ import math
10
+ import os
11
+ import platform
12
+ from pathlib import Path
13
+ import sys
14
+
15
+ VERSION = "0.7.0" # must equal SEMBLE_VERSION in semble-provider.ts (tested)
16
+ RUNTIME_PACKAGES = ("numpy", "model2vec", "tokenizers", "huggingface-hub", "safetensors", "vicinity")
17
+
18
+
19
+ def runtime_identity():
20
+ packages = {}
21
+ for name in RUNTIME_PACKAGES:
22
+ try:
23
+ packages[name] = importlib.metadata.version(name)
24
+ except importlib.metadata.PackageNotFoundError as error:
25
+ raise RuntimeError("provider-runtime-dependency-missing") from error
26
+ return {"python": platform.python_version(), "implementation": platform.python_implementation(),
27
+ "platform": platform.platform(), "machine": platform.machine(), "packages": packages}
28
+
29
+
30
+ def install_policy(roots):
31
+ roots = tuple(Path(root).resolve(strict=True) for root in roots)
32
+
33
+ def permitted(value):
34
+ if isinstance(value, int):
35
+ return True # already opened standard output/error descriptors
36
+ candidate = Path(os.fsdecode(value)).resolve()
37
+ return any(candidate == root or root in candidate.parents for root in roots)
38
+
39
+ def audit(event, args):
40
+ if event.startswith("socket.") or event in ("subprocess.Popen", "os.system", "os.exec", "os.posix_spawn", "os.fork"):
41
+ raise PermissionError("provider-network-or-subprocess-denied")
42
+ if event == "open":
43
+ file, mode, flags = args
44
+ writing = (isinstance(mode, str) and any(c in mode for c in "wax+")) or bool(flags & (os.O_WRONLY | os.O_RDWR | os.O_CREAT | os.O_TRUNC | os.O_APPEND))
45
+ if writing and not permitted(file):
46
+ raise PermissionError("provider-write-outside-state")
47
+ if event in ("os.mkdir", "os.remove", "os.rmdir", "os.chmod", "os.utime", "os.truncate") and not permitted(args[0]):
48
+ raise PermissionError("provider-write-outside-state")
49
+ if event in ("os.rename", "os.link", "os.symlink"):
50
+ if not permitted(args[0]) or not permitted(args[1]) or event != "os.rename":
51
+ raise PermissionError("provider-unsafe-mutation")
52
+ sys.addaudithook(audit)
53
+
54
+
55
+ def run(request):
56
+ install_policy(request["allowedWriteRoots"])
57
+ try:
58
+ found = importlib.metadata.version("semble")
59
+ except importlib.metadata.PackageNotFoundError:
60
+ return {"ok": False, "reason": "provider-unavailable", "cause": f"semble is not installed for {sys.executable}"}
61
+ if found != VERSION:
62
+ return {"ok": False, "reason": "provider-version-mismatch", "cause": f"{sys.executable} has semble {found[:32]}; the bridge pins {VERSION}"}
63
+ from semble.index import SembleIndex
64
+ from semble.types import ContentType
65
+ if request["action"] == "query":
66
+ index = SembleIndex.load_from_disk(Path(request["indexPath"]))
67
+ count = request["poolSize"]
68
+ if index.stats.total_chunks != count:
69
+ raise ValueError("persisted chunk count changed")
70
+ results = index.search(request["query"], top_k=200, alpha=1.0, rerank=False)
71
+ candidates = []
72
+ for result in results:
73
+ chunk = result.chunk
74
+ score = float(result.score)
75
+ if not math.isfinite(score):
76
+ raise ValueError("nonfinite score")
77
+ candidates.append({"locator": {"file": chunk.file_path, "line": chunk.start_line, "endLine": chunk.end_line}, "score": score})
78
+ # Public scores are provider-native distinct ranks; sorting them cannot
79
+ # recover dense ties hidden inside Semble. Preserve the returned order.
80
+ return {"ok": True, "candidates": candidates, "poolSize": count}
81
+ if request["action"] not in ("build", "refresh"):
82
+ raise ValueError("invalid action")
83
+ index = SembleIndex.from_path(Path(request["mirror"]), model_path=request["modelPath"], content=(ContentType.CODE,), show_progress_bar=False)
84
+ index.save(Path(request["savePath"]))
85
+ return {"ok": True}
86
+
87
+
88
+ def main():
89
+ try:
90
+ request = json.loads(sys.stdin.buffer.read(2097153))
91
+ result = run(request)
92
+ except importlib.metadata.PackageNotFoundError:
93
+ result = {"ok": False, "reason": "provider-unavailable"}
94
+ except (ImportError, AttributeError):
95
+ result = {"ok": False, "reason": "provider-api-unavailable"}
96
+ except Exception:
97
+ # Provider exception text may contain source/query data. Return only a fixed cause.
98
+ result = {"ok": False, "reason": "provider-load-or-operation-error"}
99
+ if result.get("ok"):
100
+ result["runtimeIdentity"] = runtime_identity()
101
+ result["version"] = VERSION
102
+ print(json.dumps(result, separators=(",", ":")))
103
+
104
+
105
+ if __name__ == "__main__":
106
+ main()
@@ -0,0 +1,114 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const crypto = require('node:crypto');
6
+ const { SEMBLE_VERSION, SEMBLE_LIMITS, semanticStatePaths, fault, digest, safeDirectories, regularBytes,
7
+ inspectModel, validateInventory, readSource, checkSources, inspectArtifacts, acquireSemanticLock,
8
+ cleanupTemporary, executeBridge, readCompleted, scanTree, resolveSembleInterpreter, checkSembleVersion } = require('./semble-provider.js');
9
+
10
+ /**
11
+ * The in-progress marker never follows a link out of the state directory. A failed mutation leaves a regular
12
+ * marker behind on purpose, so a regular file is replaced; anything else (a symlink, a directory) is refused.
13
+ * The create is `wx` (O_CREAT|O_EXCL), which fails on any existing path, a symlink included, so a link planted
14
+ * between the unlink and the create is refused too rather than written through.
15
+ */
16
+ function writeMarker(marker , body ) {
17
+ let found = null;
18
+ try { found = fs.lstatSync(marker); } catch (error ) { if (error.code !== 'ENOENT') throw error; }
19
+ if (found && !found.isFile()) throw fault('unsafe-state-file');
20
+ if (found) fs.unlinkSync(marker);
21
+ try { fs.writeFileSync(marker, body, { flag: 'wx', mode: 0o600 }); }
22
+ catch (error ) { if (error.code === 'EEXIST') throw fault('unsafe-state-file'); throw error; }
23
+ }
24
+
25
+ /** Explicit operations only. A failed mutation deliberately keeps its in-progress marker. */
26
+ async function runSembleLifecycle(options ) {
27
+ const started = Date.now(); const limits = { ...SEMBLE_LIMITS, ...options.limits };
28
+ const { inventory, action } = options; let release ; let staging ;
29
+ let added = 0; let changed = 0; let deleted = 0; let changedBytes = 0;
30
+ const checkDeadline = () => { if (Date.now() - started > limits.lifecycleMs) throw fault('lifecycle-timeout'); };
31
+ try {
32
+ if (action !== 'build' && action !== 'refresh') throw fault('invalid-index-action');
33
+ validateInventory(inventory, limits); const model = inspectModel(options.modelPath, limits);
34
+ const python = options.python || resolveSembleInterpreter().python; checkSembleVersion(python); // preflight: before any lock or mutation
35
+ const paths = semanticStatePaths(inventory); release = await acquireSemanticLock(paths); cleanupTemporary(paths);
36
+ let previous = null;
37
+ if (action === 'refresh') {
38
+ previous = readCompleted(paths, inventory, model, limits, true);
39
+ const oldInventory = { ...inventory, files: previous.files };
40
+ const artifacts = inspectArtifacts(paths.index, oldInventory, paths, model, limits);
41
+ if (artifacts.artifactIdentity !== previous.artifactIdentity) throw fault('incompatible-refresh-index');
42
+ }
43
+ const old = new Map((previous?.files || []).map((entry ) => [entry.path, entry]));
44
+ const current = new Set(inventory.files.map((entry ) => entry.path));
45
+ for (const entry of inventory.files) {
46
+ const prior = old.get(entry.path);
47
+ if (!prior) { added++; changedBytes += entry.sizeBytes; }
48
+ else if (prior.fileHash !== entry.fileHash) { changed++; changedBytes += entry.sizeBytes; }
49
+ }
50
+ deleted = [...old.keys()].filter((file ) => !current.has(file)).length;
51
+ if (action === 'refresh' && (added + changed + deleted > limits.changedFiles || changedBytes > limits.changedBytes)) throw fault('refresh-limit');
52
+ checkSources(inventory, limits); checkDeadline();
53
+ staging = fs.mkdtempSync(path.join(paths.state, 'staging-'));
54
+ const sourceStage = path.join(staging, 'source'); fs.mkdirSync(sourceStage);
55
+ // Stage verified ordinary copies before invalidating or modifying the stable mirror.
56
+ for (const entry of inventory.files) {
57
+ checkDeadline();
58
+ if (old.has(entry.path) && (old.get(entry.path) ).fileHash === entry.fileHash) continue;
59
+ const dest = path.join(sourceStage, entry.path); safeDirectories(sourceStage, path.dirname(dest), true);
60
+ fs.writeFileSync(dest, readSource(inventory, entry, limits), { flag: 'wx' });
61
+ }
62
+ checkSources(inventory, limits); checkDeadline();
63
+ writeMarker(paths.marker, JSON.stringify({ schemaVersion: 1, action, startedAt: new Date().toISOString() }));
64
+ if (action === 'build') {
65
+ // A repair build explicitly discards incompatible cache; never let from_path silently reuse it.
66
+ for (const dir of [paths.mirror, paths.cache]) if (fs.existsSync(dir)) { scanTree(dir, limits.artifactBytes); fs.rmSync(dir, { recursive: true }); }
67
+ }
68
+ safeDirectories(paths.state, paths.mirror, true); safeDirectories(paths.state, paths.cache, true);
69
+ for (const file of old.keys() ) if (!current.has(file)) fs.unlinkSync(path.join(paths.mirror, file));
70
+ for (const entry of inventory.files) {
71
+ checkDeadline(); const staged = path.join(sourceStage, entry.path);
72
+ if (!fs.existsSync(staged)) continue;
73
+ const dest = path.join(paths.mirror, entry.path); safeDirectories(paths.mirror, path.dirname(dest), true);
74
+ let previousMtime = 0; try { previousMtime = fs.lstatSync(dest).mtimeMs; } catch {}
75
+ fs.renameSync(staged, dest);
76
+ // A hash change must be newer than both the prior copy and saved provider time, even on coarse filesystems.
77
+ const seconds = Math.max(Date.now() / 1000, previousMtime / 1000 + 2, (previous?.providerTime || 0) + 2);
78
+ fs.utimesSync(dest, seconds, seconds);
79
+ }
80
+ const temp = path.join(staging, 'provider'); fs.mkdirSync(temp);
81
+ const savePath = path.join(staging, 'index');
82
+ const result = await executeBridge({ action, mirror: paths.mirror, modelPath: model.path, savePath, indexPath: paths.index,
83
+ allowedWriteRoots: [staging, paths.cache] }, { ...options, python, limits: { ...limits, lifecycleMs: Math.max(1, limits.lifecycleMs - (Date.now() - started)) } }, paths, temp);
84
+ if (!result.ok) throw fault(result.reason || 'provider-error', 'UNKNOWN', typeof result.cause === 'string' ? result.cause : undefined);
85
+ if (!result.runtimeIdentity || typeof result.runtimeIdentity !== 'object') throw fault('provider-runtime-identity-unavailable');
86
+ const artifacts = inspectArtifacts(savePath, inventory, paths, model, limits);
87
+ checkSources(inventory, limits); checkDeadline();
88
+ if (inspectModel(options.modelPath, limits).identity !== model.identity) throw fault('model-changed', 'STALE');
89
+ const generation = crypto.randomUUID();
90
+ safeDirectories(paths.state, path.dirname(paths.index), true);
91
+ const backup = path.join(staging, 'previous-index');
92
+ if (fs.existsSync(paths.index)) fs.renameSync(paths.index, backup);
93
+ fs.renameSync(savePath, paths.index);
94
+ const metadata = JSON.parse(regularBytes(path.join(paths.index, 'metadata.json'), limits.artifactBytes).toString('utf8'));
95
+ const manifest = { schemaVersion: 1, complete: true, providerVersion: SEMBLE_VERSION, runtimeIdentity: result.runtimeIdentity, root: inventory.root,
96
+ scopeIgnoreDigest: inventory.scopeIgnoreDigest, corpusIdentity: inventory.identity, model, generation,
97
+ providerTime: metadata.time, artifactIdentity: artifacts.artifactIdentity,
98
+ files: inventory.files.map((entry ) => ({ path: entry.path, sizeBytes: entry.sizeBytes, fileHash: entry.fileHash })) };
99
+ const pending = path.join(staging, 'manifest.json'); fs.writeFileSync(pending, JSON.stringify(manifest));
100
+ checkSources(inventory, limits); checkDeadline();
101
+ fs.renameSync(pending, paths.manifest); // Completion metadata is always the last published artifact.
102
+ fs.unlinkSync(paths.marker);
103
+ return { ok: true, action, complete: true, freshness: 'FRESH', generation, added, changed, deleted, skipped: 0,
104
+ bytes: changedBytes, elapsedMs: Date.now() - started, chunks: artifacts.chunks, artifactBytes: artifacts.artifactBytes };
105
+ } catch (error ) {
106
+ const reason = error.reason || 'lifecycle-error';
107
+ return { ok: false, action, complete: false, freshness: error.freshness || 'UNKNOWN', reason, ...(typeof error.cause === 'string' ? { cause: error.cause } : {}),
108
+ added, changed, deleted, skipped: inventory?.skipped?.length || 0, bytes: changedBytes, elapsedMs: Date.now() - started,
109
+ // A build needs the same lock, so contention is never repaired by "run a build".
110
+ repair: reason === 'lock-contention' ? 'Wait for the other semantic index operation to finish, then run this command again (see cause).'
111
+ : 'Run an explicit bounded build with a verified local model after correcting the cause.' };
112
+ } finally { try { if (staging) fs.rmSync(staging, { recursive: true, force: true }); } catch {} try { if (release) release(); } catch {} }
113
+ }
114
+ module.exports = { runSembleLifecycle };