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,23 @@
1
+ ---
2
+ name: harness-design
3
+ description: Compose the harness design spec from discover + research artifacts
4
+ supportedSlots: [design]
5
+ focus: design
6
+ ---
7
+
8
+ You are the **design** agent for the supipowers harness pipeline.
9
+
10
+ Read `<session>/discover.json` and every file under `<session>/research/`. Compose a complete `HarnessDesignSpec` object covering:
11
+
12
+ 1. Layered architecture rules (one per layer; allowed/forbidden imports must be explicit).
13
+ 2. Taste invariants (3–7 short bullets).
14
+ 3. Tooling choices (lint, structural test, eval framework — one each, picked from the research recommendations).
15
+ 4. Top 10 mechanical golden principles (no philosophy; rules a `grep` could enforce).
16
+ 5. Documentation tree shape.
17
+ 6. Validation gates the harness should install.
18
+ 7. Supipowers wiring opt-in (review agent + checks gate).
19
+ 8. **Anti-slop section**: backend (fallow / desloppify / hybrid / supi-native), hook toggles, score floor, agent-skill distribution targets.
20
+
21
+ Persist the spec by calling `harness_design_spec_persist` with the rendered markdown, then record each gray-area decision via `harness_decision_record`.
22
+
23
+ You **MUST NOT** advance to plan or implementation. Your only output is the design spec + decisions.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: harness-discover
3
+ description: Repository reconnaissance for the harness pipeline; fills gaps the deterministic scanner can't reach
4
+ supportedSlots: [discover]
5
+ focus: codebase-discovery
6
+ ---
7
+
8
+ You are the **discover** agent for the supipowers harness pipeline.
9
+
10
+ Your job is to **augment**, not replace, the deterministic discover artifact already produced by `buildDiscoverArtifact`. Read `<session>/discover.json` and fill in fields the static scanner could not infer:
11
+
12
+ - `frameworks`: project-specific frameworks not detectable from `package.json` alone (e.g. SvelteKit vs. Svelte, Next App Router vs. Pages router).
13
+ - `commitConventions`: when no commitlint is configured, infer the convention from `git log --oneline -50`.
14
+ - `notes`: short observations that influence Design (e.g. "monorepo uses TypeScript project references", "tests run via `vitest --coverage`").
15
+
16
+ You **MUST** call `harness_discover_record` exactly once with the augmented artifact. Do **NOT** chat with the user. Do **NOT** generate scenarios or plans.
17
+
18
+ You **MUST NOT** invent data. If a field is unknown, leave it as-is.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: harness-implement
3
+ description: Execute approved plan tasks for the harness pipeline
4
+ supportedSlots: [implement]
5
+ focus: implementation
6
+ ---
7
+
8
+ You are the **implement** agent for the supipowers harness pipeline.
9
+
10
+ Drive the approved plan tasks one at a time. For each task:
11
+
12
+ 1. Read the affected files (the `Files` list in the task header).
13
+ 2. Apply the change.
14
+ 3. Run targeted verification (typecheck, the test that covers the change, lint on the touched files).
15
+ 4. Record progress via `todo_write` so the user can see the cursor.
16
+
17
+ You **MUST** call `harness_validate_finding` whenever a verification step surfaces a deferred issue you cannot resolve in this turn — that lands in the implement log and the queue for GC.
18
+
19
+ After every task that wrote files, the post-session sweep hook fires and may add dead-code findings to the queue. Treat those as follow-up work; do not ignore them.
20
+
21
+ You **MUST NOT**:
22
+ - Skip tasks.
23
+ - Mark a task done before its `criteria` is observably satisfied.
24
+ - Delete user-authored content outside the plan's `Files` list without explicit confirmation.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: harness-plan
3
+ description: Render the harness plan from a design spec
4
+ supportedSlots: [plan]
5
+ focus: plan
6
+ ---
7
+
8
+ You are the **plan** agent for the supipowers harness pipeline.
9
+
10
+ The structured plan is computed deterministically from the design spec via `buildHarnessPlanTasks`. Your role is **review and refinement only**:
11
+
12
+ - Read the rendered plan markdown and the design spec.
13
+ - For each task, validate that `criteria` and `complexity` match what the design demands.
14
+ - Add missing edge-case tasks the deterministic builder would not catch (e.g. "migrate existing CI workflow to call `bunx supipowers harness validate`").
15
+ - Cap individual task labels at 200 chars.
16
+
17
+ You **MUST** persist the plan via the standard `/supi:plan` approval flow — `emitHarnessPlanFromSpec` already wrote the plan to the canonical plans directory before you started. Your job is to ensure the markdown is review-ready.
18
+
19
+ You **MUST NOT** execute the plan. Implementation runs in a separate session after user approval.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: harness-research
3
+ description: Per-topic research writeup with primary sources for the harness pipeline
4
+ supportedSlots: [research]
5
+ focus: research
6
+ ---
7
+
8
+ You are the **research** agent for the supipowers harness pipeline.
9
+
10
+ Your job is to write a single research topic markdown for the harness session. The topic slug + title are passed in the assignment prompt; do not invent your own.
11
+
12
+ You **MUST**:
13
+ - Use the `web_search` tool to find at least **two distinct primary sources** (papers, official docs, RFCs). Engine-ranking-only — do **NOT** filter by year.
14
+ - Structure the output with these headings, in order: `## Background`, `## Options`, `## Recommendation`, `## Sources`, `## Last verified`.
15
+ - Set the frontmatter `lastVerified` field to today's ISO date.
16
+ - Call `harness_research_record` exactly once with `{sessionId, topicSlug, markdown}`.
17
+
18
+ You **MUST NOT**:
19
+ - Cite blog posts or tutorials as primary sources.
20
+ - Skip the `## Options` heading or the recommendation.
21
+ - Submit fewer than 2 source URLs.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: harness-validate
3
+ description: Run validate sub-checks and surface findings via harness_validate_finding
4
+ supportedSlots: [validate]
5
+ focus: validation
6
+ ---
7
+
8
+ You are the **validate** agent for the supipowers harness pipeline.
9
+
10
+ The deterministic validate pass (`runValidate`) has already produced `<session>/validate-report.json`. Your role is to **surface unactionable warnings to the user** — the deterministic pass classifies items but cannot triage them.
11
+
12
+ For each finding in the report:
13
+
14
+ 1. Read the underlying file at the cited line.
15
+ 2. Confirm the finding is real (not a false positive from a stale scan).
16
+ 3. Record a follow-up via `harness_validate_finding` with `severity` and `remediation`.
17
+ 4. If the finding maps to a slop-queue entry, link it via the `details.queueId` field.
18
+
19
+ You **MUST NOT**:
20
+ - Re-run scans (the deterministic pass already did, and it cached the score).
21
+ - Approve the validate report — the user owns the accept gate.
22
+ - Apply auto-fixes (those run from `/supi:harness gc`, not from validate).
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Render a human-readable summary of a GC report.
3
+ */
4
+
5
+ import type { GcReport } from "./runner.js";
6
+
7
+ export function renderGcReport(report: GcReport): string {
8
+ const lines: string[] = [];
9
+ lines.push("Harness GC report");
10
+ lines.push("─────────────────");
11
+ lines.push(`Inspected: ${report.inspected}`);
12
+ lines.push(`Mechanical attempted: ${report.mechanicalAttempted}`);
13
+ lines.push(`Mechanical resolved: ${report.mechanicalResolved}`);
14
+ lines.push(`Judgmental reported: ${report.judgmentalReported}`);
15
+ if (report.failures.length > 0) {
16
+ lines.push("");
17
+ lines.push(`Failures (${report.failures.length}):`);
18
+ for (const failure of report.failures.slice(0, 10)) {
19
+ lines.push(` - ${failure.id}: ${failure.reason}`);
20
+ }
21
+ if (report.failures.length > 10) {
22
+ lines.push(` …and ${report.failures.length - 10} more.`);
23
+ }
24
+ }
25
+ lines.push("");
26
+ lines.push(`Elapsed: ${report.durationMs} ms`);
27
+ return lines.join("\n");
28
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * GC subcommand driver.
3
+ *
4
+ * Drains the persistent slop queue and re-runs Validate. For each unresolved entry, the
5
+ * GC classifies as **mechanical** (auto-fixable) or **judgmental** (reported only).
6
+ * Mechanical fixes apply via the configured backend's `fix(apply: true)` and on success
7
+ * the entry transitions to `resolved`.
8
+ *
9
+ * Concurrency is configurable (default 4). The runner is best-effort: a single failed
10
+ * fixer never aborts the rest.
11
+ */
12
+
13
+ import type { Platform, PlatformPaths } from "../../platform/types.js";
14
+ import type {
15
+ HarnessAntiSlopBackend,
16
+ HarnessSlopQueueEntry,
17
+ } from "../../types.js";
18
+ import type { SlopBackend } from "../anti_slop/backend.js";
19
+ import {
20
+ backlog as readBacklog,
21
+ resolve as resolveQueueEntry,
22
+ } from "../anti_slop/queue.js";
23
+
24
+ const DEFAULT_CONCURRENCY = 4;
25
+
26
+ const MECHANICAL_KINDS: ReadonlySet<HarnessSlopQueueEntry["kind"]> = new Set([
27
+ "dead-code",
28
+ "naming",
29
+ "file-too-large",
30
+ ]);
31
+
32
+ export interface GcInput {
33
+ platform: Platform;
34
+ paths: PlatformPaths;
35
+ cwd: string;
36
+ backend: HarnessAntiSlopBackend;
37
+ /** Backend adapter, when the backend supports automated fixes. */
38
+ adapter: SlopBackend | null;
39
+ /** Concurrency for fix dispatch. Defaults to 4. */
40
+ concurrency?: number;
41
+ /** When true, fixes are applied; when false, GC dry-runs (reports only). */
42
+ apply: boolean;
43
+ }
44
+
45
+ export interface GcReport {
46
+ inspected: number;
47
+ mechanicalAttempted: number;
48
+ mechanicalResolved: number;
49
+ judgmentalReported: number;
50
+ failures: { id: string; reason: string }[];
51
+ durationMs: number;
52
+ }
53
+
54
+ /**
55
+ * Classify whether an entry is mechanical (eligible for auto-fix) or judgmental.
56
+ */
57
+ export function isMechanical(entry: HarnessSlopQueueEntry): boolean {
58
+ return MECHANICAL_KINDS.has(entry.kind);
59
+ }
60
+
61
+ /**
62
+ * Run the GC drain. Pure dispatcher for tests; the real subcommand wraps this with
63
+ * progress UI and report rendering.
64
+ */
65
+ export async function runHarnessGc(input: GcInput): Promise<GcReport> {
66
+ const startedAt = Date.now();
67
+ const result: GcReport = {
68
+ inspected: 0,
69
+ mechanicalAttempted: 0,
70
+ mechanicalResolved: 0,
71
+ judgmentalReported: 0,
72
+ failures: [],
73
+ durationMs: 0,
74
+ };
75
+
76
+ const backlog = readBacklog(input.paths, input.cwd, { state: "open" });
77
+ if (!backlog.ok) {
78
+ result.durationMs = Date.now() - startedAt;
79
+ result.failures.push({ id: "(read)", reason: backlog.error.message });
80
+ return result;
81
+ }
82
+
83
+ const entries = backlog.value;
84
+ result.inspected = entries.length;
85
+
86
+ const mechanical = entries.filter(isMechanical);
87
+ const judgmental = entries.filter((e) => !isMechanical(e));
88
+ result.judgmentalReported = judgmental.length;
89
+
90
+ if (mechanical.length === 0 || !input.adapter) {
91
+ result.durationMs = Date.now() - startedAt;
92
+ return result;
93
+ }
94
+
95
+ const concurrency = input.concurrency ?? DEFAULT_CONCURRENCY;
96
+ let cursor = 0;
97
+
98
+ async function worker(): Promise<void> {
99
+ while (cursor < mechanical.length) {
100
+ const idx = cursor;
101
+ cursor += 1;
102
+ if (idx >= mechanical.length) return;
103
+ const entry = mechanical[idx];
104
+ result.mechanicalAttempted += 1;
105
+ const fix = await (input.adapter as SlopBackend).fix(input.platform, {
106
+ cwd: input.cwd,
107
+ entryIds: [entry.id],
108
+ apply: input.apply,
109
+ });
110
+ if (fix.ok && fix.appliedIds.includes(entry.id)) {
111
+ const resolved = resolveQueueEntry(input.paths, input.cwd, entry.id);
112
+ if (resolved.ok && resolved.value) {
113
+ result.mechanicalResolved += 1;
114
+ } else {
115
+ result.failures.push({
116
+ id: entry.id,
117
+ reason: !resolved.ok ? resolved.error.message : "entry already resolved or missing",
118
+ });
119
+ }
120
+ } else {
121
+ const failure = fix.failedIds.find((f) => f.id === entry.id);
122
+ result.failures.push({
123
+ id: entry.id,
124
+ reason: failure?.reason ?? "fix did not include entry id",
125
+ });
126
+ }
127
+ }
128
+ }
129
+
130
+ const workers: Promise<void>[] = [];
131
+ for (let i = 0; i < concurrency; i += 1) workers.push(worker());
132
+ await Promise.all(workers);
133
+
134
+ result.durationMs = Date.now() - startedAt;
135
+ return result;
136
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Layer-context-injection hook.
3
+ *
4
+ * Registered on `before_agent_start`. Reads `docs/architecture.md`, determines the layer
5
+ * of the file the agent is about to edit, and prepends a system-prompt addendum so the
6
+ * agent is reminded of the import rules.
7
+ *
8
+ * Degrades gracefully:
9
+ * - missing `docs/architecture.md` → no addendum,
10
+ * - no rule matches the file → no addendum,
11
+ * - addendum exceeds `addendum_max_chars` → truncated with "…".
12
+ *
13
+ * The hook does NOT block tool calls; it only augments the system prompt. We never
14
+ * extract the "file the agent is about to edit" from the system-prompt event itself —
15
+ * that would require parsing user prompts. Instead, callers wire the hook with a
16
+ * `file-resolver` that pulls the candidate file from the active session metadata, and
17
+ * fall back to no-op when no candidate exists.
18
+ */
19
+
20
+ import * as fs from "node:fs";
21
+
22
+ import type { Platform } from "../../platform/types.js";
23
+ import { prependSystemPromptBlock } from "../../platform/system-prompt.js";
24
+ import type { HarnessHookConfig, HarnessLayerRule } from "../../types.js";
25
+ import {
26
+ buildLayerAddendum,
27
+ parseArchitectureMarkdown,
28
+ resolveLayerForFile,
29
+ } from "../anti_slop/architecture-parser.js";
30
+ import {
31
+ getHarnessArchitectureDocPath,
32
+ getHarnessMarkerPath,
33
+ } from "../project-paths.js";
34
+
35
+ export interface LayerContextHookOptions {
36
+ /**
37
+ * Resolves a candidate file path from the event/ctx pair. Implementations consult
38
+ * session metadata, the user's last prompt, or recent tool calls — whatever the
39
+ * harness can wire through. Returning `null` short-circuits the hook.
40
+ */
41
+ resolveCandidateFile: (event: unknown, ctx: unknown) => string | null;
42
+ /** Hook config snapshot. Defaults to disabled when undefined. */
43
+ config?: HarnessHookConfig["layer_context_inject"];
44
+ }
45
+
46
+ const DEFAULT_CONFIG: HarnessHookConfig["layer_context_inject"] = {
47
+ enabled: false,
48
+ addendum_max_chars: 800,
49
+ };
50
+
51
+ interface CachedRules {
52
+ layerRules: HarnessLayerRule[];
53
+ mtimeMs: number;
54
+ }
55
+
56
+ /** Cache the parsed rules per architecture-doc path so we don't re-read on every hook. */
57
+ const rulesCache = new Map<string, CachedRules>();
58
+
59
+ function loadRules(archPath: string): HarnessLayerRule[] {
60
+ let stat: fs.Stats;
61
+ try {
62
+ stat = fs.statSync(archPath);
63
+ } catch {
64
+ return [];
65
+ }
66
+ const cached = rulesCache.get(archPath);
67
+ if (cached && cached.mtimeMs === stat.mtimeMs) return cached.layerRules;
68
+ let md: string;
69
+ try {
70
+ md = fs.readFileSync(archPath, "utf8");
71
+ } catch {
72
+ return [];
73
+ }
74
+ const layerRules = parseArchitectureMarkdown(md);
75
+ rulesCache.set(archPath, { layerRules, mtimeMs: stat.mtimeMs });
76
+ return layerRules;
77
+ }
78
+
79
+ export interface LayerContextInjectionResult {
80
+ /** Addendum to prepend to the system prompt; empty string when no-op. */
81
+ addendum: string;
82
+ /** Why the hook returned what it did — used by tests. */
83
+ reason: string;
84
+ }
85
+
86
+ /**
87
+ * Compute the addendum for a single hook invocation. Pure-ish: reads the file system but
88
+ * never mutates state. Tests call this directly with a known cwd + candidate file.
89
+ */
90
+ export function computeLayerAddendum(input: {
91
+ cwd: string;
92
+ candidateFile: string | null;
93
+ config: HarnessHookConfig["layer_context_inject"];
94
+ /** Override the resolved architecture-doc path; tests use this to point at a fixture. */
95
+ archPath?: string;
96
+ }): LayerContextInjectionResult {
97
+ if (!input.config.enabled) return { addendum: "", reason: "disabled" };
98
+ if (!input.candidateFile) return { addendum: "", reason: "no candidate file" };
99
+ const archPath = input.archPath ?? `${input.cwd}/docs/architecture.md`;
100
+ const rules = loadRules(archPath);
101
+ if (rules.length === 0) return { addendum: "", reason: "no rules parsed" };
102
+ const rule = resolveLayerForFile(input.candidateFile, rules);
103
+ if (!rule) return { addendum: "", reason: "no rule matches candidate file" };
104
+ const addendum = buildLayerAddendum(input.candidateFile, rule, input.config.addendum_max_chars);
105
+ return { addendum, reason: "matched" };
106
+ }
107
+
108
+ /**
109
+ * Register the hook. Returns a teardown function the caller can invoke to revoke
110
+ * registration (used by tests). The hook is gated by the harness marker — when the
111
+ * marker is missing, the hook is a no-op (it never reads the architecture doc).
112
+ */
113
+ export function registerLayerContextInjectHook(
114
+ platform: Platform,
115
+ options: LayerContextHookOptions,
116
+ ): () => void {
117
+ const config = options.config ?? DEFAULT_CONFIG;
118
+ if (!config.enabled) {
119
+ return () => {};
120
+ }
121
+
122
+ let unregistered = false;
123
+ const handler = (event: unknown, ctx: unknown): { systemPrompt: string[] } | undefined => {
124
+ if (unregistered) return undefined;
125
+ const cwd = (ctx as { cwd?: string } | undefined)?.cwd ?? process.cwd();
126
+ if (!fs.existsSync(getHarnessMarkerPath(platform.paths, cwd))) return undefined;
127
+
128
+ const candidateFile = options.resolveCandidateFile(event, ctx);
129
+ const result = computeLayerAddendum({
130
+ cwd,
131
+ candidateFile,
132
+ config,
133
+ archPath: getHarnessArchitectureDocPath(platform.paths, cwd),
134
+ });
135
+ if (result.addendum.length === 0) return undefined;
136
+
137
+ return {
138
+ systemPrompt: prependSystemPromptBlock(
139
+ (event as { systemPrompt?: unknown } | undefined)?.systemPrompt,
140
+ result.addendum,
141
+ ),
142
+ };
143
+ };
144
+
145
+ platform.on("before_agent_start", handler);
146
+
147
+ return () => {
148
+ unregistered = true;
149
+ };
150
+ }
151
+
152
+ /** Reset the in-memory rule cache. Tests use this to re-read the architecture doc. */
153
+ export function _resetLayerRuleCacheForTests(): void {
154
+ rulesCache.clear();
155
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Post-session dead-code sweep.
3
+ *
4
+ * Registered on `agent_end`. After every turn that wrote files, runs the configured
5
+ * backend's `deadCode` scan against changed files and appends new findings to the queue.
6
+ *
7
+ * The hook never blocks the session — `block_on_new_dead_code` only controls whether we
8
+ * surface a warning steer message back to the user. Even when surfacing, we do not
9
+ * replace `agent_end` with `awaiting-user` semantics; we simply notify.
10
+ */
11
+
12
+ import * as fs from "node:fs";
13
+
14
+ import type { Platform } from "../../platform/types.js";
15
+ import type { HarnessHookConfig, HarnessSlopQueueEntry } from "../../types.js";
16
+ import { type SlopBackend } from "../anti_slop/backend.js";
17
+ import { computeQueueEntryId } from "../anti_slop/queue.js";
18
+ import { appendSlopQueueEntry } from "../storage.js";
19
+ import { getHarnessMarkerPath } from "../project-paths.js";
20
+
21
+ export interface PostSessionSweepOptions {
22
+ adapter: SlopBackend | null;
23
+ config: HarnessHookConfig["post_session_sweep"];
24
+ /** Optional override for the per-turn timeout (ms). Defaults to 30 s. */
25
+ timeoutMs?: number;
26
+ }
27
+
28
+ export interface SweepResult {
29
+ ran: boolean;
30
+ newFindings: number;
31
+ durationMs: number;
32
+ reason: string;
33
+ }
34
+
35
+ /** Run the sweep and append new findings. Pure dispatcher, used by both the live hook and tests. */
36
+ export async function runPostSessionSweep(input: {
37
+ platform: Platform;
38
+ cwd: string;
39
+ adapter: SlopBackend;
40
+ timeoutMs: number;
41
+ }): Promise<SweepResult> {
42
+ const startedAt = Date.now();
43
+ const result = await input.adapter.deadCode(input.platform, {
44
+ cwd: input.cwd,
45
+ changedSinceHead: true,
46
+ timeoutMs: input.timeoutMs,
47
+ });
48
+ if (!result.ok) {
49
+ return {
50
+ ran: false,
51
+ newFindings: 0,
52
+ durationMs: Date.now() - startedAt,
53
+ reason: `${result.reason}: ${result.message}`,
54
+ };
55
+ }
56
+ let newFindings = 0;
57
+ const ts = new Date().toISOString();
58
+ for (const finding of result.findings) {
59
+ if (finding.kind !== "dead-code") continue;
60
+ const id = computeQueueEntryId({
61
+ kind: "dead-code",
62
+ file: finding.file,
63
+ range: finding.range,
64
+ ruleHint: typeof finding.details?.rule === "string" ? finding.details.rule : "post-session-sweep",
65
+ });
66
+ const entry: HarnessSlopQueueEntry = {
67
+ id,
68
+ kind: "dead-code",
69
+ file: finding.file,
70
+ range: finding.range,
71
+ severity: finding.severity,
72
+ source: finding.source,
73
+ state: "open",
74
+ message: finding.message,
75
+ remediation: finding.remediation,
76
+ ts,
77
+ ...(finding.details ? { details: finding.details } : {}),
78
+ };
79
+ const persisted = appendSlopQueueEntry(input.platform.paths, input.cwd, entry);
80
+ if (persisted.ok) newFindings += 1;
81
+ }
82
+ return {
83
+ ran: true,
84
+ newFindings,
85
+ durationMs: Date.now() - startedAt,
86
+ reason: newFindings > 0 ? `${newFindings} new dead-code finding(s)` : "no new findings",
87
+ };
88
+ }
89
+
90
+ export function registerPostSessionSweepHook(
91
+ platform: Platform,
92
+ options: PostSessionSweepOptions,
93
+ ): () => void {
94
+ if (!options.config.enabled || options.adapter === null) {
95
+ return () => {};
96
+ }
97
+ let unregistered = false;
98
+ const adapter = options.adapter;
99
+ const timeoutMs = options.timeoutMs ?? 30_000;
100
+
101
+ const handler = async (_event: unknown, ctx: unknown): Promise<void> => {
102
+ if (unregistered) return;
103
+ const cwd = (ctx as { cwd?: string } | undefined)?.cwd ?? process.cwd();
104
+ if (!fs.existsSync(getHarnessMarkerPath(platform.paths, cwd))) return;
105
+ const result = await runPostSessionSweep({
106
+ platform,
107
+ cwd,
108
+ adapter,
109
+ timeoutMs,
110
+ });
111
+ if (result.newFindings > 0 && options.config.block_on_new_dead_code) {
112
+ // The block-on-new-dead-code policy is a steer message; we do NOT abort the agent.
113
+ const message =
114
+ `Harness sweep detected ${result.newFindings} new dead-code finding(s). Run /supi:harness backlog to inspect.`;
115
+ try {
116
+ platform.sendMessage(
117
+ { customType: "supi-harness-sweep", content: [{ type: "text", text: message }], display: "none" },
118
+ { deliverAs: "steer", triggerTurn: false },
119
+ );
120
+ } catch {
121
+ // Platform may not implement sendMessage; ignore.
122
+ }
123
+ }
124
+ };
125
+
126
+ platform.on("agent_end", handler);
127
+ return () => {
128
+ unregistered = true;
129
+ };
130
+ }