@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,97 @@
1
+ // research mark <done|aborted> <sessionId> [--no-promote | --promote]
2
+ //
3
+ // Set a terminal status on a session: `done` (finalised) or `aborted` (abandoned,
4
+ // e.g. the workflow's >10%-unsourced guardrail). The only verb that mutates an
5
+ // existing session's status, and both transitions are one-way — a session already
6
+ // terminal (done/aborted) is refused (exit 2).
7
+ //
8
+ // The status write goes through the store chokepoint (store.updateManifestStatus),
9
+ // which reads → guards the terminal transition → validates → persists.
10
+ //
11
+ // On `mark done` for a NORMAL or DEEP session we then promote answer.md into the
12
+ // operator knowledge library (w-021). Promotion NEVER fails the mark: the status
13
+ // is already `done` on disk before we touch the library, and promotion skips (with
14
+ // a note where relevant) rather than throwing on expected conditions. Light mode
15
+ // is never promoted — `--promote` on light is a usage error (exit 1). `--no-promote`
16
+ // skips promotion on normal/deep with a one-line note. `mark aborted` never promotes.
17
+ import { parseArgs } from 'node:util';
18
+ import { getDefaultStore } from '../store/index.mjs';
19
+ import { decidePromotion, promoteSession, refreshHint } from '../promote.mjs';
20
+
21
+ const SUBVERBS = ['done', 'aborted'];
22
+
23
+ function usage(msg) {
24
+ return Object.assign(new Error(`usage: research mark <done|aborted> <sessionId> [--no-promote | --promote]${msg ? `\n${msg}` : ''}`), { exitCode: 1 });
25
+ }
26
+
27
+ export async function markCommand(argv, { store, now = Date.now, stdout = process.stdout, promote = promoteSession, knowledgeDir } = {}) {
28
+ if (!store) store = await getDefaultStore();
29
+ let parsed;
30
+ try {
31
+ parsed = parseArgs({
32
+ args: argv,
33
+ options: {
34
+ 'no-promote': { type: 'boolean' },
35
+ promote: { type: 'boolean' },
36
+ },
37
+ allowPositionals: true,
38
+ strict: true,
39
+ });
40
+ } catch (e) {
41
+ throw usage(e.message);
42
+ }
43
+ const [subverb, id, ...extra] = parsed.positionals;
44
+ const noPromote = parsed.values['no-promote'] === true;
45
+ const forcePromote = parsed.values.promote === true;
46
+
47
+ if (!subverb) throw usage('a sub-verb is required (one of "done" or "aborted")');
48
+ if (!SUBVERBS.includes(subverb)) throw usage(`unknown sub-verb "${subverb}" (one of "done" or "aborted")`);
49
+ if (!id) throw usage('a <sessionId> is required');
50
+ if (extra.length) throw usage('too many arguments');
51
+ if (noPromote && forcePromote) throw usage('--no-promote and --promote are mutually exclusive');
52
+ if (!store.isValidSessionId(id)) throw usage(`"${id}" is not a valid sessionId`);
53
+
54
+ // The promotion decision reads the session's mode; peek at the manifest BEFORE
55
+ // mutating so that a `--promote` on a light session errors out (exit 1) WITHOUT
56
+ // having already flipped the status. Missing/malformed session → exit 2 here,
57
+ // same as updateManifestStatus would have surfaced.
58
+ if (subverb === 'done') {
59
+ const current = await store.readManifest(id);
60
+ // Throws exit 1 for the light + --promote hard-rule violation. `status` is
61
+ // the post-transition status (done) since that is what we are about to set.
62
+ decidePromotion({ mode: current.mode, status: 'done', noPromote, promote: forcePromote });
63
+ }
64
+
65
+ const nowIso = new Date(now()).toISOString();
66
+ // The sub-verb IS the target terminal status. Missing session → exit 2 (not
67
+ // found); already terminal → exit 2 (refused, one-way transition). This is the
68
+ // idempotency backstop: `mark done` on an already-done session is refused here,
69
+ // so promotion can never double-write.
70
+ const updated = await store.updateManifestStatus(id, subverb, nowIso);
71
+ stdout.write(`marked ${id} ${subverb} (updatedAt ${updated.updatedAt})\n`);
72
+
73
+ if (subverb !== 'done') return 0;
74
+
75
+ const decision = decidePromotion({ mode: updated.mode, status: updated.status, noPromote, promote: forcePromote });
76
+ if (decision.action === 'skip-silent') return 0; // light → silent by design
77
+ if (decision.action === 'skip-note') {
78
+ stdout.write(` --no-promote set — skipped knowledge-library promotion\n`);
79
+ return 0;
80
+ }
81
+
82
+ // action === 'promote' (normal/deep). Never fatal: report skips/errors as a
83
+ // note and still return success, since the session is already `done`.
84
+ try {
85
+ const result = await promote(id, { store, knowledgeDir });
86
+ if (result.status === 'promoted') {
87
+ stdout.write(` ${refreshHint(result.path)}\n`);
88
+ } else if (result.status === 'already-promoted') {
89
+ stdout.write(` already promoted to ${result.path} — no change\n`);
90
+ } else if (result.status === 'skipped-no-answer') {
91
+ stdout.write(` ${result.reason}\n`);
92
+ }
93
+ } catch (e) {
94
+ stdout.write(` promotion failed (non-fatal): ${e && e.message ? e.message : e}\n`);
95
+ }
96
+ return 0;
97
+ }
@@ -0,0 +1,69 @@
1
+ // research paths [--json]
2
+ //
3
+ // Emit the absolute paths the /research skill and the workflow scripts
4
+ // consume, resolved against the operator repo root and this package's install
5
+ // location:
6
+ //
7
+ // sessionsDir — where session dirs live (default: <repoRoot>/.cache/research/sessions)
8
+ // briefsDir — dispatch briefs the workflow feeds to searcher/extractor/…
9
+ // workflowsDir — the workflow scripts themselves (research-normal.js et al.)
10
+ // schemaDir — JSON schemas for manifest/plan/finding/sources/gates
11
+ // cli — the invocation prefix the workflow uses to run this CLI
12
+ // from a subagent (`pnpm exec research`)
13
+ //
14
+ // The /research skill calls this once at the top of a session and interpolates
15
+ // the values into the Workflow dispatch args, so nothing on the skill side has
16
+ // to know where the package is installed. `pa knowledge`-style JSON contract.
17
+ //
18
+ // Exit codes: 0 ok, 1 usage, 3 transport/IO (repo-root resolution failure surfaces
19
+ // with its own exitCode via getRepoRoot()).
20
+ import { parseArgs } from 'node:util';
21
+ import { join, resolve, dirname } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { defaultSessionsDir } from '../store/index.mjs';
24
+
25
+ function usage(msg) {
26
+ return Object.assign(new Error(`usage: research paths [--json]${msg ? `\n${msg}` : ''}`), { exitCode: 1 });
27
+ }
28
+
29
+ // The research package's own root — briefs/ and workflows/ ship inside it.
30
+ // commands/paths.mjs → ../ = src/research/. Resolved from import.meta.url so
31
+ // the answer is right whether the tool is running from the source tree, from
32
+ // dist/ under a published package, or from a symlinked pnpm workspace.
33
+ const __dirname = dirname(fileURLToPath(import.meta.url));
34
+ const PACKAGE_ROOT = resolve(__dirname, '..');
35
+
36
+ export async function resolvePaths() {
37
+ return {
38
+ sessionsDir: await defaultSessionsDir(),
39
+ briefsDir: join(PACKAGE_ROOT, 'briefs'),
40
+ workflowsDir: join(PACKAGE_ROOT, 'workflows'),
41
+ schemaDir: join(PACKAGE_ROOT, 'schema'),
42
+ cli: 'pnpm exec research',
43
+ };
44
+ }
45
+
46
+ export async function pathsCommand(argv, { stdout = process.stdout } = {}) {
47
+ let parsed;
48
+ try {
49
+ parsed = parseArgs({
50
+ args: argv,
51
+ options: { json: { type: 'boolean' } },
52
+ allowPositionals: false,
53
+ strict: true,
54
+ });
55
+ } catch (e) {
56
+ throw usage(e.message);
57
+ }
58
+ const paths = await resolvePaths();
59
+ if (parsed.values.json) {
60
+ stdout.write(JSON.stringify(paths, null, 2) + '\n');
61
+ return 0;
62
+ }
63
+ stdout.write(`sessionsDir: ${paths.sessionsDir}\n`);
64
+ stdout.write(`briefsDir: ${paths.briefsDir}\n`);
65
+ stdout.write(`workflowsDir: ${paths.workflowsDir}\n`);
66
+ stdout.write(`schemaDir: ${paths.schemaDir}\n`);
67
+ stdout.write(`cli: ${paths.cli}\n`);
68
+ return 0;
69
+ }
@@ -0,0 +1,86 @@
1
+ // research prune [--older-than <days>] [--status <status>] [--dry-run]
2
+ //
3
+ // Deletes sessions older than N days AND/OR matching a status (filters AND
4
+ // together). At least one filter is required — a bare `prune` is a usage error
5
+ // so a fat-fingered command can never wipe every session. --dry-run previews.
6
+ // An explicit filter that matches nothing exits 2 (operational).
7
+ import { parseArgs } from 'node:util';
8
+ import { getDefaultStore } from '../store/index.mjs';
9
+ import { STATUSES } from '../store/manifest.mjs';
10
+ import { table, truncate } from '../format.mjs';
11
+
12
+ function usage(msg) {
13
+ return Object.assign(new Error(`usage: research prune [--older-than <days>] [--status <${STATUSES.join('|')}>] [--dry-run] (at least one filter required)${msg ? `\n${msg}` : ''}`), { exitCode: 1 });
14
+ }
15
+
16
+ const DAY_MS = 86_400_000;
17
+
18
+ // PURE: choose which sessions to prune. `sessions` is the listSessions() shape
19
+ // (each { id, manifest, error }). A session matches only if it satisfies EVERY
20
+ // provided filter. Malformed sessions (no manifest) are never matched — we won't
21
+ // delete what we can't evaluate. `nowMs` is injected for testability.
22
+ export function selectPruneTargets(sessions, { olderThanDays, status, nowMs }) {
23
+ const cutoff = olderThanDays != null ? nowMs - olderThanDays * DAY_MS : null;
24
+ return sessions.filter((s) => {
25
+ if (!s.manifest) return false;
26
+ if (status != null && s.manifest.status !== status) return false;
27
+ if (cutoff != null) {
28
+ const created = Date.parse(s.manifest.createdAt);
29
+ if (Number.isNaN(created) || created >= cutoff) return false;
30
+ }
31
+ return true;
32
+ });
33
+ }
34
+
35
+ export async function pruneCommand(argv, { store, now = Date.now, stdout = process.stdout, stderr = process.stderr } = {}) {
36
+ if (!store) store = await getDefaultStore();
37
+ let parsed;
38
+ try {
39
+ parsed = parseArgs({
40
+ args: argv,
41
+ options: {
42
+ 'older-than': { type: 'string' },
43
+ status: { type: 'string' },
44
+ 'dry-run': { type: 'boolean' },
45
+ },
46
+ allowPositionals: false,
47
+ strict: true,
48
+ });
49
+ } catch (e) {
50
+ throw usage(e.message);
51
+ }
52
+ const v = parsed.values;
53
+
54
+ const hasAge = v['older-than'] != null;
55
+ const hasStatus = v.status != null;
56
+ if (!hasAge && !hasStatus) throw usage('provide --older-than and/or --status');
57
+
58
+ let olderThanDays;
59
+ if (hasAge) {
60
+ olderThanDays = Number(v['older-than']);
61
+ if (!Number.isInteger(olderThanDays) || olderThanDays < 0) throw usage('--older-than must be a non-negative integer (days)');
62
+ }
63
+ if (hasStatus && !STATUSES.includes(v.status)) throw usage(`--status must be one of ${STATUSES.join(' | ')}`);
64
+
65
+ const sessions = await store.listSessions();
66
+ const targets = selectPruneTargets(sessions, { olderThanDays, status: v.status, nowMs: now() });
67
+
68
+ if (targets.length === 0) {
69
+ // Explicit filter matched nothing → operational failure (exit 2).
70
+ stderr.write('prune: no sessions matched the filter\n');
71
+ return 2;
72
+ }
73
+
74
+ const rows = targets.map((s) => [s.id, s.manifest.mode, s.manifest.status, s.manifest.createdAt, truncate(s.manifest.question, 40)]);
75
+
76
+ if (v['dry-run']) {
77
+ stdout.write(`DRY RUN — ${targets.length} session(s) would be deleted:\n`);
78
+ stdout.write(table(['SESSION', 'MODE', 'STATUS', 'CREATED', 'QUESTION'], rows));
79
+ return 0;
80
+ }
81
+
82
+ for (const s of targets) await store.deleteSession(s.id);
83
+ stdout.write(`deleted ${targets.length} session(s):\n`);
84
+ stdout.write(table(['SESSION', 'MODE', 'STATUS', 'CREATED', 'QUESTION'], rows));
85
+ return 0;
86
+ }
@@ -0,0 +1,94 @@
1
+ // research run — create a session (dir + manifest + skeleton plan), validate
2
+ // inputs, print the plan, return. Does NOT orchestrate research (build-spec §3).
3
+ // --dry-run validates + prints without persisting; it is the ONLY branch that
4
+ // does not write.
5
+ import { parseArgs } from 'node:util';
6
+ import { getDefaultStore } from '../store/index.mjs';
7
+ import { MODES, GATE_POLICIES, OUTPUT_MODES } from '../store/manifest.mjs';
8
+ import { skeletonPlan } from '../store/plan.mjs';
9
+ import { emptySources } from '../store/sources.mjs';
10
+ import { emptyGates } from '../store/gates.mjs';
11
+ import { manifestLine, planBlock } from '../format.mjs';
12
+
13
+ // Mode-derived scope recorded in the manifest budget (build-spec §4). Not
14
+ // enforced by the CLI — it records what the run was scoped to.
15
+ export const MODE_BUDGETS = {
16
+ light: { maxSubQuestions: 0, maxDeepeningRounds: 0, wallClockMinutes: 2 },
17
+ normal: { maxSubQuestions: 4, maxDeepeningRounds: 1, wallClockMinutes: 10 },
18
+ deep: { maxSubQuestions: 12, maxDeepeningRounds: 3, wallClockMinutes: 45 },
19
+ };
20
+
21
+ function usage(msg) {
22
+ return Object.assign(new Error(`usage: research run --mode <light|normal|deep> --question "..." [--gate <operatorPresent|background|worker>] [--intent "..."] [--output <shortAnswer|article|structured>] [--dry-run]${msg ? `\n${msg}` : ''}`), { exitCode: 1 });
23
+ }
24
+
25
+ // Build a fresh manifest from validated inputs. Pure given a clock + id.
26
+ export function buildManifest({ sessionId, mode, question, intent, gatePolicy, outputMode, nowIso }) {
27
+ const m = {
28
+ sessionId,
29
+ mode,
30
+ question,
31
+ gatePolicy,
32
+ status: 'draft',
33
+ outputMode,
34
+ budget: { ...MODE_BUDGETS[mode] },
35
+ assumptions: [],
36
+ createdAt: nowIso,
37
+ updatedAt: nowIso,
38
+ };
39
+ if (intent) m.intent = intent;
40
+ return m;
41
+ }
42
+
43
+ export async function runCommand(argv, { store, now = Date.now, stdout = process.stdout } = {}) {
44
+ if (!store) store = await getDefaultStore();
45
+ let parsed;
46
+ try {
47
+ parsed = parseArgs({
48
+ args: argv,
49
+ options: {
50
+ mode: { type: 'string' },
51
+ question: { type: 'string' },
52
+ gate: { type: 'string' },
53
+ intent: { type: 'string' },
54
+ output: { type: 'string' },
55
+ 'dry-run': { type: 'boolean' },
56
+ },
57
+ allowPositionals: false,
58
+ strict: true,
59
+ });
60
+ } catch (e) {
61
+ throw usage(e.message);
62
+ }
63
+ const v = parsed.values;
64
+
65
+ if (!v.mode) throw usage('--mode is required');
66
+ if (!MODES.includes(v.mode)) throw usage(`--mode must be one of ${MODES.join(' | ')}`);
67
+ if (!v.question || v.question.trim() === '') throw usage('--question is required and must be non-empty');
68
+
69
+ const gatePolicy = v.gate ?? 'worker';
70
+ if (!GATE_POLICIES.includes(gatePolicy)) throw usage(`--gate must be one of ${GATE_POLICIES.join(' | ')}`);
71
+
72
+ const outputMode = v.output ?? 'shortAnswer';
73
+ if (!OUTPUT_MODES.includes(outputMode)) throw usage(`--output must be one of ${OUTPUT_MODES.join(' | ')}`);
74
+
75
+ const nowIso = new Date(now()).toISOString();
76
+ const sessionId = store.newSessionId(now());
77
+ const manifest = buildManifest({ sessionId, mode: v.mode, question: v.question, intent: v.intent, gatePolicy, outputMode, nowIso });
78
+ const plan = skeletonPlan(v.mode);
79
+
80
+ if (v['dry-run']) {
81
+ stdout.write('DRY RUN — nothing persisted.\n\n');
82
+ stdout.write(manifestLine(manifest));
83
+ stdout.write('\n');
84
+ stdout.write(planBlock(plan));
85
+ return 0;
86
+ }
87
+
88
+ await store.createSession({ manifest, plan, sources: emptySources(), gates: emptyGates() });
89
+ stdout.write(`created ${sessionId}\n\n`);
90
+ stdout.write(manifestLine(manifest));
91
+ stdout.write('\n');
92
+ stdout.write(planBlock(plan));
93
+ return 0;
94
+ }
@@ -0,0 +1,43 @@
1
+ // research show <sessionId> — dump one session: manifest, plan, findings summary,
2
+ // gate summary, source count. --json emits the full assembled object.
3
+ import { parseArgs } from 'node:util';
4
+ import { existsSync } from 'node:fs';
5
+ import { getDefaultStore } from '../store/index.mjs';
6
+ import { manifestLine, planBlock, findingsSummary, gatesSummary } from '../format.mjs';
7
+
8
+ function usage(msg) {
9
+ return Object.assign(new Error(`usage: research show <sessionId> [--json]${msg ? `\n${msg}` : ''}`), { exitCode: 1 });
10
+ }
11
+
12
+ export async function showCommand(argv, { store, stdout = process.stdout } = {}) {
13
+ if (!store) store = await getDefaultStore();
14
+ let parsed;
15
+ try {
16
+ parsed = parseArgs({ args: argv, options: { json: { type: 'boolean' } }, allowPositionals: true, strict: true });
17
+ } catch (e) {
18
+ throw usage(e.message);
19
+ }
20
+ const id = parsed.positionals[0];
21
+ if (parsed.positionals.length !== 1) throw usage('exactly one <sessionId> is required');
22
+ if (!store.isValidSessionId(id)) throw usage(`"${id}" is not a valid sessionId`);
23
+
24
+ const manifest = await store.readManifest(id); // exit 2 if not found / malformed
25
+ const plan = existsSync(store.paths(id).plan) ? await store.readPlan(id) : null;
26
+ const sources = await store.readSources(id);
27
+ const gates = await store.readGates(id);
28
+ const findings = await store.listFindings(id);
29
+
30
+ if (parsed.values.json) {
31
+ stdout.write(JSON.stringify({ manifest, plan, sources, gates, findings }, null, 2) + '\n');
32
+ return 0;
33
+ }
34
+
35
+ stdout.write(manifestLine(manifest));
36
+ stdout.write('\n');
37
+ stdout.write(plan ? planBlock(plan) : 'plan: none\n');
38
+ stdout.write('\n');
39
+ stdout.write(findingsSummary(findings));
40
+ stdout.write(`sources: ${sources.items.length}\n`);
41
+ stdout.write(gatesSummary(gates));
42
+ return 0;
43
+ }
@@ -0,0 +1,120 @@
1
+ # Operator-present gate flow
2
+
3
+ How Dave clears human gates **live** during a research run, and how the same
4
+ in-session presence sweeps the queue of gates that earlier `background`-posture runs
5
+ left behind. This is the runbook for the `operatorPresent` gate policy (build-spec
6
+ §6). It is a **flow doc, not a code path** — the Playwright-MCP integration in the
7
+ skill body is a later concern; here we describe what the operator and Dave actually do.
8
+ **Baz** is the operator (the human in the session); **Dave** is the operator's model; a
9
+ **gate** is any fetch blocked by a login wall, paywall, Cloudflare/Turnstile challenge,
10
+ or captcha.
11
+
12
+ ---
13
+
14
+ ## 1. When to use `operatorPresent`
15
+
16
+ Reach for `--gate operatorPresent` when all three hold:
17
+
18
+ - **Baz is in-session with Dave** — a live, interactive run, not a cron/scheduled one.
19
+ - **The research will touch gated sources** — the answer depends on paywalled docs, a
20
+ logged-in dashboard, or a Cloudflare-fronted site that a headless fetch can't pass.
21
+ - **The answer is worth Baz's attention** — clearing a gate costs a few seconds of the
22
+ operator's time per gate; only spend it when getting the real source materially
23
+ improves the answer over dropping-with-caveat.
24
+
25
+ If Baz is not present, or the run is scheduled, use `background` (queue the gates) or
26
+ `worker` (the default for dispatched agents; park/resume is v2). A worker **never**
27
+ self-upgrades to headed browsing.
28
+
29
+ ## 2. The mechanics
30
+
31
+ Dave invokes the run, declaring the posture:
32
+
33
+ ```
34
+ /research <question> --mode <light|normal> --gate operatorPresent
35
+ ```
36
+
37
+ On a gate hit, Dave does **not** drop the source. Instead:
38
+
39
+ 1. Dave escalates to Baz in plain language, naming the URL and the obstacle — e.g.
40
+ *"Cloudflare check on docs.example.com — can you clear it?"*
41
+ 2. Baz acts in the **shared headed browser** (a real Playwright MCP session Dave
42
+ drives): Dave calls the Playwright MCP browser (in prose: `browser_navigate` to the
43
+ URL, then `browser_snapshot` so Baz sees the page; Baz solves the challenge or signs
44
+ in; Dave re-snapshots to confirm the content is now reachable).
45
+ 3. Dave reads the now-ungated content and continues the fetch as normal — the source is
46
+ cited like any other.
47
+
48
+ **The MCP browser is shared parent state.** There is exactly **one** headed consumer at
49
+ a time, and it is Dave (the parent). Subagents — the `research-normal.js` workflow's
50
+ searchers — run headless and **never** touch it. That has a hard consequence:
51
+
52
+ > **Do not run a normal-mode workflow under `operatorPresent`.** The workflow's searcher
53
+ > subagents cannot attach to Dave's headed Playwright session, so they can't benefit from
54
+ > a live clearance. Operator-present runs are effectively **light mode** (Dave does the
55
+ > fetching inline, on the shared browser) or a single-worker fetch that Dave supervises.
56
+ > A normal-mode run that expects gated sources should use `background` and be swept later
57
+ > (§3).
58
+
59
+ ## 3. Sweeping the queued `background` gates
60
+
61
+ `background`-posture runs don't block on gates: each searcher drops the source and the
62
+ workflow's Finalise phase persists the record via `research gates --append`, so the
63
+ gate lands in `sessions/<id>/gates.json` with `status: pending`. Those records
64
+ accumulate across runs. A later operator-present session drains them:
65
+
66
+ 1. **See what's queued** — across all sessions, or one:
67
+
68
+ ```sh
69
+ research gates --list # every session's pending/retrying gates
70
+ research gates --list <id> # just one session
71
+ ```
72
+
73
+ 2. **Clear each gate Baz wants** — for a chosen row, Dave drives the shared Playwright
74
+ MCP browser to the `url` (in prose: `browser_navigate` + `browser_snapshot`), Baz
75
+ clears the challenge/login, and Dave captures the page. Because browser sessions
76
+ don't transfer between processes, **clearance produces an artifact, not a cleared
77
+ path**: Dave saves the fetched content to `sessions/<id>/gated/<hash>.md` so it can be
78
+ re-read exactly like a fetch.
79
+
80
+ 3. **Mark the swept items** — flag the session's eligible gates for follow-up:
81
+
82
+ ```sh
83
+ research gates --retry <id> # marks pending/retrying items as `retrying`
84
+ ```
85
+
86
+ In v1, `--retry` **only marks** — it does not re-run the pipeline. `retrying` means
87
+ *"queued for the operator to hand-run the fetch"*; Dave (or Baz) reads the saved
88
+ `gated/<hash>.md` artifact and folds it into the answer by hand. The automated
89
+ re-run of just the parked sub-questions is v2 (§4).
90
+
91
+ ## 4. What v1 covers vs what v2 adds
92
+
93
+ **v1 (this and w-018):**
94
+ - `background`-posture gates queue automatically via `research gates --append` (workflow
95
+ Finalise phase).
96
+ - `operatorPresent` runs skip gates live: Dave escalates, Baz clears in the shared headed
97
+ Playwright browser, the fetch continues.
98
+ - `research gates --list` aggregates the queue; `research gates --retry` marks items for
99
+ operator follow-up; clearance content is saved to `sessions/<id>/gated/<hash>.md`.
100
+
101
+ **v2 (deferred):**
102
+ - Worker-posture **park → escalate → resume** automation: a dispatched worker parks the
103
+ gated sub-question, checkpoints `GATE: {...}` up its channel, continues its remaining
104
+ queue, and is resumed from the clearance artifact.
105
+ - A `research resume <sessionId>` verb that re-runs extract+verify for just the parked
106
+ sub-questions against `gated/<hash>.md`.
107
+ - `research gates --retry` triggering that automated re-run rather than only marking.
108
+
109
+ ## 5. Anti-patterns
110
+
111
+ - **Do not try to defeat a gate from a worker.** Spec §6: a worker never self-upgrades to
112
+ headed browsing. Background workers drop-and-log; that is correct, not a failure.
113
+ - **Do not run headed Playwright from a subagent.** The MCP browser is shared parent
114
+ state with one headed consumer. Only Dave (the parent) drives it; searchers stay
115
+ headless.
116
+ - **Do not auto-approve gate clearances.** The entire point of `operatorPresent` is live
117
+ consent — Baz decides which gates to clear. Never script past a login/paywall on Baz's
118
+ behalf without the explicit ask.
119
+ - **Do not run `operatorPresent` for a normal-mode workflow.** Its searchers can't attach
120
+ to the shared browser (§2). Use `background` + a later sweep instead.
@@ -0,0 +1,59 @@
1
+ // Pure presentation helpers. No I/O — every function returns a string. Commands
2
+ // write these to their injected out/err streams. Keeps rendering testable and
3
+ // keeps the exit-code/side-effect logic out of the formatting layer.
4
+
5
+ export function truncate(s, n) {
6
+ const one = String(s ?? '').replace(/\s+/g, ' ').trim();
7
+ return one.length > n ? one.slice(0, n - 1) + '…' : one;
8
+ }
9
+
10
+ // A compact fixed-width table. rows is an array of arrays of strings.
11
+ export function table(headers, rows) {
12
+ const all = [headers, ...rows];
13
+ const widths = headers.map((_, c) => Math.max(...all.map((r) => String(r[c] ?? '').length)));
14
+ const line = (r) => r.map((cell, c) => String(cell ?? '').padEnd(widths[c])).join(' ').trimEnd();
15
+ const out = [line(headers), widths.map((w) => '-'.repeat(w)).join(' ').trimEnd()];
16
+ for (const r of rows) out.push(line(r));
17
+ return out.join('\n') + '\n';
18
+ }
19
+
20
+ export function manifestLine(m) {
21
+ return [
22
+ `session ${m.sessionId}`,
23
+ ` mode: ${m.mode}`,
24
+ ` status: ${m.status}`,
25
+ ` gatePolicy: ${m.gatePolicy}`,
26
+ ` outputMode: ${m.outputMode}`,
27
+ ` question: ${m.question}`,
28
+ m.intent ? ` intent: ${m.intent}` : null,
29
+ ` budget: subQ=${m.budget.maxSubQuestions} rounds=${m.budget.maxDeepeningRounds} wallMin=${m.budget.wallClockMinutes}`,
30
+ m.assumptions.length ? ` assumptions: ${m.assumptions.join('; ')}` : null,
31
+ ` created: ${m.createdAt}`,
32
+ ` updated: ${m.updatedAt}`,
33
+ ].filter((x) => x != null).join('\n') + '\n';
34
+ }
35
+
36
+ export function planBlock(p) {
37
+ const lines = [`plan: ${p.subQuestions.length} sub-question(s), deepeningRounds=${p.deepeningRounds}, verificationTier=${p.verificationTier}`];
38
+ for (const sq of p.subQuestions) {
39
+ const dep = sq.dependsOn.length ? ` (depends on ${sq.dependsOn.join(', ')})` : '';
40
+ lines.push(` [${sq.id}] ${sq.kind}${dep}: ${sq.text}`);
41
+ }
42
+ return lines.join('\n') + '\n';
43
+ }
44
+
45
+ export function findingsSummary(findings) {
46
+ if (findings.length === 0) return 'findings: none yet\n';
47
+ const lines = [`findings: ${findings.length}`];
48
+ for (const f of findings) {
49
+ const votes = f.verificationVotes.length ? ` votes=${f.verificationVotes.map((v) => v.outcome).join('/')}` : '';
50
+ lines.push(` [${f.subQuestionId}] confidence=${f.confidence}${f.unsourced ? ' UNSOURCED' : ''}${votes}: ${truncate(f.summary, 60)}`);
51
+ }
52
+ return lines.join('\n') + '\n';
53
+ }
54
+
55
+ export function gatesSummary(gates) {
56
+ const counts = { pending: 0, retrying: 0, resolved: 0, failed: 0 };
57
+ for (const g of gates.queue) counts[g.status]++;
58
+ return `gates: ${gates.queue.length} total (pending=${counts.pending}, retrying=${counts.retrying}, resolved=${counts.resolved}, failed=${counts.failed})\n`;
59
+ }