@stravica-ai/digital-operator-pa 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 (372) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/bin/desk +9 -0
  4. package/bin/distill +2 -0
  5. package/bin/estate-sync +2 -0
  6. package/bin/launch +2 -0
  7. package/bin/memory-sync +2 -0
  8. package/bin/migrate-inspect +2 -0
  9. package/bin/pa +2 -0
  10. package/bin/pa-coordinator-hook +2 -0
  11. package/bin/pa-init +2 -0
  12. package/bin/research +2 -0
  13. package/bin/scheduler +2 -0
  14. package/bin/secrets +2 -0
  15. package/bin/slice +2 -0
  16. package/bin/smoke +9 -0
  17. package/bin/sync +2 -0
  18. package/dist/engineering-pa-cli/README.md +205 -0
  19. package/dist/engineering-pa-cli/bin/estate-sync +2 -0
  20. package/dist/engineering-pa-cli/bin/launch +2 -0
  21. package/dist/engineering-pa-cli/bin/pa +2 -0
  22. package/dist/engineering-pa-cli/bin/pa-coordinator-hook +12 -0
  23. package/dist/engineering-pa-cli/bin/research +2 -0
  24. package/dist/engineering-pa-cli/bin/scheduler +2 -0
  25. package/dist/engineering-pa-cli/bin/secrets +2 -0
  26. package/dist/engineering-pa-cli/bin/smoke +9 -0
  27. package/dist/engineering-pa-cli/bin/sync +2 -0
  28. package/dist/engineering-pa-cli/config/coordinator-allowlist.json +118 -0
  29. package/dist/engineering-pa-cli/docs/coordinator-hook.md +211 -0
  30. package/dist/engineering-pa-cli/docs/estate-sync.md +412 -0
  31. package/dist/engineering-pa-cli/docs/gsc.md +175 -0
  32. package/dist/engineering-pa-cli/docs/lint-linkedin.md +139 -0
  33. package/dist/engineering-pa-cli/docs/secrets.md +221 -0
  34. package/dist/engineering-pa-cli/docs/smoke.md +113 -0
  35. package/dist/engineering-pa-cli/docs/staging-alias.md +114 -0
  36. package/dist/engineering-pa-cli/index.mjs +17 -0
  37. package/dist/engineering-pa-cli/package.json +37 -0
  38. package/dist/engineering-pa-cli/src/autonomy/cli.mjs +329 -0
  39. package/dist/engineering-pa-cli/src/autonomy/envelope.mjs +301 -0
  40. package/dist/engineering-pa-cli/src/coordinator-hook/cli.mjs +140 -0
  41. package/dist/engineering-pa-cli/src/coordinator-hook/config.mjs +134 -0
  42. package/dist/engineering-pa-cli/src/coordinator-hook/message.mjs +47 -0
  43. package/dist/engineering-pa-cli/src/coordinator-hook/policy.mjs +211 -0
  44. package/dist/engineering-pa-cli/src/coordinator-hook/repo-root.mjs +44 -0
  45. package/dist/engineering-pa-cli/src/coordinator-hook/self.mjs +30 -0
  46. package/dist/engineering-pa-cli/src/environment/cli.mjs +287 -0
  47. package/dist/engineering-pa-cli/src/environment/probes.mjs +302 -0
  48. package/dist/engineering-pa-cli/src/gsc/auth.mjs +148 -0
  49. package/dist/engineering-pa-cli/src/gsc/cli.mjs +93 -0
  50. package/dist/engineering-pa-cli/src/gsc/cloudflare.mjs +318 -0
  51. package/dist/engineering-pa-cli/src/gsc/commands/add-property.mjs +70 -0
  52. package/dist/engineering-pa-cli/src/gsc/commands/list-properties.mjs +33 -0
  53. package/dist/engineering-pa-cli/src/gsc/commands/pull-analytics.mjs +130 -0
  54. package/dist/engineering-pa-cli/src/gsc/commands/submit-sitemap.mjs +41 -0
  55. package/dist/engineering-pa-cli/src/gsc/commands/verify-via-cf-dns.mjs +189 -0
  56. package/dist/engineering-pa-cli/src/knowledge/call-log.mjs +59 -0
  57. package/dist/engineering-pa-cli/src/knowledge/cli.mjs +242 -0
  58. package/dist/engineering-pa-cli/src/knowledge/eval.mjs +446 -0
  59. package/dist/engineering-pa-cli/src/knowledge/formatters.mjs +331 -0
  60. package/dist/engineering-pa-cli/src/knowledge/graph.mjs +710 -0
  61. package/dist/engineering-pa-cli/src/launch/README.md +214 -0
  62. package/dist/engineering-pa-cli/src/launch/cli.mjs +51 -0
  63. package/dist/engineering-pa-cli/src/launch/commands/launch.mjs +106 -0
  64. package/dist/engineering-pa-cli/src/launch/identity.mjs +43 -0
  65. package/dist/engineering-pa-cli/src/launch/planner.mjs +44 -0
  66. package/dist/engineering-pa-cli/src/launch/repo-root.mjs +53 -0
  67. package/dist/engineering-pa-cli/src/launch/runner.mjs +147 -0
  68. package/dist/engineering-pa-cli/src/launch/task-loader.mjs +85 -0
  69. package/dist/engineering-pa-cli/src/lint/cli.mjs +61 -0
  70. package/dist/engineering-pa-cli/src/lint/commands/linkedin.mjs +133 -0
  71. package/dist/engineering-pa-cli/src/lint/detectors.mjs +90 -0
  72. package/dist/engineering-pa-cli/src/lint/linter.mjs +69 -0
  73. package/dist/engineering-pa-cli/src/lint/reporter.mjs +32 -0
  74. package/dist/engineering-pa-cli/src/lint/rules.mjs +132 -0
  75. package/dist/engineering-pa-cli/src/pa/cli.mjs +369 -0
  76. package/dist/engineering-pa-cli/src/pa/doc-groups.mjs +164 -0
  77. package/dist/engineering-pa-cli/src/pa/io.mjs +80 -0
  78. package/dist/engineering-pa-cli/src/pa/project-cli.mjs +385 -0
  79. package/dist/engineering-pa-cli/src/pa/projects.mjs +352 -0
  80. package/dist/engineering-pa-cli/src/pa/repo-root.mjs +64 -0
  81. package/dist/engineering-pa-cli/src/pa/session.mjs +254 -0
  82. package/dist/engineering-pa-cli/src/pa/work-cli.mjs +164 -0
  83. package/dist/engineering-pa-cli/src/pa/work.mjs +196 -0
  84. package/dist/engineering-pa-cli/src/pa/workstreams.mjs +201 -0
  85. package/dist/engineering-pa-cli/src/research/README.md +360 -0
  86. package/dist/engineering-pa-cli/src/research/briefs/extractor.md +103 -0
  87. package/dist/engineering-pa-cli/src/research/briefs/searcher.md +113 -0
  88. package/dist/engineering-pa-cli/src/research/briefs/synthesizer.md +124 -0
  89. package/dist/engineering-pa-cli/src/research/briefs/verifier.md +86 -0
  90. package/dist/engineering-pa-cli/src/research/cli.mjs +141 -0
  91. package/dist/engineering-pa-cli/src/research/commands/gates.mjs +176 -0
  92. package/dist/engineering-pa-cli/src/research/commands/list.mjs +56 -0
  93. package/dist/engineering-pa-cli/src/research/commands/mark.mjs +97 -0
  94. package/dist/engineering-pa-cli/src/research/commands/paths.mjs +69 -0
  95. package/dist/engineering-pa-cli/src/research/commands/prune.mjs +86 -0
  96. package/dist/engineering-pa-cli/src/research/commands/run.mjs +94 -0
  97. package/dist/engineering-pa-cli/src/research/commands/show.mjs +43 -0
  98. package/dist/engineering-pa-cli/src/research/docs/operator-present-flow.md +120 -0
  99. package/dist/engineering-pa-cli/src/research/format.mjs +59 -0
  100. package/dist/engineering-pa-cli/src/research/promote.mjs +260 -0
  101. package/dist/engineering-pa-cli/src/research/schema/finding.schema.json +55 -0
  102. package/dist/engineering-pa-cli/src/research/schema/gates.schema.json +34 -0
  103. package/dist/engineering-pa-cli/src/research/schema/manifest.schema.json +59 -0
  104. package/dist/engineering-pa-cli/src/research/schema/plan.schema.json +41 -0
  105. package/dist/engineering-pa-cli/src/research/schema/sources.schema.json +31 -0
  106. package/dist/engineering-pa-cli/src/research/store/findings.mjs +61 -0
  107. package/dist/engineering-pa-cli/src/research/store/gates.mjs +73 -0
  108. package/dist/engineering-pa-cli/src/research/store/index.mjs +312 -0
  109. package/dist/engineering-pa-cli/src/research/store/manifest.mjs +56 -0
  110. package/dist/engineering-pa-cli/src/research/store/plan.mjs +59 -0
  111. package/dist/engineering-pa-cli/src/research/store/sources.mjs +44 -0
  112. package/dist/engineering-pa-cli/src/research/store/validate.mjs +92 -0
  113. package/dist/engineering-pa-cli/src/research/workflows/research-normal.js +573 -0
  114. package/dist/engineering-pa-cli/src/scheduler/cli.mjs +197 -0
  115. package/dist/engineering-pa-cli/src/secrets/cli.mjs +254 -0
  116. package/dist/engineering-pa-cli/src/secrets/commands/backup-template.mjs +67 -0
  117. package/dist/engineering-pa-cli/src/secrets/commands/backup.mjs +85 -0
  118. package/dist/engineering-pa-cli/src/secrets/commands/delete.mjs +58 -0
  119. package/dist/engineering-pa-cli/src/secrets/commands/find.mjs +36 -0
  120. package/dist/engineering-pa-cli/src/secrets/commands/get.mjs +49 -0
  121. package/dist/engineering-pa-cli/src/secrets/commands/init.mjs +69 -0
  122. package/dist/engineering-pa-cli/src/secrets/commands/list.mjs +37 -0
  123. package/dist/engineering-pa-cli/src/secrets/commands/rotate.mjs +46 -0
  124. package/dist/engineering-pa-cli/src/secrets/commands/set.mjs +123 -0
  125. package/dist/engineering-pa-cli/src/secrets/commands/status.mjs +146 -0
  126. package/dist/engineering-pa-cli/src/secrets/commands/vaults.mjs +57 -0
  127. package/dist/engineering-pa-cli/src/secrets/commands/verify.mjs +143 -0
  128. package/dist/engineering-pa-cli/src/secrets/vault.mjs +766 -0
  129. package/dist/engineering-pa-cli/src/smoke/checks.mjs +199 -0
  130. package/dist/engineering-pa-cli/src/smoke/cli.mjs +108 -0
  131. package/dist/engineering-pa-cli/src/smoke/commands/run.mjs +237 -0
  132. package/dist/engineering-pa-cli/src/smoke/runner.mjs +191 -0
  133. package/dist/engineering-pa-cli/src/staging-alias/cli.mjs +91 -0
  134. package/dist/engineering-pa-cli/src/staging-alias/cloudflare.mjs +380 -0
  135. package/dist/engineering-pa-cli/src/staging-alias/commands/list.mjs +36 -0
  136. package/dist/engineering-pa-cli/src/staging-alias/commands/set.mjs +188 -0
  137. package/dist/engineering-pa-cli/src/staging-alias/commands/status.mjs +113 -0
  138. package/dist/engineering-pa-cli/src/staging-alias/commands/unset.mjs +95 -0
  139. package/dist/engineering-pa-cli/src/staging-alias/sites.mjs +105 -0
  140. package/dist/engineering-pa-cli/src/sync/cli.mjs +151 -0
  141. package/dist/engineering-pa-cli/src/sync/git.mjs +149 -0
  142. package/dist/engineering-pa-cli/src/sync/lock.mjs +30 -0
  143. package/dist/engineering-pa-cli/src/sync/regenerated-artifacts.mjs +114 -0
  144. package/dist/engineering-pa-cli/src/sync/registry-scope.mjs +260 -0
  145. package/dist/engineering-pa-cli/src/sync/run.mjs +531 -0
  146. package/dist/engineering-pa-cli/src/sync/runner.mjs +62 -0
  147. package/dist/engineering-pa-cli/src/sync/runs-digest.mjs +138 -0
  148. package/dist/engineering-pa-core/README.md +60 -0
  149. package/dist/engineering-pa-core/bin/desk +9 -0
  150. package/dist/engineering-pa-core/bin/distill +2 -0
  151. package/dist/engineering-pa-core/bin/memory-sync +2 -0
  152. package/dist/engineering-pa-core/bin/slice +2 -0
  153. package/dist/engineering-pa-core/docs/autonomy-envelope-tracker.md +111 -0
  154. package/dist/engineering-pa-core/docs/blueprints/README.md +45 -0
  155. package/dist/engineering-pa-core/docs/blueprints/docker-services/blueprint.md +168 -0
  156. package/dist/engineering-pa-core/docs/blueprints/git-identity/blueprint.md +116 -0
  157. package/dist/engineering-pa-core/docs/blueprints/ideas/custom-workspace-views.md +9 -0
  158. package/dist/engineering-pa-core/docs/blueprints/ideas/knowledge-domain-patterns.md +15 -0
  159. package/dist/engineering-pa-core/docs/blueprints/ideas/office-integration.md +11 -0
  160. package/dist/engineering-pa-core/docs/blueprints/ideas/team-scaling.md +9 -0
  161. package/dist/engineering-pa-core/docs/blueprints/ideas/work-personal-separation.md +9 -0
  162. package/dist/engineering-pa-core/docs/blueprints/scheduled-distillation/blueprint.md +129 -0
  163. package/dist/engineering-pa-core/docs/blueprints/tool-integration/blueprint.md +110 -0
  164. package/dist/engineering-pa-core/docs/commands/init.md +159 -0
  165. package/dist/engineering-pa-core/docs/commands/schedule.md +98 -0
  166. package/dist/engineering-pa-core/docs/commands/upgrade.md +67 -0
  167. package/dist/engineering-pa-core/docs/entity-location-map.md +93 -0
  168. package/dist/engineering-pa-core/docs/knowledge-scaffold.md +121 -0
  169. package/dist/engineering-pa-core/docs/lock.md +155 -0
  170. package/dist/engineering-pa-core/docs/memory-sync.md +28 -0
  171. package/dist/engineering-pa-core/docs/pa-operating-model.md +457 -0
  172. package/dist/engineering-pa-core/docs/scheduling.md +35 -0
  173. package/dist/engineering-pa-core/docs/standards/README.md +24 -0
  174. package/dist/engineering-pa-core/docs/standards/briefing-contract.md +161 -0
  175. package/dist/engineering-pa-core/docs/standards/tooling.md +240 -0
  176. package/dist/engineering-pa-core/docs/tools/distill.md +230 -0
  177. package/dist/engineering-pa-core/docs/tools/memory-sync.md +98 -0
  178. package/dist/engineering-pa-core/docs/tools/scheduler.md +243 -0
  179. package/dist/engineering-pa-core/docs/tools/slice.md +150 -0
  180. package/dist/engineering-pa-core/docs/upstream-issue-filing.md +88 -0
  181. package/dist/engineering-pa-core/docs/working-directory.md +29 -0
  182. package/dist/engineering-pa-core/docs/workspace-operations.md +46 -0
  183. package/dist/engineering-pa-core/index.mjs +21 -0
  184. package/dist/engineering-pa-core/knowledge/README.md +53 -0
  185. package/dist/engineering-pa-core/knowledge/canonical/.gitkeep +0 -0
  186. package/dist/engineering-pa-core/knowledge/content-voice/README.md +64 -0
  187. package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-baseline.md +133 -0
  188. package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-shape.md +58 -0
  189. package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-taxonomy.md +33 -0
  190. package/dist/engineering-pa-core/knowledge/content-voice/content-pipeline-routing.md +58 -0
  191. package/dist/engineering-pa-core/knowledge/content-voice/new-tell-capture-procedure.md +40 -0
  192. package/dist/engineering-pa-core/knowledge/content-voice/voice-guide-shape.md +43 -0
  193. package/dist/engineering-pa-core/knowledge/delegation-dispatch/README.md +34 -0
  194. package/dist/engineering-pa-core/knowledge/delegation-dispatch/briefing-contract.md +77 -0
  195. package/dist/engineering-pa-core/knowledge/delegation-dispatch/delegation-modes.md +84 -0
  196. package/dist/engineering-pa-core/knowledge/delegation-dispatch/dispatch-envelope.md +238 -0
  197. package/dist/engineering-pa-core/knowledge/delegation-dispatch/task-groups-and-orchestrators.md +62 -0
  198. package/dist/engineering-pa-core/knowledge/delegation-dispatch/team-improvement-loop.md +48 -0
  199. package/dist/engineering-pa-core/knowledge/delegation-dispatch/tool-development-policy.md +48 -0
  200. package/dist/engineering-pa-core/knowledge/engineering-discipline/README.md +33 -0
  201. package/dist/engineering-pa-core/knowledge/engineering-discipline/blast-radius-and-safety.md +50 -0
  202. package/dist/engineering-pa-core/knowledge/engineering-discipline/investigate-root-causes.md +48 -0
  203. package/dist/engineering-pa-core/knowledge/engineering-discipline/role-ladder.md +57 -0
  204. package/dist/engineering-pa-core/knowledge/engineering-discipline/verify-runtime-behaviour.md +53 -0
  205. package/dist/engineering-pa-core/knowledge/engineering-discipline/worktree-isolation.md +50 -0
  206. package/dist/engineering-pa-core/knowledge/knowledge-memory/README.md +33 -0
  207. package/dist/engineering-pa-core/knowledge/knowledge-memory/claude-md-hygiene.md +47 -0
  208. package/dist/engineering-pa-core/knowledge/knowledge-memory/journal-and-self-improvement.md +53 -0
  209. package/dist/engineering-pa-core/knowledge/knowledge-memory/knowledge-retrieval-discipline.md +62 -0
  210. package/dist/engineering-pa-core/knowledge/knowledge-memory/librarian-synthesis-mandate.md +56 -0
  211. package/dist/engineering-pa-core/knowledge/knowledge-memory/staging-and-observations.md +58 -0
  212. package/dist/engineering-pa-core/knowledge/operator-interface/README.md +32 -0
  213. package/dist/engineering-pa-core/knowledge/operator-interface/communication-style.md +33 -0
  214. package/dist/engineering-pa-core/knowledge/operator-interface/escalation-and-correction.md +45 -0
  215. package/dist/engineering-pa-core/knowledge/operator-interface/push-back-discipline.md +42 -0
  216. package/dist/engineering-pa-core/knowledge/operator-interface/session-boot-and-end.md +56 -0
  217. package/dist/engineering-pa-core/knowledge/platform-tooling/README.md +37 -0
  218. package/dist/engineering-pa-core/knowledge/platform-tooling/desk-cli-reference.md +52 -0
  219. package/dist/engineering-pa-core/knowledge/platform-tooling/environment-awareness.md +91 -0
  220. package/dist/engineering-pa-core/knowledge/platform-tooling/mcp-servers-catalogue.md +52 -0
  221. package/dist/engineering-pa-core/knowledge/platform-tooling/pa-cli-reference.md +55 -0
  222. package/dist/engineering-pa-core/knowledge/platform-tooling/scheduling-and-launchd.md +56 -0
  223. package/dist/engineering-pa-core/knowledge/platform-tooling/tool-discovery-discipline.md +49 -0
  224. package/dist/engineering-pa-core/knowledge/platform-tooling/working-directory-vs-project-root.md +43 -0
  225. package/dist/engineering-pa-core/knowledge/platform-tooling/workspace-server.md +51 -0
  226. package/dist/engineering-pa-core/knowledge/raw/.gitkeep +0 -0
  227. package/dist/engineering-pa-core/knowledge/scaffold/domains.json +5 -0
  228. package/dist/engineering-pa-core/knowledge/schema/.gitkeep +0 -0
  229. package/dist/engineering-pa-core/knowledge/work-management/README.md +33 -0
  230. package/dist/engineering-pa-core/knowledge/work-management/desk-cli.md +84 -0
  231. package/dist/engineering-pa-core/knowledge/work-management/progress-md.md +48 -0
  232. package/dist/engineering-pa-core/knowledge/work-management/projects.md +64 -0
  233. package/dist/engineering-pa-core/knowledge/work-management/spawn-log.md +48 -0
  234. package/dist/engineering-pa-core/knowledge/work-management/work-items.md +67 -0
  235. package/dist/engineering-pa-core/package.json +26 -0
  236. package/dist/engineering-pa-core/roles/agent-ops/definition.md +79 -0
  237. package/dist/engineering-pa-core/roles/dispatch-briefer/definition.md +195 -0
  238. package/dist/engineering-pa-core/roles/librarian/definition.md +176 -0
  239. package/dist/engineering-pa-core/roles/pa/definition.md +93 -0
  240. package/dist/engineering-pa-core/roles/system-admin/definition.md +106 -0
  241. package/dist/engineering-pa-core/roles/tool-developer/definition.md +116 -0
  242. package/dist/engineering-pa-core/roles/writer/definition.md +130 -0
  243. package/dist/engineering-pa-core/schema/autonomy-envelope.schema.json +61 -0
  244. package/dist/engineering-pa-core/schema/project.json +114 -0
  245. package/dist/engineering-pa-core/schema/schedule.json +63 -0
  246. package/dist/engineering-pa-core/schema/work-item.json +92 -0
  247. package/dist/engineering-pa-core/src/config/pa-package-name.mjs +30 -0
  248. package/dist/engineering-pa-core/src/desk/cli.mjs +95 -0
  249. package/dist/engineering-pa-core/src/desk/commands.mjs +398 -0
  250. package/dist/engineering-pa-core/src/desk/format.mjs +84 -0
  251. package/dist/engineering-pa-core/src/desk/repo.mjs +172 -0
  252. package/dist/engineering-pa-core/src/desk/team-scope.mjs +142 -0
  253. package/dist/engineering-pa-core/src/distill/cli.mjs +112 -0
  254. package/dist/engineering-pa-core/src/distill/prereqs.mjs +171 -0
  255. package/dist/engineering-pa-core/src/distill/prompt.mjs +74 -0
  256. package/dist/engineering-pa-core/src/distill/run.mjs +230 -0
  257. package/dist/engineering-pa-core/src/distill/runner.mjs +86 -0
  258. package/dist/engineering-pa-core/src/distill/staging.mjs +59 -0
  259. package/dist/engineering-pa-core/src/knowledge/retrieval/backlink-indexer.mjs +154 -0
  260. package/dist/engineering-pa-core/src/knowledge/retrieval/graph-builder.mjs +186 -0
  261. package/dist/engineering-pa-core/src/knowledge/retrieval/index-builder.mjs +225 -0
  262. package/dist/engineering-pa-core/src/knowledge/retrieval/query.mjs +263 -0
  263. package/dist/engineering-pa-core/src/lock/lock.mjs +202 -0
  264. package/dist/engineering-pa-core/src/memory-sync/cli-support.mjs +12 -0
  265. package/dist/engineering-pa-core/src/memory-sync/cli.mjs +56 -0
  266. package/dist/engineering-pa-core/src/memory-sync/commands/pull.mjs +44 -0
  267. package/dist/engineering-pa-core/src/memory-sync/commands/push.mjs +46 -0
  268. package/dist/engineering-pa-core/src/memory-sync/mirror.mjs +114 -0
  269. package/dist/engineering-pa-core/src/memory-sync/repo.mjs +65 -0
  270. package/dist/engineering-pa-core/src/scheduler/detect.mjs +111 -0
  271. package/dist/engineering-pa-core/src/scheduler/host.mjs +38 -0
  272. package/dist/engineering-pa-core/src/scheduler/index.mjs +13 -0
  273. package/dist/engineering-pa-core/src/scheduler/install.mjs +854 -0
  274. package/dist/engineering-pa-core/src/scheduler/list.mjs +168 -0
  275. package/dist/engineering-pa-core/src/scheduler/remove.mjs +176 -0
  276. package/dist/engineering-pa-core/src/scheduler/verify.mjs +435 -0
  277. package/dist/engineering-pa-core/src/session-boot/autonomy-injection.mjs +84 -0
  278. package/dist/engineering-pa-core/src/slice/cli.mjs +139 -0
  279. package/dist/engineering-pa-core/src/slice/inputs.mjs +174 -0
  280. package/dist/engineering-pa-core/src/slice/prompt.mjs +94 -0
  281. package/dist/engineering-pa-core/src/slice/prompts/dave-boot.md +91 -0
  282. package/dist/engineering-pa-core/src/slice/run.mjs +334 -0
  283. package/dist/engineering-pa-core-extensions-atlassian/README.md +31 -0
  284. package/dist/engineering-pa-core-extensions-atlassian/index.mjs +9 -0
  285. package/dist/engineering-pa-core-extensions-atlassian/package.json +19 -0
  286. package/dist/engineering-pa-core-extensions-n8n/README.md +29 -0
  287. package/dist/engineering-pa-core-extensions-n8n/index.mjs +8 -0
  288. package/dist/engineering-pa-core-extensions-n8n/package.json +19 -0
  289. package/dist/engineering-pa-librarian/README.md +38 -0
  290. package/dist/engineering-pa-librarian/index.mjs +12 -0
  291. package/dist/engineering-pa-librarian/package.json +19 -0
  292. package/dist/engineering-pa-migrate-inspect/README.md +131 -0
  293. package/dist/engineering-pa-migrate-inspect/bin/migrate-inspect +2 -0
  294. package/dist/engineering-pa-migrate-inspect/package.json +21 -0
  295. package/dist/engineering-pa-migrate-inspect/src/age-key-migrate.mjs +83 -0
  296. package/dist/engineering-pa-migrate-inspect/src/cli.mjs +97 -0
  297. package/dist/engineering-pa-migrate-inspect/src/inspector.mjs +237 -0
  298. package/dist/engineering-pa-migrate-inspect/src/platforms/linux.mjs +87 -0
  299. package/dist/engineering-pa-migrate-inspect/src/platforms/macos.mjs +105 -0
  300. package/dist/engineering-pa-migrate-inspect/src/runner.mjs +87 -0
  301. package/dist/engineering-pa-runbook/README.md +103 -0
  302. package/dist/engineering-pa-runbook/package.json +18 -0
  303. package/dist/engineering-pa-runbook/reference/dex-template.runbook.json +66 -0
  304. package/dist/engineering-pa-runbook/reference/hq-dave.runbook.json +69 -0
  305. package/dist/engineering-pa-runbook/reference/smarthome01.runbook.json +92 -0
  306. package/dist/engineering-pa-runbook/schema/inspection.schema.json +113 -0
  307. package/dist/engineering-pa-runbook/schema/runbook.schema.json +67 -0
  308. package/dist/engineering-pa-runbook/src/validator.mjs +167 -0
  309. package/dist/engineering-pa-scaffold/README.md +164 -0
  310. package/dist/engineering-pa-scaffold/bin/pa-init +2 -0
  311. package/dist/engineering-pa-scaffold/index.mjs +42 -0
  312. package/dist/engineering-pa-scaffold/package.json +22 -0
  313. package/dist/engineering-pa-scaffold/src/cli.mjs +115 -0
  314. package/dist/engineering-pa-scaffold/src/commands/init.mjs +169 -0
  315. package/dist/engineering-pa-scaffold/src/generator.mjs +354 -0
  316. package/dist/engineering-pa-scaffold/src/prompts.mjs +125 -0
  317. package/dist/engineering-pa-scaffold/src/runner.mjs +142 -0
  318. package/dist/engineering-pa-scaffold/templates/CLAUDE.md.template +196 -0
  319. package/dist/engineering-pa-scaffold/templates/operator-README.md.template +44 -0
  320. package/dist/engineering-pa-types-engineering/README.md +35 -0
  321. package/dist/engineering-pa-types-engineering/docs/commands/product-build.md +120 -0
  322. package/dist/engineering-pa-types-engineering/index.mjs +9 -0
  323. package/dist/engineering-pa-types-engineering/package.json +19 -0
  324. package/dist/engineering-pa-types-engineering/roles/product-engineer/definition.md +650 -0
  325. package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/build-spec.md +82 -0
  326. package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/preflight-checklist.md +158 -0
  327. package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/worker-brief.md +130 -0
  328. package/dist/engineering-pa-workspace/README.md +197 -0
  329. package/dist/engineering-pa-workspace/app/assets/md.js +187 -0
  330. package/dist/engineering-pa-workspace/app/assets/modal.js +120 -0
  331. package/dist/engineering-pa-workspace/app/assets/theme.css +132 -0
  332. package/dist/engineering-pa-workspace/app/assets/theme.js +159 -0
  333. package/dist/engineering-pa-workspace/app/banner.js +320 -0
  334. package/dist/engineering-pa-workspace/app/delegations.html +345 -0
  335. package/dist/engineering-pa-workspace/app/home.html +1060 -0
  336. package/dist/engineering-pa-workspace/app/index.html +361 -0
  337. package/dist/engineering-pa-workspace/app/knowledge-map.html +163 -0
  338. package/dist/engineering-pa-workspace/app/knowledge.html +304 -0
  339. package/dist/engineering-pa-workspace/app/nav.json +75 -0
  340. package/dist/engineering-pa-workspace/app/notes.html +199 -0
  341. package/dist/engineering-pa-workspace/app/onboarding.html +592 -0
  342. package/dist/engineering-pa-workspace/app/profile.html +243 -0
  343. package/dist/engineering-pa-workspace/app/project-detail.html +432 -0
  344. package/dist/engineering-pa-workspace/app/projects.html +297 -0
  345. package/dist/engineering-pa-workspace/app/repos.html +598 -0
  346. package/dist/engineering-pa-workspace/app/schedules.html +486 -0
  347. package/dist/engineering-pa-workspace/app/secrets.html +164 -0
  348. package/dist/engineering-pa-workspace/app/staging.html +319 -0
  349. package/dist/engineering-pa-workspace/app/tasks.html +465 -0
  350. package/dist/engineering-pa-workspace/app/vendor/chart.umd.min.js +21 -0
  351. package/dist/engineering-pa-workspace/app/viewer.html +116 -0
  352. package/dist/engineering-pa-workspace/docs/DAEMON.md +104 -0
  353. package/dist/engineering-pa-workspace/docs/page-blueprint.md +286 -0
  354. package/dist/engineering-pa-workspace/docs/status-mon.md +168 -0
  355. package/dist/engineering-pa-workspace/index.mjs +12 -0
  356. package/dist/engineering-pa-workspace/nav.json.example +8 -0
  357. package/dist/engineering-pa-workspace/package.json +27 -0
  358. package/dist/engineering-pa-workspace/src/api.mjs +2086 -0
  359. package/dist/engineering-pa-workspace/src/install-daemon.mjs +573 -0
  360. package/dist/engineering-pa-workspace/src/nav.mjs +190 -0
  361. package/dist/engineering-pa-workspace/src/secrets-api.mjs +175 -0
  362. package/dist/engineering-pa-workspace/src/server.mjs +516 -0
  363. package/dist/engineering-pa-workspace/src/status-mon/poll.mjs +220 -0
  364. package/dist/engineering-pa-workspace/src/status-mon/poller.mjs +113 -0
  365. package/dist/engineering-pa-workspace/src/status-mon/run.mjs +133 -0
  366. package/dist/engineering-pa-workspace/src/supervisor.mjs +264 -0
  367. package/dist/engineering-pa-workspace/src/ws.mjs +633 -0
  368. package/index.mjs +60 -0
  369. package/package.json +58 -0
  370. package/templates/banned-ai-tells.md +102 -0
  371. package/templates/purpose.md +105 -0
  372. package/templates/voice-guide.md +98 -0
@@ -0,0 +1,301 @@
1
+ // envelope.mjs — pure functions for autonomy-envelope frontmatter parsing +
2
+ // rendering. Zero IO. All filesystem side effects live in cli.mjs.
3
+ //
4
+ // The envelope is a markdown file with a YAML frontmatter block carrying the
5
+ // machine-readable state. We ship our own minimal YAML reader/writer here
6
+ // (limited to the shape the schema defines) to avoid pulling in a YAML dep
7
+ // for such a narrow surface. Any file whose frontmatter falls outside the
8
+ // documented shape is rejected as invalid.
9
+
10
+ export const VALID_STATES = ['fullyApproved', 'checkBeforeCommitting', 'needsFullSupervision'];
11
+
12
+ const STATE_LABELS = {
13
+ fullyApproved: 'fully approved',
14
+ checkBeforeCommitting: 'check before committing',
15
+ needsFullSupervision: 'needs full supervision',
16
+ };
17
+
18
+ /**
19
+ * Parse an autonomy-envelope markdown file. Returns
20
+ * { frontmatter, body }
21
+ * where `frontmatter` matches the schema shape and `body` is the markdown
22
+ * after the closing `---`. Throws on malformed input; the error carries an
23
+ * `exitCode` for the CLI to propagate.
24
+ */
25
+ export function parseEnvelope(source) {
26
+ if (typeof source !== 'string' || source.length === 0) {
27
+ throwUsage('envelope file is empty');
28
+ }
29
+ const lines = source.split(/\r?\n/);
30
+ if (lines[0].trim() !== '---') {
31
+ throwParse('envelope must start with YAML frontmatter delimited by ---');
32
+ }
33
+ let closeIdx = -1;
34
+ for (let i = 1; i < lines.length; i++) {
35
+ if (lines[i].trim() === '---') {
36
+ closeIdx = i;
37
+ break;
38
+ }
39
+ }
40
+ if (closeIdx < 0) {
41
+ throwParse('unterminated YAML frontmatter (missing closing ---)');
42
+ }
43
+ const fmLines = lines.slice(1, closeIdx);
44
+ const bodyLines = lines.slice(closeIdx + 1);
45
+ const frontmatter = parseFrontmatter(fmLines);
46
+ return { frontmatter, body: bodyLines.join('\n') };
47
+ }
48
+
49
+ /**
50
+ * Parse a limited-shape YAML block. Supports:
51
+ * key: value (string)
52
+ * key: (empty list start)
53
+ * - key: value (list item — object)
54
+ * key: value
55
+ * Numbers, booleans, and nested maps beyond one level are NOT supported —
56
+ * the schema doesn't need them. Values are always treated as strings.
57
+ */
58
+ function parseFrontmatter(lines) {
59
+ const out = {};
60
+ let i = 0;
61
+ while (i < lines.length) {
62
+ const raw = lines[i];
63
+ if (raw.trim() === '' || raw.trim().startsWith('#')) { i++; continue; }
64
+ const match = raw.match(/^([a-zA-Z][a-zA-Z0-9]*):(?:\s*(.*))?$/);
65
+ if (!match) {
66
+ throwParse(`could not parse frontmatter line ${i + 1}: ${raw}`);
67
+ }
68
+ const key = match[1];
69
+ const value = (match[2] ?? '').trim();
70
+ if (value === '') {
71
+ // Expect either a list (starts with "- " at next non-empty indented
72
+ // line) or an empty value.
73
+ const listItems = [];
74
+ let j = i + 1;
75
+ while (j < lines.length) {
76
+ const peek = lines[j];
77
+ if (peek.trim() === '' || peek.trim().startsWith('#')) { j++; continue; }
78
+ if (!/^\s+-\s/.test(peek)) break;
79
+ const item = readListItem(lines, j);
80
+ listItems.push(item.value);
81
+ j = item.next;
82
+ }
83
+ out[key] = listItems;
84
+ i = j;
85
+ } else {
86
+ out[key] = stripQuotes(value);
87
+ i++;
88
+ }
89
+ }
90
+ return out;
91
+ }
92
+
93
+ function readListItem(lines, start) {
94
+ const first = lines[start];
95
+ const indentMatch = first.match(/^(\s+)-\s/);
96
+ if (!indentMatch) {
97
+ throwParse(`expected list item at line ${start + 1}: ${first}`);
98
+ }
99
+ const itemIndent = indentMatch[1] + ' '; // continuation is deeper than "- "
100
+ const item = {};
101
+ // The "- key: value" first line is the first key on the item.
102
+ const firstBody = first.slice(indentMatch[0].length);
103
+ const firstMatch = firstBody.match(/^([a-zA-Z][a-zA-Z0-9]*):\s*(.*)$/);
104
+ if (!firstMatch) {
105
+ throwParse(`could not parse list item at line ${start + 1}: ${first}`);
106
+ }
107
+ item[firstMatch[1]] = stripQuotes(firstMatch[2].trim());
108
+ let j = start + 1;
109
+ while (j < lines.length) {
110
+ const peek = lines[j];
111
+ if (peek.trim() === '' || peek.trim().startsWith('#')) { j++; continue; }
112
+ // Terminate when indent doesn't extend the item (either new list item
113
+ // at the same "- " indent, or dedent back to a top-level key).
114
+ if (peek.startsWith(itemIndent)) {
115
+ const bodyLine = peek.slice(itemIndent.length);
116
+ const m = bodyLine.match(/^([a-zA-Z][a-zA-Z0-9]*):\s*(.*)$/);
117
+ if (!m) {
118
+ throwParse(`could not parse list item continuation at line ${j + 1}: ${peek}`);
119
+ }
120
+ item[m[1]] = stripQuotes(m[2].trim());
121
+ j++;
122
+ } else {
123
+ break;
124
+ }
125
+ }
126
+ return { value: item, next: j };
127
+ }
128
+
129
+ function stripQuotes(value) {
130
+ if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
131
+ return value.slice(1, -1);
132
+ }
133
+ if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) {
134
+ return value.slice(1, -1);
135
+ }
136
+ return value;
137
+ }
138
+
139
+ /**
140
+ * Render an envelope object (frontmatter shape) back to markdown. Body is
141
+ * regenerated: a current-state table + a history log preserved from prior
142
+ * body sections. This keeps the file readable + deterministic.
143
+ */
144
+ export function renderEnvelope(frontmatter, history = []) {
145
+ const fm = renderFrontmatter(frontmatter);
146
+ const body = renderBody(frontmatter, history);
147
+ return `---\n${fm}---\n\n${body}\n`;
148
+ }
149
+
150
+ function renderFrontmatter(fm) {
151
+ const lines = [];
152
+ lines.push(`agent: ${quoteIfNeeded(fm.agent)}`);
153
+ lines.push(`owner: ${quoteIfNeeded(fm.owner)}`);
154
+ lines.push(`updated: ${quoteIfNeeded(fm.updated)}`);
155
+ lines.push('taskTypes:');
156
+ const items = fm.taskTypes ?? [];
157
+ for (const item of items) {
158
+ lines.push(` - id: ${quoteIfNeeded(item.id)}`);
159
+ lines.push(` label: ${quoteIfNeeded(item.label)}`);
160
+ lines.push(` state: ${quoteIfNeeded(item.state)}`);
161
+ if (item.stateSince) lines.push(` stateSince: ${quoteIfNeeded(item.stateSince)}`);
162
+ if (item.operatorNote) lines.push(` operatorNote: ${quoteIfNeeded(item.operatorNote)}`);
163
+ }
164
+ return lines.join('\n') + '\n';
165
+ }
166
+
167
+ function quoteIfNeeded(value) {
168
+ if (value == null) return '""';
169
+ const str = String(value);
170
+ // Quote values that could be misparsed as YAML control sequences.
171
+ if (/^[\s"'#\-\[\{,&*!|>%@`]/.test(str)) return JSON.stringify(str);
172
+ if (/[:#]\s/.test(str)) return JSON.stringify(str);
173
+ if (str.trim() !== str) return JSON.stringify(str);
174
+ return str;
175
+ }
176
+
177
+ function renderBody(fm, history) {
178
+ const lines = [];
179
+ lines.push(`# Autonomy envelope — ${fm.agent}`);
180
+ lines.push('');
181
+ lines.push('## Current state');
182
+ lines.push('');
183
+ if (!fm.taskTypes || fm.taskTypes.length === 0) {
184
+ lines.push('_No task types configured. Use `pa autonomy set <agent> <task-type> <state>` to add one._');
185
+ } else {
186
+ lines.push('| Task type | State | Since | Note |');
187
+ lines.push('|---|---|---|---|');
188
+ for (const item of fm.taskTypes) {
189
+ const since = (item.stateSince ?? '').slice(0, 10);
190
+ const note = (item.operatorNote ?? '—').replace(/\|/g, '\\|');
191
+ lines.push(`| ${escapeCell(item.label)} | ${STATE_LABELS[item.state] ?? item.state} | ${since || '—'} | ${note} |`);
192
+ }
193
+ }
194
+ lines.push('');
195
+ lines.push('## History');
196
+ lines.push('');
197
+ const entries = [...history].sort((a, b) => (b.at ?? '').localeCompare(a.at ?? ''));
198
+ if (entries.length === 0) {
199
+ lines.push('_No history yet._');
200
+ } else {
201
+ for (const entry of entries) {
202
+ lines.push(`### ${entry.at} — ${entry.taskTypeId} → ${entry.state}`);
203
+ if (entry.note) {
204
+ lines.push('');
205
+ lines.push(`Operator note: ${entry.note}`);
206
+ }
207
+ lines.push('');
208
+ }
209
+ }
210
+ return lines.join('\n');
211
+ }
212
+
213
+ function escapeCell(str) {
214
+ return String(str).replace(/\|/g, '\\|');
215
+ }
216
+
217
+ /**
218
+ * Extract history entries from a rendered body. Returns an array of
219
+ * { at, taskTypeId, state, note }
220
+ * entries. Best-effort — malformed sections are skipped, not raised.
221
+ */
222
+ export function extractHistory(body) {
223
+ const entries = [];
224
+ if (typeof body !== 'string') return entries;
225
+ const lines = body.split(/\r?\n/);
226
+ let i = 0;
227
+ while (i < lines.length) {
228
+ const line = lines[i];
229
+ const match = line.match(/^###\s+(\S+)\s+—\s+([a-z0-9][a-z0-9-]*)\s+→\s+([A-Za-z]+)\s*$/);
230
+ if (!match) { i++; continue; }
231
+ const at = match[1];
232
+ const taskTypeId = match[2];
233
+ const state = match[3];
234
+ let note = null;
235
+ let j = i + 1;
236
+ while (j < lines.length && lines[j].trim() === '') j++;
237
+ if (j < lines.length && lines[j].startsWith('Operator note:')) {
238
+ note = lines[j].slice('Operator note:'.length).trim();
239
+ }
240
+ entries.push({ at, taskTypeId, state, note });
241
+ i = j + 1;
242
+ }
243
+ return entries;
244
+ }
245
+
246
+ /**
247
+ * Validate a frontmatter object against the schema. Throws on invalid;
248
+ * returns nothing on valid.
249
+ */
250
+ export function validateFrontmatter(fm) {
251
+ if (!fm || typeof fm !== 'object') throwParse('frontmatter must be an object');
252
+ requireString(fm, 'agent');
253
+ requireString(fm, 'owner');
254
+ requireString(fm, 'updated');
255
+ if (!Array.isArray(fm.taskTypes)) throwParse('taskTypes must be an array');
256
+ for (const [i, item] of fm.taskTypes.entries()) {
257
+ if (!item || typeof item !== 'object') throwParse(`taskTypes[${i}] must be an object`);
258
+ requireString(item, `taskTypes[${i}].id`, item.id);
259
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(item.id)) throwParse(`taskTypes[${i}].id '${item.id}' must match ^[a-z0-9][a-z0-9-]*$`);
260
+ requireString(item, `taskTypes[${i}].label`, item.label);
261
+ requireString(item, `taskTypes[${i}].state`, item.state);
262
+ if (!VALID_STATES.includes(item.state)) {
263
+ throwParse(`taskTypes[${i}].state '${item.state}' must be one of ${VALID_STATES.join(', ')}`);
264
+ }
265
+ }
266
+ }
267
+
268
+ function requireString(obj, field, value) {
269
+ const v = value ?? obj?.[field];
270
+ if (typeof v !== 'string' || v.length === 0) {
271
+ throwParse(`${field} must be a non-empty string`);
272
+ }
273
+ }
274
+
275
+ function throwParse(msg) {
276
+ const err = new Error(msg);
277
+ err.exitCode = 2;
278
+ throw err;
279
+ }
280
+
281
+ function throwUsage(msg) {
282
+ const err = new Error(msg);
283
+ err.exitCode = 1;
284
+ throw err;
285
+ }
286
+
287
+ export function nowIso() {
288
+ return new Date().toISOString();
289
+ }
290
+
291
+ export function emptyEnvelope(agent, owner) {
292
+ return {
293
+ frontmatter: {
294
+ agent,
295
+ owner,
296
+ updated: nowIso(),
297
+ taskTypes: [],
298
+ },
299
+ history: [],
300
+ };
301
+ }
@@ -0,0 +1,140 @@
1
+ // cli.mjs — pa-coordinator-hook entry point.
2
+ //
3
+ // This is a Claude Code PreToolUse hook, NOT a normal repo CLI — its exit
4
+ // code contract is dictated by Claude Code's hook protocol
5
+ // (https://code.claude.com/docs/en/hooks), not by this monorepo's usual
6
+ // "0 ok / 1 usage / 2 logical failure / 3 transport failure" convention
7
+ // (CONTRIBUTING.md). Deliberately:
8
+ //
9
+ // exit 0 — allow. Either coordinator mode is off, the tool is
10
+ // unconditionally allowed, or the tier2 arguments matched an
11
+ // allow pattern. No stdout JSON is emitted — Claude Code falls
12
+ // through to its normal permission flow, which is exactly what
13
+ // we want (the hook only ever tightens, never auto-grants
14
+ // something the user's own settings wouldn't already allow).
15
+ // exit 2 — block. stderr carries the message Claude Code shows the
16
+ // model. tool_input is never mutated. Also used for a hook-
17
+ // internal failure (config missing/corrupted, or any other
18
+ // unexpected exception while deciding) — a security-relevant
19
+ // gate fails CLOSED on its own bugs, never open.
20
+ // exit 1 — malformed input (unparseable stdin JSON, missing tool_name).
21
+ // Per the hooks doc this is a NON-BLOCKING error — the tool
22
+ // call proceeds normally. We'd rather fail open on a malformed
23
+ // payload than break every tool call estate-wide because of a
24
+ // hook bug; the alternative (fail closed) turns one hook bug
25
+ // into a total PA outage. Logged to stderr either way, so it's
26
+ // visible in the transcript.
27
+ //
28
+ // Input: PreToolUse JSON on stdin — { tool_name, tool_input, cwd, ... }
29
+ // (see packages/cli/docs/coordinator-hook.md for the full contract this
30
+ // was verified against).
31
+ //
32
+ // `pa-coordinator-hook --help` prints usage and exits 0 without touching
33
+ // stdin — matches the "every bin runs --help and exits 0" install-health
34
+ // convention documented in packages/engineering-pa/README.md, and gives
35
+ // operators a way to sanity-check the install without constructing a fake
36
+ // hook payload.
37
+
38
+ import { loadEffectiveConfig, overlayPaths } from './config.mjs';
39
+ import { decide } from './policy.mjs';
40
+ import { formatBlockMessage } from './message.mjs';
41
+ import { resolveRepoRoot } from './repo-root.mjs';
42
+ import { resolveSelfAgent } from './self.mjs';
43
+
44
+ const USAGE = `pa-coordinator-hook — Claude Code PreToolUse hook enforcing the three-tier
45
+ coordinator-mode tool policy for interactive PA main threads.
46
+
47
+ Not meant to be invoked by hand — wired up via settings.json's PreToolUse
48
+ hooks (see packages/cli/docs/coordinator-hook.md for the snippet). Reads a
49
+ PreToolUse JSON payload from stdin, exits 0 (allow) or 2 (block, message on
50
+ stderr).
51
+
52
+ Toggle: set PA_COORDINATOR_MODE=1 to enforce. Unset (or any other value)
53
+ is a transparent no-op — exits 0 for everything, including malformed input.
54
+
55
+ Usage:
56
+ pa-coordinator-hook Read a PreToolUse payload from stdin
57
+ pa-coordinator-hook --help Show this help and exit 0
58
+ `;
59
+
60
+ export async function main(argv = [], { stdin = process.stdin, stderr = process.stderr, env = process.env } = {}) {
61
+ if (argv.includes('-h') || argv.includes('--help')) {
62
+ stderr.write(USAGE);
63
+ return 0;
64
+ }
65
+
66
+ const mode = env.PA_COORDINATOR_MODE;
67
+ if (mode !== '1') {
68
+ // Transparent no-op — don't even read stdin, nothing to decide.
69
+ return 0;
70
+ }
71
+
72
+ if (stdin.isTTY) {
73
+ // Invoked bare in an interactive terminal — there is no PreToolUse
74
+ // payload coming. Don't hang waiting for stdin to close; fail open
75
+ // and tell the human what happened.
76
+ stderr.write('pa-coordinator-hook: no stdin payload (interactive terminal) — nothing to decide, allowing. Use --help for usage.\n');
77
+ return 1;
78
+ }
79
+
80
+ let payload;
81
+ try {
82
+ const raw = await readAll(stdin);
83
+ payload = JSON.parse(raw);
84
+ } catch (err) {
85
+ stderr.write(`pa-coordinator-hook: malformed stdin payload (${err.message}) — failing open (allow)\n`);
86
+ return 1; // non-blocking per the hooks contract — tool call proceeds
87
+ }
88
+
89
+ const toolName = payload?.tool_name;
90
+ const toolInput = payload?.tool_input ?? {};
91
+ const cwd = payload?.cwd || process.cwd();
92
+
93
+ if (!toolName || typeof toolName !== 'string') {
94
+ stderr.write('pa-coordinator-hook: payload missing tool_name — failing open (allow)\n');
95
+ return 1;
96
+ }
97
+
98
+ // Everything from here on is "the gate itself" — config load, repo-root /
99
+ // self-agent resolution, and the actual policy decision. This is
100
+ // deliberately distinct from the malformed-stdin-JSON case above (which
101
+ // is a legitimate exit-1/fail-open case per the hooks contract): an
102
+ // exception in here means the gate itself is broken (missing/corrupted
103
+ // config, a bug in the decision logic, whatever) and a security-relevant
104
+ // gate must fail CLOSED on its own failures, not silently fall through to
105
+ // allow. Previously an uncaught exception here (e.g. loadEffectiveConfig
106
+ // throwing on a corrupted coordinator-allowlist.json) propagated out of
107
+ // main() entirely and crashed the process — which the hooks contract
108
+ // reads as a non-blocking/allow outcome, silently disabling the whole
109
+ // gate on a bad install.
110
+ try {
111
+ // PA_COORDINATOR_CORE_CONFIG_PATH is an internal test seam (also usable
112
+ // for a deliberate ops override) — unset in normal operation, so
113
+ // loadEffectiveConfig falls back to its own CORE_CONFIG_PATH default.
114
+ const configPath = env.PA_COORDINATOR_CORE_CONFIG_PATH || undefined;
115
+ const { config, warnings } = await loadEffectiveConfig({ cwd, env, configPath });
116
+ for (const w of warnings) stderr.write(`pa-coordinator-hook: ${w}\n`);
117
+
118
+ const repoRoot = await resolveRepoRoot(cwd, env);
119
+ const selfAgent = await resolveSelfAgent(repoRoot, env);
120
+
121
+ const result = decide(toolName, toolInput, config, { cwd, repoRoot, selfAgent });
122
+
123
+ if (result.decision === 'allow') return 0;
124
+
125
+ const { workspace } = overlayPaths({ repoRoot, cwd, env });
126
+ const message = formatBlockMessage(toolName, result, config, workspace);
127
+ stderr.write(message + '\n');
128
+ return 2;
129
+ } catch (err) {
130
+ stderr.write(`pa-coordinator-hook: internal error (${err && err.message}) — failing closed (block)\n`);
131
+ return 2;
132
+ }
133
+ }
134
+
135
+ async function readAll(stream) {
136
+ if (stream.readableEnded || stream.destroyed) return '';
137
+ const chunks = [];
138
+ for await (const chunk of stream) chunks.push(chunk);
139
+ return Buffer.concat(chunks.map((c) => (Buffer.isBuffer(c) ? c : Buffer.from(c)))).toString('utf8');
140
+ }
@@ -0,0 +1,134 @@
1
+ // config.mjs — load + merge the coordinator-hook allowlist config.
2
+ //
3
+ // Three layers, in priority order (lowest to highest — later layers only
4
+ // ADD allow-pattern entries, they never remove or reclassify anything):
5
+ // 1. Core config — packages/cli/config/coordinator-allowlist.json,
6
+ // resolved relative to this module via import.meta.url so it works
7
+ // identically from source (packages/cli/src/coordinator-hook/…) and
8
+ // from the bundled dist tree (dist/engineering-pa-cli/src/coordinator-hook/…) —
9
+ // build.mjs preserves the package's internal relative layout.
10
+ // 2. Home overlay — ~/.claude/coordinator-overlay.json
11
+ // 3. Workspace overlay — <repoRoot or cwd>/.claude/coordinator-overlay.json
12
+ //
13
+ // Overlay contract (spec-locked, do not relax): an overlay may ONLY extend
14
+ // `tier2.<Bash|Read|Write>.allowPatterns` / `allowPathPatterns`. It cannot
15
+ // move a tool between tiers, cannot touch tier1/tier3, and cannot touch
16
+ // hardDeny. Anything else in an overlay file is ignored with a stderr
17
+ // warning — silently accepting unknown shape would be how a stray overlay
18
+ // key quietly widens the policy.
19
+
20
+ import { readFile } from 'node:fs/promises';
21
+ import { dirname, join, resolve } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { homedir } from 'node:os';
24
+
25
+ const __dirname = dirname(fileURLToPath(import.meta.url));
26
+ const CORE_CONFIG_PATH = resolve(__dirname, '..', '..', 'config', 'coordinator-allowlist.json');
27
+
28
+ const OVERLAYABLE_TOOLS = ['Bash', 'Read', 'Write'];
29
+ const OVERLAYABLE_KEYS = ['allowPatterns', 'allowPathPatterns'];
30
+
31
+ export async function loadCoreConfig(configPath = CORE_CONFIG_PATH) {
32
+ const raw = await readFile(configPath, 'utf8');
33
+ return JSON.parse(raw);
34
+ }
35
+
36
+ // Discriminated result so the caller never has to guess whether a `null`
37
+ // came from "file absent" vs. "file contained the JSON literal null".
38
+ async function tryReadJson(path) {
39
+ let raw;
40
+ try {
41
+ raw = await readFile(path, 'utf8');
42
+ } catch (err) {
43
+ if (err && err.code === 'ENOENT') return { ok: false, missing: true };
44
+ return { ok: false, error: err };
45
+ }
46
+ try {
47
+ return { ok: true, data: JSON.parse(raw) };
48
+ } catch (err) {
49
+ return { ok: false, error: err };
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Merge one overlay object's allowlisted keys onto `config` (returns a new
55
+ * object — never mutates the input). Unknown/disallowed keys are dropped
56
+ * and reported via `warnings`.
57
+ */
58
+ export function mergeOverlay(config, overlay, warnings = []) {
59
+ if (!overlay || typeof overlay !== 'object') return config;
60
+
61
+ const next = {
62
+ ...config,
63
+ tier2: { ...config.tier2 },
64
+ };
65
+
66
+ for (const [key, value] of Object.entries(overlay)) {
67
+ if (key !== 'tier2') {
68
+ warnings.push(`coordinator-overlay: ignoring top-level key "${key}" (overlays may only extend tier2 allow patterns)`);
69
+ continue;
70
+ }
71
+ if (!value || typeof value !== 'object') continue;
72
+ for (const [tool, toolPatch] of Object.entries(value)) {
73
+ if (!OVERLAYABLE_TOOLS.includes(tool)) {
74
+ warnings.push(`coordinator-overlay: ignoring tier2.${tool} — overlays may only extend Bash/Read/Write`);
75
+ continue;
76
+ }
77
+ if (!toolPatch || typeof toolPatch !== 'object') continue;
78
+ const mergedTool = { ...(next.tier2[tool] ?? {}) };
79
+ for (const [patchKey, patternList] of Object.entries(toolPatch)) {
80
+ if (!OVERLAYABLE_KEYS.includes(patchKey)) {
81
+ warnings.push(`coordinator-overlay: ignoring tier2.${tool}.${patchKey} — only allowPatterns/allowPathPatterns may be extended`);
82
+ continue;
83
+ }
84
+ if (!Array.isArray(patternList)) continue;
85
+ const existing = Array.isArray(mergedTool[patchKey]) ? mergedTool[patchKey] : [];
86
+ mergedTool[patchKey] = [...new Set([...existing, ...patternList.filter((p) => typeof p === 'string')])];
87
+ }
88
+ next.tier2[tool] = mergedTool;
89
+ }
90
+ }
91
+
92
+ return next;
93
+ }
94
+
95
+ /**
96
+ * Resolve the two overlay file candidates (home, workspace). Workspace
97
+ * overlay is anchored at `repoRoot` when known, else `cwd` — either way it
98
+ * lives at `.claude/coordinator-overlay.json` under that directory.
99
+ */
100
+ export function overlayPaths({ repoRoot, cwd, env = process.env }) {
101
+ const home = env.HOME || homedir();
102
+ const workspaceBase = repoRoot || cwd;
103
+ return {
104
+ home: home ? join(home, '.claude', 'coordinator-overlay.json') : null,
105
+ workspace: workspaceBase ? join(workspaceBase, '.claude', 'coordinator-overlay.json') : null,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Load the fully-merged effective config: core + home overlay + workspace
111
+ * overlay (workspace applied last, so it can extend past whatever the home
112
+ * overlay already added). Returns `{ config, warnings }` — warnings is a
113
+ * flat array of human-readable strings for anything ignored along the way.
114
+ */
115
+ export async function loadEffectiveConfig({ repoRoot, cwd, env = process.env, configPath } = {}) {
116
+ const warnings = [];
117
+ let config = await loadCoreConfig(configPath);
118
+
119
+ const { home, workspace } = overlayPaths({ repoRoot, cwd, env });
120
+ for (const overlayPath of [home, workspace]) {
121
+ if (!overlayPath) continue;
122
+ const result = await tryReadJson(overlayPath);
123
+ if (!result.ok) {
124
+ if (result.missing) continue; // no overlay at this path — normal case
125
+ warnings.push(`coordinator-overlay: failed to parse ${overlayPath} (${result.error.message}) — ignoring`);
126
+ continue;
127
+ }
128
+ config = mergeOverlay(config, result.data, warnings);
129
+ }
130
+
131
+ return { config, warnings };
132
+ }
133
+
134
+ export { CORE_CONFIG_PATH };
@@ -0,0 +1,47 @@
1
+ // message.mjs — formats the exit-2 stderr message a blocked tool call sees.
2
+ //
3
+ // Format is spec-locked (agentic-harness product-vision.md §1 item 6):
4
+ //
5
+ // coordinator-mode: <ToolName> blocked (<tier> - <reason>).
6
+ // Try: <specific alternative>
7
+ // - Dispatch a worker: `Agent(...)` with the appropriate role.
8
+ // - Retrieve knowledge: `Bash(pa knowledge search "...")`.
9
+ // - Named exception needed? Add to allowlist: <config path>.
10
+ //
11
+ // The "Try:" line is tool-specific (config.messages[toolName], falling back
12
+ // to a generic line) — concrete alternatives matter more than a generic
13
+ // "dispatch instead" for the model reading the block.
14
+
15
+ export function formatBlockMessage(toolName, decisionResult, config, overlayPath) {
16
+ const { tier, reason, matched } = decisionResult;
17
+
18
+ const tryLine = pickTryLine(toolName, decisionResult, config);
19
+ const configPath = overlayPath || '~/.claude/coordinator-overlay.json (or <workspace>/.claude/coordinator-overlay.json)';
20
+
21
+ const lines = [
22
+ `coordinator-mode: ${toolName} blocked (${tier} - ${reason}).`,
23
+ `Try: ${tryLine}`,
24
+ '- Dispatch a worker: `Agent(...)` with the appropriate role.',
25
+ '- Retrieve knowledge: `Bash(pa knowledge search "...")`.',
26
+ `- Named exception needed? Add to allowlist: ${configPath} (tier2 allowPatterns/allowPathPatterns only — cannot move a tool between tiers).`,
27
+ ];
28
+ return lines.join('\n');
29
+ }
30
+
31
+ function pickTryLine(toolName, decisionResult, config) {
32
+ const messages = config.messages ?? {};
33
+
34
+ // Read blocked specifically by the operator/knowledge blockPathPatterns
35
+ // entry gets its own, more specific message than a generic Read-denied one.
36
+ if (toolName === 'Read' && decisionResult.tier === 'tier2-explicit-block' && messages['operator/knowledge/**']) {
37
+ return messages['operator/knowledge/**'];
38
+ }
39
+
40
+ if (decisionResult.tier === 'tier2-hard-deny' && messages.hardDeny) {
41
+ return messages.hardDeny;
42
+ }
43
+
44
+ if (messages[toolName]) return messages[toolName];
45
+
46
+ return `dispatch a worker instead of calling ${toolName} inline — main thread is coordinator-mode.`;
47
+ }