@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,516 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Dave Workspace -- persistent dev server.
5
+ *
6
+ * Serves the dave repo as static HTML pages plus a JSON API.
7
+ * Auto-shuts down after 2 hours of idle time.
8
+ *
9
+ * Live-reload / SSE was removed pending a workspace rebuild — see PR
10
+ * "Remove live-reload SSE mechanism (temporary — pending workspace rebuild)".
11
+ * Manual browser refresh (Cmd+R / Ctrl+R) is the current model.
12
+ *
13
+ * Usage:
14
+ * node server.mjs Start on default port (4200)
15
+ * node server.mjs --port 5555 Use specific port
16
+ * node server.mjs --no-open Don't auto-open browser
17
+ * node server.mjs --timeout 60 Idle timeout in minutes (default: 120)
18
+ * node server.mjs --no-timeout Disable idle timeout
19
+ */
20
+
21
+ import { createServer } from 'node:http';
22
+ import { readFile, stat, readdir } from 'node:fs/promises';
23
+ import { readFileSync, existsSync, realpathSync } from 'node:fs';
24
+ import { execSync } from 'node:child_process';
25
+ import { resolve, join, extname } from 'node:path';
26
+ import { fileURLToPath } from 'node:url';
27
+ import { handleApi } from './api.mjs';
28
+ import { loadNav } from './nav.mjs';
29
+ import { startPoller as startStatusMonPoller } from './status-mon/poller.mjs';
30
+
31
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
32
+
33
+ // In v2 the workspace package is installed inside the operator repo at
34
+ // `node_modules/@stravica-ai/engineering-pa-workspace/`. The operator repo root
35
+ // is wherever `.git` lives — discovered by walking up from process.cwd(), or
36
+ // taken from DAVE_REPO_ROOT / PA_REPO_ROOT for tests and ephemeral harnesses.
37
+ // The package's own assets live at `../app/` (one level up from src/).
38
+ function findRepoRootSync(start) {
39
+ let d = start;
40
+ let prev;
41
+ while (d && d !== prev) {
42
+ try {
43
+ const s = existsSync(join(d, '.git'));
44
+ if (s) return d;
45
+ } catch { /* ignore */ }
46
+ prev = d;
47
+ d = resolve(d, '..');
48
+ }
49
+ return null;
50
+ }
51
+
52
+ const envRepoRoot = process.env.DAVE_REPO_ROOT || process.env.PA_REPO_ROOT;
53
+ const REPO_ROOT = envRepoRoot
54
+ ? resolve(envRepoRoot)
55
+ : (findRepoRootSync(process.cwd()) || process.cwd());
56
+ const APP_DIR = resolve(__dirname, '..', 'app');
57
+
58
+ // Silent by default. Set WS_DEBUG=1 to re-enable startup banner, file-change
59
+ // notifications, extension-load messages, and shutdown traces.
60
+ const DEBUG = process.env.WS_DEBUG === '1';
61
+ const log = DEBUG ? console.log.bind(console) : function () {};
62
+ const warn = DEBUG ? console.warn.bind(console) : function () {};
63
+
64
+ // --- Extension dir ---
65
+ // Convention: operator/extensions/workspace/ overlays core app pages and
66
+ // can register additional API routes. No config required — presence of the
67
+ // directory activates the mechanism.
68
+ const EXT_DIR_PATH = join(REPO_ROOT, 'operator', 'extensions', 'workspace');
69
+ const EXT_DIR = existsSync(EXT_DIR_PATH) ? EXT_DIR_PATH : null;
70
+
71
+ // --- Args ---
72
+ const args = process.argv.slice(2);
73
+ let port = 4200;
74
+ let autoOpen = true;
75
+ let timeoutMinutes = 120;
76
+ let noTimeout = false;
77
+
78
+ // Read configured port from preferences if available
79
+ try {
80
+ const prefsPath = join(REPO_ROOT, 'operator', 'config', 'preferences.json');
81
+ const prefs = JSON.parse(readFileSync(prefsPath, 'utf-8'));
82
+ if (prefs.workspacePort) port = prefs.workspacePort;
83
+ } catch { /* no prefs yet — use default */ }
84
+
85
+ // CLI flags override preferences
86
+ for (let i = 0; i < args.length; i++) {
87
+ switch (args[i]) {
88
+ case '--port': port = parseInt(args[++i], 10); break;
89
+ case '--no-open': autoOpen = false; break;
90
+ case '--timeout': timeoutMinutes = parseInt(args[++i], 10); break;
91
+ case '--no-timeout': noTimeout = true; break;
92
+ }
93
+ }
94
+
95
+ const IDLE_TIMEOUT_MS = timeoutMinutes * 60 * 1000;
96
+
97
+ // Side-effect gate. This file is imported by tests to assert exports (Option
98
+ // D). When it is imported (not run), we must NOT attach status-mon or bind a
99
+ // port. Everything side-effectful below is guarded on this flag.
100
+ //
101
+ // Under pnpm's hoisted layout, this file's real path lives under
102
+ // `node_modules/.pnpm/...`, while `process.argv[1]` keeps the symlinked path
103
+ // at `node_modules/@stravica-ai/engineering-pa-workspace/src/server.mjs`. A naive
104
+ // equality check would always be false. Realpath both sides so the comparison
105
+ // reflects the underlying file identity.
106
+ const isMainModule = (() => {
107
+ if (!process.argv[1]) return false;
108
+ try {
109
+ return fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
110
+ } catch {
111
+ return false;
112
+ }
113
+ })();
114
+
115
+ // --- Extension API routes ---
116
+ // Populated by loadExtensions() before the server starts.
117
+ // Extension routes shadow core routes when method + pathname match.
118
+ const extRoutes = [];
119
+
120
+ // --- MIME types ---
121
+ const MIME = {
122
+ '.html': 'text/html',
123
+ '.css': 'text/css',
124
+ '.js': 'application/javascript',
125
+ '.mjs': 'application/javascript',
126
+ '.json': 'application/json',
127
+ '.png': 'image/png',
128
+ '.jpg': 'image/jpeg',
129
+ '.jpeg': 'image/jpeg',
130
+ '.svg': 'image/svg+xml',
131
+ '.ico': 'image/x-icon',
132
+ '.md': 'text/html',
133
+ '.txt': 'text/plain',
134
+ '.woff': 'font/woff',
135
+ '.woff2': 'font/woff2',
136
+ };
137
+
138
+ // --- Page URL resolution ---
139
+ // Workspace pages are addressable by two URL shapes:
140
+ // - the bare top-level form: /<page>.html
141
+ // - the shell-prefixed form: /core/tools/workspace/app/<page>.html
142
+ //
143
+ // The hash-routed shell at / loads inner pages via the prefixed form; older
144
+ // direct links use the bare form. Both must honour the operator overlay the
145
+ // same way — pre-1.0 a regex pinned the overlay block to the bare form only
146
+ // and the prefixed form silently went to the bundled APP_DIR, defeating the
147
+ // overlay for anyone who navigated via the shell.
148
+ //
149
+ // Returns the basename (e.g. 'project-detail.html') when pathname targets an
150
+ // .html app page in either form; returns null for assets, deep paths,
151
+ // dotfile probes, or non-html URLs. Exported for unit testing.
152
+ export const WORKSPACE_PREFIX = '/core/tools/workspace/app/';
153
+ export function appPageBasename(pathname) {
154
+ if (!pathname || pathname.startsWith('/.')) return null;
155
+ const stripped = pathname.startsWith(WORKSPACE_PREFIX)
156
+ ? '/' + pathname.slice(WORKSPACE_PREFIX.length)
157
+ : pathname;
158
+ const m = stripped.match(/^\/([^/]+\.html)$/);
159
+ return m ? m[1] : null;
160
+ }
161
+
162
+ // --- Activity timer ---
163
+ // The server auto-shuts after IDLE_TIMEOUT_MS from startup unless
164
+ // --no-timeout is set (the daemon path always passes --no-timeout). The
165
+ // previous implementation reset the timer from the SSE file-watcher; with
166
+ // live-reload gone, the timer is armed once at listen() and fires on the
167
+ // wall clock — sufficient for the daemon (never fires) and for interactive
168
+ // sessions (a 2-hour cap on a lingering foreground process).
169
+ let idleTimer;
170
+ function resetIdle() {
171
+ if (noTimeout) return;
172
+ clearTimeout(idleTimer);
173
+ idleTimer = setTimeout(() => {
174
+ log('[workspace] Idle for ' + timeoutMinutes + ' minutes. Shutting down.');
175
+ process.exit(0);
176
+ }, IDLE_TIMEOUT_MS);
177
+ }
178
+
179
+ // --- Markdown HTML template ---
180
+ //
181
+ // Auto-wraps a raw .md request into a styled HTML page. The chrome here
182
+ // duplicates viewer.html's surface — both used to embed their own :root
183
+ // palette block, which broke the theme toggle on the content-calendar
184
+ // preview iframe (operator-reported, 2026-06-27). The fix matches what
185
+ // viewer.html does: link the shared theme.css, defer-load theme.js, pre-paint
186
+ // init reads localStorage 'dave.theme', body in humanist sans for prose, and
187
+ // .md-body strong uses the new --emphasis token (matching .content strong).
188
+ // Exported so unit tests can assert on the output without spinning up the
189
+ // HTTP server.
190
+ export function markdownPage(rawContent, filePath) {
191
+ const escaped = rawContent
192
+ .replace(/\\/g, '\\\\')
193
+ .replace(/`/g, '\\`')
194
+ .replace(/\$/g, '\\$');
195
+ const title = filePath.split('/').pop().replace(/\.md$/, '');
196
+ return `<!DOCTYPE html>
197
+ <html lang="en">
198
+ <head>
199
+ <meta charset="UTF-8">
200
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
201
+ <title>${title}</title>
202
+ <script>(function(){try{var t=localStorage.getItem('dave.theme');document.documentElement.dataset.theme=(t==='light'||t==='dark')?t:'dark';}catch(_){document.documentElement.dataset.theme='dark';}})();</script>
203
+ <link rel="stylesheet" href="/core/tools/workspace/app/assets/theme.css">
204
+ <script src="/core/tools/workspace/app/assets/theme.js" defer></script>
205
+ <style>
206
+ * { margin: 0; padding: 0; box-sizing: border-box; }
207
+ body {
208
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
209
+ background: var(--bg); color: var(--text); padding: 2rem; line-height: 1.7;
210
+ font-size: 16px;
211
+ }
212
+ .md-body { max-width: 760px; margin: 0 auto; }
213
+ .md-body h1 { color: var(--purple); font-size: 1.8rem; margin: 1.5rem 0 0.75rem; border-bottom: 1px solid var(--border); padding-bottom: 0.4rem; line-height: 1.25; }
214
+ .md-body h2 { color: var(--accent); font-size: 1.4rem; margin: 1.3rem 0 0.6rem; line-height: 1.3; }
215
+ .md-body h3 { color: var(--cyan); font-size: 1.15rem; margin: 1.1rem 0 0.5rem; line-height: 1.35; }
216
+ .md-body h4 { color: var(--text-bright); font-size: 1rem; margin: 1rem 0 0.4rem; line-height: 1.4; }
217
+ .md-body p { margin: 0.6rem 0; }
218
+ .md-body a { color: var(--accent); text-decoration: none; }
219
+ .md-body a:hover { text-decoration: underline; }
220
+ .md-body strong { color: var(--emphasis); font-weight: 700; }
221
+ .md-body em { color: var(--text); font-style: italic; }
222
+ .md-body code { background: var(--bg-surface); color: var(--orange); padding: 0.15rem 0.35rem; border-radius: 3px; font-size: 0.9em; font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; }
223
+ .md-body pre { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; padding: 1rem; overflow-x: auto; margin: 0.8rem 0; }
224
+ .md-body pre code { background: none; color: var(--text); padding: 0; font-size: 0.85rem; font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; }
225
+ .md-body ul, .md-body ol { margin: 0.5rem 0 0.5rem 1.5rem; }
226
+ .md-body li { margin: 0.25rem 0; }
227
+ .md-body li::marker { color: var(--text-dim); }
228
+ .md-body blockquote { border-left: 3px solid var(--accent); margin: 0.8rem 0; padding: 0.4rem 0 0.4rem 1rem; color: var(--text-dim); background: var(--bg-surface); border-radius: 0 4px 4px 0; }
229
+ .md-body hr { border: none; border-top: 1px solid var(--border); margin: 1.5rem 0; }
230
+ .md-body table { border-collapse: collapse; margin: 0.8rem 0; width: 100%; }
231
+ .md-body th, .md-body td { border: 1px solid var(--border); padding: 0.4rem 0.7rem; text-align: left; font-size: 0.85rem; }
232
+ .md-body th { background: var(--bg-highlight); color: var(--text-bright); }
233
+ .md-body td { background: var(--bg-surface); }
234
+ </style>
235
+ </head>
236
+ <body>
237
+ <div class="md-body" id="content"></div>
238
+ <script>
239
+ (function() {
240
+ var raw = \`${escaped}\`;
241
+ function parseMd(src) {
242
+ var codeBlocks = [];
243
+ src = src.replace(/\\\`\\\`\\\`(\\w*)\\n([\\s\\S]*?)\\\`\\\`\\\`/g, function(_, lang, code) {
244
+ codeBlocks.push('<pre><code>' + esc(code.replace(/\\n$/, '')) + '</code></pre>');
245
+ return '%%CB_' + (codeBlocks.length - 1) + '%%';
246
+ });
247
+ var lines = src.split('\\n');
248
+ var html = '';
249
+ var inList = false, listType = '', inBq = false, bqLines = [];
250
+ function flushBq() { if (inBq) { html += '<blockquote>' + bqLines.map(function(l) { return '<p>' + inline(l) + '</p>'; }).join('') + '</blockquote>'; bqLines = []; inBq = false; } }
251
+ function closeList() { if (inList) { html += '</' + listType + '>'; inList = false; listType = ''; } }
252
+ for (var i = 0; i < lines.length; i++) {
253
+ var line = lines[i];
254
+ var cbm = line.match(/^%%CB_(\\d+)%%$/);
255
+ if (cbm) { flushBq(); closeList(); html += codeBlocks[parseInt(cbm[1])]; continue; }
256
+ if (line.match(/^>\\s?/)) { closeList(); inBq = true; bqLines.push(line.replace(/^>\\s?/, '')); continue; } else { flushBq(); }
257
+ var hm = line.match(/^(#{1,6})\\s+(.+)$/);
258
+ if (hm) { closeList(); html += '<h' + hm[1].length + '>' + inline(hm[2]) + '</h' + hm[1].length + '>'; continue; }
259
+ if (line.match(/^(---+|\\*\\*\\*+|___+)\\s*$/)) { closeList(); html += '<hr>'; continue; }
260
+ var ulm = line.match(/^\\s*[-*+]\\s+(.+)$/);
261
+ if (ulm) { if (!inList || listType !== 'ul') { closeList(); html += '<ul>'; inList = true; listType = 'ul'; } html += '<li>' + inline(ulm[1]) + '</li>'; continue; }
262
+ var olm = line.match(/^\\s*\\d+\\.\\s+(.+)$/);
263
+ if (olm) { if (!inList || listType !== 'ol') { closeList(); html += '<ol>'; inList = true; listType = 'ol'; } html += '<li>' + inline(olm[1]) + '</li>'; continue; }
264
+ closeList();
265
+ if (line.trim() === '') continue;
266
+ if (line.includes('|') && line.trim().startsWith('|')) {
267
+ var tl = []; var j = i;
268
+ while (j < lines.length && lines[j].trim().startsWith('|')) { tl.push(lines[j]); j++; }
269
+ if (tl.length >= 2) { html += renderTable(tl); i = j - 1; continue; }
270
+ }
271
+ html += '<p>' + inline(line) + '</p>';
272
+ }
273
+ closeList(); flushBq();
274
+ return html;
275
+ }
276
+ function renderTable(rows) {
277
+ var p = function(r) { return r.replace(/^\\|/, '').replace(/\\|$/, '').split('|').map(function(c) { return c.trim(); }); };
278
+ var hdr = p(rows[0]); var h = '<table><thead><tr>';
279
+ hdr.forEach(function(c) { h += '<th>' + inline(c) + '</th>'; });
280
+ h += '</tr></thead><tbody>';
281
+ for (var r = 2; r < rows.length; r++) { var cells = p(rows[r]); h += '<tr>'; cells.forEach(function(c) { h += '<td>' + inline(c) + '</td>'; }); h += '</tr>'; }
282
+ h += '</tbody></table>'; return h;
283
+ }
284
+ function esc(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
285
+ function inline(s) {
286
+ s = esc(s);
287
+ s = s.replace(/\\\`([^\\\`]+)\\\`/g, '<code>$1</code>');
288
+ s = s.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, '<strong><em>$1</em></strong>');
289
+ s = s.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');
290
+ s = s.replace(/__(.+?)__/g, '<strong>$1</strong>');
291
+ s = s.replace(/\\*(.+?)\\*/g, '<em>$1</em>');
292
+ s = s.replace(/_(.+?)_/g, '<em>$1</em>');
293
+ s = s.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href="$2">$1</a>');
294
+ return s;
295
+ }
296
+ document.getElementById('content').innerHTML = parseMd(raw);
297
+ })();
298
+ </script>
299
+ </body>
300
+ </html>`;
301
+ }
302
+
303
+ // --- HTTP server ---
304
+ const server = createServer(async (req, res) => {
305
+ const url = new URL(req.url, 'http://localhost:' + port);
306
+ const pathname = decodeURIComponent(url.pathname);
307
+
308
+ // API routes -- extension routes shadow core; handleApi handles the rest
309
+ if (pathname.startsWith('/__api/') || pathname.startsWith('/api/')) {
310
+ const extRoute = extRoutes.find(r => r.method === req.method && r.pathname === pathname);
311
+ if (extRoute) { extRoute.handler(req, res, url, REPO_ROOT); return; }
312
+
313
+ // GET /__api/nav -- merged core + extension nav manifest
314
+ if (req.method === 'GET' && pathname === '/__api/nav') {
315
+ try {
316
+ const items = loadNav({ appDir: APP_DIR, extDir: EXT_DIR, warn: warn });
317
+ const body = JSON.stringify({ items: items });
318
+ res.writeHead(200, {
319
+ 'Content-Type': 'application/json',
320
+ 'Content-Length': Buffer.byteLength(body),
321
+ });
322
+ res.end(body);
323
+ } catch (e) {
324
+ const body = JSON.stringify({ error: e.message, items: [] });
325
+ res.writeHead(500, {
326
+ 'Content-Type': 'application/json',
327
+ 'Content-Length': Buffer.byteLength(body),
328
+ });
329
+ res.end(body);
330
+ }
331
+ return;
332
+ }
333
+
334
+ const handled = handleApi(req, res, url, REPO_ROOT);
335
+ if (handled) return;
336
+ }
337
+
338
+ // Root serves the shell
339
+ if (pathname === '/' || pathname === '/index.html') {
340
+ try {
341
+ const indexPath = join(APP_DIR, 'index.html');
342
+ const html = await readFile(indexPath, 'utf-8');
343
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
344
+ res.end(html);
345
+ } catch {
346
+ res.writeHead(404);
347
+ res.end('Workspace index not found');
348
+ }
349
+ return;
350
+ }
351
+
352
+ // Top-level workspace assets served out of APP_DIR. Kept here rather than
353
+ // under a workspace-relative prefix so the page-level includes
354
+ // (e.g. <script src="/banner.js">) stay terse and version-independent.
355
+ if (pathname === '/banner.js') {
356
+ try {
357
+ const content = await readFile(join(APP_DIR, 'banner.js'));
358
+ res.writeHead(200, { 'Content-Type': 'application/javascript; charset=utf-8' });
359
+ res.end(content);
360
+ } catch {
361
+ res.writeHead(404);
362
+ res.end('Not found');
363
+ }
364
+ return;
365
+ }
366
+
367
+ // Workspace app pages: both /<page>.html and /core/tools/workspace/app/<page>.html
368
+ // check EXT_DIR first (operator overlay), then APP_DIR (core). The shell at /
369
+ // hash-routes inner pages via the prefixed form, so honouring overlays for that
370
+ // form too is what lets operator extensions actually shadow shell-loaded pages.
371
+ // Fall through to asset/repo-root serving when absent in both.
372
+ const pageBase = appPageBasename(pathname);
373
+ if (pageBase) {
374
+ const candidates = EXT_DIR
375
+ ? [join(EXT_DIR, pageBase), join(APP_DIR, pageBase)]
376
+ : [join(APP_DIR, pageBase)];
377
+ for (const candidate of candidates) {
378
+ try {
379
+ const html = await readFile(candidate, 'utf-8');
380
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
381
+ res.end(html);
382
+ return;
383
+ } catch { /* try next candidate */ }
384
+ }
385
+ // Not found in EXT_DIR or APP_DIR — fall through to asset/repo-root serving
386
+ }
387
+
388
+ // Workspace app assets live with the server code, not under REPO_ROOT.
389
+ // When DAVE_REPO_ROOT is overridden (E2E fixtures), absolute paths that
390
+ // point at the workspace script tree must still resolve against APP_DIR's
391
+ // parent so pages can load their CSS/JS regardless of the fixture root.
392
+ // Historical absolute-URL prefix preserved so existing operator pages that
393
+ // hard-code these paths keep working through the transition. The server
394
+ // strips the prefix and serves out of the package's bundled APP_DIR.
395
+ const filePath = pathname.startsWith(WORKSPACE_PREFIX)
396
+ ? join(APP_DIR, pathname.slice(WORKSPACE_PREFIX.length))
397
+ : join(REPO_ROOT, pathname);
398
+
399
+ // Security: no traversal outside repo, no .git or .env. Workspace app
400
+ // assets under APP_DIR are always allowed regardless of REPO_ROOT.
401
+ const allowedBase = pathname.startsWith(WORKSPACE_PREFIX) ? APP_DIR : REPO_ROOT;
402
+ if (!filePath.startsWith(allowedBase) || pathname.includes('/.git/') || pathname.includes('/.env')) {
403
+ res.writeHead(403);
404
+ res.end('Forbidden');
405
+ return;
406
+ }
407
+
408
+ try {
409
+ const fileStat = await stat(filePath);
410
+
411
+ if (fileStat.isDirectory()) {
412
+ const indexPath = join(filePath, 'index.html');
413
+ try {
414
+ const html = await readFile(indexPath, 'utf-8');
415
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
416
+ res.end(html);
417
+ } catch {
418
+ res.writeHead(404);
419
+ res.end('Not found');
420
+ }
421
+ return;
422
+ }
423
+
424
+ const content = await readFile(filePath);
425
+ const ext = extname(filePath);
426
+ const mime = MIME[ext] || 'application/octet-stream';
427
+
428
+ if (ext === '.md') {
429
+ const mdContent = content.toString('utf-8');
430
+ const html = markdownPage(mdContent, pathname);
431
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
432
+ res.end(html);
433
+ } else {
434
+ res.writeHead(200, { 'Content-Type': mime });
435
+ res.end(content);
436
+ }
437
+ } catch {
438
+ res.writeHead(404);
439
+ res.end('Not found');
440
+ }
441
+ });
442
+
443
+ // --- Extension loader ---
444
+ // Imports operator/extensions/workspace/api.mjs (if present) and calls its
445
+ // register(addRoute) export. Extensions can add routes or shadow core routes.
446
+ // A shadowed route is logged at startup so operators know the override is live.
447
+ async function loadExtensions() {
448
+ if (!EXT_DIR) return;
449
+ const extApiPath = join(EXT_DIR, 'api.mjs');
450
+ if (!existsSync(extApiPath)) return;
451
+ try {
452
+ const extApi = await import(extApiPath);
453
+ if (typeof extApi.register === 'function') {
454
+ extApi.register(function addRoute(method, pathname, handler) {
455
+ const shadows = extRoutes.some(r => r.method === method && r.pathname === pathname);
456
+ if (!shadows) {
457
+ // Check if it shadows a core route (informational only).
458
+ log('[workspace] Extension route registered: ' + method + ' ' + pathname);
459
+ }
460
+ extRoutes.push({ method: method, pathname: pathname, handler: handler });
461
+ });
462
+ }
463
+ } catch (e) {
464
+ warn('[workspace] Extension api.mjs failed to load: ' + e.message);
465
+ }
466
+ }
467
+
468
+ // --- Status-mon poller ---
469
+ // Runs inside the workspace process because the server is the always-on
470
+ // component on this host (launchd-supervised). A separate scheduled task would
471
+ // duplicate supervision. Disabled when DAVE_REPO_ROOT is overridden (E2E
472
+ // fixture runs), because tests drive the state file directly via fixtures.
473
+ let statusMonHandle = null;
474
+ if (isMainModule && !process.env.DAVE_REPO_ROOT && process.env.WS_STATUS_MON !== '0') {
475
+ try {
476
+ statusMonHandle = startStatusMonPoller({
477
+ repoRoot: REPO_ROOT,
478
+ onError: (err) => warn('[workspace] status-mon poll error: ' + err.message),
479
+ });
480
+ log('[workspace] status-mon poller started (60s cadence)');
481
+ } catch (err) {
482
+ warn('[workspace] status-mon poller failed to start: ' + err.message);
483
+ }
484
+ }
485
+
486
+ // --- Start ---
487
+ // Only auto-start when this file is the process entry point. Tests import
488
+ // server.mjs to assert exports; they must not spawn a listening server as a
489
+ // side effect.
490
+ if (isMainModule) (async function () {
491
+ await loadExtensions();
492
+
493
+ server.listen(port, () => {
494
+ const url = 'http://localhost:' + port;
495
+ log('[workspace] Dave Workspace running at ' + url);
496
+ log('[workspace] Serving from: ' + REPO_ROOT);
497
+ if (EXT_DIR) log('[workspace] Extensions: ' + EXT_DIR.replace(REPO_ROOT + '/', ''));
498
+ log('[workspace] Idle timeout: ' + (noTimeout ? 'disabled (persistent)' : timeoutMinutes + ' minutes'));
499
+
500
+ if (autoOpen) {
501
+ try { execSync('open "' + url + '"'); } catch { /* non-fatal */ }
502
+ }
503
+
504
+ resetIdle();
505
+ });
506
+ }());
507
+
508
+ function shutdown(signal) {
509
+ if (signal === 'SIGINT') console.log('\n[workspace] Shutting down.');
510
+ if (statusMonHandle) { try { statusMonHandle.stop(); } catch { /* ignore */ } }
511
+ server.close();
512
+ process.exit(0);
513
+ }
514
+
515
+ process.on('SIGINT', () => shutdown('SIGINT'));
516
+ process.on('SIGTERM', () => shutdown('SIGTERM'));