supipowers 1.5.2 → 2.0.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 (340) hide show
  1. package/README.md +14 -8
  2. package/bin/install.mjs +20 -5
  3. package/bin/install.ts +95 -0
  4. package/package.json +8 -4
  5. package/skills/context-mode/SKILL.md +17 -10
  6. package/skills/harness/SKILL.md +94 -0
  7. package/skills/ui-design/SKILL.md +63 -0
  8. package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
  9. package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
  10. package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
  11. package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
  12. package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
  13. package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
  14. package/skills/ultraplan-discover/SKILL.md +96 -0
  15. package/skills/ultraplan-intake/SKILL.md +89 -0
  16. package/skills/ultraplan-research/SKILL.md +129 -0
  17. package/skills/ultraplan-review/SKILL.md +86 -0
  18. package/skills/ultraplan-review-scope/SKILL.md +111 -0
  19. package/skills/ultraplan-review-structure/SKILL.md +120 -0
  20. package/skills/ultraplan-review-tdd/SKILL.md +142 -0
  21. package/skills/ultraplan-scout/SKILL.md +110 -0
  22. package/skills/ultraplan-synthesize/SKILL.md +124 -0
  23. package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
  24. package/src/ai/schema-text.ts +129 -0
  25. package/src/ai/structured-output.ts +274 -0
  26. package/src/ai/template.ts +27 -0
  27. package/src/bootstrap.ts +63 -28
  28. package/src/commands/agents.ts +149 -45
  29. package/src/commands/ai-review.ts +251 -30
  30. package/src/commands/clear.ts +434 -0
  31. package/src/commands/commit.ts +1 -0
  32. package/src/commands/config.ts +242 -44
  33. package/src/commands/context.ts +55 -28
  34. package/src/commands/doctor.ts +234 -6
  35. package/src/commands/fix-pr.ts +306 -131
  36. package/src/commands/generate.ts +111 -21
  37. package/src/commands/memory.ts +192 -0
  38. package/src/commands/model-picker.ts +28 -21
  39. package/src/commands/model.ts +19 -9
  40. package/src/commands/optimize-context.ts +408 -29
  41. package/src/commands/plan.ts +2 -0
  42. package/src/commands/qa.ts +312 -137
  43. package/src/commands/release.ts +259 -76
  44. package/src/commands/review.ts +293 -59
  45. package/src/commands/status.ts +200 -13
  46. package/src/commands/supi.ts +3 -35
  47. package/src/commands/ui-design.ts +394 -0
  48. package/src/commands/ultraplan.ts +1518 -0
  49. package/src/commands/update.ts +86 -0
  50. package/src/config/defaults.ts +62 -0
  51. package/src/config/loader.ts +448 -60
  52. package/src/config/schema.ts +108 -2
  53. package/src/context/optimizer.ts +25 -33
  54. package/src/context/rule-renderer.ts +223 -0
  55. package/src/context/savings.ts +258 -0
  56. package/src/context/startup-check.ts +380 -0
  57. package/src/context/startup-optimizer.ts +355 -0
  58. package/src/context/tokenignore.ts +146 -0
  59. package/src/context-mode/cache-handle.ts +49 -0
  60. package/src/context-mode/cache-preview.ts +71 -0
  61. package/src/context-mode/cache-store.ts +738 -0
  62. package/src/context-mode/compressor.ts +131 -26
  63. package/src/context-mode/dedup.ts +108 -0
  64. package/src/context-mode/detector.ts +35 -4
  65. package/src/context-mode/event-extractor.ts +14 -12
  66. package/src/context-mode/event-store.ts +91 -36
  67. package/src/context-mode/hooks.ts +798 -56
  68. package/src/context-mode/knowledge/store.ts +255 -11
  69. package/src/context-mode/memory-store.ts +325 -0
  70. package/src/context-mode/metrics-recorder.ts +158 -0
  71. package/src/context-mode/metrics-store.ts +765 -0
  72. package/src/context-mode/model.ts +24 -0
  73. package/src/context-mode/processor-keys.ts +29 -0
  74. package/src/context-mode/processors/build.ts +66 -0
  75. package/src/context-mode/processors/docker.ts +57 -0
  76. package/src/context-mode/processors/git.ts +111 -0
  77. package/src/context-mode/processors/json.ts +112 -0
  78. package/src/context-mode/processors/k8s.ts +67 -0
  79. package/src/context-mode/processors/lint.ts +67 -0
  80. package/src/context-mode/processors/log.ts +86 -0
  81. package/src/context-mode/processors/registry.ts +116 -0
  82. package/src/context-mode/processors/test-runner.ts +102 -0
  83. package/src/context-mode/processors/types.ts +20 -0
  84. package/src/context-mode/repomap.ts +400 -0
  85. package/src/context-mode/routing.ts +97 -24
  86. package/src/context-mode/sandbox/runners.ts +5 -1
  87. package/src/context-mode/snapshot-builder.ts +106 -11
  88. package/src/context-mode/source-hash.ts +173 -0
  89. package/src/context-mode/tool-name.ts +11 -0
  90. package/src/context-mode/tools.ts +654 -22
  91. package/src/context-mode/web/fetcher.ts +31 -12
  92. package/src/debug/logger.ts +2 -1
  93. package/src/deps/registry.ts +1 -1
  94. package/src/discipline/failure-summarizer.ts +170 -0
  95. package/src/discipline/failure-taxonomy.ts +131 -0
  96. package/src/discipline/workflow-invariants.ts +125 -0
  97. package/src/discovery/index.ts +31 -0
  98. package/src/discovery/lsp.ts +87 -0
  99. package/src/discovery/rank.ts +144 -0
  100. package/src/discovery/sources.ts +89 -0
  101. package/src/discovery/workflow.ts +87 -0
  102. package/src/docs/contracts.ts +39 -0
  103. package/src/docs/drift.ts +117 -87
  104. package/src/fix-pr/assessment.ts +200 -0
  105. package/src/fix-pr/contracts.ts +47 -0
  106. package/src/fix-pr/fetch-comments.ts +80 -0
  107. package/src/fix-pr/prompt-builder.ts +58 -40
  108. package/src/fix-pr/scripts/exec.ts +34 -0
  109. package/src/fix-pr/scripts/trigger-review.ts +106 -0
  110. package/src/fix-pr/scripts/wait-and-check.ts +108 -0
  111. package/src/fix-pr/types.ts +4 -0
  112. package/src/git/branch-finish.ts +5 -0
  113. package/src/git/commit-contract.ts +83 -0
  114. package/src/git/commit.ts +121 -184
  115. package/src/git/status.ts +62 -8
  116. package/src/harness/anti_slop/architecture-parser.ts +210 -0
  117. package/src/harness/anti_slop/backend-factory.ts +30 -0
  118. package/src/harness/anti_slop/backend.ts +140 -0
  119. package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
  120. package/src/harness/anti_slop/fallow-adapter.ts +305 -0
  121. package/src/harness/anti_slop/installer.ts +227 -0
  122. package/src/harness/anti_slop/queue.ts +216 -0
  123. package/src/harness/anti_slop/recommend.ts +84 -0
  124. package/src/harness/anti_slop/score.ts +180 -0
  125. package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
  126. package/src/harness/artifacts/agents-md.ts +88 -0
  127. package/src/harness/artifacts/checks-wiring.ts +57 -0
  128. package/src/harness/artifacts/docs-tree.ts +79 -0
  129. package/src/harness/artifacts/lint-configs.ts +136 -0
  130. package/src/harness/artifacts/review-agents.ts +67 -0
  131. package/src/harness/bare-entry.ts +108 -0
  132. package/src/harness/command.ts +1010 -0
  133. package/src/harness/default-agents/design.md +23 -0
  134. package/src/harness/default-agents/discover.md +18 -0
  135. package/src/harness/default-agents/implement.md +24 -0
  136. package/src/harness/default-agents/plan.md +19 -0
  137. package/src/harness/default-agents/research.md +21 -0
  138. package/src/harness/default-agents/validate.md +22 -0
  139. package/src/harness/gc/reporter.ts +28 -0
  140. package/src/harness/gc/runner.ts +136 -0
  141. package/src/harness/hooks/layer-context-inject.ts +155 -0
  142. package/src/harness/hooks/post-session-sweep.ts +130 -0
  143. package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
  144. package/src/harness/hooks/register.ts +118 -0
  145. package/src/harness/model.ts +117 -0
  146. package/src/harness/pipeline.ts +348 -0
  147. package/src/harness/project-paths.ts +235 -0
  148. package/src/harness/stage-runner.ts +107 -0
  149. package/src/harness/stages/design.ts +386 -0
  150. package/src/harness/stages/discover.ts +454 -0
  151. package/src/harness/stages/implement.ts +162 -0
  152. package/src/harness/stages/plan.ts +335 -0
  153. package/src/harness/stages/research.ts +263 -0
  154. package/src/harness/stages/validate.ts +684 -0
  155. package/src/harness/storage.ts +467 -0
  156. package/src/harness/tools.ts +426 -0
  157. package/src/lsp/bridge.ts +56 -95
  158. package/src/lsp/capabilities.ts +108 -0
  159. package/src/lsp/contracts.ts +35 -0
  160. package/src/lsp/detector.ts +8 -12
  161. package/src/markdown-frontmatter.ts +68 -0
  162. package/src/mempalace/bridge.ts +129 -0
  163. package/src/mempalace/config.ts +75 -0
  164. package/src/mempalace/format.ts +163 -0
  165. package/src/mempalace/hooks.ts +370 -0
  166. package/src/mempalace/installer-helper.ts +194 -0
  167. package/src/mempalace/python/mempalace_bridge.py +440 -0
  168. package/src/mempalace/runtime.ts +565 -0
  169. package/src/mempalace/schema.ts +264 -0
  170. package/src/mempalace/session-summary.ts +198 -0
  171. package/src/mempalace/tool.ts +186 -0
  172. package/src/mempalace/uv.ts +256 -0
  173. package/src/migrate/runner.ts +354 -0
  174. package/src/planning/approval-flow.ts +206 -9
  175. package/src/planning/plan-writer-prompt.ts +4 -3
  176. package/src/planning/planning-ask-tool.ts +39 -0
  177. package/src/planning/render-markdown.ts +74 -0
  178. package/src/planning/spec.ts +42 -0
  179. package/src/planning/system-prompt.ts +11 -8
  180. package/src/planning/validate.ts +84 -0
  181. package/src/platform/omp.ts +15 -2
  182. package/src/platform/system-prompt.ts +37 -0
  183. package/src/platform/test-utils.ts +3 -0
  184. package/src/platform/types.ts +6 -1
  185. package/src/qa/config.ts +12 -6
  186. package/src/qa/detect-app-type.ts +13 -6
  187. package/src/qa/matrix.ts +12 -6
  188. package/src/qa/prompt-builder.ts +28 -30
  189. package/src/qa/scripts/dev-server-utils.ts +72 -0
  190. package/src/qa/scripts/run-e2e-tests.ts +226 -0
  191. package/src/qa/scripts/start-dev-server.ts +138 -0
  192. package/src/qa/scripts/stop-dev-server.ts +77 -0
  193. package/src/qa/session.ts +13 -7
  194. package/src/quality/ai-setup.ts +27 -25
  195. package/src/quality/contracts.ts +34 -0
  196. package/src/quality/gates/ai-review.ts +20 -58
  197. package/src/quality/gates/command.ts +249 -46
  198. package/src/quality/review-gates.ts +18 -2
  199. package/src/quality/runner.ts +63 -22
  200. package/src/quality/schemas.ts +37 -2
  201. package/src/quality/setup.ts +96 -16
  202. package/src/release/changelog.ts +1 -1
  203. package/src/release/channels/custom.ts +13 -3
  204. package/src/release/channels/types.ts +5 -0
  205. package/src/release/contracts.ts +90 -0
  206. package/src/release/executor.ts +122 -45
  207. package/src/release/prompt.ts +18 -2
  208. package/src/release/targets.ts +86 -0
  209. package/src/release/version.ts +96 -71
  210. package/src/review/agent-loader.ts +298 -127
  211. package/src/review/fixer.ts +10 -6
  212. package/src/review/multi-agent-runner.ts +115 -14
  213. package/src/review/output.ts +12 -139
  214. package/src/review/runner.ts +12 -6
  215. package/src/review/scope.ts +144 -24
  216. package/src/review/types.ts +11 -20
  217. package/src/review/validator.ts +12 -6
  218. package/src/storage/fix-pr-sessions.ts +21 -14
  219. package/src/storage/plans.ts +14 -5
  220. package/src/storage/qa-sessions.ts +25 -19
  221. package/src/storage/reliability-metrics.ts +180 -0
  222. package/src/storage/reports.ts +8 -7
  223. package/src/storage/review-sessions.ts +55 -20
  224. package/src/tool-catalog/active-tool-controller.ts +164 -0
  225. package/src/tool-catalog/active-tool-planner.ts +212 -0
  226. package/src/tool-catalog/tool-groups.ts +102 -0
  227. package/src/types.ts +1401 -5
  228. package/src/ui-design/backend-adapter.ts +78 -0
  229. package/src/ui-design/backends/local-html.ts +82 -0
  230. package/src/ui-design/backends/pencil-mcp.ts +111 -0
  231. package/src/ui-design/components-scanner.ts +124 -0
  232. package/src/ui-design/config.ts +55 -0
  233. package/src/ui-design/pen-scanner.ts +95 -0
  234. package/src/ui-design/pen-selector.ts +72 -0
  235. package/src/ui-design/prompt-builder.ts +73 -0
  236. package/src/ui-design/scanner.ts +136 -0
  237. package/src/ui-design/session.ts +974 -0
  238. package/src/ui-design/system-prompt.ts +312 -0
  239. package/src/ui-design/tokens-scanner.ts +181 -0
  240. package/src/ui-design/types.ts +96 -0
  241. package/src/ultraplan/agent-catalog.ts +522 -0
  242. package/src/ultraplan/authoring/agent-catalog.ts +310 -0
  243. package/src/ultraplan/authoring/authoring-tools.ts +552 -0
  244. package/src/ultraplan/authoring/command-handlers.ts +339 -0
  245. package/src/ultraplan/authoring/markdown.ts +510 -0
  246. package/src/ultraplan/authoring/model.ts +162 -0
  247. package/src/ultraplan/authoring/pipeline.ts +319 -0
  248. package/src/ultraplan/authoring/stage-runner.ts +141 -0
  249. package/src/ultraplan/authoring/stages/approve.ts +249 -0
  250. package/src/ultraplan/authoring/stages/discover.ts +289 -0
  251. package/src/ultraplan/authoring/stages/intake.ts +203 -0
  252. package/src/ultraplan/authoring/stages/research.ts +399 -0
  253. package/src/ultraplan/authoring/stages/review.ts +333 -0
  254. package/src/ultraplan/authoring/stages/scout.ts +188 -0
  255. package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
  256. package/src/ultraplan/authoring/storage.ts +594 -0
  257. package/src/ultraplan/authoring/synth-gate.ts +165 -0
  258. package/src/ultraplan/authoring-draft.ts +653 -0
  259. package/src/ultraplan/authoring-persist.ts +180 -0
  260. package/src/ultraplan/authoring-tool.ts +608 -0
  261. package/src/ultraplan/authoring-wizard.ts +587 -0
  262. package/src/ultraplan/batch/merge.ts +98 -0
  263. package/src/ultraplan/batch/planner.ts +150 -0
  264. package/src/ultraplan/batch/presenter.ts +97 -0
  265. package/src/ultraplan/batch/storage.ts +420 -0
  266. package/src/ultraplan/batch/supervisor.ts +317 -0
  267. package/src/ultraplan/batch/worker.ts +26 -0
  268. package/src/ultraplan/batch/worktree.ts +110 -0
  269. package/src/ultraplan/contracts.ts +1593 -0
  270. package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
  271. package/src/ultraplan/default-agents/authoring/intake.md +12 -0
  272. package/src/ultraplan/default-agents/authoring/planner.md +12 -0
  273. package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
  274. package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
  275. package/src/ultraplan/default-agents/authoring/scout.md +12 -0
  276. package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
  277. package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
  278. package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
  279. package/src/ultraplan/default-agents/backend-executor.md +10 -0
  280. package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
  281. package/src/ultraplan/default-agents/backend-tester.md +10 -0
  282. package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
  283. package/src/ultraplan/default-agents/frontend-executor.md +10 -0
  284. package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
  285. package/src/ultraplan/default-agents/frontend-tester.md +10 -0
  286. package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
  287. package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
  288. package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
  289. package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
  290. package/src/ultraplan/execution/contract.ts +71 -0
  291. package/src/ultraplan/execution/policy.ts +217 -0
  292. package/src/ultraplan/execution/runtime-tools.ts +107 -0
  293. package/src/ultraplan/execution/session-runner.ts +281 -0
  294. package/src/ultraplan/next-router.ts +85 -0
  295. package/src/ultraplan/presenter.ts +359 -0
  296. package/src/ultraplan/project-paths.ts +342 -0
  297. package/src/ultraplan/runtime/active-execution.ts +72 -0
  298. package/src/ultraplan/runtime/apply-mutation.ts +416 -0
  299. package/src/ultraplan/runtime/blockers.ts +243 -0
  300. package/src/ultraplan/runtime/hook-bridge.ts +486 -0
  301. package/src/ultraplan/runtime/launch-context.ts +207 -0
  302. package/src/ultraplan/runtime/migration.ts +524 -0
  303. package/src/ultraplan/runtime/normalize.ts +281 -0
  304. package/src/ultraplan/runtime/proof.ts +260 -0
  305. package/src/ultraplan/runtime/reducer.ts +416 -0
  306. package/src/ultraplan/runtime/repair.ts +251 -0
  307. package/src/ultraplan/runtime/tracker-storage.ts +368 -0
  308. package/src/ultraplan/session-selection.ts +291 -0
  309. package/src/ultraplan/storage.ts +374 -0
  310. package/src/utils/editor.ts +38 -0
  311. package/src/utils/executable.ts +80 -0
  312. package/src/utils/paths.ts +1 -20
  313. package/src/utils/shell.ts +31 -0
  314. package/src/visual/companion.ts +2 -1
  315. package/src/visual/scripts/frame-template.html +60 -0
  316. package/src/visual/scripts/index.js +59 -13
  317. package/src/visual/scripts/package.json +3 -0
  318. package/src/visual/start-server.ts +2 -1
  319. package/src/workspace/git-scope.ts +64 -0
  320. package/src/workspace/locks.ts +23 -0
  321. package/src/workspace/package-manager.ts +117 -0
  322. package/src/workspace/path-mapping.ts +75 -0
  323. package/src/workspace/project-slug.ts +92 -0
  324. package/src/workspace/repo-root.ts +137 -0
  325. package/src/workspace/selector.ts +115 -0
  326. package/src/workspace/state-paths.ts +118 -0
  327. package/src/workspace/targets.ts +313 -0
  328. package/src/fix-pr/scripts/diff-comments.sh +0 -33
  329. package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
  330. package/src/fix-pr/scripts/trigger-review.sh +0 -36
  331. package/src/fix-pr/scripts/wait-and-check.sh +0 -37
  332. package/src/qa/scripts/detect-app-type.sh +0 -68
  333. package/src/qa/scripts/discover-routes.sh +0 -143
  334. package/src/qa/scripts/run-e2e-tests.sh +0 -131
  335. package/src/qa/scripts/start-dev-server.sh +0 -46
  336. package/src/qa/scripts/stop-dev-server.sh +0 -36
  337. package/src/review/prompts/fix-output-schema.md +0 -18
  338. package/src/review/prompts/review-output-schema.md +0 -38
  339. package/src/review/template.ts +0 -15
  340. /package/src/{review → ai}/prompts/invalid-output-retry.md +0 -0
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Authoring agent catalog (parallel namespace to `agent-catalog.ts`).
3
+ *
4
+ * Resolves the spawnable agent prompt body for each authoring slot. Precedence:
5
+ * 1. Project-local override at `.omp/supipowers/ultraplan-authoring-agents/<slot>.md`
6
+ * 2. Global override at `~/.omp/supipowers/ultraplan-authoring-agents/<slot>.md`
7
+ * 3. Built-in default at `src/ultraplan/default-agents/authoring/<slot>.md`
8
+ *
9
+ * Model and thinkingLevel are NOT resolved here — they go through `resolveAuthoringSlotModel`
10
+ * in `model.ts` so the per-stack action ids work uniformly. This module only owns:
11
+ * - the markdown body (system prompt) the spawned agent receives,
12
+ * - frontmatter sanity (name + supportedSlots),
13
+ * - load errors translated to the same `UltraPlanCatalogError` shape as execution slots so
14
+ * the picker / status renderer can show a unified error list.
15
+ */
16
+
17
+ import * as fs from "node:fs";
18
+ import * as path from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+
21
+ import intakeAsset from "../default-agents/authoring/intake.md" with { type: "text" };
22
+ import scoutAsset from "../default-agents/authoring/scout.md" with { type: "text" };
23
+ import discovererAsset from "../default-agents/authoring/discoverer.md" with { type: "text" };
24
+ import researcherAsset from "../default-agents/authoring/researcher.md" with { type: "text" };
25
+ import plannerAsset from "../default-agents/authoring/planner.md" with { type: "text" };
26
+ import structureCheckerAsset from "../default-agents/authoring/structure-checker.md" with { type: "text" };
27
+ import scopeCheckerAsset from "../default-agents/authoring/scope-checker.md" with { type: "text" };
28
+ import tddCheckerAsset from "../default-agents/authoring/tdd-checker.md" with { type: "text" };
29
+
30
+ import { MarkdownFrontmatterError, parseMarkdownFrontmatter } from "../../markdown-frontmatter.js";
31
+ import type { PlatformPaths } from "../../platform/types.js";
32
+ import type {
33
+ UltraPlanAuthoringSlotName,
34
+ UltraPlanCatalogError,
35
+ } from "../../types.js";
36
+ import { ULTRAPLAN_AUTHORING_SLOT_NAMES } from "../contracts.js";
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Constants and types
40
+ // ---------------------------------------------------------------------------
41
+
42
+ /** Subdirectory used for project- and global-scoped authoring overrides. */
43
+ export const ULTRAPLAN_AUTHORING_AGENTS_DIRNAME = "ultraplan-authoring-agents";
44
+
45
+ export type UltraPlanAuthoringDefinitionSource = "built-in" | "global" | "project";
46
+
47
+ export interface UltraPlanAuthoringAgentDefinition {
48
+ slot: UltraPlanAuthoringSlotName;
49
+ name: string;
50
+ description: string;
51
+ supportedSlots: UltraPlanAuthoringSlotName[];
52
+ focus: string | null;
53
+ prompt: string;
54
+ filePath: string;
55
+ source: UltraPlanAuthoringDefinitionSource;
56
+ }
57
+
58
+ export interface ResolvedUltraPlanAuthoringSlotBinding {
59
+ slot: UltraPlanAuthoringSlotName;
60
+ definition: UltraPlanAuthoringAgentDefinition;
61
+ }
62
+
63
+ export interface ResolvedUltraPlanAuthoringCatalog {
64
+ slots: Record<UltraPlanAuthoringSlotName, ResolvedUltraPlanAuthoringSlotBinding>;
65
+ }
66
+
67
+ export interface UltraPlanAuthoringCatalogLoadResult {
68
+ ok: boolean;
69
+ value: ResolvedUltraPlanAuthoringCatalog;
70
+ errors: UltraPlanCatalogError[];
71
+ }
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Built-in asset table (one entry per slot)
75
+ // ---------------------------------------------------------------------------
76
+
77
+ const BUILT_IN_AUTHORING_ASSETS: Record<
78
+ UltraPlanAuthoringSlotName,
79
+ { content: string; filePath: string }
80
+ > = {
81
+ "intake": {
82
+ content: intakeAsset,
83
+ filePath: fileURLToPath(new URL("../default-agents/authoring/intake.md", import.meta.url)),
84
+ },
85
+ "scout": {
86
+ content: scoutAsset,
87
+ filePath: fileURLToPath(new URL("../default-agents/authoring/scout.md", import.meta.url)),
88
+ },
89
+ "discoverer": {
90
+ content: discovererAsset,
91
+ filePath: fileURLToPath(new URL("../default-agents/authoring/discoverer.md", import.meta.url)),
92
+ },
93
+ "researcher": {
94
+ content: researcherAsset,
95
+ filePath: fileURLToPath(new URL("../default-agents/authoring/researcher.md", import.meta.url)),
96
+ },
97
+ "planner": {
98
+ content: plannerAsset,
99
+ filePath: fileURLToPath(new URL("../default-agents/authoring/planner.md", import.meta.url)),
100
+ },
101
+ "structure-checker": {
102
+ content: structureCheckerAsset,
103
+ filePath: fileURLToPath(new URL("../default-agents/authoring/structure-checker.md", import.meta.url)),
104
+ },
105
+ "scope-checker": {
106
+ content: scopeCheckerAsset,
107
+ filePath: fileURLToPath(new URL("../default-agents/authoring/scope-checker.md", import.meta.url)),
108
+ },
109
+ "tdd-checker": {
110
+ content: tddCheckerAsset,
111
+ filePath: fileURLToPath(new URL("../default-agents/authoring/tdd-checker.md", import.meta.url)),
112
+ },
113
+ };
114
+
115
+ // ---------------------------------------------------------------------------
116
+ // Internal helpers
117
+ // ---------------------------------------------------------------------------
118
+
119
+ const KNOWN_SLOTS = new Set<UltraPlanAuthoringSlotName>(ULTRAPLAN_AUTHORING_SLOT_NAMES);
120
+
121
+ function makeError(
122
+ slot: UltraPlanAuthoringSlotName | null,
123
+ code: UltraPlanCatalogError["code"],
124
+ message: string,
125
+ filePath: string | null = null,
126
+ ): UltraPlanCatalogError {
127
+ // The unified UltraPlanCatalogError carries an execution-slot name in `slot`. Authoring
128
+ // slots are not part of that enum, so we annotate the message with the authoring slot
129
+ // name and leave the field null. The picker/status renderer renders messages verbatim.
130
+ const annotated = slot ? `[authoring/${slot}] ${message}` : message;
131
+ return { slot: null, code, message: annotated, path: filePath };
132
+ }
133
+
134
+ function parseAuthoringMarkdown(
135
+ content: string,
136
+ filePath: string,
137
+ source: UltraPlanAuthoringDefinitionSource,
138
+ ): UltraPlanAuthoringAgentDefinition {
139
+ const { frontmatter, body } = parseMarkdownFrontmatter(content, filePath);
140
+ const fm = frontmatter as Partial<{
141
+ name: unknown;
142
+ description: unknown;
143
+ supportedSlots: unknown;
144
+ focus: unknown;
145
+ }>;
146
+
147
+ if (typeof fm.name !== "string" || fm.name.length === 0) {
148
+ throw new MarkdownFrontmatterError("invalid-frontmatter", filePath, "Authoring agent frontmatter requires `name`.");
149
+ }
150
+ if (typeof fm.description !== "string" || fm.description.length === 0) {
151
+ throw new MarkdownFrontmatterError("invalid-frontmatter", filePath, "Authoring agent frontmatter requires `description`.");
152
+ }
153
+ if (!Array.isArray(fm.supportedSlots) || fm.supportedSlots.length === 0) {
154
+ throw new MarkdownFrontmatterError("invalid-frontmatter", filePath, "Authoring agent frontmatter requires non-empty `supportedSlots` list.");
155
+ }
156
+
157
+ const slots: UltraPlanAuthoringSlotName[] = [];
158
+ for (const raw of fm.supportedSlots as unknown[]) {
159
+ if (typeof raw !== "string" || !KNOWN_SLOTS.has(raw as UltraPlanAuthoringSlotName)) {
160
+ throw new MarkdownFrontmatterError("invalid-frontmatter", filePath, `Authoring agent frontmatter references unknown slot ${JSON.stringify(raw)}.`);
161
+ }
162
+ slots.push(raw as UltraPlanAuthoringSlotName);
163
+ }
164
+
165
+ // For built-in slot definitions, `name` must equal the slot. For overrides we allow any
166
+ // name as long as the slot is present in `supportedSlots` — this mirrors the behavior of
167
+ // the execution catalog for global agents.
168
+ const slot = slots[0]!;
169
+
170
+ return {
171
+ slot,
172
+ name: fm.name,
173
+ description: fm.description,
174
+ supportedSlots: slots,
175
+ focus: typeof fm.focus === "string" && fm.focus.length > 0 ? fm.focus : null,
176
+ prompt: body,
177
+ filePath,
178
+ source,
179
+ };
180
+ }
181
+
182
+ function loadBuiltInDefinitions(): Map<UltraPlanAuthoringSlotName, UltraPlanAuthoringAgentDefinition> {
183
+ const bySlot = new Map<UltraPlanAuthoringSlotName, UltraPlanAuthoringAgentDefinition>();
184
+ for (const slot of ULTRAPLAN_AUTHORING_SLOT_NAMES) {
185
+ const asset = BUILT_IN_AUTHORING_ASSETS[slot];
186
+ const definition = parseAuthoringMarkdown(asset.content, asset.filePath, "built-in");
187
+
188
+ // Guard rail: built-in `name` MUST equal the slot. This prevents silent typos in the
189
+ // markdown frontmatter from changing slot resolution. Tests assert this.
190
+ if (definition.name !== slot) {
191
+ throw new MarkdownFrontmatterError("invalid-frontmatter", asset.filePath, `Built-in authoring agent ${asset.filePath} must use name "${slot}" (got ${JSON.stringify(definition.name)}).`);
192
+ }
193
+ if (definition.supportedSlots.length !== 1 || definition.supportedSlots[0] !== slot) {
194
+ throw new MarkdownFrontmatterError("invalid-frontmatter", asset.filePath, `Built-in authoring agent ${asset.filePath} must support exactly slot "${slot}".`);
195
+ }
196
+
197
+ bySlot.set(slot, definition);
198
+ }
199
+ return bySlot;
200
+ }
201
+
202
+ let cachedBuiltIn: Map<UltraPlanAuthoringSlotName, UltraPlanAuthoringAgentDefinition> | null = null;
203
+ function getBuiltInDefinitions(): Map<UltraPlanAuthoringSlotName, UltraPlanAuthoringAgentDefinition> {
204
+ cachedBuiltIn ??= loadBuiltInDefinitions();
205
+ return cachedBuiltIn;
206
+ }
207
+
208
+ function loadOverrideDefinition(
209
+ filePath: string,
210
+ source: UltraPlanAuthoringDefinitionSource,
211
+ ): { definition: UltraPlanAuthoringAgentDefinition | null; error: UltraPlanCatalogError | null } {
212
+ if (!fs.existsSync(filePath)) {
213
+ return { definition: null, error: null };
214
+ }
215
+ try {
216
+ const raw = fs.readFileSync(filePath, "utf8");
217
+ const definition = parseAuthoringMarkdown(raw, filePath, source);
218
+ return { definition, error: null };
219
+ } catch (error) {
220
+ if (error instanceof MarkdownFrontmatterError) {
221
+ return {
222
+ definition: null,
223
+ error: makeError(null, "invalid-agent-definition", error.message, error.filePath ?? filePath),
224
+ };
225
+ }
226
+ const message = error instanceof Error ? error.message : `Unable to read ${filePath}`;
227
+ return {
228
+ definition: null,
229
+ error: makeError(null, "catalog-io", message, filePath),
230
+ };
231
+ }
232
+ }
233
+
234
+ function resolveOverrideForSlot(
235
+ slot: UltraPlanAuthoringSlotName,
236
+ paths: PlatformPaths,
237
+ cwd: string,
238
+ ): { definition: UltraPlanAuthoringAgentDefinition | null; error: UltraPlanCatalogError | null } {
239
+ // 1. Project-local: .omp/supipowers/ultraplan-authoring-agents/<slot>.md
240
+ const projectPath = paths.project(cwd, ULTRAPLAN_AUTHORING_AGENTS_DIRNAME, `${slot}.md`);
241
+ const projectResult = loadOverrideDefinition(projectPath, "project");
242
+ if (projectResult.error) return projectResult;
243
+ if (projectResult.definition) return projectResult;
244
+
245
+ // 2. Global: ~/.omp/supipowers/ultraplan-authoring-agents/<slot>.md
246
+ const globalPath = paths.global(ULTRAPLAN_AUTHORING_AGENTS_DIRNAME, `${slot}.md`);
247
+ const globalResult = loadOverrideDefinition(globalPath, "global");
248
+ return globalResult;
249
+ }
250
+
251
+ // ---------------------------------------------------------------------------
252
+ // Public API
253
+ // ---------------------------------------------------------------------------
254
+
255
+ /**
256
+ * Resolve every authoring slot to a concrete agent definition. Errors that prevent at least
257
+ * one slot from resolving are returned in `errors`; the catalog still surfaces the built-in
258
+ * fallback for those slots so the rest of the pipeline can report a structured blocker.
259
+ */
260
+ export function loadUltraPlanAuthoringCatalog(
261
+ paths: PlatformPaths,
262
+ cwd: string,
263
+ ): UltraPlanAuthoringCatalogLoadResult {
264
+ const builtIns = getBuiltInDefinitions();
265
+ const slots: Partial<Record<UltraPlanAuthoringSlotName, ResolvedUltraPlanAuthoringSlotBinding>> = {};
266
+ const errors: UltraPlanCatalogError[] = [];
267
+
268
+ for (const slot of ULTRAPLAN_AUTHORING_SLOT_NAMES) {
269
+ const builtIn = builtIns.get(slot);
270
+ if (!builtIn) {
271
+ // Should be impossible — the built-in table is exhaustive at module load.
272
+ errors.push(
273
+ makeError(slot, "missing-built-in-definition", `No built-in definition registered for authoring slot ${slot}`, null),
274
+ );
275
+ continue;
276
+ }
277
+
278
+ const overrideResult = resolveOverrideForSlot(slot, paths, cwd);
279
+ if (overrideResult.error) {
280
+ errors.push(overrideResult.error);
281
+ // Fall back to the built-in so other slots still resolve.
282
+ slots[slot] = { slot, definition: builtIn };
283
+ continue;
284
+ }
285
+
286
+ const chosen = overrideResult.definition ?? builtIn;
287
+ slots[slot] = { slot, definition: chosen };
288
+ }
289
+
290
+ const ok = errors.length === 0 && ULTRAPLAN_AUTHORING_SLOT_NAMES.every((s) => slots[s] !== undefined);
291
+ return {
292
+ ok,
293
+ value: { slots: slots as ResolvedUltraPlanAuthoringCatalog["slots"] },
294
+ errors,
295
+ };
296
+ }
297
+
298
+ /** Convenience: fetch a single slot binding without resolving the whole catalog. */
299
+ export function resolveAuthoringSlot(
300
+ slot: UltraPlanAuthoringSlotName,
301
+ paths: PlatformPaths,
302
+ cwd: string,
303
+ ): ResolvedUltraPlanAuthoringSlotBinding {
304
+ const catalog = loadUltraPlanAuthoringCatalog(paths, cwd);
305
+ const binding = catalog.value.slots[slot];
306
+ if (!binding) {
307
+ throw new Error(`Authoring slot ${slot} did not resolve (errors: ${catalog.errors.map((e) => e.message).join("; ")})`);
308
+ }
309
+ return binding;
310
+ }