@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,191 @@
1
+ // runner.mjs — external-effects chokepoint for the smoke tool.
2
+ //
3
+ // Everything that touches the outside world (spawning processes, copying
4
+ // files, HTTP requests) lives in this module. Commands and checks depend
5
+ // on this module; nothing else spawns or fetches.
6
+ //
7
+ // All helpers return plain Promises resolving to structured results —
8
+ // they never throw for caller-recoverable outcomes (non-zero exits,
9
+ // HTTP errors, missing files). They throw only for programmer errors
10
+ // (bad arguments, missing binaries that the host platform lacks).
11
+
12
+ import { spawn } from 'node:child_process';
13
+ import { mkdtemp, cp, rm, access, stat } from 'node:fs/promises';
14
+ import { tmpdir } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { constants as fsConstants } from 'node:fs';
17
+
18
+ /**
19
+ * Spawn a process without a shell. Returns { code, signal, stdout, stderr }.
20
+ * Never rejects for non-zero exits — callers must inspect `code`.
21
+ *
22
+ * @param {string} command
23
+ * @param {string[]} args
24
+ * @param {object} [opts] { cwd, env, timeoutMs, stdin }
25
+ */
26
+ export function spawnProcess(command, args = [], opts = {}) {
27
+ return new Promise((resolve, reject) => {
28
+ const child = spawn(command, args, {
29
+ cwd: opts.cwd,
30
+ env: opts.env ?? process.env,
31
+ shell: false,
32
+ stdio: ['pipe', 'pipe', 'pipe'],
33
+ });
34
+
35
+ let stdout = '';
36
+ let stderr = '';
37
+ let timedOut = false;
38
+
39
+ child.stdout.on('data', (chunk) => { stdout += chunk.toString('utf8'); });
40
+ child.stderr.on('data', (chunk) => { stderr += chunk.toString('utf8'); });
41
+
42
+ const timer = opts.timeoutMs
43
+ ? setTimeout(() => { timedOut = true; child.kill('SIGTERM'); }, opts.timeoutMs)
44
+ : null;
45
+
46
+ child.on('error', (err) => {
47
+ if (timer) clearTimeout(timer);
48
+ reject(err);
49
+ });
50
+
51
+ child.on('close', (code, signal) => {
52
+ if (timer) clearTimeout(timer);
53
+ resolve({ code, signal, stdout, stderr, timedOut });
54
+ });
55
+
56
+ if (opts.stdin != null) {
57
+ child.stdin.write(opts.stdin);
58
+ }
59
+ child.stdin.end();
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Launch a long-running process and return the ChildProcess handle.
65
+ * The caller is responsible for killing it.
66
+ */
67
+ export function launchProcess(command, args = [], opts = {}) {
68
+ return spawn(command, args, {
69
+ cwd: opts.cwd,
70
+ env: opts.env ?? process.env,
71
+ shell: false,
72
+ stdio: opts.stdio ?? ['ignore', 'ignore', 'ignore'],
73
+ detached: false,
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Kill a child process and await exit. Safe to call on an already-exited child.
79
+ */
80
+ export async function killProcess(child) {
81
+ if (!child || child.exitCode != null || child.signalCode != null) return;
82
+ child.kill('SIGTERM');
83
+ await new Promise((resolve) => {
84
+ const timer = setTimeout(() => { try { child.kill('SIGKILL'); } catch {} resolve(); }, 2000);
85
+ child.once('close', () => { clearTimeout(timer); resolve(); });
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Create a temp directory with a stable prefix. Returns the absolute path.
91
+ */
92
+ export async function makeTempDir(prefix = 'dave-smoke-') {
93
+ return mkdtemp(join(tmpdir(), prefix));
94
+ }
95
+
96
+ /**
97
+ * Remove a directory recursively. Never rejects for missing paths.
98
+ */
99
+ export async function removeDir(dir) {
100
+ if (!dir) return;
101
+ await rm(dir, { recursive: true, force: true });
102
+ }
103
+
104
+ /**
105
+ * Copy a directory tree from src to dest, excluding a fixed set of top-level
106
+ * names. Matches the behaviour of `rsync -a --exclude=.git --exclude=node_modules`.
107
+ */
108
+ export async function copyTree(src, dest, excludes = ['.git', 'node_modules']) {
109
+ const excludeSet = new Set(excludes);
110
+ await cp(src, dest, {
111
+ recursive: true,
112
+ dereference: false,
113
+ preserveTimestamps: true,
114
+ filter: (source) => {
115
+ // Only filter at the top level — once inside an included dir, copy
116
+ // everything. This matches rsync --exclude='.git' semantics where
117
+ // only top-level matches are excluded (our exclusion list is
118
+ // ".git" and "node_modules", both only meaningful at the root).
119
+ const rel = source.slice(src.length).replace(/^[\\/]+/, '');
120
+ if (rel === '') return true;
121
+ const firstSegment = rel.split(/[\\/]/)[0];
122
+ return !excludeSet.has(firstSegment);
123
+ },
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Check that a path exists. Returns true/false.
129
+ */
130
+ export async function pathExists(p) {
131
+ try {
132
+ await access(p, fsConstants.F_OK);
133
+ return true;
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Check that a path exists and is executable.
141
+ */
142
+ export async function pathExecutable(p) {
143
+ try {
144
+ await access(p, fsConstants.F_OK | fsConstants.X_OK);
145
+ const s = await stat(p);
146
+ return s.isFile();
147
+ } catch {
148
+ return false;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Perform an HTTP GET. Returns { status, body }. Never rejects for HTTP
154
+ * errors — callers inspect status. Rejects only for network/DNS/abort.
155
+ *
156
+ * Uses the global `fetch` available in Node 20+.
157
+ */
158
+ export async function httpGet(url, opts = {}) {
159
+ const controller = new AbortController();
160
+ const timer = opts.timeoutMs
161
+ ? setTimeout(() => controller.abort(), opts.timeoutMs)
162
+ : null;
163
+ try {
164
+ const res = await fetch(url, { signal: controller.signal });
165
+ const body = await res.text();
166
+ return { status: res.status, body };
167
+ } finally {
168
+ if (timer) clearTimeout(timer);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Poll until an HTTP endpoint becomes reachable or the attempt budget
174
+ * is exhausted. Returns true on success.
175
+ */
176
+ export async function waitForHttp(url, { attempts = 20, intervalMs = 500, timeoutMs = 1000 } = {}) {
177
+ for (let i = 0; i < attempts; i++) {
178
+ try {
179
+ const res = await httpGet(url, { timeoutMs });
180
+ if (res.status >= 200 && res.status < 500) return true;
181
+ } catch {
182
+ // swallow — connection refused / reset during boot is expected
183
+ }
184
+ await sleep(intervalMs);
185
+ }
186
+ return false;
187
+ }
188
+
189
+ export function sleep(ms) {
190
+ return new Promise((resolve) => setTimeout(resolve, ms));
191
+ }
@@ -0,0 +1,91 @@
1
+ // staging-alias — verb router for `pa staging-alias <verb>`.
2
+ //
3
+ // Pattern: a tiny "router worker" bound as a Custom Domain on
4
+ // `staging.<site>` proxies to the desired preview-URL on workers.dev.
5
+ // Cloudflare Workers Custom Domains cannot be pointed at a specific
6
+ // version, and Preview URLs cannot run on a non-workers.dev subdomain
7
+ // (CF docs, confirmed 2026-05-21), so the router-worker indirection is
8
+ // the cleanest available pattern.
9
+ //
10
+ // The CLI enforces the multi-CF-account safety drill (read /accounts/{id}
11
+ // and assert `result.name` matches the per-site expected name) before
12
+ // any write. Aborts loudly on mismatch.
13
+ //
14
+ // Exit codes (engineering-pa-core/docs/standards/tooling.md §6):
15
+ // 0 ok | 1 usage error | 2 operational failure | 3 transport/IO failure
16
+
17
+ import { runSet } from './commands/set.mjs';
18
+ import { runUnset } from './commands/unset.mjs';
19
+ import { runStatus } from './commands/status.mjs';
20
+ import { runList } from './commands/list.mjs';
21
+
22
+ const HELP = `pa staging-alias — canonical staging.<site> alias for CF-hosted sites
23
+
24
+ Usage:
25
+ pa staging-alias set --site <hostname> --branch <branch> [--version <id>]
26
+ Wire staging.<hostname> to the source worker's latest preview
27
+ version (or the explicit --version). Idempotent — re-runs flip
28
+ the alias to a new branch's preview cleanly.
29
+
30
+ pa staging-alias unset --site <hostname> [--keep-worker]
31
+ Remove the staging.<hostname> binding and delete the router worker.
32
+ --keep-worker leaves the router script in place (binding still
33
+ removed).
34
+
35
+ pa staging-alias status --site <hostname>
36
+ Show current target (router worker, STAGING_TARGET, custom-domain
37
+ binding) for one site. JSON on stdout.
38
+
39
+ pa staging-alias list
40
+ Across every registered site, the current staging target. JSON
41
+ array on stdout.
42
+
43
+ pa staging-alias -h, --help
44
+ Show this help.
45
+
46
+ How it works:
47
+ staging.<hostname> --CF Custom Domain--> <site>-staging worker
48
+ \\__ proxies STAGING_TARGET
49
+ (the workers.dev preview URL)
50
+
51
+ Multi-account safety:
52
+ Every write runs the 6-step CF-account drill. Vault keys are picked from
53
+ a per-site lookup table; the CLI then reads /accounts/{id} and aborts
54
+ unless result.name matches the site's expected account name.
55
+
56
+ Registered sites: stravica.ai, cliveelliott.net, besafetraining.co.uk.
57
+ Add a fourth via src/staging-alias/sites.mjs (one entry).
58
+ `;
59
+
60
+ export async function run(argv, overrides = {}) {
61
+ const verb = argv[0];
62
+ const rest = argv.slice(1);
63
+ if (!verb || verb === '--help' || verb === '-h' || verb === 'help') {
64
+ process.stdout.write(HELP);
65
+ return verb ? 0 : 1;
66
+ }
67
+ switch (verb) {
68
+ case 'set': return runSet(rest, overrides);
69
+ case 'unset': return runUnset(rest, overrides);
70
+ case 'status': return runStatus(rest, overrides);
71
+ case 'list': return runList(rest, overrides);
72
+ default: {
73
+ process.stderr.write(`[pa staging-alias] unknown verb: ${verb}\n`);
74
+ process.stderr.write(HELP);
75
+ return 1;
76
+ }
77
+ }
78
+ }
79
+
80
+ export async function main(argv, overrides = {}) {
81
+ try {
82
+ const code = await run(argv, overrides);
83
+ return code ?? 0;
84
+ } catch (err) {
85
+ const code = err && typeof err.exitCode === 'number' ? err.exitCode : 2;
86
+ if (!err || err.exitCode == null) {
87
+ process.stderr.write(`pa staging-alias: ${err && err.message ? err.message : err}\n`);
88
+ }
89
+ return code;
90
+ }
91
+ }
@@ -0,0 +1,380 @@
1
+ // cloudflare.mjs — Cloudflare API helpers for staging-alias.
2
+ //
3
+ // Builds on the lower-level `cfFetch` from src/gsc/cloudflare.mjs. The
4
+ // added surface here is the set of operations the staging-alias CLI
5
+ // performs:
6
+ //
7
+ // - verifyAccount(creds, expectedName) — the safety drill
8
+ // - listWorkerVersions(creds, worker) — to pick "latest" for --branch
9
+ // - resolveZoneId(creds, zoneName) — re-exported from gsc helpers
10
+ // - listWorkerDomains(creds, worker) — for status + idempotency
11
+ // - bindWorkerCustomDomain(creds, …) — bind hostname → router worker
12
+ // - unbindWorkerCustomDomain(creds, domainId) — remove the binding
13
+ // - uploadRouterWorker(creds, name, target) — push the router worker w/ env
14
+ // - workerScriptExists(creds, name) — for idempotent ensure
15
+ // - resolveAccountSubdomain(creds) — for the workers.dev URL
16
+ //
17
+ // The router worker is a tiny proxy. Its source is built into this module
18
+ // (no separate file to ship) so the CLI is self-contained.
19
+
20
+ import { cfFetch, resolveZoneId } from '../gsc/cloudflare.mjs';
21
+
22
+ export { cfFetch, resolveZoneId };
23
+
24
+ /**
25
+ * Read /accounts/{account_id} and assert the display name matches.
26
+ * Throws with exitCode=2 on mismatch — this is the load-bearing safety
27
+ * drill per `feedback_cf_multi_account_discipline.md`.
28
+ *
29
+ * Returns the verified account object so the caller can echo it.
30
+ *
31
+ * @param {{token: string, accountId: string}} creds
32
+ * @param {string} expectedName
33
+ * @param {Function} [fetchImpl]
34
+ */
35
+ export async function verifyAccount(creds, expectedName, fetchImpl) {
36
+ const body = await cfFetch(
37
+ creds.token,
38
+ `/accounts/${creds.accountId}`,
39
+ {},
40
+ fetchImpl,
41
+ );
42
+ const actual = body && body.result && body.result.name;
43
+ if (!actual) {
44
+ throw Object.assign(
45
+ new Error(`CF /accounts/${creds.accountId} returned no result.name (got ${JSON.stringify(body).slice(0, 200)})`),
46
+ { exitCode: 2 },
47
+ );
48
+ }
49
+ if (actual !== expectedName) {
50
+ throw Object.assign(
51
+ new Error(
52
+ `CF account-name mismatch — refusing to write.\n` +
53
+ ` account_id : ${creds.accountId}\n` +
54
+ ` expected name : ${expectedName}\n` +
55
+ ` actual name : ${actual}\n` +
56
+ `Check that the vault keys you loaded match the site you are operating on ` +
57
+ `(see operator/knowledge/systems/web-properties/).`,
58
+ ),
59
+ { exitCode: 2 },
60
+ );
61
+ }
62
+ return { id: body.result.id, name: actual };
63
+ }
64
+
65
+ /**
66
+ * Read the account-level workers.dev subdomain (e.g. `barry-ab9`). Used to
67
+ * build the preview-URL the router worker proxies to.
68
+ */
69
+ export async function resolveAccountSubdomain(creds, fetchImpl) {
70
+ const body = await cfFetch(
71
+ creds.token,
72
+ `/accounts/${creds.accountId}/workers/subdomain`,
73
+ {},
74
+ fetchImpl,
75
+ );
76
+ const subdomain = body && body.result && body.result.subdomain;
77
+ if (!subdomain) {
78
+ throw Object.assign(
79
+ new Error('CF account has no workers.dev subdomain. Enable it in the dashboard.'),
80
+ { exitCode: 2 },
81
+ );
82
+ }
83
+ return subdomain;
84
+ }
85
+
86
+ /**
87
+ * List Worker versions for `worker`, newest-first. Returns the parsed
88
+ * result.items array (limited by CF default page size).
89
+ *
90
+ * Throws with exitCode=1 when the worker doesn't exist.
91
+ */
92
+ export async function listWorkerVersions(creds, worker, fetchImpl) {
93
+ try {
94
+ const body = await cfFetch(
95
+ creds.token,
96
+ `/accounts/${creds.accountId}/workers/scripts/${encodeURIComponent(worker)}/versions`,
97
+ {},
98
+ fetchImpl,
99
+ );
100
+ return (body.result && body.result.items) || [];
101
+ } catch (e) {
102
+ if (e.status === 404) {
103
+ throw Object.assign(
104
+ new Error(`Worker "${worker}" not found in account ${creds.accountId}.`),
105
+ { exitCode: 1 },
106
+ );
107
+ }
108
+ throw e;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Return the version-id prefix used to build the workers.dev preview URL.
114
+ * CF documents the preview URL as `<version-id-prefix>-<worker>.<subdomain>.workers.dev`
115
+ * with the prefix being the first 8 chars of the full UUID, OR (more
116
+ * recently) the first hyphen-separated segment. We use the first 8 chars,
117
+ * which matches both formats since UUIDs begin with 8 hex chars.
118
+ */
119
+ export function versionPreviewPrefix(versionId) {
120
+ const s = String(versionId || '');
121
+ // UUID first segment is 8 hex chars.
122
+ const m = s.match(/^[0-9a-f]{8}/i);
123
+ if (!m) {
124
+ throw Object.assign(
125
+ new Error(`version_id "${s}" is not a valid UUID prefix`),
126
+ { exitCode: 1 },
127
+ );
128
+ }
129
+ return m[0];
130
+ }
131
+
132
+ /**
133
+ * Build the workers.dev preview URL for a (version, worker, subdomain) trio.
134
+ * https://<prefix>-<worker>.<subdomain>.workers.dev
135
+ */
136
+ export function previewHostname(versionId, worker, subdomain) {
137
+ const prefix = versionPreviewPrefix(versionId);
138
+ return `${prefix}-${worker}.${subdomain}.workers.dev`;
139
+ }
140
+
141
+ /**
142
+ * List Worker domains (Custom Domains bound to the script). Returns the
143
+ * result array, possibly empty.
144
+ */
145
+ export async function listWorkerDomains(creds, worker, fetchImpl) {
146
+ const q = new URLSearchParams({ service: worker });
147
+ const body = await cfFetch(
148
+ creds.token,
149
+ `/accounts/${creds.accountId}/workers/domains?${q.toString()}`,
150
+ {},
151
+ fetchImpl,
152
+ );
153
+ return body.result || [];
154
+ }
155
+
156
+ /**
157
+ * Find a Worker domain binding by hostname (case-insensitive). Returns
158
+ * the binding object or null. Used for idempotency.
159
+ */
160
+ export async function findWorkerDomain(creds, hostname, fetchImpl) {
161
+ const target = String(hostname || '').toLowerCase();
162
+ const body = await cfFetch(
163
+ creds.token,
164
+ `/accounts/${creds.accountId}/workers/domains`,
165
+ {},
166
+ fetchImpl,
167
+ );
168
+ const list = body.result || [];
169
+ return list.find((d) => String(d.hostname || '').toLowerCase() === target) || null;
170
+ }
171
+
172
+ /**
173
+ * Bind a hostname to a Worker as a Custom Domain. Idempotent: if the
174
+ * binding already exists pointing at the same worker, returns
175
+ * { action: 'unchanged', record }.
176
+ */
177
+ export async function bindWorkerCustomDomain(creds, hostname, worker, zoneId, fetchImpl) {
178
+ const existing = await findWorkerDomain(creds, hostname, fetchImpl);
179
+ if (existing) {
180
+ if (existing.service === worker) {
181
+ return { action: 'unchanged', record: existing };
182
+ }
183
+ // Different worker — rebinding is a delete + create rather than
184
+ // an update; the CF API does not expose a PATCH on this resource.
185
+ await cfFetch(
186
+ creds.token,
187
+ `/accounts/${creds.accountId}/workers/domains/${existing.id}`,
188
+ { method: 'DELETE' },
189
+ fetchImpl,
190
+ );
191
+ }
192
+ const body = await cfFetch(
193
+ creds.token,
194
+ `/accounts/${creds.accountId}/workers/domains`,
195
+ {
196
+ method: 'PUT',
197
+ body: JSON.stringify({
198
+ environment: 'production',
199
+ hostname,
200
+ service: worker,
201
+ zone_id: zoneId,
202
+ }),
203
+ },
204
+ fetchImpl,
205
+ );
206
+ return { action: existing ? 'rebound' : 'created', record: body.result };
207
+ }
208
+
209
+ /**
210
+ * Remove a Worker Custom Domain binding by hostname. Idempotent — no-op
211
+ * when nothing is bound.
212
+ */
213
+ export async function unbindWorkerCustomDomain(creds, hostname, fetchImpl) {
214
+ const existing = await findWorkerDomain(creds, hostname, fetchImpl);
215
+ if (!existing) return { action: 'unchanged' };
216
+ await cfFetch(
217
+ creds.token,
218
+ `/accounts/${creds.accountId}/workers/domains/${existing.id}`,
219
+ { method: 'DELETE' },
220
+ fetchImpl,
221
+ );
222
+ return { action: 'deleted', record: existing };
223
+ }
224
+
225
+ /**
226
+ * Check whether a Worker script exists in the account.
227
+ */
228
+ export async function workerScriptExists(creds, worker, fetchImpl) {
229
+ try {
230
+ await cfFetch(
231
+ creds.token,
232
+ `/accounts/${creds.accountId}/workers/scripts/${encodeURIComponent(worker)}`,
233
+ {},
234
+ fetchImpl,
235
+ );
236
+ return true;
237
+ } catch (e) {
238
+ if (e.status === 404) return false;
239
+ throw e;
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Router-worker source. Reads `STAGING_TARGET` from env (set per-version
245
+ * via the script binding) and proxies the incoming request through.
246
+ *
247
+ * Two important details:
248
+ * 1. We preserve the request method, headers, body, and pathname/query
249
+ * so the staging hostname is fully transparent.
250
+ * 2. We strip the `Host:` header on the outgoing fetch so the upstream
251
+ * Worker sees its own hostname (and the assets handler picks the
252
+ * right file). The fetch API does this implicitly when we change
253
+ * the URL host, but we set it explicitly for clarity.
254
+ */
255
+ export const ROUTER_SOURCE = String.raw`// staging-router — proxies staging.<site> -> STAGING_TARGET workers.dev URL.
256
+ // Generated by @stravica-ai/engineering-pa-cli (pa staging-alias).
257
+ export default {
258
+ async fetch(request, env, ctx) {
259
+ const target = env && env.STAGING_TARGET;
260
+ if (!target) {
261
+ return new Response('staging-router: STAGING_TARGET not configured', { status: 503 });
262
+ }
263
+ const inUrl = new URL(request.url);
264
+ const outUrl = new URL(inUrl.pathname + inUrl.search, 'https://' + target);
265
+ const init = {
266
+ method: request.method,
267
+ headers: new Headers(request.headers),
268
+ redirect: 'manual',
269
+ };
270
+ init.headers.delete('host');
271
+ if (!/^(GET|HEAD)$/i.test(request.method)) {
272
+ init.body = request.body;
273
+ }
274
+ const upstream = await fetch(outUrl.toString(), init);
275
+ return new Response(upstream.body, {
276
+ status: upstream.status,
277
+ statusText: upstream.statusText,
278
+ headers: upstream.headers,
279
+ });
280
+ },
281
+ };
282
+ `;
283
+
284
+ /**
285
+ * Upload the router worker with `STAGING_TARGET` bound to the given target
286
+ * hostname. Uses the modules-format multipart upload.
287
+ *
288
+ * `compatibility_date` defaults to 2026-05-21 — the day this CLI was
289
+ * written. Workers Builds normally pins a date; we pin ours so the
290
+ * router behaves consistently regardless of when it was first deployed.
291
+ *
292
+ * Returns { etag, deployedTarget }.
293
+ */
294
+ export async function uploadRouterWorker(creds, worker, targetHost, fetchImpl, opts = {}) {
295
+ const compatDate = opts.compatibilityDate || '2026-05-21';
296
+ const metadata = {
297
+ main_module: 'worker.mjs',
298
+ compatibility_date: compatDate,
299
+ bindings: [
300
+ { type: 'plain_text', name: 'STAGING_TARGET', text: targetHost },
301
+ ],
302
+ };
303
+ const form = new FormData();
304
+ form.set('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
305
+ form.set(
306
+ 'worker.mjs',
307
+ new Blob([ROUTER_SOURCE], { type: 'application/javascript+module' }),
308
+ 'worker.mjs',
309
+ );
310
+ const fetchFn = fetchImpl || globalThis.fetch;
311
+ const url = `https://api.cloudflare.com/client/v4/accounts/${creds.accountId}/workers/scripts/${encodeURIComponent(worker)}`;
312
+ const res = await fetchFn(url, {
313
+ method: 'PUT',
314
+ headers: { Authorization: `Bearer ${creds.token}` },
315
+ body: form,
316
+ });
317
+ const text = await res.text();
318
+ let body;
319
+ try { body = text ? JSON.parse(text) : {}; } catch {
320
+ throw Object.assign(
321
+ new Error(`CF worker upload: non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`),
322
+ { exitCode: 3 },
323
+ );
324
+ }
325
+ if (!res.ok || body.success === false) {
326
+ const detail = (body.errors || []).map((e) => `${e.code}: ${e.message}`).join('; ')
327
+ || `HTTP ${res.status}`;
328
+ throw Object.assign(
329
+ new Error(`CF worker upload PUT /workers/scripts/${worker} failed: ${detail}`),
330
+ { exitCode: 2, status: res.status, body },
331
+ );
332
+ }
333
+ return {
334
+ etag: body.result && body.result.etag,
335
+ deployedTarget: targetHost,
336
+ };
337
+ }
338
+
339
+ /**
340
+ * Delete a Worker script entirely. Used by `unset` to clean up the
341
+ * router worker. Idempotent: 404 is treated as success.
342
+ */
343
+ export async function deleteWorkerScript(creds, worker, fetchImpl) {
344
+ try {
345
+ await cfFetch(
346
+ creds.token,
347
+ `/accounts/${creds.accountId}/workers/scripts/${encodeURIComponent(worker)}?force=true`,
348
+ { method: 'DELETE' },
349
+ fetchImpl,
350
+ );
351
+ return { action: 'deleted' };
352
+ } catch (e) {
353
+ if (e.status === 404) return { action: 'unchanged' };
354
+ throw e;
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Read the current `STAGING_TARGET` binding on the router worker by
360
+ * fetching its settings. Returns null when the worker doesn't exist
361
+ * or the binding is absent.
362
+ */
363
+ export async function readRouterTarget(creds, worker, fetchImpl) {
364
+ let body;
365
+ try {
366
+ body = await cfFetch(
367
+ creds.token,
368
+ `/accounts/${creds.accountId}/workers/scripts/${encodeURIComponent(worker)}/settings`,
369
+ {},
370
+ fetchImpl,
371
+ );
372
+ } catch (e) {
373
+ if (e.status === 404) return null;
374
+ throw e;
375
+ }
376
+ const bindings = (body.result && body.result.bindings) || [];
377
+ const target = bindings.find((b) => b && b.name === 'STAGING_TARGET');
378
+ if (!target) return null;
379
+ return target.text || target.value || null;
380
+ }
@@ -0,0 +1,36 @@
1
+ // list.mjs — `pa staging-alias list`
2
+ //
3
+ // Status across all registered sites. Per-site failures are surfaced as
4
+ // `error` fields on the entry rather than aborting the whole listing.
5
+
6
+ import { allSites } from '../sites.mjs';
7
+ import { loadCloudflareCreds } from '../../gsc/cloudflare.mjs';
8
+ import { buildStatus } from './status.mjs';
9
+
10
+ export async function runList(args, overrides = {}) {
11
+ if (args.length > 0) {
12
+ process.stderr.write(`[staging-alias list] unexpected arguments: ${args.join(' ')}\n`);
13
+ return 1;
14
+ }
15
+ const out = overrides.stdout || process.stdout;
16
+ const entries = [];
17
+
18
+ for (const site of allSites()) {
19
+ try {
20
+ const creds = await loadCloudflareCreds({ ...overrides, account: site.accountKey });
21
+ const report = await buildStatus(site, creds, overrides.fetchImpl);
22
+ entries.push(report);
23
+ } catch (e) {
24
+ entries.push({
25
+ site: site.hostname,
26
+ staging: `staging.${site.hostname}`,
27
+ accountKey: site.accountKey,
28
+ error: e.message,
29
+ });
30
+ }
31
+ }
32
+
33
+ out.write(JSON.stringify(entries, null, 2) + '\n');
34
+ // Any per-site error -> exit 2 so CI/operators notice.
35
+ return entries.some((e) => e.error || e.accountWarning) ? 2 : 0;
36
+ }