@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,369 @@
1
+ // pa — operator-facing top-level CLI.
2
+ //
3
+ // Status: minimal v0.1.0 surface. The verbs landing here are the ones the
4
+ // scaffolder (`pa-init`) and the operator runbook rely on. Each verb routes
5
+ // to a specialist CLI or library.
6
+
7
+ import { spawn } from 'node:child_process';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { dirname, join, resolve } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { run as runDesk } from '../../../engineering-pa-core/src/desk/cli.mjs';
12
+ import { PA_PACKAGE_NAME } from '../../../engineering-pa-core/src/config/pa-package-name.mjs';
13
+ import { main as runMigrateInspect } from '../../../engineering-pa-migrate-inspect/src/cli.mjs';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+
17
+ const USAGE = `pa — operator personal-assistant CLI
18
+
19
+ Usage:
20
+ pa session Start a PA session — chdir to agent dir, exec \`claude\`
21
+ pa status Probe operator content, installed package, and workspace reachability, then print a desk overview
22
+ pa workspace <verb> Workspace server lifecycle (start | stop | status | open)
23
+ pa project <verb> Project state writes (create | status | doc add/rm | list)
24
+ pa work <verb> Work-item state writes (create | status | list)
25
+ pa gsc <verb> Google Search Console automation (add-property | verify-via-cf-dns | submit-sitemap | pull-analytics | list-properties)
26
+ pa knowledge <verb> Query the operator's knowledge graph (related | search | domain | orphans | path)
27
+ pa research <verb> Deep-research session store (run | list | show | gates | prune | mark | paths)
28
+ pa autonomy <verb> Per-agent per-task-type approval state (init | get | set | list)
29
+ pa environment [verb] Session-boot environment cache (default | refresh | extended)
30
+ pa staging-alias <verb> Canonical staging.<site> alias for CF Workers sites (set | unset | status | list)
31
+ pa lint <verb> Lint operator text against voice rules (linkedin)
32
+ pa migrate-inspect [options] Host inspection for migration planning
33
+ pa launch --agent=<n> --task=<id> [--dry-run]
34
+ Boot a scoped agent instance bound to an identity and task
35
+ pa -h, --help Show this help
36
+
37
+ Routed sub-CLIs (also available as standalone bins):
38
+ desk Task and project queries (read-side complement of \`pa project\` / \`pa work\`)
39
+ secrets Vault management
40
+ sync Per-host single-writer git sync
41
+ scheduler Scheduling primitives
42
+ memory-sync PA-memory cache mirror
43
+ distill Librarian distillation sweep
44
+
45
+ Exit codes (tooling standard §6):
46
+ 0 ok | 1 usage error | 2 operational failure | 3 transport/IO failure
47
+ `;
48
+
49
+ export async function main(argv) {
50
+ if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
51
+ process.stdout.write(USAGE);
52
+ return 0;
53
+ }
54
+
55
+ const verb = argv[0];
56
+ const rest = argv.slice(1);
57
+
58
+ switch (verb) {
59
+ case 'session':
60
+ return await doSession(rest);
61
+ case 'status':
62
+ return await doStatus();
63
+ case 'workspace':
64
+ return await doWorkspace(rest);
65
+ case 'project':
66
+ return await doProject(rest);
67
+ case 'work':
68
+ return await doWork(rest);
69
+ case 'gsc':
70
+ return await doGsc(rest);
71
+ case 'knowledge':
72
+ return await doKnowledge(rest);
73
+ case 'research':
74
+ return await doResearch(rest);
75
+ case 'autonomy':
76
+ return await doAutonomy(rest);
77
+ case 'environment':
78
+ return await doEnvironment(rest);
79
+ case 'lint':
80
+ return await doLint(rest);
81
+ case 'staging-alias':
82
+ return await doStagingAlias(rest);
83
+ case 'migrate-inspect':
84
+ return await runMigrateInspect(rest);
85
+ case 'launch':
86
+ return await doLaunch(rest);
87
+ default:
88
+ process.stderr.write(`[pa] unknown verb: ${verb}\n`);
89
+ process.stderr.write(USAGE);
90
+ return 1;
91
+ }
92
+ }
93
+
94
+ async function doStatus(opts = {}) {
95
+ // Three structured probes followed by a desk overview snapshot.
96
+ //
97
+ // 1. Operator content present — does the cwd look like an operator repo?
98
+ // Reports each well-known path as "present" or "missing".
99
+ // 2. Package install integrity — is `@stravica-ai/digital-operator-pa` installed
100
+ // under node_modules/? If so, report its version.
101
+ // 3. Workspace reachability — try GET /__api/identity on the configured
102
+ // workspace port (default 4200). Reports "reachable", "not running",
103
+ // or "error: …". Workspace-not-running is informational, not failure.
104
+ //
105
+ // After the probes, run `desk overview` in-process and emit its output as
106
+ // the final section. Exit 0 if all structural prerequisites are present
107
+ // (operator/, installed package), 2 if any are missing.
108
+ //
109
+ // Why `desk` runs in-process rather than spawning `node_modules/.bin/desk`:
110
+ // under pnpm's hoisted install layout, no `node_modules/.bin/desk` is
111
+ // adjacent to this package; the bin shim lives off the operator-repo root.
112
+ // Subpath import via `@stravica-ai/engineering-pa-core/src/desk/cli.mjs` is
113
+ // permitted by the widened `exports` map in the core package.
114
+ const out = opts.stdout ?? process.stdout;
115
+ const err = opts.stderr ?? process.stderr;
116
+ const cwd = opts.cwd ?? process.cwd();
117
+ const repoRoot = opts.repoRoot
118
+ ?? process.env.DAVE_REPO_ROOT
119
+ ?? process.env.PA_REPO_ROOT
120
+ ?? cwd;
121
+ const workspacePort = resolveWorkspacePort(repoRoot, opts);
122
+
123
+ let allOk = true;
124
+
125
+ // 1. Operator content probes.
126
+ out.write('Operator content:\n');
127
+ const operatorPaths = [
128
+ 'operator/',
129
+ 'operator/profile/profile.md',
130
+ 'agents/',
131
+ 'work/',
132
+ 'projects/',
133
+ ];
134
+ const operatorMissing = [];
135
+ for (const rel of operatorPaths) {
136
+ const present = existsSync(join(repoRoot, rel));
137
+ out.write(` ${rel.padEnd(36)} ${present ? 'present' : 'missing'}\n`);
138
+ if (!present) operatorMissing.push(rel);
139
+ }
140
+ // Treat absence of `operator/` itself as a structural failure — the other
141
+ // paths are recommended but not all are required on every operator repo
142
+ // (e.g. a brand-new scaffold may not yet have a profile.md).
143
+ if (operatorMissing.includes('operator/')) allOk = false;
144
+
145
+ // 2. Package install probe. Informational: a missing
146
+ // node_modules/@stravica-ai/digital-operator-pa is reported in the output so the
147
+ // operator can see it, but does not flip the exit code. Rationale: this
148
+ // verb is exercised against scenarios (CI fixtures, pre-install operator
149
+ // repos, pa-init dry-runs) where the package is intentionally absent.
150
+ // The pa-cli is sometimes invoked directly from the dev monorepo against
151
+ // an operator-shape repo before `pnpm install` has populated
152
+ // node_modules; treating that as a structural failure would block
153
+ // legitimate diagnostic use. Operator content remains the load-bearing
154
+ // exit-code probe (#1 above).
155
+ out.write('\nInstalled package:\n');
156
+ const pkgJson = join(repoRoot, 'node_modules', PA_PACKAGE_NAME, 'package.json');
157
+ if (existsSync(pkgJson)) {
158
+ try {
159
+ const meta = JSON.parse(readFileSync(pkgJson, 'utf8'));
160
+ out.write(` ${PA_PACKAGE_NAME} ${meta.version ?? '(no version)'}\n`);
161
+ } catch (e) {
162
+ out.write(` ${PA_PACKAGE_NAME} error reading package.json: ${e.message}\n`);
163
+ }
164
+ } else {
165
+ out.write(` ${PA_PACKAGE_NAME} missing (informational)\n`);
166
+ }
167
+
168
+ // 3. Workspace reachability probe.
169
+ out.write('\nWorkspace:\n');
170
+ const probeUrl = `http://localhost:${workspacePort}/__api/identity`;
171
+ const reachability = await probeWorkspace(probeUrl, opts.fetchImpl);
172
+ out.write(` ${probeUrl}\n`);
173
+ out.write(` status: ${reachability.status}`);
174
+ if (reachability.detail) out.write(` (${reachability.detail})`);
175
+ out.write('\n');
176
+ // Workspace-not-running is OK — operators may run pa status before
177
+ // starting the workspace server.
178
+
179
+ // 4. Desk overview snapshot.
180
+ out.write('\nOverview:\n');
181
+ try {
182
+ const code = await runDesk(['overview']);
183
+ if (typeof code === 'number' && code !== 0) {
184
+ // Desk reported a non-zero — propagate as operational failure.
185
+ return 2;
186
+ }
187
+ } catch (e) {
188
+ err.write(`[pa status] ${e?.message || e}\n`);
189
+ return 2;
190
+ }
191
+
192
+ return allOk ? 0 : 2;
193
+ }
194
+
195
+ function resolveWorkspacePort(repoRoot, opts = {}) {
196
+ if (opts.workspacePort) return opts.workspacePort;
197
+ try {
198
+ const prefsPath = join(repoRoot, 'operator', 'config', 'preferences.json');
199
+ if (existsSync(prefsPath)) {
200
+ const prefs = JSON.parse(readFileSync(prefsPath, 'utf8'));
201
+ if (typeof prefs.workspacePort === 'number') return prefs.workspacePort;
202
+ }
203
+ } catch { /* fall through to default */ }
204
+ return 4200;
205
+ }
206
+
207
+ async function probeWorkspace(url, fetchImpl) {
208
+ const fetchFn = fetchImpl ?? globalThis.fetch;
209
+ if (typeof fetchFn !== 'function') {
210
+ return { status: 'error', detail: 'fetch unavailable' };
211
+ }
212
+ const controller = new AbortController();
213
+ const timer = setTimeout(() => controller.abort(), 1500);
214
+ try {
215
+ const res = await fetchFn(url, { signal: controller.signal });
216
+ if (res.status >= 200 && res.status < 500) {
217
+ return { status: 'reachable', detail: `HTTP ${res.status}` };
218
+ }
219
+ return { status: 'error', detail: `HTTP ${res.status}` };
220
+ } catch (e) {
221
+ // ECONNREFUSED / abort / DNS — server is not running.
222
+ const code = e && (e.cause?.code || e.code);
223
+ if (code === 'ECONNREFUSED' || code === 'ENOTFOUND' || e?.name === 'AbortError') {
224
+ return { status: 'not running', detail: null };
225
+ }
226
+ return { status: 'error', detail: e?.message || String(e) };
227
+ } finally {
228
+ clearTimeout(timer);
229
+ }
230
+ }
231
+
232
+ export { doStatus, probeWorkspace, resolveWorkspacePort };
233
+
234
+ async function doLaunch(rest) {
235
+ const { run } = await import('../launch/cli.mjs');
236
+ return await run(rest);
237
+ }
238
+
239
+ async function doProject(rest) {
240
+ const { run } = await import('./project-cli.mjs');
241
+ return await run(rest);
242
+ }
243
+
244
+ async function doWork(rest) {
245
+ const { run } = await import('./work-cli.mjs');
246
+ return await run(rest);
247
+ }
248
+
249
+ async function doGsc(rest) {
250
+ const { run } = await import('../gsc/cli.mjs');
251
+ return await run(rest);
252
+ }
253
+
254
+ async function doLint(rest) {
255
+ const { main } = await import('../lint/cli.mjs');
256
+ return await main(rest);
257
+ }
258
+
259
+ async function doKnowledge(rest) {
260
+ const { run } = await import('../knowledge/cli.mjs');
261
+ return await run(rest);
262
+ }
263
+
264
+ async function doResearch(rest) {
265
+ const { main } = await import('../research/cli.mjs');
266
+ return await main(rest);
267
+ }
268
+
269
+ async function doAutonomy(rest) {
270
+ const { run } = await import('../autonomy/cli.mjs');
271
+ return await run(rest);
272
+ }
273
+
274
+ async function doEnvironment(rest) {
275
+ const { run } = await import('../environment/cli.mjs');
276
+ return await run(rest);
277
+ }
278
+
279
+ async function doStagingAlias(rest) {
280
+ const { main } = await import('../staging-alias/cli.mjs');
281
+ return await main(rest);
282
+ }
283
+
284
+ async function doSession(rest) {
285
+ // `pa session` takes no arguments today. Reject anything to make typos
286
+ // (`pa session help`, `pa session start`) surface fast rather than
287
+ // silently boot a Claude session.
288
+ if (rest.length > 0) {
289
+ if (rest[0] === '-h' || rest[0] === '--help') {
290
+ process.stdout.write(SESSION_USAGE);
291
+ return 0;
292
+ }
293
+ process.stderr.write(`[pa session] unexpected arguments: ${rest.join(' ')}\n`);
294
+ process.stderr.write(SESSION_USAGE);
295
+ return 1;
296
+ }
297
+ const { executeSession } = await import('./session.mjs');
298
+ return await executeSession();
299
+ }
300
+
301
+ const SESSION_USAGE = `pa session — start a PA session
302
+
303
+ Usage:
304
+ pa session Chdir to the agent dir for the configured PA and exec \`claude\`
305
+ pa session -h, --help Show this help
306
+
307
+ Resolution order for the operator repo root:
308
+ 1. \$DAVE_REPO_ROOT (if set)
309
+ 2. \$PA_REPO_ROOT (if set)
310
+ 3. Walk upward from CWD looking for a \`.git\` directory
311
+ 4. Fall back to CWD (with a warning)
312
+
313
+ Reads \`operator/config/preferences.json\`; the \`paName\` field selects
314
+ which \`agents/<paName>/\` directory the session runs in.
315
+
316
+ Exit codes (tooling standard §6):
317
+ 0 ok | 1 usage/config error | 2 operational failure
318
+ `;
319
+
320
+ const WORKSPACE_USAGE = `pa workspace — workspace server lifecycle
321
+
322
+ Usage:
323
+ pa workspace start [--port N] [--no-open] Start the workspace server
324
+ pa workspace stop Stop the running server (refuses if supervised)
325
+ pa workspace restart [--port N] [--no-open] Restart (supervisor-aware: launchctl kickstart / systemctl restart)
326
+ pa workspace status Show server status (supervisor-aware)
327
+ pa workspace open Open the workspace URL in a browser
328
+ pa workspace -h, --help Show this help
329
+
330
+ When the workspace is supervised by launchd (~/Library/LaunchAgents/com.dave.workspace.plist)
331
+ or systemd (~/.config/systemd/user/dave-workspace.service), \`stop\` is refused and \`restart\`
332
+ delegates to the supervisor — this is the in-place version-pickup path after \`pnpm update\`.
333
+
334
+ Exit codes (tooling standard §6):
335
+ 0 ok | 1 usage error | 2 operational failure | 3 transport/IO failure
336
+ `;
337
+
338
+ async function doWorkspace(rest) {
339
+ // Intercept --help / -h before routing — keeps the verb consistent with
340
+ // every other `pa` verb and avoids surfacing "Unknown command: --help"
341
+ // from the underlying ws.mjs.
342
+ if (rest.length > 0 && (rest[0] === '--help' || rest[0] === '-h' || rest[0] === 'help')) {
343
+ process.stdout.write(WORKSPACE_USAGE);
344
+ return 0;
345
+ }
346
+
347
+ // Defer to @stravica-ai/engineering-pa-workspace/src/ws.mjs by argv proxy.
348
+ // ws.mjs handles start/stop/status/open/restart.
349
+ try {
350
+ const wsPath = await import('../../../engineering-pa-workspace/src/ws.mjs');
351
+ // ws.mjs is currently a CLI script with its own main() — execute via
352
+ // argv when imported. The runtime emits an exit code that we propagate.
353
+ // Implementation detail: when imported (not executed) ws.mjs exposes a
354
+ // run() function in v2; here we just invoke its top-level for the
355
+ // common verbs.
356
+ if (typeof wsPath.run === 'function') {
357
+ return await wsPath.run(rest);
358
+ }
359
+ // Fallback: spawn ws.mjs as a child process.
360
+ const child = spawn(process.execPath, [
361
+ resolve(__dirname, '..', '..', '..', 'engineering-pa-workspace', 'src', 'ws.mjs'),
362
+ ...rest,
363
+ ], { stdio: 'inherit' });
364
+ return await new Promise((res) => child.on('close', (code) => res(code ?? 0)));
365
+ } catch (err) {
366
+ process.stderr.write(`[pa workspace] ${err.message || err}\n`);
367
+ return 2;
368
+ }
369
+ }
@@ -0,0 +1,164 @@
1
+ // doc-groups.mjs — schema migration + write helpers for project.json:docs.
2
+ //
3
+ // `docs` historically was a flat array of {label, path}. The new shape is
4
+ // an object keyed by group name; each value is an array of {label, path}.
5
+ //
6
+ // Legacy: "docs": [ { "label": "README", "path": "..." } ]
7
+ // New: "docs": { "Documents": [ { "label": "README", "path": "..." } ] }
8
+ //
9
+ // Backwards-compat is strict: a flat array means a single "Documents"
10
+ // group. The first write through `addDoc` migrates the project to the
11
+ // grouped shape; reads via `readGroups` work for both shapes.
12
+ //
13
+ // Group order is preserved as insertion order — JavaScript Map / plain
14
+ // object semantics are sufficient. "Documents" stays first when it exists.
15
+ //
16
+ // Doc entries may carry an optional `status` field:
17
+ // "draft" | "review" | "approved" | undefined
18
+ // The field is preserved through normalisation and addDoc; setDocStatus
19
+ // provides a dedicated write path.
20
+
21
+ export const DEFAULT_GROUP = 'Documents';
22
+
23
+ export const VALID_DOC_STATUSES = new Set(['draft', 'review', 'approved']);
24
+
25
+ /**
26
+ * Normalise a project's `docs` field into the new {group: entry[]} shape.
27
+ *
28
+ * - undefined / null → {}
29
+ * - flat array → { [DEFAULT_GROUP]: array }
30
+ * - object → returned as-is (defensive copy, arrays cloned)
31
+ *
32
+ * Defensive copy so callers can mutate without leaking back to the input.
33
+ */
34
+ export function normaliseDocs(docs) {
35
+ if (docs == null) return {};
36
+ if (Array.isArray(docs)) {
37
+ if (docs.length === 0) return {};
38
+ return { [DEFAULT_GROUP]: docs.map((d) => ({ ...d })) };
39
+ }
40
+ if (typeof docs === 'object') {
41
+ const out = {};
42
+ for (const [k, v] of Object.entries(docs)) {
43
+ if (!Array.isArray(v)) continue;
44
+ out[k] = v.map((d) => ({ ...d }));
45
+ }
46
+ return out;
47
+ }
48
+ return {};
49
+ }
50
+
51
+ /**
52
+ * True iff the project's docs field is already in the grouped shape
53
+ * (object of arrays). Empty objects count as grouped.
54
+ */
55
+ export function isGrouped(docs) {
56
+ return docs != null && !Array.isArray(docs) && typeof docs === 'object';
57
+ }
58
+
59
+ /**
60
+ * Add a doc entry to a group. Returns a new docs object — pure, does
61
+ * not mutate the input.
62
+ *
63
+ * - Migrates flat-array shape to grouped shape under DEFAULT_GROUP.
64
+ * - Creates the group if missing.
65
+ * - Idempotent: if {label, path} already exists in the target group,
66
+ * returns the input unchanged (still normalised to grouped shape).
67
+ */
68
+ export function addDoc(docs, group, entry) {
69
+ if (!entry || typeof entry !== 'object') {
70
+ throw new Error('addDoc: entry must be { label, path }');
71
+ }
72
+ if (!entry.label || !entry.path) {
73
+ throw new Error('addDoc: entry must have label and path');
74
+ }
75
+ const groupKey = group || DEFAULT_GROUP;
76
+ const next = normaliseDocs(docs);
77
+ const existing = next[groupKey] || [];
78
+ const dup = existing.find((d) => d.path === entry.path && d.label === entry.label);
79
+ if (dup) {
80
+ // Already present — return the normalised-but-unchanged shape so
81
+ // callers writing it back still benefit from the migration even on
82
+ // a no-op add.
83
+ next[groupKey] = existing;
84
+ return next;
85
+ }
86
+ const newEntry = { label: entry.label, path: entry.path };
87
+ if (entry.status) newEntry.status = entry.status;
88
+ next[groupKey] = [...existing, newEntry];
89
+ return next;
90
+ }
91
+
92
+ /**
93
+ * Remove all entries with `path` from every group. Returns:
94
+ * { docs: <new docs>, removed: <number> }
95
+ *
96
+ * Empty groups are dropped so the project doesn't accumulate dead
97
+ * headings.
98
+ */
99
+ export function removeDocByPath(docs, path) {
100
+ const next = normaliseDocs(docs);
101
+ let removed = 0;
102
+ for (const [group, entries] of Object.entries(next)) {
103
+ const kept = entries.filter((d) => {
104
+ if (d.path === path) {
105
+ removed += 1;
106
+ return false;
107
+ }
108
+ return true;
109
+ });
110
+ if (kept.length === 0) {
111
+ delete next[group];
112
+ } else {
113
+ next[group] = kept;
114
+ }
115
+ }
116
+ return { docs: next, removed };
117
+ }
118
+
119
+ /**
120
+ * Iterate groups in display order. Returns [{group, entries}] with
121
+ * DEFAULT_GROUP first (if present), then the rest in insertion order.
122
+ */
123
+ export function listGroups(docs) {
124
+ const normalised = normaliseDocs(docs);
125
+ const keys = Object.keys(normalised);
126
+ const ordered = [];
127
+ if (Object.prototype.hasOwnProperty.call(normalised, DEFAULT_GROUP)) {
128
+ ordered.push(DEFAULT_GROUP);
129
+ }
130
+ for (const k of keys) {
131
+ if (k !== DEFAULT_GROUP) ordered.push(k);
132
+ }
133
+ return ordered.map((g) => ({ group: g, entries: normalised[g] }));
134
+ }
135
+
136
+ /**
137
+ * Set or remove the status field on doc entries matching `path`.
138
+ *
139
+ * - `status` must be one of VALID_DOC_STATUSES, or falsy to remove.
140
+ * - Searches across all groups.
141
+ * - Returns { docs, matched } where matched is the count of entries updated.
142
+ */
143
+ export function setDocStatus(docs, path, status) {
144
+ if (status && !VALID_DOC_STATUSES.has(status)) {
145
+ throw new Error(
146
+ `invalid doc status: ${status} (expected one of: ${[...VALID_DOC_STATUSES].join(', ')})`,
147
+ );
148
+ }
149
+ const next = normaliseDocs(docs);
150
+ let matched = 0;
151
+ for (const entries of Object.values(next)) {
152
+ for (const entry of entries) {
153
+ if (entry.path === path) {
154
+ if (status) {
155
+ entry.status = status;
156
+ } else {
157
+ delete entry.status;
158
+ }
159
+ matched += 1;
160
+ }
161
+ }
162
+ }
163
+ return { docs: next, matched };
164
+ }
@@ -0,0 +1,80 @@
1
+ // io.mjs — shared JSON read/write helpers for the pa write-side CLIs.
2
+ //
3
+ // The operator-repo convention is 2-space-indented JSON with a trailing
4
+ // newline. We always honour that on write so diffs stay clean.
5
+ //
6
+ // Read helpers are intentionally thin — node:fs/promises already throws
7
+ // sensible errors for ENOENT/EACCES; callers translate to exit codes.
8
+
9
+ import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';
10
+ import { dirname, join } from 'node:path';
11
+
12
+ export async function readJson(path) {
13
+ const raw = await readFile(path, 'utf8');
14
+ return JSON.parse(raw);
15
+ }
16
+
17
+ /**
18
+ * Write a JSON file with the operator-repo convention: 2-space indent and a
19
+ * trailing newline. Creates parent directories if needed.
20
+ */
21
+ export async function writeJson(path, value) {
22
+ await mkdir(dirname(path), { recursive: true });
23
+ const body = JSON.stringify(value, null, 2) + '\n';
24
+ await writeFile(path, body, 'utf8');
25
+ }
26
+
27
+ /**
28
+ * Ensure a directory exists. Returns the absolute path.
29
+ */
30
+ export async function ensureDir(path) {
31
+ await mkdir(path, { recursive: true });
32
+ return path;
33
+ }
34
+
35
+ /**
36
+ * List the directories inside `dir`. Returns an empty array if `dir`
37
+ * does not exist; throws on other errors.
38
+ */
39
+ export async function listSubdirs(dir) {
40
+ let entries;
41
+ try {
42
+ entries = await readdir(dir, { withFileTypes: true });
43
+ } catch (err) {
44
+ if (err.code === 'ENOENT') return [];
45
+ throw err;
46
+ }
47
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
48
+ }
49
+
50
+ /**
51
+ * List the .json files in `dir`. Returns an empty array if `dir`
52
+ * does not exist; throws on other errors.
53
+ */
54
+ export async function listJsonFiles(dir) {
55
+ let entries;
56
+ try {
57
+ entries = await readdir(dir, { withFileTypes: true });
58
+ } catch (err) {
59
+ if (err.code === 'ENOENT') return [];
60
+ throw err;
61
+ }
62
+ return entries
63
+ .filter((e) => e.isFile() && e.name.endsWith('.json'))
64
+ .map((e) => e.name);
65
+ }
66
+
67
+ /**
68
+ * Build an absolute path inside the repo. Convenience wrapper for callers
69
+ * that already have the repo root resolved.
70
+ */
71
+ export function repoPath(repoRoot, ...parts) {
72
+ return join(repoRoot, ...parts);
73
+ }
74
+
75
+ /**
76
+ * Today's date in YYYY-MM-DD (UTC).
77
+ */
78
+ export function today() {
79
+ return new Date().toISOString().slice(0, 10);
80
+ }