supipowers 1.5.3 → 2.0.1

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 +131 -42
  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 +18 -8
  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 +135 -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 +268 -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 +221 -109
  211. package/src/review/fixer.ts +10 -6
  212. package/src/review/multi-agent-runner.ts +114 -13
  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 +1 -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 +1399 -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,522 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import backendDomainReviewerAsset from "./default-agents/backend-domain-reviewer.md" with { type: "text" };
5
+ import backendExecutorAsset from "./default-agents/backend-executor.md" with { type: "text" };
6
+ import backendStackReviewerAsset from "./default-agents/backend-stack-reviewer.md" with { type: "text" };
7
+ import backendTesterAsset from "./default-agents/backend-tester.md" with { type: "text" };
8
+ import frontendDomainReviewerAsset from "./default-agents/frontend-domain-reviewer.md" with { type: "text" };
9
+ import frontendExecutorAsset from "./default-agents/frontend-executor.md" with { type: "text" };
10
+ import frontendStackReviewerAsset from "./default-agents/frontend-stack-reviewer.md" with { type: "text" };
11
+ import frontendTesterAsset from "./default-agents/frontend-tester.md" with { type: "text" };
12
+ import infrastructureDomainReviewerAsset from "./default-agents/infrastructure-domain-reviewer.md" with { type: "text" };
13
+ import infrastructureExecutorAsset from "./default-agents/infrastructure-executor.md" with { type: "text" };
14
+ import infrastructureStackReviewerAsset from "./default-agents/infrastructure-stack-reviewer.md" with { type: "text" };
15
+ import infrastructureTesterAsset from "./default-agents/infrastructure-tester.md" with { type: "text" };
16
+ import { inspectConfig, inspectConfigScopes } from "../config/loader.js";
17
+ import { MarkdownFrontmatterError, parseMarkdownFrontmatter } from "../markdown-frontmatter.js";
18
+ import type { PlatformPaths } from "../platform/types.js";
19
+ import type {
20
+ ResolvedUltraPlanCatalog,
21
+ ResolvedUltraPlanSlotBinding,
22
+ UltraPlanAgentDefinition,
23
+ UltraPlanAgentDefinitionSource,
24
+ UltraPlanAgentSlotName,
25
+ UltraPlanCatalogError,
26
+ UltraPlanCatalogErrorCode,
27
+ UltraPlanCatalogLoadResult,
28
+ UltraPlanConfig,
29
+ } from "../types.js";
30
+ import {
31
+ getUltraPlanSchemaErrors,
32
+ ULTRAPLAN_AGENT_SLOT_NAMES,
33
+ ULTRAPLAN_REVIEWER_SLOT_NAMES,
34
+ UltraPlanAgentDefinitionFrontmatterSchema,
35
+ } from "./contracts.js";
36
+
37
+ const RESERVED_BUILT_IN_AGENT_NAMES = new Set<string>(ULTRAPLAN_AGENT_SLOT_NAMES);
38
+ const REVIEWER_SLOT_NAMES = new Set<UltraPlanAgentSlotName>(ULTRAPLAN_REVIEWER_SLOT_NAMES);
39
+
40
+ type UltraPlanCatalogLoadErrorCode = Extract<
41
+ UltraPlanCatalogErrorCode,
42
+ "invalid-agent-definition" | "duplicate-agent-name" | "reserved-agent-name" | "catalog-io"
43
+ >;
44
+
45
+ class UltraPlanCatalogLoadError extends Error {
46
+ constructor(
47
+ public readonly code: UltraPlanCatalogLoadErrorCode,
48
+ message: string,
49
+ public readonly path: string | null,
50
+ ) {
51
+ super(message);
52
+ this.name = "UltraPlanCatalogLoadError";
53
+ }
54
+ }
55
+
56
+ const BUILT_IN_AGENT_ASSETS = {
57
+ "frontend-executor": {
58
+ content: frontendExecutorAsset,
59
+ filePath: fileURLToPath(new URL("./default-agents/frontend-executor.md", import.meta.url)),
60
+ },
61
+ "frontend-tester": {
62
+ content: frontendTesterAsset,
63
+ filePath: fileURLToPath(new URL("./default-agents/frontend-tester.md", import.meta.url)),
64
+ },
65
+ "frontend-domain-reviewer": {
66
+ content: frontendDomainReviewerAsset,
67
+ filePath: fileURLToPath(new URL("./default-agents/frontend-domain-reviewer.md", import.meta.url)),
68
+ },
69
+ "frontend-stack-reviewer": {
70
+ content: frontendStackReviewerAsset,
71
+ filePath: fileURLToPath(new URL("./default-agents/frontend-stack-reviewer.md", import.meta.url)),
72
+ },
73
+ "backend-executor": {
74
+ content: backendExecutorAsset,
75
+ filePath: fileURLToPath(new URL("./default-agents/backend-executor.md", import.meta.url)),
76
+ },
77
+ "backend-tester": {
78
+ content: backendTesterAsset,
79
+ filePath: fileURLToPath(new URL("./default-agents/backend-tester.md", import.meta.url)),
80
+ },
81
+ "backend-domain-reviewer": {
82
+ content: backendDomainReviewerAsset,
83
+ filePath: fileURLToPath(new URL("./default-agents/backend-domain-reviewer.md", import.meta.url)),
84
+ },
85
+ "backend-stack-reviewer": {
86
+ content: backendStackReviewerAsset,
87
+ filePath: fileURLToPath(new URL("./default-agents/backend-stack-reviewer.md", import.meta.url)),
88
+ },
89
+ "infrastructure-executor": {
90
+ content: infrastructureExecutorAsset,
91
+ filePath: fileURLToPath(new URL("./default-agents/infrastructure-executor.md", import.meta.url)),
92
+ },
93
+ "infrastructure-tester": {
94
+ content: infrastructureTesterAsset,
95
+ filePath: fileURLToPath(new URL("./default-agents/infrastructure-tester.md", import.meta.url)),
96
+ },
97
+ "infrastructure-domain-reviewer": {
98
+ content: infrastructureDomainReviewerAsset,
99
+ filePath: fileURLToPath(new URL("./default-agents/infrastructure-domain-reviewer.md", import.meta.url)),
100
+ },
101
+ "infrastructure-stack-reviewer": {
102
+ content: infrastructureStackReviewerAsset,
103
+ filePath: fileURLToPath(new URL("./default-agents/infrastructure-stack-reviewer.md", import.meta.url)),
104
+ },
105
+ } satisfies Record<UltraPlanAgentSlotName, { content: string; filePath: string }>;
106
+
107
+ function createCatalogError(
108
+ slot: UltraPlanAgentSlotName | null,
109
+ code: UltraPlanCatalogErrorCode,
110
+ message: string,
111
+ path: string | null = null,
112
+ ): UltraPlanCatalogError {
113
+ return { slot, code, message, path };
114
+ }
115
+
116
+ function emptyResolvedCatalog(config: UltraPlanConfig | null = null): ResolvedUltraPlanCatalog {
117
+ return {
118
+ slots: Object.fromEntries(
119
+ ULTRAPLAN_AGENT_SLOT_NAMES.map((slot) => [slot, null]),
120
+ ) as ResolvedUltraPlanCatalog["slots"],
121
+ reviewGates: structuredClone(config?.reviewGates ?? {}),
122
+ };
123
+ }
124
+
125
+ function mapDefinitionsByName(definitions: UltraPlanAgentDefinition[]): Map<string, UltraPlanAgentDefinition> {
126
+ return new Map(definitions.map((definition) => [definition.name, definition]));
127
+ }
128
+
129
+ function mapBuiltInDefinitionsBySlot(
130
+ definitions: UltraPlanAgentDefinition[],
131
+ ): Map<UltraPlanAgentSlotName, UltraPlanAgentDefinition> {
132
+ const bySlot = new Map<UltraPlanAgentSlotName, UltraPlanAgentDefinition>();
133
+
134
+ for (const definition of definitions) {
135
+ for (const slot of definition.supportedSlots) {
136
+ if (!RESERVED_BUILT_IN_AGENT_NAMES.has(slot)) {
137
+ continue;
138
+ }
139
+
140
+ bySlot.set(slot, definition);
141
+ }
142
+ }
143
+
144
+ return bySlot;
145
+ }
146
+
147
+ function isSlotRequired(slot: UltraPlanAgentSlotName, config: UltraPlanConfig): boolean {
148
+ if (!REVIEWER_SLOT_NAMES.has(slot)) {
149
+ return true;
150
+ }
151
+
152
+ const reviewerSlot = slot as (typeof ULTRAPLAN_REVIEWER_SLOT_NAMES)[number];
153
+ return config.reviewGates[reviewerSlot]?.enabled !== false;
154
+ }
155
+
156
+ function assertUniqueCustomDefinitionNames(definitions: UltraPlanAgentDefinition[]): void {
157
+ const seen = new Map<string, string>();
158
+
159
+ for (const definition of definitions) {
160
+ if (RESERVED_BUILT_IN_AGENT_NAMES.has(definition.name)) {
161
+ throw new UltraPlanCatalogLoadError(
162
+ "reserved-agent-name",
163
+ `Global UltraPlan agent "${definition.name}" reuses reserved built-in name. Choose a different custom agent name.`,
164
+ definition.filePath,
165
+ );
166
+ }
167
+
168
+ const existing = seen.get(definition.name);
169
+ if (existing) {
170
+ throw new UltraPlanCatalogLoadError(
171
+ "duplicate-agent-name",
172
+ `Duplicate UltraPlan agent name "${definition.name}" found in ${existing} and ${definition.filePath}.`,
173
+ definition.filePath,
174
+ );
175
+ }
176
+
177
+ seen.set(definition.name, definition.filePath);
178
+ }
179
+ }
180
+
181
+ function mapExpectedCatalogLoadError(error: unknown): UltraPlanCatalogError | null {
182
+ if (error instanceof UltraPlanCatalogLoadError) {
183
+ return createCatalogError(null, error.code, error.message, error.path);
184
+ }
185
+
186
+ if (error instanceof MarkdownFrontmatterError) {
187
+ return createCatalogError(null, "invalid-agent-definition", error.message, error.filePath);
188
+ }
189
+
190
+ const ioError = error as NodeJS.ErrnoException;
191
+ if (error instanceof Error && typeof ioError.code === "string") {
192
+ return createCatalogError(null, "catalog-io", error.message, ioError.path ?? null);
193
+ }
194
+
195
+ return null;
196
+ }
197
+
198
+ function describeConfigSource(source: "global" | "root"): string {
199
+ return source === "root" ? "repository" : source;
200
+ }
201
+
202
+ function mapConfigInspectionErrors(scopes: ReturnType<typeof inspectConfigScopes>): UltraPlanCatalogError[] {
203
+ return scopes.flatMap((scope) => [
204
+ ...(scope.parseError
205
+ ? [
206
+ createCatalogError(
207
+ null,
208
+ "invalid-config",
209
+ `${describeConfigSource(scope.scope)} config ${scope.path}: ${scope.parseError.message}`,
210
+ scope.path,
211
+ ),
212
+ ]
213
+ : []),
214
+ ...scope.validationErrors.map((error) =>
215
+ createCatalogError(
216
+ null,
217
+ "invalid-config",
218
+ `${describeConfigSource(scope.scope)} config ${scope.path}: ${error.path}: ${error.message}`,
219
+ scope.path,
220
+ ),
221
+ ),
222
+ ]);
223
+ }
224
+
225
+ function blockCatalogFailure(
226
+ errors: UltraPlanCatalogError[],
227
+ config: UltraPlanConfig | null = null,
228
+ ): UltraPlanCatalogLoadResult {
229
+ return {
230
+ ok: false,
231
+ value: emptyResolvedCatalog(config),
232
+ errors,
233
+ };
234
+ }
235
+
236
+ function appendCatalogErrors(
237
+ result: UltraPlanCatalogLoadResult,
238
+ additionalErrors: UltraPlanCatalogError[],
239
+ config: UltraPlanConfig | null,
240
+ ): UltraPlanCatalogLoadResult {
241
+ if (additionalErrors.length === 0) {
242
+ return result.ok ? result : blockCatalogFailure(result.errors, config);
243
+ }
244
+
245
+ return blockCatalogFailure(
246
+ result.ok ? additionalErrors : [...additionalErrors, ...result.errors],
247
+ config,
248
+ );
249
+ }
250
+
251
+ export function parseUltraPlanAgentMarkdown(
252
+ content: string,
253
+ filePath: string,
254
+ source: UltraPlanAgentDefinitionSource,
255
+ ): UltraPlanAgentDefinition {
256
+ const { frontmatter, body } = parseMarkdownFrontmatter(content, filePath);
257
+ const errors = getUltraPlanSchemaErrors(UltraPlanAgentDefinitionFrontmatterSchema, frontmatter);
258
+ if (errors.length > 0) {
259
+ throw new UltraPlanCatalogLoadError(
260
+ "invalid-agent-definition",
261
+ `Invalid UltraPlan agent frontmatter in ${filePath}: ${errors.join("; ")}`,
262
+ filePath,
263
+ );
264
+ }
265
+
266
+ const parsed = frontmatter as {
267
+ name: string;
268
+ description: string;
269
+ supportedSlots: UltraPlanAgentSlotName[];
270
+ model?: string;
271
+ thinkingLevel?: UltraPlanAgentDefinition["thinkingLevel"];
272
+ focus?: string;
273
+ };
274
+
275
+ return {
276
+ name: parsed.name,
277
+ description: parsed.description,
278
+ supportedSlots: [...parsed.supportedSlots],
279
+ model: parsed.model,
280
+ thinkingLevel: parsed.thinkingLevel,
281
+ focus: parsed.focus,
282
+ prompt: body,
283
+ filePath,
284
+ source,
285
+ };
286
+ }
287
+
288
+ export function getGlobalUltraPlanAgentsDir(paths: PlatformPaths): string {
289
+ return paths.global("ultraplan-agents");
290
+ }
291
+
292
+ function cloneAgentDefinition(definition: UltraPlanAgentDefinition): UltraPlanAgentDefinition {
293
+ return {
294
+ ...definition,
295
+ supportedSlots: [...definition.supportedSlots],
296
+ };
297
+ }
298
+
299
+ function assertBuiltInDefinitionIntegrity(
300
+ slot: UltraPlanAgentSlotName,
301
+ definition: UltraPlanAgentDefinition,
302
+ ): void {
303
+ if (definition.name !== slot) {
304
+ throw new UltraPlanCatalogLoadError(
305
+ "invalid-agent-definition",
306
+ `Built-in UltraPlan agent ${definition.filePath} must use reserved name "${slot}".`,
307
+ definition.filePath,
308
+ );
309
+ }
310
+
311
+ if (definition.supportedSlots.length !== 1 || definition.supportedSlots[0] !== slot) {
312
+ throw new UltraPlanCatalogLoadError(
313
+ "invalid-agent-definition",
314
+ `Built-in UltraPlan agent ${definition.filePath} must support exactly the reserved slot "${slot}".`,
315
+ definition.filePath,
316
+ );
317
+ }
318
+ }
319
+
320
+ let cachedBuiltInAgentDefinitions: UltraPlanAgentDefinition[] | null = null;
321
+
322
+ function parseBuiltInUltraPlanAgentDefinitions(): UltraPlanAgentDefinition[] {
323
+ return ULTRAPLAN_AGENT_SLOT_NAMES.map((slot) => {
324
+ const asset = BUILT_IN_AGENT_ASSETS[slot];
325
+ const definition = parseUltraPlanAgentMarkdown(asset.content, asset.filePath, "built-in");
326
+ assertBuiltInDefinitionIntegrity(slot, definition);
327
+ return definition;
328
+ });
329
+ }
330
+
331
+ export function loadBuiltInUltraPlanAgentDefinitions(): UltraPlanAgentDefinition[] {
332
+ cachedBuiltInAgentDefinitions ??= parseBuiltInUltraPlanAgentDefinitions();
333
+ return cachedBuiltInAgentDefinitions.map(cloneAgentDefinition);
334
+ }
335
+
336
+ export function loadGlobalUltraPlanAgentDefinitions(paths: PlatformPaths): UltraPlanAgentDefinition[] {
337
+ const agentsDir = getGlobalUltraPlanAgentsDir(paths);
338
+ if (!fs.existsSync(agentsDir)) {
339
+ return [];
340
+ }
341
+
342
+ try {
343
+ const definitions = fs.readdirSync(agentsDir, { withFileTypes: true })
344
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
345
+ .map((entry) => path.join(agentsDir, entry.name))
346
+ .sort((left, right) => left.localeCompare(right))
347
+ .map((filePath) => parseUltraPlanAgentMarkdown(fs.readFileSync(filePath, "utf-8"), filePath, "global"));
348
+
349
+ assertUniqueCustomDefinitionNames(definitions);
350
+ return definitions;
351
+ } catch (error) {
352
+ if (error instanceof UltraPlanCatalogLoadError) {
353
+ throw error;
354
+ }
355
+
356
+ if (error instanceof MarkdownFrontmatterError) {
357
+ throw new UltraPlanCatalogLoadError(
358
+ "invalid-agent-definition",
359
+ error.message,
360
+ error.filePath,
361
+ );
362
+ }
363
+
364
+ throw new UltraPlanCatalogLoadError(
365
+ "catalog-io",
366
+ `Failed to load global UltraPlan agents from ${agentsDir}: ${(error as Error).message}`,
367
+ agentsDir,
368
+ );
369
+ }
370
+ }
371
+
372
+ function resolveConfiguredDefinition(
373
+ slot: UltraPlanAgentSlotName,
374
+ config: UltraPlanConfig,
375
+ builtInDefinitionsBySlot: Map<UltraPlanAgentSlotName, UltraPlanAgentDefinition>,
376
+ globalDefinitionsByName: Map<string, UltraPlanAgentDefinition>,
377
+ ): { binding: ResolvedUltraPlanSlotBinding | null; error: UltraPlanCatalogError | null } {
378
+ const builtInDefinition = builtInDefinitionsBySlot.get(slot);
379
+ if (!builtInDefinition) {
380
+ return {
381
+ binding: null,
382
+ error: createCatalogError(
383
+ slot,
384
+ "missing-built-in-definition",
385
+ `Missing built-in UltraPlan definition for slot "${slot}".`,
386
+ ),
387
+ };
388
+ }
389
+
390
+ const slotConfig = config.slots[slot];
391
+ const selectedDefinition = slotConfig?.agentName
392
+ ? globalDefinitionsByName.get(slotConfig.agentName)
393
+ : builtInDefinition;
394
+ if (!selectedDefinition) {
395
+ return {
396
+ binding: null,
397
+ error: createCatalogError(
398
+ slot,
399
+ "required-slot-unresolved",
400
+ `UltraPlan slot "${slot}" references unknown global agent "${slotConfig?.agentName}".`,
401
+ ),
402
+ };
403
+ }
404
+
405
+ if (!selectedDefinition.supportedSlots.includes(slot)) {
406
+ return {
407
+ binding: null,
408
+ error: createCatalogError(
409
+ slot,
410
+ "unsupported-slot",
411
+ `UltraPlan agent "${selectedDefinition.name}" does not support slot "${slot}".`,
412
+ selectedDefinition.filePath,
413
+ ),
414
+ };
415
+ }
416
+
417
+ return {
418
+ binding: {
419
+ slot,
420
+ agentType: selectedDefinition.source === "built-in" ? "built-in" : "named",
421
+ agentName: selectedDefinition.name,
422
+ model: slotConfig?.model ?? selectedDefinition.model ?? null,
423
+ thinkingLevel: slotConfig?.thinkingLevel ?? selectedDefinition.thinkingLevel ?? null,
424
+ selectionSource: slotConfig?.agentName ? "project" : "default",
425
+ definitionSource: selectedDefinition.source,
426
+ modelSource: slotConfig?.model
427
+ ? "project"
428
+ : selectedDefinition.model
429
+ ? selectedDefinition.source
430
+ : "unset",
431
+ thinkingLevelSource: slotConfig?.thinkingLevel
432
+ ? "project"
433
+ : selectedDefinition.thinkingLevel
434
+ ? selectedDefinition.source
435
+ : "unset",
436
+ definitionPath: selectedDefinition.filePath,
437
+ },
438
+ error: null,
439
+ };
440
+ }
441
+
442
+ function resolveUltraPlanAgentCatalog(
443
+ config: UltraPlanConfig,
444
+ builtInDefinitions: UltraPlanAgentDefinition[],
445
+ globalDefinitions: UltraPlanAgentDefinition[],
446
+ ): UltraPlanCatalogLoadResult {
447
+ const builtInDefinitionsBySlot = mapBuiltInDefinitionsBySlot(builtInDefinitions);
448
+ const globalDefinitionsByName = mapDefinitionsByName(globalDefinitions);
449
+ const errors: UltraPlanCatalogError[] = [];
450
+ const slots = {} as ResolvedUltraPlanCatalog["slots"];
451
+
452
+ for (const slot of ULTRAPLAN_AGENT_SLOT_NAMES) {
453
+ if (!isSlotRequired(slot, config)) {
454
+ slots[slot] = null;
455
+ continue;
456
+ }
457
+
458
+ const { binding, error } = resolveConfiguredDefinition(
459
+ slot,
460
+ config,
461
+ builtInDefinitionsBySlot,
462
+ globalDefinitionsByName,
463
+ );
464
+
465
+ slots[slot] = binding;
466
+ if (error) {
467
+ errors.push(error);
468
+ }
469
+ }
470
+
471
+ const value: ResolvedUltraPlanCatalog = {
472
+ slots,
473
+ reviewGates: structuredClone(config.reviewGates),
474
+ };
475
+
476
+ return errors.length === 0
477
+ ? { ok: true, value }
478
+ : { ok: false, value, errors };
479
+ }
480
+
481
+ export function loadUltraPlanAgentCatalog(
482
+ paths: PlatformPaths,
483
+ cwd: string,
484
+ ): UltraPlanCatalogLoadResult {
485
+ const inspection = inspectConfig(paths, cwd);
486
+ if (!inspection.effectiveConfig) {
487
+ return blockCatalogFailure(mapConfigInspectionErrors(inspectConfigScopes(paths, cwd)));
488
+ }
489
+
490
+ const config = inspection.effectiveConfig.ultraplan;
491
+
492
+ let builtInDefinitions: UltraPlanAgentDefinition[];
493
+ try {
494
+ builtInDefinitions = loadBuiltInUltraPlanAgentDefinitions();
495
+ } catch (error) {
496
+ const mapped = mapExpectedCatalogLoadError(error);
497
+ if (!mapped) {
498
+ throw error;
499
+ }
500
+
501
+ return blockCatalogFailure([mapped], config);
502
+ }
503
+
504
+ let globalDefinitions: UltraPlanAgentDefinition[] = [];
505
+ const loadErrors: UltraPlanCatalogError[] = [];
506
+ try {
507
+ globalDefinitions = loadGlobalUltraPlanAgentDefinitions(paths);
508
+ } catch (error) {
509
+ const mapped = mapExpectedCatalogLoadError(error);
510
+ if (!mapped) {
511
+ throw error;
512
+ }
513
+
514
+ loadErrors.push(mapped);
515
+ }
516
+
517
+ return appendCatalogErrors(
518
+ resolveUltraPlanAgentCatalog(config, builtInDefinitions, globalDefinitions),
519
+ loadErrors,
520
+ config,
521
+ );
522
+ }