zob-harness 0.1.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 (356) hide show
  1. package/.pi/adapters/registry.json +103 -0
  2. package/.pi/agents/architecture-cartographer.md +53 -0
  3. package/.pi/agents/chief-vision.md +39 -0
  4. package/.pi/agents/clarifier.md +58 -0
  5. package/.pi/agents/context-steward.md +52 -0
  6. package/.pi/agents/doc-steward.md +34 -0
  7. package/.pi/agents/explore.md +49 -0
  8. package/.pi/agents/factory.md +41 -0
  9. package/.pi/agents/implementer.md +44 -0
  10. package/.pi/agents/librarian.md +32 -0
  11. package/.pi/agents/oracle-merge.md +50 -0
  12. package/.pi/agents/oracle.md +55 -0
  13. package/.pi/agents/pattern-miner.md +53 -0
  14. package/.pi/agents/planner.md +39 -0
  15. package/.pi/agents/project-dna-golden-evaluator.md +32 -0
  16. package/.pi/agents/project-dna-ontology-steward.md +30 -0
  17. package/.pi/agents/project-dna-oracle.md +56 -0
  18. package/.pi/agents/project-dna-orchestrator.md +60 -0
  19. package/.pi/agents/project-dna-query-steward.md +38 -0
  20. package/.pi/agents/project-dna-safety-preflight.md +54 -0
  21. package/.pi/agents/project-dna-test-linker.md +27 -0
  22. package/.pi/agents/qa.md +38 -0
  23. package/.pi/agents/refactor-cartographer.md +28 -0
  24. package/.pi/agents/refactor-mover.md +31 -0
  25. package/.pi/agents/refactor-oracle.md +49 -0
  26. package/.pi/agents/repo-scout.md +60 -0
  27. package/.pi/agents/sample-architect.md +48 -0
  28. package/.pi/agents/specifier.md +57 -0
  29. package/.pi/agents/symbol-range-curator.md +41 -0
  30. package/.pi/agents/synthesis.md +52 -0
  31. package/.pi/agents/temp-agent-creator.md +35 -0
  32. package/.pi/autonomy-policy.json +67 -0
  33. package/.pi/budget-policy.json +54 -0
  34. package/.pi/capabilities/zob-public-runtime-capabilities.json +1700 -0
  35. package/.pi/chains/explore-plan-oracle.json +78 -0
  36. package/.pi/chains/explore-spec-clarify-plan-oracle.json +64 -0
  37. package/.pi/chains/explore-spec-plan-oracle.json +53 -0
  38. package/.pi/chains/spec-clarify-plan-oracle.json +53 -0
  39. package/.pi/chains/spec-factory-oracle.json +42 -0
  40. package/.pi/chains/spec-plan-oracle.json +42 -0
  41. package/.pi/compute-profiles/defaults.json +19 -0
  42. package/.pi/compute-profiles/overrides.json +13 -0
  43. package/.pi/compute-profiles/risk-rules.json +16 -0
  44. package/.pi/daemon-policy.json +80 -0
  45. package/.pi/damage-control-rules.json +45 -0
  46. package/.pi/extensions/zob-child-safety/index.ts +212 -0
  47. package/.pi/extensions/zob-harness/AGENTS.md +28 -0
  48. package/.pi/extensions/zob-harness/index.ts +391 -0
  49. package/.pi/extensions/zob-harness/src/AGENTS.md +25 -0
  50. package/.pi/extensions/zob-harness/src/agents.ts +82 -0
  51. package/.pi/extensions/zob-harness/src/autonomous-runtime.ts +2912 -0
  52. package/.pi/extensions/zob-harness/src/autonomy-readiness.ts +778 -0
  53. package/.pi/extensions/zob-harness/src/budget-policy.ts +308 -0
  54. package/.pi/extensions/zob-harness/src/capabilities.ts +249 -0
  55. package/.pi/extensions/zob-harness/src/child-runner.ts +249 -0
  56. package/.pi/extensions/zob-harness/src/chronicle.ts +262 -0
  57. package/.pi/extensions/zob-harness/src/compute-profile.ts +602 -0
  58. package/.pi/extensions/zob-harness/src/compute-workflow-shape.ts +168 -0
  59. package/.pi/extensions/zob-harness/src/coms-v2/AGENTS.md +16 -0
  60. package/.pi/extensions/zob-harness/src/coms-v2/envelope.ts +121 -0
  61. package/.pi/extensions/zob-harness/src/coms-v2/identity.ts +53 -0
  62. package/.pi/extensions/zob-harness/src/coms-v2/ledger-bridge.ts +67 -0
  63. package/.pi/extensions/zob-harness/src/coms-v2/local-transport.ts +147 -0
  64. package/.pi/extensions/zob-harness/src/coms-v2/pending-replies.ts +80 -0
  65. package/.pi/extensions/zob-harness/src/coms-v2/policy.ts +125 -0
  66. package/.pi/extensions/zob-harness/src/coms-v2/presence.ts +55 -0
  67. package/.pi/extensions/zob-harness/src/coms-v2/registry.ts +113 -0
  68. package/.pi/extensions/zob-harness/src/coms-v2/response-capture.ts +50 -0
  69. package/.pi/extensions/zob-harness/src/coms-v2/transcript-capture.ts +164 -0
  70. package/.pi/extensions/zob-harness/src/coms-v2/types.ts +149 -0
  71. package/.pi/extensions/zob-harness/src/coms-v2/zpeer-profile.ts +140 -0
  72. package/.pi/extensions/zob-harness/src/coms-v2/zpeer.ts +452 -0
  73. package/.pi/extensions/zob-harness/src/constants.ts +108 -0
  74. package/.pi/extensions/zob-harness/src/context-gbrain.ts +465 -0
  75. package/.pi/extensions/zob-harness/src/daemon-policy.ts +223 -0
  76. package/.pi/extensions/zob-harness/src/daemon-readiness.ts +134 -0
  77. package/.pi/extensions/zob-harness/src/daemon-runtime.ts +393 -0
  78. package/.pi/extensions/zob-harness/src/factory/AGENTS.md +24 -0
  79. package/.pi/extensions/zob-harness/src/factory/agentic-plan.ts +65 -0
  80. package/.pi/extensions/zob-harness/src/factory/quarantine.ts +319 -0
  81. package/.pi/extensions/zob-harness/src/factory/run.ts +520 -0
  82. package/.pi/extensions/zob-harness/src/factory/validation.ts +454 -0
  83. package/.pi/extensions/zob-harness/src/factory-selector.ts +318 -0
  84. package/.pi/extensions/zob-harness/src/full-autonomy-test.ts +226 -0
  85. package/.pi/extensions/zob-harness/src/git-ops.ts +868 -0
  86. package/.pi/extensions/zob-harness/src/goal-room.ts +178 -0
  87. package/.pi/extensions/zob-harness/src/goal-runtime.ts +1569 -0
  88. package/.pi/extensions/zob-harness/src/goal-todo-imports.ts +111 -0
  89. package/.pi/extensions/zob-harness/src/goal-todo-types.ts +231 -0
  90. package/.pi/extensions/zob-harness/src/goal-todos.ts +1410 -0
  91. package/.pi/extensions/zob-harness/src/goal.ts +152 -0
  92. package/.pi/extensions/zob-harness/src/governed-requests.ts +436 -0
  93. package/.pi/extensions/zob-harness/src/interactive-autonomy.ts +595 -0
  94. package/.pi/extensions/zob-harness/src/launch-apply.ts +313 -0
  95. package/.pi/extensions/zob-harness/src/merge-queue.ts +290 -0
  96. package/.pi/extensions/zob-harness/src/mission-control.ts +573 -0
  97. package/.pi/extensions/zob-harness/src/model-availability.ts +52 -0
  98. package/.pi/extensions/zob-harness/src/model-routing.ts +429 -0
  99. package/.pi/extensions/zob-harness/src/orchestration/AGENTS.md +23 -0
  100. package/.pi/extensions/zob-harness/src/orchestration/adaptive-delegation.ts +547 -0
  101. package/.pi/extensions/zob-harness/src/orchestration/adaptive-workflow.ts +585 -0
  102. package/.pi/extensions/zob-harness/src/orchestration/lead-plan.ts +192 -0
  103. package/.pi/extensions/zob-harness/src/orchestration/plan.ts +168 -0
  104. package/.pi/extensions/zob-harness/src/orchestration/room.ts +346 -0
  105. package/.pi/extensions/zob-harness/src/orchestration/run.ts +134 -0
  106. package/.pi/extensions/zob-harness/src/orchestration/supervised-readonly.ts +1147 -0
  107. package/.pi/extensions/zob-harness/src/orchestration/widget-readers.ts +132 -0
  108. package/.pi/extensions/zob-harness/src/output-contracts.ts +656 -0
  109. package/.pi/extensions/zob-harness/src/project-dna.ts +533 -0
  110. package/.pi/extensions/zob-harness/src/promotion/AGENTS.md +24 -0
  111. package/.pi/extensions/zob-harness/src/promotion/candidate.ts +336 -0
  112. package/.pi/extensions/zob-harness/src/promotion/coms.ts +127 -0
  113. package/.pi/extensions/zob-harness/src/promotion/documentation.ts +142 -0
  114. package/.pi/extensions/zob-harness/src/promotion/factory.ts +107 -0
  115. package/.pi/extensions/zob-harness/src/promotion/ledger.ts +2 -0
  116. package/.pi/extensions/zob-harness/src/promotion/temp-agent.ts +151 -0
  117. package/.pi/extensions/zob-harness/src/promotion/types.ts +149 -0
  118. package/.pi/extensions/zob-harness/src/promotion/validate.ts +6 -0
  119. package/.pi/extensions/zob-harness/src/promotion/write-lane.ts +162 -0
  120. package/.pi/extensions/zob-harness/src/prompt-packs.ts +239 -0
  121. package/.pi/extensions/zob-harness/src/queue.ts +386 -0
  122. package/.pi/extensions/zob-harness/src/rules.ts +225 -0
  123. package/.pi/extensions/zob-harness/src/runtime/AGENTS.md +26 -0
  124. package/.pi/extensions/zob-harness/src/runtime/adaptive-zmode.ts +116 -0
  125. package/.pi/extensions/zob-harness/src/runtime/auto-compaction.ts +715 -0
  126. package/.pi/extensions/zob-harness/src/runtime/commands.ts +1315 -0
  127. package/.pi/extensions/zob-harness/src/runtime/compaction-policy.ts +516 -0
  128. package/.pi/extensions/zob-harness/src/runtime/delegation-click-markers.ts +141 -0
  129. package/.pi/extensions/zob-harness/src/runtime/delegation-feed.ts +415 -0
  130. package/.pi/extensions/zob-harness/src/runtime/delegation-markdown.ts +97 -0
  131. package/.pi/extensions/zob-harness/src/runtime/delegation-monitor.ts +553 -0
  132. package/.pi/extensions/zob-harness/src/runtime/delegation-mouse.ts +205 -0
  133. package/.pi/extensions/zob-harness/src/runtime/delegation-overlay.ts +434 -0
  134. package/.pi/extensions/zob-harness/src/runtime/events.ts +736 -0
  135. package/.pi/extensions/zob-harness/src/runtime/goal-todo-overlay.ts +214 -0
  136. package/.pi/extensions/zob-harness/src/runtime/mode-intent.ts +144 -0
  137. package/.pi/extensions/zob-harness/src/runtime/plan-capture.ts +270 -0
  138. package/.pi/extensions/zob-harness/src/runtime/state.ts +403 -0
  139. package/.pi/extensions/zob-harness/src/runtime/tools-autonomous.ts +117 -0
  140. package/.pi/extensions/zob-harness/src/runtime/tools-compute.ts +136 -0
  141. package/.pi/extensions/zob-harness/src/runtime/tools-coms.ts +365 -0
  142. package/.pi/extensions/zob-harness/src/runtime/tools-context.ts +70 -0
  143. package/.pi/extensions/zob-harness/src/runtime/tools-delegation.ts +1854 -0
  144. package/.pi/extensions/zob-harness/src/runtime/tools-factory.ts +810 -0
  145. package/.pi/extensions/zob-harness/src/runtime/tools-goal-room.ts +46 -0
  146. package/.pi/extensions/zob-harness/src/runtime/tools-governed-requests.ts +38 -0
  147. package/.pi/extensions/zob-harness/src/runtime/tools-merge-queue.ts +61 -0
  148. package/.pi/extensions/zob-harness/src/runtime/tools-mission-control.ts +77 -0
  149. package/.pi/extensions/zob-harness/src/runtime/tools-orchestration.ts +106 -0
  150. package/.pi/extensions/zob-harness/src/runtime/tools-project-dna.ts +123 -0
  151. package/.pi/extensions/zob-harness/src/runtime/tools-worker-pool.ts +93 -0
  152. package/.pi/extensions/zob-harness/src/runtime/tools-workspace-claims.ts +62 -0
  153. package/.pi/extensions/zob-harness/src/runtime/tools-zcommit.ts +147 -0
  154. package/.pi/extensions/zob-harness/src/runtime/widget.ts +353 -0
  155. package/.pi/extensions/zob-harness/src/runtime/zobHarness.ts +60 -0
  156. package/.pi/extensions/zob-harness/src/safety.ts +338 -0
  157. package/.pi/extensions/zob-harness/src/sandbox.ts +1508 -0
  158. package/.pi/extensions/zob-harness/src/schemas-project-dna.ts +47 -0
  159. package/.pi/extensions/zob-harness/src/schemas.ts +695 -0
  160. package/.pi/extensions/zob-harness/src/telemetry.ts +373 -0
  161. package/.pi/extensions/zob-harness/src/topology/AGENTS.md +22 -0
  162. package/.pi/extensions/zob-harness/src/topology/chains.ts +236 -0
  163. package/.pi/extensions/zob-harness/src/topology/coms.ts +211 -0
  164. package/.pi/extensions/zob-harness/src/topology/orchestration-profiles.ts +204 -0
  165. package/.pi/extensions/zob-harness/src/topology/teams.ts +113 -0
  166. package/.pi/extensions/zob-harness/src/types/core.ts +47 -0
  167. package/.pi/extensions/zob-harness/src/types.ts +939 -0
  168. package/.pi/extensions/zob-harness/src/utils/AGENTS.md +22 -0
  169. package/.pi/extensions/zob-harness/src/utils/formatting.ts +34 -0
  170. package/.pi/extensions/zob-harness/src/utils/hashing.ts +11 -0
  171. package/.pi/extensions/zob-harness/src/utils/json.ts +28 -0
  172. package/.pi/extensions/zob-harness/src/utils/paths.ts +54 -0
  173. package/.pi/extensions/zob-harness/src/utils/records.ts +25 -0
  174. package/.pi/extensions/zob-harness/src/utils/resources.ts +38 -0
  175. package/.pi/extensions/zob-harness/src/worker-pool.ts +672 -0
  176. package/.pi/extensions/zob-harness/src/workspace-claims.ts +297 -0
  177. package/.pi/extensions/zob-switch/index.ts +180 -0
  178. package/.pi/factories/budget-preflight-dry-run/batch-manifest.json +59 -0
  179. package/.pi/factories/budget-preflight-dry-run/factory.json +94 -0
  180. package/.pi/factories/budget-preflight-dry-run/pilot-manifest.json +50 -0
  181. package/.pi/factories/budget-preflight-dry-run/smoke-manifest.json +43 -0
  182. package/.pi/factories/code-review-matrix/batch-manifest.json +61 -0
  183. package/.pi/factories/code-review-matrix/factory.json +163 -0
  184. package/.pi/factories/code-review-matrix/pilot-manifest.json +41 -0
  185. package/.pi/factories/code-review-matrix/smoke-manifest.json +35 -0
  186. package/.pi/factories/factory-forge/batch-manifest.json +56 -0
  187. package/.pi/factories/factory-forge/factory.json +84 -0
  188. package/.pi/factories/factory-forge/pilot-manifest.json +32 -0
  189. package/.pi/factories/factory-forge/smoke-manifest.json +19 -0
  190. package/.pi/factories/opencode-pattern-canonizer/batch-manifest.json +54 -0
  191. package/.pi/factories/opencode-pattern-canonizer/factory.json +86 -0
  192. package/.pi/factories/opencode-pattern-canonizer/pilot-manifest.json +39 -0
  193. package/.pi/factories/opencode-pattern-canonizer/smoke-manifest.json +26 -0
  194. package/.pi/factories/project-dna/README.md +182 -0
  195. package/.pi/factories/project-dna/batch-manifest.json +37 -0
  196. package/.pi/factories/project-dna/example-project-dna-manifest-v2.json +80 -0
  197. package/.pi/factories/project-dna/example-project-dna-manifest.json +58 -0
  198. package/.pi/factories/project-dna/factory.json +131 -0
  199. package/.pi/factories/project-dna/golden-cases-smoke.json +62 -0
  200. package/.pi/factories/project-dna/pi-agentic-ontology.json +88 -0
  201. package/.pi/factories/project-dna/pilot-manifest.json +32 -0
  202. package/.pi/factories/project-dna/schemas/benchmark-suite.schema.json +27 -0
  203. package/.pi/factories/project-dna/schemas/code-knowledge-graph.schema.json +97 -0
  204. package/.pi/factories/project-dna/schemas/context-pack.schema.json +43 -0
  205. package/.pi/factories/project-dna/schemas/golden-case.schema.json +36 -0
  206. package/.pi/factories/project-dna/schemas/manifest-v2.schema.json +128 -0
  207. package/.pi/factories/project-dna/schemas/manifest.schema.json +77 -0
  208. package/.pi/factories/project-dna/schemas/ontology.schema.json +45 -0
  209. package/.pi/factories/project-dna/schemas/project-fingerprint.schema.json +28 -0
  210. package/.pi/factories/project-dna/schemas/query-steward-report.schema.json +52 -0
  211. package/.pi/factories/project-dna/smoke-manifest.json +27 -0
  212. package/.pi/factories/roadmap-smoke-lots/batch-manifest.json +49 -0
  213. package/.pi/factories/roadmap-smoke-lots/factory.json +89 -0
  214. package/.pi/factories/roadmap-smoke-lots/pilot-manifest.json +50 -0
  215. package/.pi/factories/roadmap-smoke-lots/smoke-manifest.json +35 -0
  216. package/.pi/git-policy.json +120 -0
  217. package/.pi/mission-control/zob_coms_transport.json +64 -0
  218. package/.pi/model-catalog.example.json +345 -0
  219. package/.pi/model-economy.example.json +196 -0
  220. package/.pi/model-routing.json +86 -0
  221. package/.pi/orchestrations/adaptive-chief-vision.json +193 -0
  222. package/.pi/orchestrations/ceo-feature-build.json +182 -0
  223. package/.pi/orchestrations/readonly-dynamic-smoke.json +75 -0
  224. package/.pi/output-contracts/agent-event.v1.json +19 -0
  225. package/.pi/output-contracts/base.v1.json +24 -0
  226. package/.pi/output-contracts/brain-lookup.v1.json +21 -0
  227. package/.pi/output-contracts/clarification.v1.json +21 -0
  228. package/.pi/output-contracts/context-pack.v1.json +20 -0
  229. package/.pi/output-contracts/context-request.v1.json +21 -0
  230. package/.pi/output-contracts/context-steward.v1.json +19 -0
  231. package/.pi/output-contracts/context-writeback-proposal.v1.json +18 -0
  232. package/.pi/output-contracts/delegation-request.v1.json +21 -0
  233. package/.pi/output-contracts/explore.v1.json +52 -0
  234. package/.pi/output-contracts/factory.v1.json +48 -0
  235. package/.pi/output-contracts/guidance-steward.v1.json +18 -0
  236. package/.pi/output-contracts/implement.v1.json +40 -0
  237. package/.pi/output-contracts/launch-authorization.v1.json +21 -0
  238. package/.pi/output-contracts/lead-plan.v1.json +22 -0
  239. package/.pi/output-contracts/mission-readiness.v1.json +20 -0
  240. package/.pi/output-contracts/oracle-merge.v1.json +44 -0
  241. package/.pi/output-contracts/oracle-request.v1.json +20 -0
  242. package/.pi/output-contracts/oracle.v1.json +44 -0
  243. package/.pi/output-contracts/orchestration-profile.v1.json +22 -0
  244. package/.pi/output-contracts/plan.v1.json +48 -0
  245. package/.pi/output-contracts/prompt-pack.v1.json +20 -0
  246. package/.pi/output-contracts/qa.v1.json +40 -0
  247. package/.pi/output-contracts/research.v1.json +36 -0
  248. package/.pi/output-contracts/spec.v1.json +22 -0
  249. package/.pi/output-contracts/synthesis.v1.json +44 -0
  250. package/.pi/output-contracts/temp-agent-card.v1.json +23 -0
  251. package/.pi/output-contracts/todo-child-result.v1.json +20 -0
  252. package/.pi/output-contracts/todo-child-result.v2.json +22 -0
  253. package/.pi/output-contracts/todo-claim-validation.v1.json +22 -0
  254. package/.pi/output-contracts/todo-split-request.v1.json +20 -0
  255. package/.pi/prompts/adaptive-workflow.md +63 -0
  256. package/.pi/prompts/autonomous-runtime.md +15 -0
  257. package/.pi/prompts/benchmark-contender.md +15 -0
  258. package/.pi/prompts/benchmark-judge.md +19 -0
  259. package/.pi/prompts/clarify-spec.md +20 -0
  260. package/.pi/prompts/compute-plan.md +36 -0
  261. package/.pi/prompts/compute-preview.md +42 -0
  262. package/.pi/prompts/contract.md +29 -0
  263. package/.pi/prompts/explore.md +13 -0
  264. package/.pi/prompts/factory-run.md +36 -0
  265. package/.pi/prompts/factory.md +20 -0
  266. package/.pi/prompts/implement.md +27 -0
  267. package/.pi/prompts/model-catalog.md +68 -0
  268. package/.pi/prompts/model-economy.md +64 -0
  269. package/.pi/prompts/oracle-merge.md +18 -0
  270. package/.pi/prompts/oracle.md +13 -0
  271. package/.pi/prompts/orchestrator.md +48 -0
  272. package/.pi/prompts/parallel-review.md +21 -0
  273. package/.pi/prompts/plan.md +21 -0
  274. package/.pi/prompts/project-dna.md +90 -0
  275. package/.pi/prompts/refactor-oracle.md +23 -0
  276. package/.pi/prompts/refactor-slice.md +24 -0
  277. package/.pi/prompts/research.md +20 -0
  278. package/.pi/prompts/spec.md +19 -0
  279. package/.pi/prompts/synthesis.md +18 -0
  280. package/.pi/rules/always.md +38 -0
  281. package/.pi/rules/docs.md +32 -0
  282. package/.pi/rules/factory.md +44 -0
  283. package/.pi/rules/oracle.md +34 -0
  284. package/.pi/rules/orchestration.md +44 -0
  285. package/.pi/rules/project.md +34 -0
  286. package/.pi/rules/prompts.md +43 -0
  287. package/.pi/rules/runtime.md +43 -0
  288. package/.pi/rules/sandbox.md +43 -0
  289. package/.pi/settings.json +28 -0
  290. package/.pi/skills/zob-agentic-access/SKILL.md +20 -0
  291. package/.pi/skills/zob-autonomous-runtime/SKILL.md +41 -0
  292. package/.pi/skills/zob-commit/SKILL.md +79 -0
  293. package/.pi/skills/zob-compaction-policy/SKILL.md +92 -0
  294. package/.pi/skills/zob-compute-profile/SKILL.md +108 -0
  295. package/.pi/skills/zob-coms-safety/SKILL.md +54 -0
  296. package/.pi/skills/zob-coms-v2-live/SKILL.md +47 -0
  297. package/.pi/skills/zob-delegation-routing/SKILL.md +82 -0
  298. package/.pi/skills/zob-factory/SKILL.md +28 -0
  299. package/.pi/skills/zob-goal-todo-tree/SKILL.md +279 -0
  300. package/.pi/skills/zob-harness/SKILL.md +68 -0
  301. package/.pi/skills/zob-mission-control-coms/SKILL.md +39 -0
  302. package/.pi/skills/zob-oracle/SKILL.md +21 -0
  303. package/.pi/skills/zob-owner-pool-drill-writer/SKILL.md +244 -0
  304. package/.pi/skills/zob-owner-pool-launcher/SKILL.md +261 -0
  305. package/.pi/skills/zob-project-dna/SKILL.md +275 -0
  306. package/.pi/skills/zob-sandbox/SKILL.md +29 -0
  307. package/.pi/skills/zob-spec/SKILL.md +25 -0
  308. package/.pi/skills/zob-split-refactor/SKILL.md +39 -0
  309. package/.pi/skills/zob-tool-router/SKILL.md +104 -0
  310. package/.pi/teams/zob-core.json +122 -0
  311. package/AGENTS.md +89 -0
  312. package/CONTRIBUTING.md +56 -0
  313. package/LICENSE +21 -0
  314. package/README.md +360 -0
  315. package/SECURITY.md +35 -0
  316. package/SOURCE_INDEX.md +46 -0
  317. package/package.json +135 -0
  318. package/scripts/README.md +57 -0
  319. package/scripts/autonomy/mission-readiness-secret-smoke.mjs +90 -0
  320. package/scripts/compute-profile/plan-workflow.mjs +85 -0
  321. package/scripts/compute-profile/preview.mjs +242 -0
  322. package/scripts/compute-profile/regression-smoke.mjs +38 -0
  323. package/scripts/compute-profile/summarize.mjs +72 -0
  324. package/scripts/compute-profile/validate-policy.mjs +50 -0
  325. package/scripts/compute-profile/validate-preview.mjs +95 -0
  326. package/scripts/compute-profile/validate-workflow.mjs +58 -0
  327. package/scripts/git-ops/commit-policy-smoke.mjs +221 -0
  328. package/scripts/goal-todo/child-goal-ref-smoke.mjs +252 -0
  329. package/scripts/harness-switch/static-smoke.mjs +43 -0
  330. package/scripts/model-catalog/validate-economy.mjs +223 -0
  331. package/scripts/model-catalog/validate.mjs +199 -0
  332. package/scripts/package-surface/validate-script-refs.mjs +190 -0
  333. package/scripts/path-policy/validate-smoke.mjs +103 -0
  334. package/scripts/project-dna/bench-smoke.mjs +217 -0
  335. package/scripts/project-dna/build-capsules.mjs +207 -0
  336. package/scripts/project-dna/build-sample-spec.mjs +140 -0
  337. package/scripts/project-dna/emit-golden-cases.mjs +75 -0
  338. package/scripts/project-dna/emit-ontology.mjs +75 -0
  339. package/scripts/project-dna/generate-sample.mjs +302 -0
  340. package/scripts/project-dna/oracle-review-smoke.mjs +157 -0
  341. package/scripts/project-dna/plan-workflow.mjs +289 -0
  342. package/scripts/project-dna/query-context.mjs +276 -0
  343. package/scripts/project-dna/query-steward.mjs +149 -0
  344. package/scripts/project-dna/scan.mjs +553 -0
  345. package/scripts/project-dna/validate-5of5.mjs +159 -0
  346. package/scripts/project-dna/validate-golden-cases.mjs +78 -0
  347. package/scripts/project-dna/validate-ontology.mjs +97 -0
  348. package/scripts/project-dna/validate-sample-project.mjs +105 -0
  349. package/scripts/project-dna/validate-scaffold.mjs +383 -0
  350. package/scripts/project-dna/validate-scan-artifacts.mjs +187 -0
  351. package/scripts/project-dna/validate-workflow.mjs +166 -0
  352. package/scripts/start-pi.sh +4 -0
  353. package/scripts/worker-pool/static-smoke.mjs +54 -0
  354. package/scripts/zpeer-local-e2e-smoke.mjs +395 -0
  355. package/scripts/zpeer-static-smoke.mjs +129 -0
  356. package/tsconfig.json +12 -0
@@ -0,0 +1,736 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { compact, generateBranchSummary, isToolCallEventType } from "@earendil-works/pi-coding-agent";
3
+ import { Text } from "@earendil-works/pi-tui";
4
+
5
+ import { MODE_PROMPTS, ZOB_COMPACTION_CONTINUITY_CONTRACT, ZOB_TOOL_ROUTING_CONTRACT } from "../constants.js";
6
+ import { buildCurrentZobLivePeerCard } from "../coms-v2/identity.js";
7
+ import { buildZobLiveAckEnvelope, buildZobLiveErrorEnvelope, buildZobLivePongEnvelope } from "../coms-v2/envelope.js";
8
+ import { appendLiveCompletedRef } from "../coms-v2/ledger-bridge.js";
9
+ import { bindZobLocalEndpoint, makeZobLocalEndpoint, sendZobLocalEnvelope } from "../coms-v2/local-transport.js";
10
+ import { readZobComsV2Policy } from "../coms-v2/policy.js";
11
+ import { registerCurrentZobLivePeer, touchCurrentZobLivePeer, unregisterCurrentZobLivePeer, writeZobLivePeerCard } from "../coms-v2/registry.js";
12
+ import { readZpeerLocalProfile } from "../coms-v2/zpeer-profile.js";
13
+ import { buildZpeerRoomSummary, ensureZpeerFields, refreshZpeerSelf } from "../coms-v2/zpeer.js";
14
+ import { buildZobLiveResponseEnvelope } from "../coms-v2/response-capture.js";
15
+ import { writeZobComsRedactedCapture } from "../coms-v2/transcript-capture.js";
16
+ import { formatGoalActivationMode, runtimeGoalStatusLine } from "../goal-runtime.js";
17
+ import { formatInteractiveAutonomyPromptHint, formatMissionReadinessForUi, scoreMissionReadiness, toMissionReadinessLedgerEntry } from "../interactive-autonomy.js";
18
+ import { formatGoalTodoPromptHint } from "../goal-todos.js";
19
+ import { resolveRuleProfile } from "../rules.js";
20
+ import { loadDamageRules } from "../safety.js";
21
+ import { loadTeamDefinition, validateTeamDefinition } from "../topology/teams.js";
22
+ import type { AssistantLikeMessage } from "../types.js";
23
+ import { blockedFeedback } from "../utils/formatting.js";
24
+ import { sha256 } from "../utils/hashing.js";
25
+ import { buildZcommitPlan, recordZcommitTouchedFile, runGovernedZcommitCommit, runGovernedZcommitPush, type ZcommitCommandResult, type ZcommitOwnedPathRef, type ZcommitPlan } from "../git-ops.js";
26
+ import { pathMatches } from "../utils/paths.js";
27
+ import { isRecord, textFromMessage } from "../utils/records.js";
28
+ import { showDelegationOverlay } from "./delegation-overlay.js";
29
+ import { buildDeterministicZobCompactionResult, buildDeterministicZobCompactionSummary, buildZobCompactionInstructions, buildZobCompactionLedgerEntry, withZobCompactionDetails, ZOB_COMPACTION_ENTRY_TYPE, zobCompactionBodyFreeViolations } from "./compaction-policy.js";
30
+ import { buildZcompactPreparation, cancelZcompactPending, maybeTriggerZcompact, runZcompactCompactionHook } from "./auto-compaction.js";
31
+ import { disposeDelegationMouseSupport } from "./delegation-mouse.js";
32
+ import type { HarnessRuntimeState, ZobLiveLastEvent } from "./state.js";
33
+ import { bashLooksLikeFileMutation, inferModeFromUserIntent, restoreHarnessState } from "./state.js";
34
+ import { extractModeIntent, stripModeIntentMarkup, validateModeIntent, type ZobModeIntent } from "./mode-intent.js";
35
+ import { capturePlanArtifact } from "./plan-capture.js";
36
+ import { applyMode, renderHarnessWidget } from "./widget.js";
37
+
38
+ function safelyUpdateZobLivePeer(repoRoot: string, action: "register" | "touch" | "unregister"): void {
39
+ try {
40
+ if (action === "register") registerCurrentZobLivePeer(repoRoot);
41
+ else if (action === "touch") touchCurrentZobLivePeer(repoRoot);
42
+ else unregisterCurrentZobLivePeer(repoRoot);
43
+ } catch {
44
+ // Live presence is observe-only in this phase and must not break the harness runtime.
45
+ }
46
+ }
47
+
48
+ function setZpeerLastEvent(state: HarnessRuntimeState, event: Omit<ZobLiveLastEvent, "at" | "localOnly" | "networkEnabled" | "bodyStored"> & { at?: string }): void {
49
+ state.zobLive.lastEvent = {
50
+ ...event,
51
+ at: event.at ?? new Date().toISOString(),
52
+ localOnly: true,
53
+ networkEnabled: false,
54
+ bodyStored: false,
55
+ };
56
+ }
57
+
58
+ const ZPEER_HEARTBEAT_MIN_INTERVAL_MS = 20_000;
59
+
60
+ function clearZpeerHeartbeatTimer(state: HarnessRuntimeState): void {
61
+ if (state.zobLive.heartbeatTimer) clearTimeout(state.zobLive.heartbeatTimer);
62
+ state.zobLive.heartbeatTimer = undefined;
63
+ }
64
+
65
+ function scheduleZpeerHeartbeat(state: HarnessRuntimeState, repoRoot: string): void {
66
+ if (!state.zobLive.server || !state.zobLive.peerCard) return;
67
+ clearZpeerHeartbeatTimer(state);
68
+ const peer = state.zobLive.peerCard;
69
+ const intervalMs = Math.max(ZPEER_HEARTBEAT_MIN_INTERVAL_MS, Math.min(peer.staleAfterMs / 2, 60_000));
70
+ const timer = setTimeout(() => {
71
+ try {
72
+ if (!state.zobLive.server || !state.zobLive.peerCard) return;
73
+ state.zobLive.peerCard = refreshZpeerSelf(repoRoot, state.zobLive.peerCard);
74
+ state.zobLive.lastHeartbeatMs = Date.now();
75
+ } catch {
76
+ // Heartbeat is best-effort and must not break the harness runtime.
77
+ } finally {
78
+ if (state.zobLive.server && state.zobLive.peerCard) scheduleZpeerHeartbeat(state, repoRoot);
79
+ }
80
+ }, intervalMs);
81
+ timer.unref?.();
82
+ state.zobLive.heartbeatTimer = timer;
83
+ }
84
+
85
+ function formatZpeerLastEvent(event: ZobLiveLastEvent | undefined): string {
86
+ if (!event) return "none";
87
+ const route = event.fromAlias || event.toAlias ? `${event.fromAlias ? `@${event.fromAlias}` : "?"}→${event.toAlias ? `@${event.toAlias}` : "?"}` : "room";
88
+ const hash = event.outputHash ? ` outputHash=${event.outputHash.slice(0, 12)}` : event.taskHash ? ` taskHash=${event.taskHash.slice(0, 12)}` : "";
89
+ const reason = event.reason ? ` · ${event.reason}` : "";
90
+ return `${event.kind} ${route} ${event.status}${hash}${reason}`;
91
+ }
92
+
93
+ function buildZpeerAwarenessPrompt(state: HarnessRuntimeState, repoRoot: string): string {
94
+ if (!state.zobLive.peerCard) {
95
+ return "\n\nZPEER AWARENESS\n- local peer endpoint: unavailable this turn\n- Use zpeer_ask with mode=\"async\" or /zpeer only when useful or user-requested for peer coordination; avoid spam/loops and do not invent hidden worker-to-worker chat.";
96
+ }
97
+ const summary = buildZpeerRoomSummary(repoRoot, state.zobLive.peerCard);
98
+ const memberships = state.zobLive.peerCard.zpeerMemberships?.length ?? summary.membershipCount ?? 1;
99
+ const selfAlias = summary.selfAlias ?? "?";
100
+ const peerAliases = summary.aliases.filter((alias) => alias !== selfAlias).slice(0, 8).map((alias) => `@${alias}`);
101
+ const unavailable = summary.stale + summary.offline;
102
+ const duplicateLine = summary.duplicateAliases.length > 0 ? `\n- duplicate aliases: ${summary.duplicateAliases.map((alias) => `@${alias}`).join(", ")}` : "";
103
+ return `\n\nZPEER AWARENESS (transient, rebuilt each turn)\n- room: ${summary.roomId}\n- memberships: ${memberships}\n- self: @${selfAlias}\n- online peers: ${peerAliases.join(", ") || "none"}\n- unavailable peers: ${unavailable} (stale=${summary.stale}, offline=${summary.offline})${duplicateLine}\n- posture: local_socket-only, room-scoped, hash-only durable ledgers, bodyStored=false, networkEnabled=false\n- For non-trivial review/debug/planning peer coordination, agents may use zpeer_ask with mode=\"async\" so the request is visible, governed, and non-blocking; /zpeer remains the interactive command path.\n- Use ZPeer only when useful or user-requested; avoid spam, duplicate asks, and reply loops; do not use it for hidden free chat or to bypass topology/safety gates.\n- Raw ZPeer bodies are transient; durable records must remain hash-only/bodyStored=false.\n- last ZPeer event: ${formatZpeerLastEvent(state.zobLive.lastEvent)}`;
104
+ }
105
+
106
+ const SAME_AGENT_MODE_INTENT_PROMPT = [
107
+ "ZOB SAME-AGENT AUTO-MODE INTENT",
108
+ "- If the current ZOB mode does not match the next required action, emit at most one standalone intent line:",
109
+ " <zob_mode_intent mode=\"explore|plan|implement|oracle|factory|orchestrator\" confidence=\"low|medium|high\" risk=\"low|medium|high\" reason=\"short reason\"/>",
110
+ "- This is only a suggestion; the harness validates and applies mode changes.",
111
+ "- Do not claim the mode switched unless the harness reports it.",
112
+ "- SINGLE-PLAN RULE: if you produce a complete plan in this response, do not also emit a plan-mode intent.",
113
+ "- Emit mode=plan only when deferring the actual detailed plan to a follow-up turn; in that case keep this response to a short handoff.",
114
+ "- Never both: full plan content and mode=plan intent in the same response.",
115
+ "- Prefer orchestrator for multi-agent decomposition, Chief Vision coordination, Lead/Worker orchestration, TODO/workgraph routing, and parent-owned dispatch.",
116
+ "- Prefer implement for code/file edits, oracle for validation/review/no-ship, factory for reusable repeatable workflows/factories.",
117
+ "- Do not emit an intent for ordinary discussion or when the current mode already fits.",
118
+ ].join("\n");
119
+
120
+ function latestAssistantText(event: unknown): string {
121
+ const messages = isRecord(event) && Array.isArray(event.messages) ? event.messages : [];
122
+ const assistantMessages = messages.filter((message): message is AssistantLikeMessage => isRecord(message) && message.role === "assistant");
123
+ return textFromMessage(assistantMessages.at(-1));
124
+ }
125
+
126
+ function stripModeIntentFromMessage<T extends { content?: unknown }>(message: T): T {
127
+ const content = message.content;
128
+ if (typeof content === "string") return { ...message, content: stripModeIntentMarkup(content) };
129
+ if (!Array.isArray(content)) return message;
130
+ const mapped = content.map((part) => {
131
+ if (!isRecord(part) || part.type !== "text" || typeof part.text !== "string") return part;
132
+ return { ...part, text: stripModeIntentMarkup(part.text) };
133
+ }).filter((part) => !(isRecord(part) && part.type === "text" && typeof part.text === "string" && part.text.trim().length === 0));
134
+ return { ...message, content: mapped.length > 0 ? mapped : "" } as T;
135
+ }
136
+
137
+ function modeIntentContent(intent: ZobModeIntent, previousMode: string, accepted: boolean, validationReason: string): string {
138
+ const status = accepted ? `${previousMode} → ${intent.mode}` : `${intent.mode} ignored`;
139
+ return `${status} · ${intent.confidence}${intent.risk ? `/${intent.risk}` : ""} · ${intent.reason} · ${validationReason}`;
140
+ }
141
+
142
+ function handleSameAgentModeIntent(pi: ExtensionAPI, state: HarnessRuntimeState, ctx: ExtensionContext, intent: ZobModeIntent, assistantText = ""): void {
143
+ const previousMode = state.activeMode;
144
+ const validation = validateModeIntent(intent, state.activeMode, state.lastUserInputText ?? "", assistantText);
145
+ state.lastModeIntent = { ...intent, at: Date.now(), accepted: validation.accepted, validationReason: validation.reason };
146
+ if (validation.accepted) {
147
+ applyMode(pi, state, ctx, intent.mode);
148
+ ctx.ui.notify(`ZOB same-agent auto-mode: ${previousMode} → ${intent.mode} (${intent.confidence}; ${intent.reason})`, "info");
149
+ } else {
150
+ renderHarnessWidget(pi, state, ctx);
151
+ }
152
+ pi.sendMessage({
153
+ customType: "zob-mode-intent",
154
+ content: modeIntentContent(intent, previousMode, validation.accepted, validation.reason),
155
+ display: true,
156
+ details: { intent, previousMode, accepted: validation.accepted, validationReason: validation.reason, at: new Date().toISOString() },
157
+ }, { triggerTurn: false });
158
+ }
159
+
160
+ async function startOrRefreshZobLiveRuntime(pi: ExtensionAPI, state: HarnessRuntimeState, repoRoot: string): Promise<void> {
161
+ const policy = readZobComsV2Policy(repoRoot);
162
+ if (policy.mode === "off" || policy.mode === "required_network") {
163
+ safelyUpdateZobLivePeer(repoRoot, state.zobLive.peerCard ? "touch" : "register");
164
+ return;
165
+ }
166
+ const team = loadTeamDefinition(repoRoot, "zob-core");
167
+ if (!team.definition && team.errors.some((error) => error.startsWith("Team topology not found:"))) {
168
+ safelyUpdateZobLivePeer(repoRoot, state.zobLive.peerCard ? "touch" : "register");
169
+ return;
170
+ }
171
+ const errors = [...team.errors, ...validateTeamDefinition(repoRoot, team.definition)];
172
+ if (errors.length > 0 || !team.definition) throw new Error(errors.join("; "));
173
+ const definition = team.definition;
174
+ const zpeerProfile = readZpeerLocalProfile(repoRoot);
175
+ if (!state.zobLive.server || !state.zobLive.peerCard) {
176
+ const basePeer = buildCurrentZobLivePeerCard(repoRoot, definition, policy);
177
+ const endpoint = makeZobLocalEndpoint(basePeer.sessionId);
178
+ const server = await bindZobLocalEndpoint(endpoint, async (envelope) => {
179
+ if (envelope.type === "ping") return buildZobLivePongEnvelope(envelope);
180
+ if (envelope.type === "response") {
181
+ state.zobLive.pendingReplies.complete(envelope.msgId, envelope);
182
+ setZpeerLastEvent(state, {
183
+ kind: "reply",
184
+ roomId: envelope.runId?.startsWith("zpeer:") ? envelope.runId.slice("zpeer:".length) : undefined,
185
+ fromAlias: envelope.sender,
186
+ toAlias: envelope.receiver,
187
+ status: "reply",
188
+ msgId: envelope.msgId,
189
+ taskHash: envelope.taskHash,
190
+ outputHash: envelope.outputHash,
191
+ });
192
+ void pi.sendMessage({
193
+ customType: "zob-zpeer-event",
194
+ content: "ZPeer reply received (transient response available; durable records remain hash-only)",
195
+ display: true,
196
+ details: { kind: "reply", roomId: state.zobLive.lastEvent?.roomId, fromAlias: envelope.sender, toAlias: envelope.receiver, status: "reply", msgId: envelope.msgId, taskHash: envelope.taskHash, outputHash: envelope.outputHash, bodyStored: false, localOnly: true, networkEnabled: false },
197
+ }, { triggerTurn: false });
198
+ if (envelope.transientResponse) {
199
+ void pi.sendMessage({
200
+ customType: "zob-zpeer-response",
201
+ content: envelope.transientResponse,
202
+ display: true,
203
+ details: { msgId: envelope.msgId, outputHash: envelope.outputHash, bodyStored: false, localOnly: true, networkEnabled: false },
204
+ }, { triggerTurn: false });
205
+ }
206
+ const parentMsgId = envelope.runId && envelope.receiver && envelope.sender ? `${envelope.runId}:${envelope.receiver}:${envelope.sender}:${envelope.msgId}` : undefined;
207
+ if (parentMsgId) {
208
+ try { appendLiveCompletedRef(repoRoot, definition, parentMsgId, envelope); } catch { /* best-effort ledger correlation; await response still completes */ }
209
+ }
210
+ return buildZobLiveAckEnvelope(envelope);
211
+ }
212
+ if (envelope.type !== "prompt") return buildZobLiveErrorEnvelope(envelope, `Unsupported inbound envelope type: ${envelope.type}`, "unsupported_envelope");
213
+ state.zobLive.inbound = { envelope, receivedAt: new Date().toISOString(), responseSent: false, repoRoot };
214
+ setZpeerLastEvent(state, {
215
+ kind: "inbound",
216
+ roomId: envelope.runId?.startsWith("zpeer:") ? envelope.runId.slice("zpeer:".length) : undefined,
217
+ fromAlias: envelope.sender,
218
+ toAlias: envelope.receiver,
219
+ status: "prompt_received",
220
+ msgId: envelope.msgId,
221
+ taskHash: envelope.taskHash,
222
+ });
223
+ void pi.sendMessage({
224
+ customType: "zob-zpeer-event",
225
+ content: "ZPeer inbound prompt received (transient body delivered only to agent turn)",
226
+ display: true,
227
+ details: { kind: "inbound", roomId: state.zobLive.lastEvent?.roomId, fromAlias: envelope.sender, toAlias: envelope.receiver, status: "prompt_received", msgId: envelope.msgId, taskHash: envelope.taskHash, bodyStored: false, localOnly: true, networkEnabled: false },
228
+ }, { triggerTurn: false });
229
+ void pi.sendMessage({
230
+ customType: "zob-coms-inbound",
231
+ content: envelope.transientPrompt ?? "",
232
+ display: false,
233
+ details: { kind: "zob-coms-inbound", msgId: envelope.msgId, runId: envelope.runId, sender: envelope.sender, receiver: envelope.receiver, taskHash: envelope.taskHash },
234
+ }, { triggerTurn: true, deliverAs: "followUp" });
235
+ return buildZobLiveAckEnvelope(envelope);
236
+ });
237
+ const peerCard = ensureZpeerFields(repoRoot, { ...basePeer, transport: "local_socket" as const, endpoint, endpointHash: sha256(endpoint), status: "online" as const }, zpeerProfile?.activeRoomId ?? zpeerProfile?.roomId, zpeerProfile?.alias, zpeerProfile?.memberships);
238
+ state.zobLive.server = server;
239
+ state.zobLive.peerCard = refreshZpeerSelf(repoRoot, peerCard);
240
+ state.zobLive.lastHeartbeatMs = Date.now();
241
+ scheduleZpeerHeartbeat(state, repoRoot);
242
+ } else {
243
+ state.zobLive.peerCard = refreshZpeerSelf(repoRoot, ensureZpeerFields(repoRoot, { ...state.zobLive.peerCard, heartbeatAt: new Date().toISOString(), status: "online" }, zpeerProfile?.activeRoomId ?? zpeerProfile?.roomId, zpeerProfile?.alias, zpeerProfile?.memberships));
244
+ state.zobLive.lastHeartbeatMs = Date.now();
245
+ scheduleZpeerHeartbeat(state, repoRoot);
246
+ }
247
+ }
248
+
249
+ async function stopZobLiveRuntime(state: HarnessRuntimeState, repoRoot: string): Promise<void> {
250
+ try {
251
+ clearZpeerHeartbeatTimer(state);
252
+ if (state.zobLive.peerCard) writeZobLivePeerCard(repoRoot, { ...state.zobLive.peerCard, heartbeatAt: new Date().toISOString(), status: "offline" });
253
+ if (state.zobLive.server) await state.zobLive.server.close();
254
+ } finally {
255
+ state.zobLive = { pendingReplies: state.zobLive.pendingReplies };
256
+ }
257
+ }
258
+
259
+ function notifyWhenUi(ctx: ExtensionContext, message: string, level: "info" | "warning" | "error" = "info"): void {
260
+ if (ctx.hasUI) ctx.ui.notify(message, level);
261
+ }
262
+
263
+ function zcommitOwnedPathLedgerRefs(state: HarnessRuntimeState): Array<Pick<ZcommitOwnedPathRef, "path" | "source" | "pathHash" | "lastOwnedAt">> {
264
+ return Object.values(state.zcommit.ownedPathRefs ?? {}).map((ref) => ({ path: ref.path, source: ref.source, pathHash: ref.pathHash, lastOwnedAt: ref.lastOwnedAt })).sort((a, b) => a.path.localeCompare(b.path));
265
+ }
266
+
267
+ function zcommitContinuityLedgerEntry(action: string, state: HarnessRuntimeState): Record<string, unknown> {
268
+ return {
269
+ schema: "zob.zcommit-continuity.v1",
270
+ bodyStored: false,
271
+ action,
272
+ autocommit: state.zcommit.autocommit,
273
+ autopush: state.zcommit.autopush,
274
+ ownedPathRefs: zcommitOwnedPathLedgerRefs(state),
275
+ generatedAt: new Date().toISOString(),
276
+ };
277
+ }
278
+
279
+ function zcommitAutomationLedgerEntry(action: string, state: HarnessRuntimeState, plan: ZcommitPlan, result?: ZcommitCommandResult): Record<string, unknown> {
280
+ return {
281
+ schema: "zob.zcommit-message-end.v1",
282
+ bodyStored: false,
283
+ action,
284
+ status: result ? (result.ok ? "ok" : "blocked_or_failed") : undefined,
285
+ autocommit: state.zcommit.autocommit,
286
+ autopush: state.zcommit.autopush,
287
+ policyLoaded: plan.policyLoaded,
288
+ selectionMode: plan.selectionMode,
289
+ validationMode: plan.validationMode,
290
+ selectionPathspecHashes: plan.selectionPathspecs.map((pathspec) => sha256(pathspec)),
291
+ dirtyCount: plan.dirtyFiles.length,
292
+ touchedCount: plan.touchedFiles.length,
293
+ eligibleCount: plan.eligible.length,
294
+ excludedCount: plan.excluded.length,
295
+ forbiddenCount: plan.forbidden.length,
296
+ unexpectedStagedCount: plan.unexpectedStaged.length,
297
+ eligiblePathHashes: plan.eligible.map((file) => sha256(file.path)),
298
+ excludedPathHashes: plan.excluded.map((file) => sha256(file.path)),
299
+ ownedPathRefs: zcommitOwnedPathLedgerRefs(state),
300
+ noShip: plan.noShip,
301
+ commitEnabled: plan.commitEnabled,
302
+ pushEnabled: plan.pushEnabled,
303
+ lastCommitHash: state.zcommit.lastCommit?.hash,
304
+ lastCommitShortHash: state.zcommit.lastCommit?.shortHash,
305
+ validationOk: result?.validation?.ok,
306
+ validationCommand: result?.validation?.command,
307
+ errorHashes: result?.errors.map((error) => sha256(error)),
308
+ actualGitCommitRun: result?.actualGitCommitRun ?? false,
309
+ actualGitPushRun: result?.actualGitPushRun ?? false,
310
+ generatedAt: new Date().toISOString(),
311
+ };
312
+ }
313
+
314
+ async function maybeRunZcommitMessageEndAutomation(pi: ExtensionAPI, state: HarnessRuntimeState, ctx: ExtensionContext): Promise<void> {
315
+ if (state.zcommit.autocommit !== "on") return;
316
+ try {
317
+ const plan = buildZcommitPlan(ctx.cwd, state.zcommit);
318
+ const commitResult = runGovernedZcommitCommit(ctx.cwd, state.zcommit);
319
+ pi.appendEntry("zob-zcommit", zcommitAutomationLedgerEntry(commitResult.ok ? "autocommit_created" : "autocommit_blocked", state, commitResult.plan ?? plan, commitResult));
320
+ notifyWhenUi(ctx, `zcommit autocommit: ${commitResult.message}`, commitResult.ok ? "info" : "warning");
321
+ if (commitResult.ok && state.zcommit.autopush === "on") {
322
+ const pushResult = runGovernedZcommitPush(ctx.cwd, state.zcommit, { explicitPush: false });
323
+ pi.appendEntry("zob-zcommit", zcommitAutomationLedgerEntry(pushResult.ok ? "autopush_completed" : "autopush_blocked", state, pushResult.plan, pushResult));
324
+ notifyWhenUi(ctx, `zcommit autopush: ${pushResult.message}`, pushResult.ok ? "info" : "warning");
325
+ }
326
+ renderHarnessWidget(pi, state, ctx);
327
+ } catch (error) {
328
+ const message = error instanceof Error ? error.message : String(error);
329
+ const plan = buildZcommitPlan(ctx.cwd, state.zcommit);
330
+ pi.appendEntry("zob-zcommit", {
331
+ ...zcommitAutomationLedgerEntry("autocommit_error", state, plan),
332
+ status: "blocked_or_failed",
333
+ errorHashes: [sha256(message)],
334
+ });
335
+ notifyWhenUi(ctx, "zcommit autocommit hook failed; see body-free ledger hashes", "warning");
336
+ }
337
+ }
338
+
339
+ async function compactionAuth(ctx: ExtensionContext): Promise<{ apiKey?: string; headers?: Record<string, string> } | undefined> {
340
+ const model = ctx.model;
341
+ if (!model) return undefined;
342
+ const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
343
+ if (!auth.ok) return undefined;
344
+ return { apiKey: auth.apiKey, headers: auth.headers };
345
+ }
346
+
347
+ async function sendInboundZobLiveResponse(pi: ExtensionAPI, state: HarnessRuntimeState, event: unknown): Promise<void> {
348
+ const inbound = state.zobLive.inbound;
349
+ if (!inbound || inbound.responseSent || !inbound.envelope.replyEndpoint) return;
350
+ const responseText = latestAssistantText(event);
351
+ if (!responseText.trim()) return;
352
+ const policy = readZobComsV2Policy(inbound.repoRoot);
353
+ let responseCapture: ReturnType<typeof writeZobComsRedactedCapture>;
354
+ try {
355
+ responseCapture = writeZobComsRedactedCapture(inbound.repoRoot, policy.transcriptCapture, {
356
+ runId: inbound.envelope.runId,
357
+ msgId: inbound.envelope.msgId,
358
+ sender: inbound.envelope.receiver,
359
+ receiver: inbound.envelope.sender,
360
+ team: inbound.envelope.team,
361
+ kind: "live_exchange",
362
+ taskHash: inbound.envelope.taskHash,
363
+ outputHash: sha256(responseText),
364
+ transientPrompt: inbound.envelope.transientPrompt,
365
+ transientResponse: responseText,
366
+ artifactRefs: inbound.envelope.artifactRefs,
367
+ });
368
+ } catch {
369
+ responseCapture = undefined;
370
+ }
371
+ const artifactRefs = responseCapture ? [...(inbound.envelope.artifactRefs ?? []), responseCapture.artifactRef] : inbound.envelope.artifactRefs;
372
+ const artifactHashes = responseCapture ? [...(inbound.envelope.artifactHashes ?? []), responseCapture.artifactHash] : inbound.envelope.artifactHashes;
373
+ const responseEnvelope = buildZobLiveResponseEnvelope(inbound.envelope, responseText, artifactRefs, artifactHashes);
374
+ await sendZobLocalEnvelope(inbound.envelope.replyEndpoint, responseEnvelope, { timeoutMs: 5_000 });
375
+ state.zobLive.inbound = { ...inbound, responseSent: true };
376
+ setZpeerLastEvent(state, {
377
+ kind: "response_sent",
378
+ roomId: inbound.envelope.runId?.startsWith("zpeer:") ? inbound.envelope.runId.slice("zpeer:".length) : undefined,
379
+ fromAlias: inbound.envelope.receiver,
380
+ toAlias: inbound.envelope.sender,
381
+ status: "response_sent",
382
+ msgId: inbound.envelope.msgId,
383
+ taskHash: inbound.envelope.taskHash,
384
+ outputHash: responseEnvelope.outputHash,
385
+ });
386
+ void pi.sendMessage({
387
+ customType: "zob-zpeer-event",
388
+ content: "ZPeer response sent (transient response delivered over local socket; durable records remain hash-only)",
389
+ display: true,
390
+ details: { kind: "response_sent", roomId: state.zobLive.lastEvent?.roomId, fromAlias: inbound.envelope.receiver, toAlias: inbound.envelope.sender, status: "response_sent", msgId: inbound.envelope.msgId, taskHash: inbound.envelope.taskHash, outputHash: responseEnvelope.outputHash, bodyStored: false, localOnly: true, networkEnabled: false },
391
+ }, { triggerTurn: false });
392
+ }
393
+
394
+ export function registerHarnessEvents(pi: ExtensionAPI, state: HarnessRuntimeState): void {
395
+ pi.registerMessageRenderer("zob-zpeer-event", (message, { expanded }, theme) => {
396
+ const details = isRecord(message.details) ? message.details : {};
397
+ const kind = typeof details.kind === "string" ? details.kind : "event";
398
+ const roomId = typeof details.roomId === "string" ? details.roomId : "default";
399
+ const fromAlias = typeof details.fromAlias === "string" ? details.fromAlias : undefined;
400
+ const toAlias = typeof details.toAlias === "string" ? details.toAlias : undefined;
401
+ const status = typeof details.status === "string" ? details.status : "unknown";
402
+ const reason = typeof details.reason === "string" ? details.reason : undefined;
403
+ const taskHash = typeof details.taskHash === "string" ? details.taskHash : undefined;
404
+ const outputHash = typeof details.outputHash === "string" ? details.outputHash : undefined;
405
+ const route = fromAlias || toAlias ? `${fromAlias ? `@${fromAlias}` : "?"} → ${toAlias ? `@${toAlias}` : "?"}` : "room status";
406
+ const statusColor = status === "completed" || status === "sent" || status === "prompt_received" || status === "response_sent" ? "success" : status === "blocked" || status === "timeout" || status === "error" ? "warning" : "muted";
407
+ const line = [
408
+ theme.fg("accent", "◆ ZPeer"),
409
+ theme.fg("muted", kind),
410
+ theme.fg("dim", `room ${roomId}`),
411
+ theme.fg("muted", route),
412
+ theme.fg(statusColor, status),
413
+ ].join(theme.fg("dim", " · "));
414
+ const hashes = [taskHash ? `taskHash=${taskHash.slice(0, 12)}` : undefined, outputHash ? `outputHash=${outputHash.slice(0, 12)}` : undefined].filter(Boolean).join(" · ");
415
+ const expandedLine = expanded ? `\n${theme.fg("dim", [reason, hashes, "localOnly=true networkEnabled=false bodyStored=false"].filter(Boolean).join(" · "))}` : reason ? ` ${theme.fg("dim", `(${reason})`)}` : "";
416
+ return new Text(`${line}${expandedLine}`, 0, 0);
417
+ });
418
+
419
+ pi.registerMessageRenderer("zob-mode-intent", (message, { expanded }, theme) => {
420
+ const details = isRecord(message.details) ? message.details : {};
421
+ const intent = isRecord(details.intent) ? details.intent : {};
422
+ const mode = typeof intent.mode === "string" ? intent.mode : "mode";
423
+ const confidence = typeof intent.confidence === "string" ? intent.confidence : "?";
424
+ const risk = typeof intent.risk === "string" ? intent.risk : "low";
425
+ const previousMode = typeof details.previousMode === "string" ? details.previousMode : "current";
426
+ const accepted = details.accepted === true;
427
+ const validationReason = typeof details.validationReason === "string" ? details.validationReason : "validated";
428
+ const reason = typeof intent.reason === "string" ? intent.reason : String(message.content ?? "");
429
+ const icon = accepted ? "◆" : "◇";
430
+ const color = accepted ? "success" : "dim";
431
+ const status = accepted ? `${previousMode} → ${mode}` : `${mode} ignored`;
432
+ const line = [
433
+ theme.fg(color, `${icon} auto-mode`),
434
+ theme.fg(accepted ? "accent" : "muted", status),
435
+ theme.fg(confidence === "high" ? "success" : confidence === "medium" ? "warning" : "dim", confidence),
436
+ theme.fg(risk === "high" ? "warning" : "dim", `risk ${risk}`),
437
+ theme.fg("muted", reason),
438
+ ].join(theme.fg("dim", " · "));
439
+ const expandedLine = expanded ? `\n${theme.fg("dim", validationReason)}` : "";
440
+ return new Text(`${line}${expandedLine}`, 0, 0);
441
+ });
442
+
443
+ pi.on("input", async (event, ctx) => {
444
+ if (event.source !== "extension") {
445
+ const delegatesMatch = event.text.trim().match(/^\/(?:delegates?|view[_-]?delegates)(?:\s+(\S+))?$/i);
446
+ if (delegatesMatch) {
447
+ await showDelegationOverlay(ctx, state, delegatesMatch[1]);
448
+ return { action: "handled" as const };
449
+ }
450
+ state.lastUserInputText = event.text;
451
+ if (!event.text.trim().startsWith("/") && state.autonomy.enabled) {
452
+ const readiness = scoreMissionReadiness(event.text, { mode: state.autonomy.mode, policy: state.autonomy.policy });
453
+ state.autonomy.lastReadiness = readiness;
454
+ state.autonomy.lastLaunchAuthorization = readiness.launchAuthorization;
455
+ state.autonomy.updatedAt = readiness.generatedAt;
456
+ pi.appendEntry("zob-mission-readiness", toMissionReadinessLedgerEntry(readiness));
457
+ if (readiness.decision === "auto_launch") ctx.ui.notify(`${formatMissionReadinessForUi(readiness)} · launch authorized in-scope`, "info");
458
+ else if (readiness.decision === "block") ctx.ui.notify(formatMissionReadinessForUi(readiness), "warning");
459
+ }
460
+ }
461
+ if (event.source === "extension" || state.activeMode !== "explore") return { action: "continue" as const };
462
+ const nextMode = inferModeFromUserIntent(event.text);
463
+ if (!nextMode) return { action: "continue" as const };
464
+ applyMode(pi, state, ctx, nextMode);
465
+ const reason = nextMode === "orchestrator" ? "orchestration intent detected" : nextMode === "factory" ? "factory workflow intent detected" : "write/update intent detected";
466
+ ctx.ui.notify(`ZOB auto-mode: explore → ${nextMode} (${reason})`, "info");
467
+ return { action: "continue" as const };
468
+ });
469
+
470
+ pi.on("tool_call", async (event, ctx) => {
471
+ let violation: string | undefined;
472
+ let attempted = JSON.stringify(event.input);
473
+
474
+ const pathInputs: string[] = [];
475
+ if (isToolCallEventType("read", event) || isToolCallEventType("write", event) || isToolCallEventType("edit", event)) {
476
+ pathInputs.push(event.input.path);
477
+ }
478
+ if (isToolCallEventType("grep", event) || isToolCallEventType("find", event) || isToolCallEventType("ls", event)) {
479
+ pathInputs.push(event.input.path ?? ".");
480
+ }
481
+
482
+ for (const inputPath of pathInputs) {
483
+ for (const protectedPattern of state.currentRules.zeroAccessPaths) {
484
+ if (pathMatches(inputPath, protectedPattern, ctx.cwd)) violation = `zero-access path: ${protectedPattern}`;
485
+ }
486
+ if ((event.toolName === "write" || event.toolName === "edit") && state.activeMode === "explore" && !violation) {
487
+ violation = "explore mode is read-only; switch to /zmode implement and use edit/write for file updates";
488
+ }
489
+ if ((event.toolName === "write" || event.toolName === "edit") && !violation) {
490
+ for (const readOnly of state.currentRules.readOnlyPaths) {
491
+ if (pathMatches(inputPath, readOnly, ctx.cwd)) violation = `read-only path: ${readOnly}`;
492
+ }
493
+ }
494
+ }
495
+
496
+ if (isToolCallEventType("bash", event)) {
497
+ const command = event.input.command;
498
+ attempted = command;
499
+ if (state.activeMode === "explore" && bashLooksLikeFileMutation(command)) {
500
+ violation = "explore mode is read-only; do not mutate files through bash/python/perl/node patch scripts";
501
+ }
502
+ for (const rule of state.currentRules.bashToolPatterns) {
503
+ if (violation) break;
504
+ if (new RegExp(rule.pattern, "i").test(command)) {
505
+ if (rule.ask && ctx.hasUI) {
506
+ const ok = await ctx.ui.confirm("ZOB damage-control", `${rule.reason}\n\n${command}\n\nAllow?`, { timeout: 30000 });
507
+ if (ok) return;
508
+ }
509
+ violation = rule.reason;
510
+ break;
511
+ }
512
+ }
513
+ if (!violation) {
514
+ for (const protectedPattern of state.currentRules.zeroAccessPaths) {
515
+ if (command.includes(protectedPattern)) violation = `bash references zero-access path: ${protectedPattern}`;
516
+ }
517
+ }
518
+ if (!violation) {
519
+ for (const noDelete of state.currentRules.noDeletePaths) {
520
+ if (command.includes(noDelete) && /\b(rm|mv)\b/.test(command)) violation = `delete/move protected path: ${noDelete}`;
521
+ }
522
+ }
523
+ }
524
+
525
+ if (violation) {
526
+ pi.appendEntry("zob-damage-control", { tool: event.toolName, input: event.input, violation, timestamp: Date.now() });
527
+ ctx.ui.notify(`Blocked ${event.toolName}: ${violation}`, "warning");
528
+ return { block: true, reason: blockedFeedback(event.toolName, violation, attempted) };
529
+ }
530
+
531
+ if (isToolCallEventType("write", event) || isToolCallEventType("edit", event)) {
532
+ recordZcommitTouchedFile(state.zcommit, ctx.cwd, event.input.path, event.toolName);
533
+ }
534
+ });
535
+
536
+ pi.on("message_end", async (event, ctx) => {
537
+ if (!isRecord(event.message) || event.message.role !== "assistant") return undefined;
538
+ const text = textFromMessage(event.message as AssistantLikeMessage);
539
+ const visibleText = stripModeIntentMarkup(text);
540
+ try {
541
+ const capture = capturePlanArtifact(ctx.cwd, { assistantText: visibleText, userText: state.lastUserInputText, mode: state.activeMode });
542
+ if (capture.captured && capture.relativePath) ctx.ui.notify(`ZOB plan saved: ${capture.relativePath}`, "info");
543
+ } catch {
544
+ // Plan capture is best-effort and must not break assistant message handling.
545
+ }
546
+ const intent = extractModeIntent(text);
547
+ if (intent) handleSameAgentModeIntent(pi, state, ctx, intent, text);
548
+ await maybeRunZcommitMessageEndAutomation(pi, state, ctx);
549
+ if (!intent) return undefined;
550
+ return { message: stripModeIntentFromMessage(event.message) };
551
+ });
552
+
553
+ pi.on("session_before_compact", async (event, ctx) => {
554
+ const zcompactPending = state.zcompact.pending;
555
+ const compactionReason = zcompactPending ? zcompactPending.reason : event.customInstructions ? "manual" : "threshold";
556
+ const cancelZcompact = (reason: string) => {
557
+ cancelZcompactPending(pi, state.zcompact, reason);
558
+ notifyWhenUi(ctx, `ZOB zcompact cancelled: ${reason}`, "warning");
559
+ return { cancel: true };
560
+ };
561
+ const fallback = (reason: string) => {
562
+ notifyWhenUi(ctx, `ZOB-aware deterministic compaction fallback: ${reason}`, "warning");
563
+ let preparation = event.preparation;
564
+ try {
565
+ preparation = zcompactPending ? buildZcompactPreparation(state, event.preparation, event.branchEntries) : event.preparation;
566
+ } catch (error) {
567
+ const message = error instanceof Error ? error.message : String(error);
568
+ return cancelZcompact(message);
569
+ }
570
+ return {
571
+ compaction: buildDeterministicZobCompactionResult(state, preparation, {
572
+ reason: compactionReason,
573
+ customInstructions: event.customInstructions,
574
+ fileOps: preparation.fileOps,
575
+ }),
576
+ };
577
+ };
578
+ const auth = await compactionAuth(ctx);
579
+ if ((!ctx.model || !auth) && zcompactPending) return cancelZcompact("model/auth unavailable");
580
+ if (!ctx.model || !auth) return fallback("model/auth unavailable");
581
+ if (zcompactPending) {
582
+ try {
583
+ const compaction = await runZcompactCompactionHook(state, { preparation: event.preparation, branchEntries: event.branchEntries, ctx, apiKey: auth.apiKey, headers: auth.headers, signal: event.signal });
584
+ if (!compaction.summary.trim()) return fallback("model returned empty zcompact summary");
585
+ const violations = zobCompactionBodyFreeViolations(compaction.details);
586
+ if (violations.length > 0) return fallback(`body-free detail violation: ${violations.slice(0, 2).join(", ")}`);
587
+ return { compaction };
588
+ } catch (error) {
589
+ const message = error instanceof Error ? error.message : String(error);
590
+ return fallback(message);
591
+ }
592
+ }
593
+ const customInstructions = buildZobCompactionInstructions(state, {
594
+ reason: compactionReason,
595
+ customInstructions: event.customInstructions,
596
+ fileOps: event.preparation.fileOps,
597
+ });
598
+ try {
599
+ const result = await compact(event.preparation, ctx.model, auth.apiKey, auth.headers, customInstructions, event.signal);
600
+ if (!result.summary.trim()) return fallback("model returned empty summary");
601
+ const compaction = withZobCompactionDetails(state, result, { fileOps: event.preparation.fileOps });
602
+ const violations = zobCompactionBodyFreeViolations(compaction.details);
603
+ if (violations.length > 0) return fallback(`body-free detail violation: ${violations.slice(0, 2).join(", ")}`);
604
+ return { compaction };
605
+ } catch (error) {
606
+ const message = error instanceof Error ? error.message : String(error);
607
+ return fallback(message);
608
+ }
609
+ });
610
+
611
+ pi.on("session_compact", async (event) => {
612
+ const ledger = buildZobCompactionLedgerEntry(state, {
613
+ event: "session_compact",
614
+ summary: event.compactionEntry.summary,
615
+ firstKeptEntryId: event.compactionEntry.firstKeptEntryId,
616
+ tokensBefore: event.compactionEntry.tokensBefore,
617
+ fromExtension: event.fromExtension,
618
+ });
619
+ if (zobCompactionBodyFreeViolations(ledger).length === 0) pi.appendEntry(ZOB_COMPACTION_ENTRY_TYPE, ledger);
620
+ if (Object.keys(state.zcommit.ownedPathRefs ?? {}).length > 0) pi.appendEntry("zob-zcommit", zcommitContinuityLedgerEntry("session_compact", state));
621
+ });
622
+
623
+ pi.on("session_before_tree", async (event, ctx) => {
624
+ if (!event.preparation.userWantsSummary) return undefined;
625
+ const fallback = (reason: string) => {
626
+ notifyWhenUi(ctx, `ZOB-aware deterministic branch summary fallback: ${reason}`, "warning");
627
+ const summary = buildDeterministicZobCompactionSummary(state, {
628
+ reason: "branch_summary",
629
+ customInstructions: event.preparation.customInstructions,
630
+ });
631
+ const details = buildZobCompactionLedgerEntry(state, {
632
+ event: "session_tree",
633
+ summary,
634
+ fromExtension: true,
635
+ });
636
+ return { summary: { summary, details } };
637
+ };
638
+ const auth = await compactionAuth(ctx);
639
+ if (!ctx.model || !auth) return fallback("model/auth unavailable");
640
+ const customInstructions = buildZobCompactionInstructions(state, {
641
+ reason: "branch_summary",
642
+ customInstructions: event.preparation.customInstructions,
643
+ });
644
+ try {
645
+ const result = await generateBranchSummary(event.preparation.entriesToSummarize, {
646
+ model: ctx.model,
647
+ apiKey: auth.apiKey ?? "",
648
+ headers: auth.headers,
649
+ signal: event.signal,
650
+ customInstructions,
651
+ replaceInstructions: event.preparation.replaceInstructions,
652
+ });
653
+ if (!result.summary?.trim()) return fallback("model returned empty summary");
654
+ const details = buildZobCompactionLedgerEntry(state, {
655
+ event: "session_tree",
656
+ summary: result.summary,
657
+ readFiles: result.readFiles,
658
+ modifiedFiles: result.modifiedFiles,
659
+ fromExtension: true,
660
+ });
661
+ const violations = zobCompactionBodyFreeViolations(details);
662
+ if (violations.length > 0) return fallback(`body-free detail violation: ${violations.slice(0, 2).join(", ")}`);
663
+ return { summary: { summary: result.summary, details } };
664
+ } catch (error) {
665
+ const message = error instanceof Error ? error.message : String(error);
666
+ return fallback(message);
667
+ }
668
+ });
669
+
670
+ pi.on("before_agent_start", async (event) => {
671
+ const goalHint = state.activeGoal
672
+ ? `\n\nZOB GOAL GATE\n- ORIGINAL_USER_ASK: ${state.activeGoal.originalUserAsk}\n- ACTIVE_GOAL: ${state.activeGoal.activeGoal}\n- EXPECTED_OUTPUT: ${state.activeGoal.expectedOutput}\n- CONSTRAINTS: ${state.activeGoal.constraints}\n- VALIDATION_EVIDENCE: ${state.activeGoal.validationEvidence}`
673
+ : "\n\nZOB GOAL GATE\n- No active goal set. If the request is broad or multi-step, use /goal_gate first or restate ORIGINAL_USER_ASK / ACTIVE_GOAL explicitly before delegating.";
674
+ const runtimeGoalHint = state.runtimeGoal
675
+ ? `\n\nZOB RUNTIME GOAL\n- ${runtimeGoalStatusLine(state.runtimeGoal)}\n- activation_mode: ${formatGoalActivationMode(state.goalActivationMode)}\n- objective: ${state.runtimeGoal.objective}\n- completion policy: use resolve_goal_todo for TODO transitions; call propose_goal_completion when evidence is complete; update_goal complete is allowed only after oracle PASS/no_ship=false.\n- no_ship model: hard_no_ship blocks completion, review_no_ship is advisory review evidence, effective_no_ship is their union.\n\nZOB GOAL TODOS\n${formatGoalTodoPromptHint(state.goalTodos, state.runtimeGoal.goalId)}`
676
+ : `\n\nZOB RUNTIME GOAL\n- No runtime /goal set. Use /goal <objective> for long-running looped work; use /goal gate for strict scope.\n- activation_mode: ${formatGoalActivationMode(state.goalActivationMode)}\n\nZOB GOAL TODOS\n${formatGoalTodoPromptHint(state.goalTodos, undefined)}`;
677
+ const rules = state.activeRuleResolution;
678
+ const rulesHint = rules
679
+ ? `\n\nZOB RULE PROFILE\n- profile: ${rules.profile}\n- rule packs: ${rules.rulePacks.join(", ") || "none"}\n- required validation: ${rules.requiredValidation.join(" | ") || "not specified"}\n- oracle required: ${String(rules.oracleRequired)}\n- no-ship conditions: ${rules.noShipConditions.slice(0, 6).join(" | ") || "none"}`
680
+ : "\n\nZOB RULE PROFILE\n- Not resolved yet. Use /rules_status for diagnostics when scope is unclear.";
681
+ const autonomyHint = `\n\n${formatInteractiveAutonomyPromptHint(state.autonomy)}`;
682
+ const zpeerHint = buildZpeerAwarenessPrompt(state, state.zobLive.inbound?.repoRoot ?? process.cwd());
683
+ const contractHint = `\n\nZOB HARNESS OPERATING CONTRACT\n- Prefer Explore -> Plan -> Implement -> Oracle for non-trivial work.\n- Use the six-part contract for delegated work: TASK / EXPECTED OUTCOME / REQUIRED TOOLS / MUST DO / MUST NOT DO / CONTEXT.\n- Do not claim completion without concrete evidence.\n- If output may truncate, prioritize verdict, blockers, and next steps over exhaustive listings.\n\n${SAME_AGENT_MODE_INTENT_PROMPT}\n\n${ZOB_TOOL_ROUTING_CONTRACT}\n\n${ZOB_COMPACTION_CONTINUITY_CONTRACT}\n\n${MODE_PROMPTS[state.activeMode]}${goalHint}${runtimeGoalHint}${rulesHint}${autonomyHint}${zpeerHint}`;
684
+ return { systemPrompt: `${event.systemPrompt}${contractHint}` };
685
+ });
686
+
687
+ pi.on("session_start", async (_event, ctx) => {
688
+ disposeDelegationMouseSupport(state, { force: true });
689
+ state.currentRules = loadDamageRules(ctx.cwd);
690
+ state.delegations.runs = [];
691
+ restoreHarnessState(state, ctx);
692
+ state.activeRuleResolution = resolveRuleProfile({ repoRoot: ctx.cwd, mode: state.activeMode });
693
+ await startOrRefreshZobLiveRuntime(pi, state, ctx.cwd);
694
+ applyMode(pi, state, ctx, state.activeMode, false);
695
+ renderHarnessWidget(pi, state, ctx);
696
+ });
697
+
698
+ pi.on("tool_execution_end", async (_event, ctx) => {
699
+ await startOrRefreshZobLiveRuntime(pi, state, ctx.cwd);
700
+ renderHarnessWidget(pi, state, ctx);
701
+ });
702
+
703
+ pi.on("turn_end", async (_event, ctx) => {
704
+ await maybeTriggerZcompact(pi, state, ctx, { source: "turn_end", render: () => renderHarnessWidget(pi, state, ctx) });
705
+ renderHarnessWidget(pi, state, ctx);
706
+ });
707
+
708
+ pi.on("agent_end", async (event) => {
709
+ try {
710
+ await sendInboundZobLiveResponse(pi, state, event);
711
+ } catch {
712
+ // Response capture is best-effort until the full live await path is enabled.
713
+ }
714
+ });
715
+
716
+ pi.on("session_shutdown", async (_event, ctx) => {
717
+ if (state.daemon.loopTimer) clearTimeout(state.daemon.loopTimer);
718
+ state.daemon.loopTimer = undefined;
719
+ state.daemon.loop = {
720
+ ...state.daemon.loop,
721
+ status: "stopped",
722
+ stoppedAt: new Date().toISOString(),
723
+ blocker: state.daemon.loop.status === "running" ? "session_shutdown" : state.daemon.loop.blocker,
724
+ autoStartDaemon: false,
725
+ continuousLoop: false,
726
+ cronEnabled: false,
727
+ };
728
+ await stopZobLiveRuntime(state, ctx.cwd);
729
+ safelyUpdateZobLivePeer(ctx.cwd, "unregister");
730
+ disposeDelegationMouseSupport(state, { force: true });
731
+ ctx.ui.setWidget("zob-harness", undefined);
732
+ ctx.ui.setStatus("zob-mode", undefined);
733
+ ctx.ui.setStatus("zob-usage", undefined);
734
+ ctx.ui.setStatus("zob-zcompact", undefined);
735
+ });
736
+ }