@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,211 @@
1
+ // policy.mjs — the three-tier decision engine.
2
+ //
3
+ // Pure function of (toolName, toolInput, config, context) -> a decision.
4
+ // No I/O here — cli.mjs does the stdin/env/config-loading plumbing and
5
+ // hands this module plain data, so the allowlist-matching logic itself is
6
+ // trivially unit-testable without spawning a process or touching disk.
7
+ //
8
+ // NB: this module only ever runs for tools in the PreToolUse matcher
9
+ // (^(Bash|Read|Write|Edit|NotebookEdit|Grep|Glob|WebFetch|WebSearch)$) —
10
+ // tier1 tools never reach the hook at all, so there is no tier1 branch
11
+ // here; config.tier1 exists purely as documentation (see config file
12
+ // comment).
13
+
14
+ import { relative, resolve } from 'node:path';
15
+
16
+ /**
17
+ * @param {string} toolName
18
+ * @param {object} toolInput
19
+ * @param {object} config effective (core + overlays) merged config
20
+ * @param {object} context
21
+ * @param {string} context.cwd - cwd from the PreToolUse payload
22
+ * @param {string|null} context.repoRoot - resolved repo root, or null
23
+ * @param {string|null} context.selfAgent - resolved paName, or null
24
+ * @returns {{decision: 'allow'|'block', tier: string, reason: string, matched: (string|null)}}
25
+ */
26
+ export function decide(toolName, toolInput, config, context = {}) {
27
+ if (config.tier3.includes(toolName)) {
28
+ return block('tier3', `${toolName} is always-blocked under coordinator mode`, null);
29
+ }
30
+
31
+ if (toolName === 'Bash') return decideBash(toolInput, config);
32
+ if (toolName === 'Read') return decideReadOrWrite('Read', toolInput, config, context);
33
+ if (toolName === 'Write') return decideReadOrWrite('Write', toolInput, config, context);
34
+
35
+ // Any tool reaching the hook that is neither tier3 nor one of the three
36
+ // argument-gated tier2 tools is unrecognised under this policy — default
37
+ // deny, never default allow. (In practice the matcher regex means this
38
+ // can only happen if the settings.json snippet's matcher is edited to
39
+ // add a tool this policy doesn't know about yet.)
40
+ return block('unrecognised', `${toolName} is not covered by the coordinator policy (matcher/config drift) — defaulting to deny`, null);
41
+ }
42
+
43
+ function allow(tier, reason, matched) {
44
+ return { decision: 'allow', tier, reason, matched: matched ?? null };
45
+ }
46
+
47
+ function block(tier, reason, matched) {
48
+ return { decision: 'block', tier, reason, matched: matched ?? null };
49
+ }
50
+
51
+ function anyPatternMatches(patterns, value) {
52
+ for (const p of patterns ?? []) {
53
+ try {
54
+ if (new RegExp(p).test(value)) return p;
55
+ } catch {
56
+ // A malformed regex in config/overlay never crashes the hook — it
57
+ // just never matches. Fail closed, not open.
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ function decideBash(toolInput, config) {
64
+ const command = typeof toolInput?.command === 'string' ? toolInput.command : '';
65
+ const hardDeny = config.hardDeny ?? {};
66
+ const allowPatterns = config.tier2?.Bash?.allowPatterns ?? [];
67
+
68
+ // Belt-and-braces: the chain-guard character class now includes a literal
69
+ // newline alongside the shell-chaining metacharacters, so any multi-line
70
+ // command is blocked outright here, before the per-line pass below even
71
+ // runs. This alone stops every newline-smuggled hard-deny bypass; the
72
+ // per-line pass is kept as a second, independent layer in case the guard
73
+ // pattern is ever narrowed by a future config edit.
74
+ if (hardDeny.bashChainGuardPattern) {
75
+ const chainMatch = anyPatternMatches([hardDeny.bashChainGuardPattern], command);
76
+ if (chainMatch) {
77
+ return block(
78
+ 'tier2-hard-deny',
79
+ 'command contains a shell-chaining metacharacter (;, &&, ||, |, `, $(...), <, >) or an embedded newline — blocked even though a prefix may match an allow pattern',
80
+ chainMatch,
81
+ );
82
+ }
83
+ }
84
+
85
+ // Hard-deny is evaluated per line, never against the whole (possibly
86
+ // multi-line) command string. `^` in a hardDeny pattern has no `m` flag,
87
+ // so tested against the full string it only ever matches the very start —
88
+ // a hard-denied command hidden behind an embedded newline would sail
89
+ // through. Splitting on \n and testing each line from position 0 makes
90
+ // every hard-deny pattern effectively line-start-anchored without having
91
+ // to touch the patterns themselves. hardDeny.pathPatterns (credential
92
+ // paths) is checked here too, against the Bash command text — not just
93
+ // Read/Write file_path — so a command that references e.g. `.ssh/` via
94
+ // redirection is caught even if it slips past the chain-guard.
95
+ const lines = command.split('\n');
96
+ for (const line of lines) {
97
+ const hardDenyMatch = anyPatternMatches(hardDeny.bashPatterns, line);
98
+ if (hardDenyMatch) {
99
+ return block('tier2-hard-deny', `command matches hard-deny pattern "${hardDenyMatch}" — never allowed, overlays cannot override`, hardDenyMatch);
100
+ }
101
+ const hardDenyPathMatch = anyPatternMatches(hardDeny.pathPatterns, line);
102
+ if (hardDenyPathMatch) {
103
+ return block('tier2-hard-deny', `command references a hard-deny path pattern "${hardDenyPathMatch}" — never allowed, overlays cannot override`, hardDenyPathMatch);
104
+ }
105
+ }
106
+
107
+ // Every line must independently match an allow pattern — an allowlisted
108
+ // first line followed by an unrecognised (or hard-denied) second line is
109
+ // not enough; the whole command has to be clean end to end.
110
+ let matched = null;
111
+ for (const line of lines) {
112
+ const allowMatch = anyPatternMatches(allowPatterns, line);
113
+ if (!allowMatch) {
114
+ return block('tier2', `command does not match any Bash allow pattern (line: "${line}")`, null);
115
+ }
116
+ if (matched === null) matched = allowMatch;
117
+ }
118
+
119
+ return allow('tier2', `command matches allow pattern "${matched}"`, matched);
120
+ }
121
+
122
+ function decideReadOrWrite(toolName, toolInput, config, context) {
123
+ const rawFilePath = typeof toolInput?.file_path === 'string' ? toolInput.file_path : '';
124
+ // Normalize absolute paths (collapse `..`/`.`/`//`) before ANY pattern
125
+ // matching happens — hard-deny, absolute-allow, and (via
126
+ // toRepoRelative()) the repo-relative block/allow checks all then operate
127
+ // on the resolved path. Without this, a raw string like
128
+ // `/tmp/../operator/knowledge/foo.md` matches `^/tmp/` on the
129
+ // unresolved text even though it actually points at
130
+ // `/operator/knowledge/foo.md` once traversal is collapsed — the
131
+ // absolute-allow branch was added separately from the repo-relative
132
+ // branch below and never got the same treatment. Relative paths are left
133
+ // untouched here; toRepoRelative() already resolves those correctly
134
+ // against context.cwd.
135
+ const filePath = rawFilePath.startsWith('/') ? resolve(rawFilePath) : rawFilePath;
136
+ const toolConfig = config.tier2?.[toolName] ?? {};
137
+
138
+ // Hard-deny is checked first, against the raw path, and wins over even
139
+ // an absolute allow pattern (scratchpad included) — a determined overlay
140
+ // author extending allowAbsolutePathPatterns must not be able to smuggle
141
+ // a credentials-file read past this.
142
+ const hardDenyPatterns = config.hardDeny?.pathPatterns ?? [];
143
+ const hardDenyMatch = anyPatternMatches(hardDenyPatterns, filePath);
144
+ if (hardDenyMatch) {
145
+ return block('tier2-hard-deny', `path matches hard-deny pattern "${hardDenyMatch}" — never allowed, overlays cannot override`, hardDenyMatch);
146
+ }
147
+
148
+ // Absolute allow patterns (scratchpad etc.) are checked directly against
149
+ // the raw path — they're meaningful with or without a resolvable repo root.
150
+ const absAllow = anyPatternMatches(toolConfig.allowAbsolutePathPatterns, filePath);
151
+ if (absAllow) {
152
+ return allow('tier2', `path matches absolute allow pattern "${absAllow}"`, absAllow);
153
+ }
154
+
155
+ // Everything else is expressed relative to the repo root.
156
+ const relPath = toRepoRelative(filePath, context);
157
+
158
+ if (relPath !== null) {
159
+ const blockMatch = anyPatternMatches(toolConfig.blockPathPatterns, relPath);
160
+ if (blockMatch) {
161
+ return block('tier2-explicit-block', `path matches explicit block pattern "${blockMatch}"`, blockMatch);
162
+ }
163
+
164
+ const selfAwarePatterns = expandSelfPatterns(toolConfig.allowPathPatterns, context.selfAgent);
165
+ const allowMatch = anyPatternMatches(selfAwarePatterns, relPath);
166
+ if (allowMatch) {
167
+ return allow('tier2', `path matches allow pattern "${allowMatch}"`, allowMatch);
168
+ }
169
+
170
+ return block('tier2', `path "${relPath}" does not match any ${toolName} allow pattern`, null);
171
+ }
172
+
173
+ // Could not resolve a repo-relative path (no repo root found and the
174
+ // path wasn't under one of the absolute allow patterns) — default deny.
175
+ return block('tier2', `could not resolve "${filePath}" relative to a repo root — defaulting to deny`, null);
176
+ }
177
+
178
+ /**
179
+ * Substitutes the literal `<self>` token used in `agents/<self>/…` config
180
+ * patterns. When the calling PA's paName is known, it's substituted
181
+ * verbatim (regex-escaped); when unknown, it's substituted with `[^/]+` —
182
+ * the spec's documented fallback ("if unknown, allow any agents subdirectory").
183
+ * Applies to both core and overlay-supplied patterns, since an overlay
184
+ * author may reasonably write `<self>`-scoped patterns too.
185
+ */
186
+ function expandSelfPatterns(patterns, selfAgent) {
187
+ if (!patterns) return patterns;
188
+ const replacement = selfAgent ? escapeRegex(selfAgent) : '[^/]+';
189
+ return patterns.map((p) => p.replaceAll('<self>', replacement));
190
+ }
191
+
192
+ function escapeRegex(s) {
193
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
194
+ }
195
+
196
+ /**
197
+ * Resolve `filePath` to a repo-root-relative, forward-slash path. Returns
198
+ * null when it can't be placed under the repo root at all (no repo root
199
+ * known, or the path lies genuinely outside it).
200
+ */
201
+ function toRepoRelative(filePath, context) {
202
+ if (!filePath) return null;
203
+ const { repoRoot, cwd } = context;
204
+ const root = repoRoot || null;
205
+ if (!root) return null;
206
+
207
+ const abs = filePath.startsWith('/') ? filePath : resolve(cwd || root, filePath);
208
+ const rel = relative(root, abs);
209
+ if (rel.startsWith('..') || rel === '') return rel === '' ? '.' : null;
210
+ return rel.split('\\').join('/');
211
+ }
@@ -0,0 +1,44 @@
1
+ // repo-root.mjs — operator repo root discovery for the coordinator hook.
2
+ //
3
+ // Mirrors packages/cli/src/pa/repo-root.mjs and packages/core/src/desk/repo.mjs.
4
+ // Own copy avoids cross-module coupling for a pure utility (established
5
+ // convention in this monorepo — see the comment in pa/repo-root.mjs).
6
+ //
7
+ // Unlike the CLI-facing copies, this one takes an explicit `startDir` and
8
+ // `env` on every call instead of caching module-global state — the hook is
9
+ // a fresh process per PreToolUse invocation, and it also needs to resolve
10
+ // roots relative to the `cwd` field of the tool-use payload, which is not
11
+ // necessarily `process.cwd()`.
12
+ //
13
+ // Resolution order:
14
+ // 1. DAVE_REPO_ROOT / PA_REPO_ROOT env var (explicit override)
15
+ // 2. Walk upward from startDir looking for a `.git` entry (dir or file —
16
+ // a `.git` file means a worktree checkout)
17
+ // 3. null if nothing found (caller decides the safe-default fallback)
18
+
19
+ import { stat } from 'node:fs/promises';
20
+ import { join, resolve, dirname } from 'node:path';
21
+
22
+ async function pathKind(p) {
23
+ try {
24
+ const s = await stat(p);
25
+ if (s.isDirectory()) return 'dir';
26
+ if (s.isFile()) return 'file';
27
+ return 'other';
28
+ } catch {
29
+ return 'missing';
30
+ }
31
+ }
32
+
33
+ export async function resolveRepoRoot(startDir, env = process.env) {
34
+ const envRoot = env.DAVE_REPO_ROOT || env.PA_REPO_ROOT;
35
+ if (envRoot) return resolve(envRoot);
36
+
37
+ let d = resolve(startDir);
38
+ while (d && d !== dirname(d)) {
39
+ const k = await pathKind(join(d, '.git'));
40
+ if (k === 'dir' || k === 'file') return d;
41
+ d = dirname(d);
42
+ }
43
+ return null;
44
+ }
@@ -0,0 +1,30 @@
1
+ // self.mjs — resolve the calling PA's own agent-directory name ("<self>" in
2
+ // the allowlist spec's `agents/<self>/**` patterns).
3
+ //
4
+ // Priority:
5
+ // 1. PA_SELF_AGENT env var (explicit override — useful for tests and for
6
+ // hosts where preferences.json resolution is inconvenient).
7
+ // 2. operator/config/preferences.json → paName, read relative to the
8
+ // resolved repo root.
9
+ // 3. Unknown — caller falls back to the permissive `agents/[^/]+/`
10
+ // pattern, per the spec ("if unknown, allow any agents/*/ path").
11
+ //
12
+ // Returns a string paName, or null when unresolved.
13
+
14
+ import { readFile } from 'node:fs/promises';
15
+ import { join } from 'node:path';
16
+
17
+ export async function resolveSelfAgent(repoRoot, env = process.env) {
18
+ if (env.PA_SELF_AGENT) return env.PA_SELF_AGENT;
19
+ if (!repoRoot) return null;
20
+ try {
21
+ const raw = await readFile(join(repoRoot, 'operator', 'config', 'preferences.json'), 'utf8');
22
+ const config = JSON.parse(raw);
23
+ if (config && typeof config.paName === 'string' && config.paName.trim()) {
24
+ return config.paName.trim();
25
+ }
26
+ return null;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
@@ -0,0 +1,287 @@
1
+ // cli.mjs — argv router for `pa environment [verb]`.
2
+ //
3
+ // Verbs (three):
4
+ // pa environment Read cache, auto-refresh if stale, print summary
5
+ // pa environment refresh Force rebuild the cache
6
+ // pa environment extended Reserved verb — dispatches to operator overlay
7
+ //
8
+ // Global flags:
9
+ // --format json Machine-readable output to stdout
10
+ // --quiet Suppress human summary; file write is the payload
11
+ // --skip-network Skip network probes (fallback for slow CI or offline dev)
12
+ //
13
+ // Exit codes (tooling standard §6):
14
+ // 0 ok | 1 usage | 2 unresolvable state (extended verb without extension,
15
+ // cache-write failure) | 3 network probe failure (does NOT prevent write —
16
+ // degraded environment is still captured, but the exit code signals it)
17
+ //
18
+ // Performance target: cache-read <2s, refresh <5s. Runs at every session
19
+ // boot; slower and the operator waits.
20
+
21
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
22
+ import { join, dirname } from 'node:path';
23
+ import { pathToFileURL } from 'node:url';
24
+ import { getRepoRoot } from '../pa/repo-root.mjs';
25
+ import {
26
+ probePlatform,
27
+ probeRuntimes,
28
+ probePlatformCli,
29
+ probeCustomTools,
30
+ probeNetwork,
31
+ probeWorkspace,
32
+ probeWorkingDirectory,
33
+ } from './probes.mjs';
34
+
35
+ const CLI_VERSION = '0.2.0';
36
+ const DEFAULT_STALENESS_MINUTES = 60;
37
+
38
+ const USAGE = `pa environment — session-boot environment cache
39
+
40
+ Usage:
41
+ pa environment Read cache; auto-refresh if missing/stale
42
+ pa environment refresh Force rebuild
43
+ pa environment extended (Reserved verb — operator overlay)
44
+ pa environment -h, --help Show this help
45
+
46
+ Global flags:
47
+ --format <human|json> Output format (default: human)
48
+ --quiet Suppress stdout summary
49
+ --skip-network Skip DNS + HTTP probes
50
+
51
+ Cache file: <repo-root>/.session/environment.json.
52
+ Staleness threshold: 60 minutes (override via operator/config/preferences.json:
53
+ environment.cacheStalenessMinutes).
54
+
55
+ Extended verb loader: <repo-root>/operator/extensions/tools/environment-extended/index.mjs.
56
+
57
+ Exit codes (tooling standard §6):
58
+ 0 ok | 1 usage | 2 unresolvable state | 3 network probe failure
59
+ `;
60
+
61
+ export async function run(argv) {
62
+ const args = argv ?? [];
63
+ if (args.includes('-h') || args.includes('--help')) {
64
+ process.stdout.write(USAGE);
65
+ return 0;
66
+ }
67
+ const { positionals, flags } = parseArgs(args);
68
+ const verb = positionals[0] ?? 'default';
69
+ try {
70
+ switch (verb) {
71
+ case 'default': return await runDefault(flags);
72
+ case 'refresh': return await runRefresh(flags);
73
+ case 'extended': return await runExtended(flags, positionals.slice(1));
74
+ default:
75
+ process.stderr.write(`[pa environment] unknown verb: ${verb}\n`);
76
+ process.stderr.write(USAGE);
77
+ return 1;
78
+ }
79
+ } catch (err) {
80
+ process.stderr.write(`[pa environment] ${err.message || err}\n`);
81
+ return err.exitCode ?? 2;
82
+ }
83
+ }
84
+
85
+ function parseArgs(argv) {
86
+ const flags = { format: 'human', quiet: false, skipNetwork: false };
87
+ const positionals = [];
88
+ for (let i = 0; i < argv.length; i++) {
89
+ const arg = argv[i];
90
+ if (arg === '--format') { flags.format = argv[++i]; continue; }
91
+ if (arg.startsWith('--format=')) { flags.format = arg.slice('--format='.length); continue; }
92
+ if (arg === '--quiet') { flags.quiet = true; continue; }
93
+ if (arg === '--skip-network') { flags.skipNetwork = true; continue; }
94
+ if (arg.startsWith('--')) {
95
+ const err = new Error(`unknown flag ${arg}`);
96
+ err.exitCode = 1;
97
+ throw err;
98
+ }
99
+ positionals.push(arg);
100
+ }
101
+ return { positionals, flags };
102
+ }
103
+
104
+ async function runDefault(flags) {
105
+ const repoRoot = await getRepoRoot();
106
+ const cachePath = cacheFilePath(repoRoot);
107
+ const staleness = readStalenessMinutes(repoRoot);
108
+ const cached = readCache(cachePath);
109
+ const stale = cached ? isStale(cached, staleness) : true;
110
+ let cache;
111
+ let networkDegraded = false;
112
+ if (!cached || stale) {
113
+ ({ cache, networkDegraded } = await buildCache(repoRoot, flags));
114
+ writeCache(cachePath, cache);
115
+ } else {
116
+ cache = cached;
117
+ }
118
+ if (!flags.quiet) {
119
+ if (flags.format === 'json') {
120
+ process.stdout.write(JSON.stringify(cache, null, 2) + '\n');
121
+ } else {
122
+ process.stdout.write(formatSummary(cache) + '\n');
123
+ }
124
+ }
125
+ return networkDegraded ? 3 : 0;
126
+ }
127
+
128
+ async function runRefresh(flags) {
129
+ const repoRoot = await getRepoRoot();
130
+ const cachePath = cacheFilePath(repoRoot);
131
+ const { cache, networkDegraded } = await buildCache(repoRoot, flags);
132
+ writeCache(cachePath, cache);
133
+ if (!flags.quiet) {
134
+ if (flags.format === 'json') {
135
+ process.stdout.write(JSON.stringify(cache, null, 2) + '\n');
136
+ } else {
137
+ process.stdout.write(formatSummary(cache) + '\n');
138
+ }
139
+ }
140
+ return networkDegraded ? 3 : 0;
141
+ }
142
+
143
+ async function runExtended(flags, extraArgs) {
144
+ const repoRoot = await getRepoRoot();
145
+ const extensionPath = join(repoRoot, 'operator', 'extensions', 'tools', 'environment-extended', 'index.mjs');
146
+ if (!existsSync(extensionPath)) {
147
+ process.stderr.write(
148
+ '[pa environment extended] extended checks require operator extension — ' +
149
+ 'see operator/extensions/tools/environment-extended (missing on this repo)\n',
150
+ );
151
+ return 2;
152
+ }
153
+ // Build the core cache first — the extension receives it via context so
154
+ // it can extend rather than duplicate.
155
+ const { cache: coreCache } = await buildCache(repoRoot, flags);
156
+ const cachePath = cacheFilePath(repoRoot);
157
+ let mod;
158
+ try {
159
+ mod = await import(pathToFileURL(extensionPath).href);
160
+ } catch (err) {
161
+ process.stderr.write(`[pa environment extended] failed to load extension: ${err.message}\n`);
162
+ return 2;
163
+ }
164
+ const extendFn = mod.default;
165
+ if (typeof extendFn !== 'function') {
166
+ process.stderr.write(
167
+ '[pa environment extended] extension at operator/extensions/tools/environment-extended/index.mjs ' +
168
+ 'must default-export an async function extended({ core, cwd })\n',
169
+ );
170
+ return 2;
171
+ }
172
+ let extended;
173
+ try {
174
+ extended = await extendFn({ core: coreCache, cwd: process.cwd(), extraArgs });
175
+ } catch (err) {
176
+ // Surface the extension's error verbatim — the operator wants to know
177
+ // why the extension failed.
178
+ process.stderr.write(`[pa environment extended] extension threw: ${err.stack || err.message || err}\n`);
179
+ return 2;
180
+ }
181
+ const merged = { ...coreCache, ...(extended ?? {}) };
182
+ writeCache(cachePath, merged);
183
+ if (!flags.quiet) {
184
+ if (flags.format === 'json') {
185
+ process.stdout.write(JSON.stringify(merged, null, 2) + '\n');
186
+ } else {
187
+ process.stdout.write(formatSummary(merged) + '\n');
188
+ }
189
+ }
190
+ return 0;
191
+ }
192
+
193
+ async function buildCache(repoRoot, flags) {
194
+ const platform = probePlatform();
195
+ const [runtimes, network, workspace] = await Promise.all([
196
+ probeRuntimes(),
197
+ probeNetwork({ skip: flags.skipNetwork }),
198
+ probeWorkspace(repoRoot),
199
+ ]);
200
+ const platformCli = probePlatformCli(repoRoot);
201
+ const customTools = probeCustomTools(repoRoot);
202
+ const workingDirectory = probeWorkingDirectory();
203
+ const cache = {
204
+ capturedAt: new Date().toISOString(),
205
+ capturedBy: `pa environment@${CLI_VERSION}`,
206
+ platform,
207
+ runtimes,
208
+ platformCli,
209
+ customTools,
210
+ network,
211
+ workspace,
212
+ workingDirectory,
213
+ };
214
+ const networkDegraded = Boolean(
215
+ !flags.skipNetwork
216
+ && ((network?.dns?.error) || (network?.http?.error)),
217
+ );
218
+ return { cache, networkDegraded };
219
+ }
220
+
221
+ function cacheFilePath(repoRoot) {
222
+ return join(repoRoot, '.session', 'environment.json');
223
+ }
224
+
225
+ function readCache(path) {
226
+ if (!existsSync(path)) return null;
227
+ try {
228
+ return JSON.parse(readFileSync(path, 'utf8'));
229
+ } catch {
230
+ return null;
231
+ }
232
+ }
233
+
234
+ function writeCache(path, cache) {
235
+ try {
236
+ mkdirSync(dirname(path), { recursive: true });
237
+ writeFileSync(path, JSON.stringify(cache, null, 2) + '\n');
238
+ } catch (err) {
239
+ const wrapped = new Error(`could not write cache to ${path}: ${err.message}`);
240
+ wrapped.exitCode = 2;
241
+ throw wrapped;
242
+ }
243
+ }
244
+
245
+ function isStale(cache, stalenessMinutes) {
246
+ if (!cache?.capturedAt) return true;
247
+ const capturedMs = Date.parse(cache.capturedAt);
248
+ if (!Number.isFinite(capturedMs)) return true;
249
+ const ageMs = Date.now() - capturedMs;
250
+ return ageMs > stalenessMinutes * 60 * 1000;
251
+ }
252
+
253
+ function readStalenessMinutes(repoRoot) {
254
+ try {
255
+ const prefsPath = join(repoRoot, 'operator', 'config', 'preferences.json');
256
+ if (existsSync(prefsPath)) {
257
+ const prefs = JSON.parse(readFileSync(prefsPath, 'utf8'));
258
+ const value = prefs?.environment?.cacheStalenessMinutes;
259
+ if (typeof value === 'number' && value > 0) return value;
260
+ }
261
+ } catch {
262
+ // fall through
263
+ }
264
+ return DEFAULT_STALENESS_MINUTES;
265
+ }
266
+
267
+ function formatSummary(cache) {
268
+ const parts = [];
269
+ parts.push(`Environment snapshot @ ${cache.capturedAt}`);
270
+ parts.push(`Capturer: ${cache.capturedBy}`);
271
+ parts.push('');
272
+ const p = cache.platform || {};
273
+ parts.push(`Platform: ${p.os}/${p.arch} kernel=${p.kernel} shell=${p.shell ?? '-'}`);
274
+ const r = cache.runtimes || {};
275
+ parts.push(`Runtimes: node=${r.node?.version ?? '-'} pnpm=${r.pnpm?.version ?? '-'} git=${r.git?.version ?? '-'}`);
276
+ const n = cache.network || {};
277
+ const dnsStr = n.dns?.skipped ? 'skipped' : `${n.dns?.resolved?.[0] ?? n.dns?.error ?? '-'} (${n.dns?.elapsedMs ?? '-'}ms)`;
278
+ const httpStr = n.http?.skipped ? 'skipped' : `${n.http?.statusCode ?? n.http?.error ?? '-'} (${n.http?.elapsedMs ?? '-'}ms)`;
279
+ parts.push(`Network: dns(${n.dns?.target ?? '-'})=${dnsStr} http(${n.http?.target ?? '-'})=${httpStr}`);
280
+ const w = cache.workspace || {};
281
+ parts.push(`Workspace: ${w.url ?? '-'} ${w.running ? 'running' : 'not running'}`);
282
+ const wd = cache.workingDirectory || {};
283
+ parts.push(`Working directory: ${wd.cwd ?? '-'} → projectRoot=${wd.projectRoot ?? 'unresolved'} (via ${wd.resolvedVia ?? '-'})`);
284
+ const tools = cache.customTools || [];
285
+ parts.push(`Custom tools: ${tools.length === 0 ? '(none)' : tools.map((t) => t.name).join(', ')}`);
286
+ return parts.join('\n');
287
+ }