@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,633 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ws.mjs — Workspace server CLI
5
+ *
6
+ * Manages the workspace dev server (server.mjs) as a background process.
7
+ *
8
+ * Usage:
9
+ * node ws.mjs start [--port N] [--no-open] Start server as background daemon
10
+ * node ws.mjs stop Stop the running server
11
+ * node ws.mjs restart [--port N] [--no-open] Stop then start
12
+ * node ws.mjs status Show server status
13
+ * node ws.mjs open Open browser to server URL
14
+ */
15
+
16
+ import { spawn, execSync } from 'node:child_process';
17
+ import { readFileSync, writeFileSync, unlinkSync, existsSync, statSync, realpathSync } from 'node:fs';
18
+ import { createConnection } from 'node:net';
19
+ import { join, resolve, dirname } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+ import { platform } from 'node:os';
22
+ import { get } from 'node:http';
23
+ import {
24
+ detectSupervisor,
25
+ readSupervisorState,
26
+ findPortListener,
27
+ restartCommand,
28
+ } from './supervisor.mjs';
29
+
30
+ const __filename = fileURLToPath(import.meta.url);
31
+ const __dirname = dirname(__filename);
32
+ const REPO_ROOT = resolve(__dirname, '..', '..', '..');
33
+
34
+ const SERVER_SCRIPT = join(__dirname, 'server.mjs');
35
+ // Env overrides let tests point at a temp directory so the real repo's
36
+ // .ws.pid / .ws.log are never written to during the subprocess test runs.
37
+ const PID_FILE = process.env.WS_PID_FILE || join(REPO_ROOT, '.ws.pid');
38
+ const LOG_FILE = process.env.WS_LOG_FILE || join(REPO_ROOT, '.ws.log');
39
+ const PREFS_FILE = join(REPO_ROOT, 'operator', 'config', 'preferences.json');
40
+
41
+ // Test-only override: lets e2e tests assert cross-platform parity by forcing
42
+ // the supervisor probe to behave as if it were running on a different OS.
43
+ // Honours the same dependency-injection contract as detectSupervisor's
44
+ // `platform` argument — when set, it is the *only* value the CLI passes
45
+ // through, so the production code path (no env var) remains untouched.
46
+ const PLATFORM_OVERRIDE = process.env.WORKSPACE_SUPERVISOR_PLATFORM_OVERRIDE || undefined;
47
+
48
+ // Single-call helper so the override env var is honoured everywhere the
49
+ // CLI asks "which supervisor manages this host?". Tests set the env var
50
+ // when spawning the ws.mjs subprocess; production callers pass nothing and
51
+ // detectSupervisor falls back to os.platform().
52
+ function getSupervisor() {
53
+ return detectSupervisor(PLATFORM_OVERRIDE ? { platform: PLATFORM_OVERRIDE } : undefined);
54
+ }
55
+
56
+ // --- Arg parsing ---
57
+
58
+ const args = process.argv.slice(2);
59
+ const command = args[0];
60
+ const flags = args.slice(1);
61
+
62
+ function getFlag(name) {
63
+ const idx = flags.indexOf(name);
64
+ if (idx === -1) return undefined;
65
+ return flags[idx + 1];
66
+ }
67
+
68
+ function hasFlag(name) {
69
+ return flags.includes(name);
70
+ }
71
+
72
+ // --- Port resolution ---
73
+
74
+ function resolvePort() {
75
+ // 1. Default
76
+ let port = 4200;
77
+
78
+ // 2. Preferences override
79
+ try {
80
+ const prefs = JSON.parse(readFileSync(PREFS_FILE, 'utf-8'));
81
+ if (prefs.workspacePort) port = prefs.workspacePort;
82
+ } catch { /* no prefs — use default */ }
83
+
84
+ // 3. CLI flag override
85
+ const flagPort = getFlag('--port');
86
+ if (flagPort) {
87
+ const parsed = parseInt(flagPort, 10);
88
+ if (isNaN(parsed) || parsed < 1 || parsed > 65535) {
89
+ console.error(`Error: Invalid port "${flagPort}". Must be 1-65535.`);
90
+ process.exit(1);
91
+ }
92
+ port = parsed;
93
+ }
94
+
95
+ return port;
96
+ }
97
+
98
+ // --- PID file helpers ---
99
+
100
+ function readPid() {
101
+ try {
102
+ const raw = JSON.parse(readFileSync(PID_FILE, 'utf-8'));
103
+ return { pid: raw.pid, port: raw.port };
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ function writePid(pid, port) {
110
+ writeFileSync(PID_FILE, JSON.stringify({ pid, port }, null, 2) + '\n');
111
+ }
112
+
113
+ function removePid() {
114
+ try { unlinkSync(PID_FILE); } catch { /* already gone */ }
115
+ }
116
+
117
+ // --- Process checks ---
118
+
119
+ function isProcessAlive(pid) {
120
+ try {
121
+ process.kill(pid, 0);
122
+ return true;
123
+ } catch {
124
+ return false;
125
+ }
126
+ }
127
+
128
+ function checkPort(port, timeoutMs = 1000) {
129
+ return new Promise((resolve) => {
130
+ const sock = createConnection({ host: '127.0.0.1', port }, () => {
131
+ sock.destroy();
132
+ resolve(true);
133
+ });
134
+ sock.on('error', () => resolve(false));
135
+ sock.setTimeout(timeoutMs, () => {
136
+ sock.destroy();
137
+ resolve(false);
138
+ });
139
+ });
140
+ }
141
+
142
+ // Best-effort: identify the PID currently listening on a port. Returns
143
+ // { pid, command } or null if the information is unavailable (unsupported
144
+ // platform, no listener, or the probe fails). Used for diagnostic output
145
+ // when a stale pidfile collides with an unrelated port holder.
146
+ function findPortHolder(port) {
147
+ try {
148
+ if (platform() === 'win32') {
149
+ const raw = execSync(`netstat -ano -p tcp | findstr :${port}`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
150
+ const line = raw.split(/\r?\n/).find((l) => l.includes('LISTENING'));
151
+ if (!line) return null;
152
+ const parts = line.trim().split(/\s+/);
153
+ const pid = parseInt(parts[parts.length - 1], 10);
154
+ if (!pid || Number.isNaN(pid)) return null;
155
+ return { pid, command: null };
156
+ }
157
+ const raw = execSync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -Fpc`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
158
+ const lines = raw.split(/\r?\n/).filter(Boolean);
159
+ let pid = null; let command = null;
160
+ for (const l of lines) {
161
+ if (l.startsWith('p')) pid = parseInt(l.slice(1), 10);
162
+ else if (l.startsWith('c')) command = l.slice(1);
163
+ }
164
+ if (!pid || Number.isNaN(pid)) return null;
165
+ return { pid, command };
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+
171
+ function httpCheck(port, timeoutMs = 2000) {
172
+ return new Promise((resolve) => {
173
+ const req = get(`http://127.0.0.1:${port}/`, { timeout: timeoutMs }, (res) => {
174
+ res.resume();
175
+ resolve(res.statusCode);
176
+ });
177
+ req.on('error', () => resolve(null));
178
+ req.on('timeout', () => { req.destroy(); resolve(null); });
179
+ });
180
+ }
181
+
182
+ // --- Wait for port to become available ---
183
+
184
+ function waitForPort(port, maxMs = 3000) {
185
+ const start = Date.now();
186
+ return new Promise((resolve) => {
187
+ const check = async () => {
188
+ if (await checkPort(port)) return resolve(true);
189
+ if (Date.now() - start > maxMs) return resolve(false);
190
+ setTimeout(check, 200);
191
+ };
192
+ check();
193
+ });
194
+ }
195
+
196
+ // --- Kill process ---
197
+
198
+ async function killProcess(pid) {
199
+ const isWindows = platform() === 'win32';
200
+
201
+ if (!isProcessAlive(pid)) return true;
202
+
203
+ // Graceful shutdown
204
+ if (isWindows) {
205
+ try { execSync(`taskkill /PID ${pid}`, { stdio: 'ignore' }); } catch { /* ignore */ }
206
+ } else {
207
+ try { process.kill(pid, 'SIGTERM'); } catch { /* ignore */ }
208
+ }
209
+
210
+ // Wait up to 5s for graceful exit
211
+ const start = Date.now();
212
+ while (Date.now() - start < 5000) {
213
+ if (!isProcessAlive(pid)) return true;
214
+ await new Promise(r => setTimeout(r, 200));
215
+ }
216
+
217
+ // Force kill
218
+ if (isProcessAlive(pid)) {
219
+ if (isWindows) {
220
+ try { execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' }); } catch { /* ignore */ }
221
+ } else {
222
+ try { process.kill(pid, 'SIGKILL'); } catch { /* ignore */ }
223
+ }
224
+ // Brief wait for force kill
225
+ await new Promise(r => setTimeout(r, 500));
226
+ }
227
+
228
+ return !isProcessAlive(pid);
229
+ }
230
+
231
+ // --- Open browser ---
232
+
233
+ function openBrowser(url) {
234
+ const plat = platform();
235
+ try {
236
+ if (plat === 'darwin') {
237
+ execSync(`open "${url}"`);
238
+ } else if (plat === 'win32') {
239
+ execSync(`start "" "${url}"`);
240
+ } else {
241
+ execSync(`xdg-open "${url}"`);
242
+ }
243
+ } catch {
244
+ console.error('Could not open browser automatically. Visit: ' + url);
245
+ }
246
+ }
247
+
248
+ // --- Uptime formatting ---
249
+
250
+ function formatUptime(ms) {
251
+ const s = Math.floor(ms / 1000);
252
+ if (s < 60) return `${s}s`;
253
+ const m = Math.floor(s / 60);
254
+ if (m < 60) return `${m}m ${s % 60}s`;
255
+ const h = Math.floor(m / 60);
256
+ return `${h}h ${m % 60}m`;
257
+ }
258
+
259
+ // --- Commands ---
260
+
261
+ async function cmdStart() {
262
+ const port = resolvePort();
263
+ const noOpen = hasFlag('--no-open');
264
+
265
+ // Supervisor-aware short-circuit. When launchd / systemd is managing the
266
+ // workspace, ws.mjs MUST NOT spawn a competing process — KeepAlive /
267
+ // Restart=always would otherwise hand the port back to the supervised
268
+ // instance and ours would lose the bind race. Friendly exit-0 if the
269
+ // supervised process is up; helpful message if it's not, telling the
270
+ // operator how to bounce it.
271
+ const supervisor = getSupervisor();
272
+ if (supervisor.kind) {
273
+ const sup = readSupervisorState(supervisor);
274
+ if (sup.state === 'running' && sup.pid) {
275
+ const url = `http://127.0.0.1:${port}`;
276
+ console.log(`Workspace server already running (supervised by ${supervisor.kind}, PID ${sup.pid}).`);
277
+ console.log(` ${url}`);
278
+ if (!noOpen) openBrowser(url);
279
+ process.exit(0);
280
+ }
281
+ // Supervisor configured but not currently running. Don't spawn a
282
+ // detached one — that would race the supervisor's next relaunch.
283
+ // Tell the operator how to bring it up via the supervisor.
284
+ const restartCmd = restartCommand(supervisor);
285
+ console.error(`Error: Workspace is ${supervisor.kind}-managed at ${supervisor.unitPath} but is not currently running.`);
286
+ if (restartCmd) console.error(` Bring it up with: ${restartCmd}`);
287
+ if (supervisor.kind === 'launchd') {
288
+ console.error(` Or reload the plist: launchctl load -w ${supervisor.unitPath}`);
289
+ } else if (supervisor.kind === 'systemd') {
290
+ console.error(` Or start the unit: systemctl --user start ${supervisor.label}`);
291
+ }
292
+ process.exit(2);
293
+ }
294
+
295
+ // Check if already running
296
+ const existing = readPid();
297
+ if (existing && isProcessAlive(existing.pid)) {
298
+ const portUp = await checkPort(existing.port);
299
+ if (portUp) {
300
+ console.log(`Workspace server already running (PID ${existing.pid}, port ${existing.port}).`);
301
+ console.log(` http://127.0.0.1:${existing.port}`);
302
+ process.exit(0);
303
+ }
304
+ // Process alive but port not listening — stale state, clean up
305
+ await killProcess(existing.pid);
306
+ removePid();
307
+ } else if (existing) {
308
+ // PID file exists but process is dead. Before deleting the pidfile, check
309
+ // whether the port it claims is actually held by something unrelated — if
310
+ // so, surface a diagnostic and stop. We MUST NOT kill an unrelated holder.
311
+ if (existing.port && await checkPort(existing.port)) {
312
+ const holder = findPortHolder(existing.port);
313
+ const who = holder ? ` (held by PID ${holder.pid}${holder.command ? ` — ${holder.command}` : ''})` : '';
314
+ console.error(`Error: Stale PID file references dead PID ${existing.pid}, but port ${existing.port} is in use${who}.`);
315
+ console.error('Refusing to kill an unrelated process. Remove the PID file manually or use a different port.');
316
+ process.exit(1);
317
+ }
318
+ removePid();
319
+ }
320
+
321
+ // Check if port is already in use by something else
322
+ if (await checkPort(port)) {
323
+ console.error(`Error: Port ${port} is already in use by another process.`);
324
+ process.exit(1);
325
+ }
326
+
327
+ // Build spawn args
328
+ const serverArgs = ['--no-timeout'];
329
+ serverArgs.push('--port', String(port));
330
+ serverArgs.push('--no-open'); // CLI handles browser open, not server
331
+
332
+ // Open log file for stdout/stderr
333
+ const { openSync, close } = await import('node:fs');
334
+ const logFd = openSync(LOG_FILE, 'w');
335
+
336
+ // Spawn detached
337
+ const child = spawn(process.execPath, [SERVER_SCRIPT, ...serverArgs], {
338
+ detached: true,
339
+ stdio: ['ignore', logFd, logFd],
340
+ cwd: REPO_ROOT,
341
+ });
342
+
343
+ child.unref();
344
+ close(logFd);
345
+
346
+ const pid = child.pid;
347
+ writePid(pid, port);
348
+
349
+ // Wait for the port to come up
350
+ const ready = await waitForPort(port, 3000);
351
+
352
+ if (!ready) {
353
+ // Check if process died (e.g. port conflict detected by server itself)
354
+ if (!isProcessAlive(pid)) {
355
+ removePid();
356
+ // Try to read log for clues
357
+ try {
358
+ const log = readFileSync(LOG_FILE, 'utf-8').trim();
359
+ if (log) console.error('Server output:\n' + log);
360
+ } catch { /* ignore */ }
361
+ console.error('Error: Server failed to start. Check .ws.log for details.');
362
+ process.exit(1);
363
+ }
364
+ console.warn('Warning: Server started but port not yet responding. It may still be initialising.');
365
+ }
366
+
367
+ const url = `http://127.0.0.1:${port}`;
368
+ console.log(`Workspace server started (PID ${pid}).`);
369
+ console.log(` ${url}`);
370
+ console.log(` Log: ${LOG_FILE}`);
371
+
372
+ if (!noOpen) {
373
+ openBrowser(url);
374
+ }
375
+ }
376
+
377
+ async function cmdStop() {
378
+ // Supervisor-aware refusal. Killing a supervised process triggers an
379
+ // instant relaunch via KeepAlive / Restart=always — `stop` is a no-op at
380
+ // best and a confusing port-conflict at worst. Refuse and point the
381
+ // operator at the right tool.
382
+ const supervisor = getSupervisor();
383
+ if (supervisor.kind) {
384
+ console.error(`Error: Workspace is ${supervisor.kind}-managed at ${supervisor.unitPath}.`);
385
+ if (supervisor.kind === 'launchd') {
386
+ console.error(` To stop it: launchctl unload -w ${supervisor.unitPath}`);
387
+ } else {
388
+ console.error(` To stop it: systemctl --user stop ${supervisor.label}`);
389
+ }
390
+ console.error(' To bounce it for in-place version pickup: ws.mjs restart');
391
+ process.exit(1);
392
+ }
393
+
394
+ const existing = readPid();
395
+ if (!existing) {
396
+ console.log('Workspace server is not running (no PID file).');
397
+ process.exit(0);
398
+ }
399
+
400
+ if (!isProcessAlive(existing.pid)) {
401
+ console.log('Workspace server is not running (PID ' + existing.pid + ' is dead). Cleaning up.');
402
+ removePid();
403
+ process.exit(0);
404
+ }
405
+
406
+ console.log(`Stopping workspace server (PID ${existing.pid})...`);
407
+ const killed = await killProcess(existing.pid);
408
+ removePid();
409
+
410
+ if (killed) {
411
+ console.log('Server stopped.');
412
+ } else {
413
+ console.error('Warning: Could not confirm process termination. PID file cleaned up.');
414
+ }
415
+ }
416
+
417
+ async function cmdRestart() {
418
+ // Supervisor-aware restart. Under launchd / systemd we ask the supervisor
419
+ // to bounce the service — `launchctl kickstart -k` and
420
+ // `systemctl --user restart` are both KeepAlive-safe and idempotent.
421
+ // Under no supervisor we fall back to the legacy stop-then-start dance.
422
+ const supervisor = getSupervisor();
423
+ if (supervisor.kind) {
424
+ const cmd = restartCommand(supervisor);
425
+ if (!cmd) {
426
+ console.error(`Error: Could not build restart command for ${supervisor.kind}.`);
427
+ process.exit(2);
428
+ }
429
+ try {
430
+ execSync(cmd, { stdio: ['ignore', 'pipe', 'pipe'] });
431
+ } catch (err) {
432
+ console.error(`Error: Supervisor restart failed: ${err.message || err}`);
433
+ process.exit(3);
434
+ }
435
+ // Re-read state so we can report the new PID.
436
+ const sup = readSupervisorState(supervisor);
437
+ if (sup.pid) {
438
+ console.log(`Workspace server restarted (supervised by ${supervisor.kind}, PID ${sup.pid}).`);
439
+ } else {
440
+ // launchctl kickstart -k can return before the new PID is published.
441
+ console.log(`Workspace server restart requested (supervised by ${supervisor.kind}).`);
442
+ }
443
+ const port = resolvePort();
444
+ console.log(` http://127.0.0.1:${port}`);
445
+ return;
446
+ }
447
+ await cmdStop();
448
+ await cmdStart();
449
+ }
450
+
451
+ async function cmdStatus() {
452
+ const supervisor = getSupervisor();
453
+
454
+ // Supervisor-aware status. When a unit file is installed, the supervisor
455
+ // is the source of truth — the legacy pidfile is only written when ws.mjs
456
+ // itself spawned the server, so a supervised process is invisible to the
457
+ // pidfile-only check (bug 1 of 2 in this PR).
458
+ if (supervisor.kind) {
459
+ const port = resolvePort();
460
+ const sup = readSupervisorState(supervisor);
461
+ const listener = findPortListener(port);
462
+ const portUp = await checkPort(port);
463
+ const httpStatus = portUp ? await httpCheck(port) : null;
464
+
465
+ const running = sup.state === 'running' || portUp;
466
+ console.log(`Status: ${running ? 'running' : (sup.state === 'loaded' ? 'loaded (not running)' : 'stopped')} (supervised by ${supervisor.kind})`);
467
+ console.log(` Supervisor: ${supervisor.kind} — ${supervisor.unitPath}`);
468
+ console.log(` State: ${sup.state}`);
469
+ if (sup.pid) console.log(` PID: ${sup.pid}`);
470
+ console.log(` Port: ${port}`);
471
+ if (listener) {
472
+ const cmdName = listener.command ? ` (${listener.command})` : '';
473
+ console.log(` Listener: PID ${listener.pid}${cmdName}`);
474
+ if (sup.pid && listener.pid !== sup.pid) {
475
+ console.log(' Warning: port listener PID differs from supervised PID — another process is on this port.');
476
+ }
477
+ } else if (portUp) {
478
+ console.log(' Listener: port held (lsof/ss unavailable to identify PID)');
479
+ } else {
480
+ console.log(' Listener: none');
481
+ }
482
+ console.log(` URL: http://127.0.0.1:${port}`);
483
+ if (portUp && httpStatus !== null) {
484
+ console.log(` Health: OK (HTTP ${httpStatus})`);
485
+ } else if (portUp) {
486
+ console.log(' Health: port open, HTTP check failed');
487
+ } else {
488
+ console.log(' Health: port not responding');
489
+ }
490
+ process.exit(running ? 0 : 2);
491
+ }
492
+
493
+ // Legacy pidfile-managed status (no supervisor installed).
494
+ const existing = readPid();
495
+
496
+ if (!existing) {
497
+ console.log('Status: stopped');
498
+ console.log(' No PID file found.');
499
+ process.exit(0);
500
+ }
501
+
502
+ const alive = isProcessAlive(existing.pid);
503
+ if (!alive) {
504
+ console.log('Status: stopped (stale PID file)');
505
+ console.log(` PID ${existing.pid} is no longer running.`);
506
+ removePid();
507
+ process.exit(0);
508
+ }
509
+
510
+ // Uptime from PID file mtime
511
+ let uptime = '';
512
+ try {
513
+ const pidStat = statSync(PID_FILE);
514
+ const ms = Date.now() - pidStat.mtimeMs;
515
+ uptime = formatUptime(ms);
516
+ } catch { /* ignore */ }
517
+
518
+ const portUp = await checkPort(existing.port);
519
+ let httpStatus = null;
520
+ if (portUp) {
521
+ httpStatus = await httpCheck(existing.port);
522
+ }
523
+
524
+ console.log('Status: running');
525
+ console.log(` PID: ${existing.pid}`);
526
+ console.log(` Port: ${existing.port}`);
527
+ if (uptime) console.log(` Uptime: ${uptime}`);
528
+ console.log(` URL: http://127.0.0.1:${existing.port}`);
529
+ if (portUp && httpStatus !== null) {
530
+ console.log(` Health: OK (HTTP ${httpStatus})`);
531
+ } else if (portUp) {
532
+ console.log(' Health: port open, HTTP check failed');
533
+ } else {
534
+ console.log(' Health: port not responding');
535
+ }
536
+ }
537
+
538
+ async function cmdOpen() {
539
+ // Supervisor-aware open. Under launchd/systemd there is no pidfile, so
540
+ // we resolve the port via the standard preference chain and probe the
541
+ // socket directly.
542
+ const supervisor = getSupervisor();
543
+ if (supervisor.kind) {
544
+ const port = resolvePort();
545
+ const portUp = await checkPort(port);
546
+ if (!portUp) {
547
+ console.error(`Error: Workspace is ${supervisor.kind}-managed but port ${port} is not responding.`);
548
+ const cmd = restartCommand(supervisor);
549
+ if (cmd) console.error(` Try: ${cmd}`);
550
+ process.exit(2);
551
+ }
552
+ const url = `http://127.0.0.1:${port}`;
553
+ console.log('Opening ' + url);
554
+ openBrowser(url);
555
+ return;
556
+ }
557
+
558
+ const existing = readPid();
559
+
560
+ if (!existing || !isProcessAlive(existing.pid)) {
561
+ console.error('Error: Workspace server is not running. Start it first: node ws.mjs start');
562
+ process.exit(1);
563
+ }
564
+
565
+ const portUp = await checkPort(existing.port);
566
+ if (!portUp) {
567
+ console.error('Error: Server process exists but port ' + existing.port + ' is not responding.');
568
+ process.exit(1);
569
+ }
570
+
571
+ const url = `http://127.0.0.1:${existing.port}`;
572
+ console.log('Opening ' + url);
573
+ openBrowser(url);
574
+ }
575
+
576
+ // --- Exports for tests ---
577
+ // Helpers are exported so test.mjs can exercise them without shelling out.
578
+ // Importing this module must not trigger CLI dispatch — the entrypoint guard
579
+ // below ensures the switch only runs when ws.mjs is invoked directly.
580
+ export { isProcessAlive, checkPort, findPortHolder };
581
+
582
+ // --- Main ---
583
+
584
+ const USAGE = `Usage: node ws.mjs <command> [options]
585
+
586
+ Commands:
587
+ start [--port N] [--no-open] Start workspace server
588
+ stop Stop workspace server
589
+ restart [--port N] [--no-open] Restart workspace server
590
+ status Show server status
591
+ open Open browser to server URL`;
592
+
593
+ // Only dispatch the CLI when this file is the entrypoint. When imported as a
594
+ // module (e.g. by tests that pull in exported helpers), skip the switch so
595
+ // the importing process is not terminated by the default-case process.exit.
596
+ //
597
+ // ISMAIN-AUDIT (bug-3 sweep): the previous check compared import.meta.url
598
+ // (always realpath-resolved by Node) against `pathToFileURL(argv[1])`
599
+ // with NO symlink resolution on the argv[1] side — same class of
600
+ // fragility as the endsWith idiom fixed in the scheduler. It also threw
601
+ // outright if argv[1] was undefined. `pa workspace <verb>`'s fallback
602
+ // path spawns this file via an explicit absolute path (not a pnpm .bin
603
+ // symlink), so this has not been proven to misfire in production, but is
604
+ // fixed defensively to the same realpath-both-sides pattern used
605
+ // elsewhere (and already correct in server.mjs / install-daemon.mjs in
606
+ // this same package).
607
+ function isDirectlyInvoked() {
608
+ if (!process.argv[1]) return false;
609
+ try {
610
+ return fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
611
+ } catch {
612
+ return false;
613
+ }
614
+ }
615
+
616
+ if (isDirectlyInvoked()) {
617
+ switch (command) {
618
+ case 'start': await cmdStart(); break;
619
+ case 'stop': await cmdStop(); break;
620
+ case 'restart': await cmdRestart(); break;
621
+ case 'status': await cmdStatus(); break;
622
+ case 'open': await cmdOpen(); break;
623
+ case '--help':
624
+ case '-h':
625
+ case 'help':
626
+ console.log(USAGE);
627
+ process.exit(0);
628
+ default:
629
+ if (command) console.error(`Unknown command: ${command}\n`);
630
+ console.log(USAGE);
631
+ process.exit(command ? 1 : 0);
632
+ }
633
+ }
package/index.mjs ADDED
@@ -0,0 +1,60 @@
1
+ // @stravica-ai/digital-operator-pa — public package surface.
2
+ //
3
+ // Single-bundled wrapper for the engineering-pa platform (approach A2 — see
4
+ // ./README.md and build.mjs). The wrapper ships ONE tarball that contains
5
+ // the wrapper code plus a `dist/` tree of the internal workspace packages
6
+ // with `@stravica-ai/engineering-pa-*` imports rewritten to relative paths.
7
+ //
8
+ // Operators install one package, pin one version. Internals stay
9
+ // `private: true` in the monorepo and are not individually publishable.
10
+
11
+ export const name = '@stravica-ai/digital-operator-pa';
12
+ export const version = '0.1.1';
13
+
14
+ // Bin entry points exposed by the wrapper (mirrors package.json#bin).
15
+ // Programmatic consumers normally spawn the bins; this list is for
16
+ // introspection / scaffolders.
17
+ export const bins = [
18
+ 'pa',
19
+ 'desk',
20
+ 'launch',
21
+ 'sync',
22
+ 'secrets',
23
+ 'scheduler',
24
+ 'smoke',
25
+ 'distill',
26
+ 'memory-sync',
27
+ 'migrate-inspect',
28
+ 'pa-init',
29
+ 'slice',
30
+ 'research',
31
+ 'pa-coordinator-hook',
32
+ ];
33
+
34
+ // Bundled internal packages (mirrors build.mjs PACKAGES catalog).
35
+ // Useful for debugging install layouts.
36
+ export const bundled = [
37
+ '@stravica-ai/engineering-pa-core',
38
+ '@stravica-ai/engineering-pa-runbook',
39
+ '@stravica-ai/engineering-pa-cli',
40
+ '@stravica-ai/engineering-pa-migrate-inspect',
41
+ '@stravica-ai/engineering-pa-workspace',
42
+ '@stravica-ai/engineering-pa-scaffold',
43
+ '@stravica-ai/engineering-pa-librarian',
44
+ '@stravica-ai/engineering-pa-types-engineering',
45
+ '@stravica-ai/engineering-pa-core-extensions-atlassian',
46
+ '@stravica-ai/engineering-pa-core-extensions-n8n',
47
+ ];
48
+
49
+ /**
50
+ * Returns a metadata snapshot describing this installed wrapper. Useful for
51
+ * `pa status` and operator-side install verification.
52
+ */
53
+ export function describe() {
54
+ return {
55
+ name,
56
+ version,
57
+ bins,
58
+ bundled,
59
+ };
60
+ }