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.
- package/README.md +14 -8
- package/bin/install.mjs +20 -5
- package/bin/install.ts +95 -0
- package/package.json +8 -4
- package/skills/context-mode/SKILL.md +17 -10
- package/skills/harness/SKILL.md +94 -0
- package/skills/ui-design/SKILL.md +63 -0
- package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
- package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
- package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
- package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
- package/skills/ultraplan-discover/SKILL.md +96 -0
- package/skills/ultraplan-intake/SKILL.md +89 -0
- package/skills/ultraplan-research/SKILL.md +129 -0
- package/skills/ultraplan-review/SKILL.md +86 -0
- package/skills/ultraplan-review-scope/SKILL.md +111 -0
- package/skills/ultraplan-review-structure/SKILL.md +120 -0
- package/skills/ultraplan-review-tdd/SKILL.md +142 -0
- package/skills/ultraplan-scout/SKILL.md +110 -0
- package/skills/ultraplan-synthesize/SKILL.md +124 -0
- package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
- package/src/ai/schema-text.ts +129 -0
- package/src/ai/structured-output.ts +274 -0
- package/src/ai/template.ts +27 -0
- package/src/bootstrap.ts +63 -28
- package/src/commands/agents.ts +131 -42
- package/src/commands/ai-review.ts +251 -30
- package/src/commands/clear.ts +434 -0
- package/src/commands/commit.ts +1 -0
- package/src/commands/config.ts +242 -44
- package/src/commands/context.ts +55 -28
- package/src/commands/doctor.ts +234 -6
- package/src/commands/fix-pr.ts +306 -131
- package/src/commands/generate.ts +111 -21
- package/src/commands/memory.ts +192 -0
- package/src/commands/model-picker.ts +28 -21
- package/src/commands/model.ts +18 -8
- package/src/commands/optimize-context.ts +408 -29
- package/src/commands/plan.ts +2 -0
- package/src/commands/qa.ts +312 -137
- package/src/commands/release.ts +259 -76
- package/src/commands/review.ts +293 -59
- package/src/commands/status.ts +200 -13
- package/src/commands/supi.ts +3 -35
- package/src/commands/ui-design.ts +394 -0
- package/src/commands/ultraplan.ts +1518 -0
- package/src/commands/update.ts +86 -0
- package/src/config/defaults.ts +62 -0
- package/src/config/loader.ts +448 -60
- package/src/config/schema.ts +108 -2
- package/src/context/optimizer.ts +25 -33
- package/src/context/rule-renderer.ts +223 -0
- package/src/context/savings.ts +258 -0
- package/src/context/startup-check.ts +380 -0
- package/src/context/startup-optimizer.ts +355 -0
- package/src/context/tokenignore.ts +146 -0
- package/src/context-mode/cache-handle.ts +49 -0
- package/src/context-mode/cache-preview.ts +71 -0
- package/src/context-mode/cache-store.ts +738 -0
- package/src/context-mode/compressor.ts +131 -26
- package/src/context-mode/dedup.ts +108 -0
- package/src/context-mode/detector.ts +35 -4
- package/src/context-mode/event-extractor.ts +14 -12
- package/src/context-mode/event-store.ts +91 -36
- package/src/context-mode/hooks.ts +798 -56
- package/src/context-mode/knowledge/store.ts +255 -11
- package/src/context-mode/memory-store.ts +325 -0
- package/src/context-mode/metrics-recorder.ts +158 -0
- package/src/context-mode/metrics-store.ts +765 -0
- package/src/context-mode/model.ts +24 -0
- package/src/context-mode/processor-keys.ts +29 -0
- package/src/context-mode/processors/build.ts +66 -0
- package/src/context-mode/processors/docker.ts +57 -0
- package/src/context-mode/processors/git.ts +111 -0
- package/src/context-mode/processors/json.ts +112 -0
- package/src/context-mode/processors/k8s.ts +67 -0
- package/src/context-mode/processors/lint.ts +67 -0
- package/src/context-mode/processors/log.ts +86 -0
- package/src/context-mode/processors/registry.ts +116 -0
- package/src/context-mode/processors/test-runner.ts +102 -0
- package/src/context-mode/processors/types.ts +20 -0
- package/src/context-mode/repomap.ts +400 -0
- package/src/context-mode/routing.ts +97 -24
- package/src/context-mode/sandbox/runners.ts +5 -1
- package/src/context-mode/snapshot-builder.ts +106 -11
- package/src/context-mode/source-hash.ts +173 -0
- package/src/context-mode/tool-name.ts +11 -0
- package/src/context-mode/tools.ts +654 -22
- package/src/context-mode/web/fetcher.ts +31 -12
- package/src/debug/logger.ts +2 -1
- package/src/deps/registry.ts +1 -1
- package/src/discipline/failure-summarizer.ts +170 -0
- package/src/discipline/failure-taxonomy.ts +131 -0
- package/src/discipline/workflow-invariants.ts +125 -0
- package/src/discovery/index.ts +31 -0
- package/src/discovery/lsp.ts +87 -0
- package/src/discovery/rank.ts +144 -0
- package/src/discovery/sources.ts +89 -0
- package/src/discovery/workflow.ts +87 -0
- package/src/docs/contracts.ts +39 -0
- package/src/docs/drift.ts +117 -87
- package/src/fix-pr/assessment.ts +200 -0
- package/src/fix-pr/contracts.ts +47 -0
- package/src/fix-pr/fetch-comments.ts +80 -0
- package/src/fix-pr/prompt-builder.ts +58 -40
- package/src/fix-pr/scripts/exec.ts +34 -0
- package/src/fix-pr/scripts/trigger-review.ts +106 -0
- package/src/fix-pr/scripts/wait-and-check.ts +108 -0
- package/src/fix-pr/types.ts +4 -0
- package/src/git/branch-finish.ts +5 -0
- package/src/git/commit-contract.ts +83 -0
- package/src/git/commit.ts +121 -184
- package/src/git/status.ts +62 -8
- package/src/harness/anti_slop/architecture-parser.ts +210 -0
- package/src/harness/anti_slop/backend-factory.ts +30 -0
- package/src/harness/anti_slop/backend.ts +140 -0
- package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
- package/src/harness/anti_slop/fallow-adapter.ts +305 -0
- package/src/harness/anti_slop/installer.ts +227 -0
- package/src/harness/anti_slop/queue.ts +216 -0
- package/src/harness/anti_slop/recommend.ts +84 -0
- package/src/harness/anti_slop/score.ts +180 -0
- package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
- package/src/harness/artifacts/agents-md.ts +88 -0
- package/src/harness/artifacts/checks-wiring.ts +57 -0
- package/src/harness/artifacts/docs-tree.ts +79 -0
- package/src/harness/artifacts/lint-configs.ts +136 -0
- package/src/harness/artifacts/review-agents.ts +67 -0
- package/src/harness/bare-entry.ts +108 -0
- package/src/harness/command.ts +1010 -0
- package/src/harness/default-agents/design.md +23 -0
- package/src/harness/default-agents/discover.md +18 -0
- package/src/harness/default-agents/implement.md +24 -0
- package/src/harness/default-agents/plan.md +19 -0
- package/src/harness/default-agents/research.md +21 -0
- package/src/harness/default-agents/validate.md +22 -0
- package/src/harness/gc/reporter.ts +28 -0
- package/src/harness/gc/runner.ts +136 -0
- package/src/harness/hooks/layer-context-inject.ts +155 -0
- package/src/harness/hooks/post-session-sweep.ts +130 -0
- package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
- package/src/harness/hooks/register.ts +118 -0
- package/src/harness/model.ts +117 -0
- package/src/harness/pipeline.ts +348 -0
- package/src/harness/project-paths.ts +235 -0
- package/src/harness/stage-runner.ts +107 -0
- package/src/harness/stages/design.ts +386 -0
- package/src/harness/stages/discover.ts +454 -0
- package/src/harness/stages/implement.ts +162 -0
- package/src/harness/stages/plan.ts +335 -0
- package/src/harness/stages/research.ts +263 -0
- package/src/harness/stages/validate.ts +684 -0
- package/src/harness/storage.ts +467 -0
- package/src/harness/tools.ts +426 -0
- package/src/lsp/bridge.ts +56 -95
- package/src/lsp/capabilities.ts +108 -0
- package/src/lsp/contracts.ts +35 -0
- package/src/lsp/detector.ts +8 -12
- package/src/markdown-frontmatter.ts +68 -0
- package/src/mempalace/bridge.ts +135 -0
- package/src/mempalace/config.ts +75 -0
- package/src/mempalace/format.ts +163 -0
- package/src/mempalace/hooks.ts +370 -0
- package/src/mempalace/installer-helper.ts +194 -0
- package/src/mempalace/python/mempalace_bridge.py +440 -0
- package/src/mempalace/runtime.ts +565 -0
- package/src/mempalace/schema.ts +268 -0
- package/src/mempalace/session-summary.ts +198 -0
- package/src/mempalace/tool.ts +186 -0
- package/src/mempalace/uv.ts +256 -0
- package/src/migrate/runner.ts +354 -0
- package/src/planning/approval-flow.ts +206 -9
- package/src/planning/plan-writer-prompt.ts +4 -3
- package/src/planning/planning-ask-tool.ts +39 -0
- package/src/planning/render-markdown.ts +74 -0
- package/src/planning/spec.ts +42 -0
- package/src/planning/system-prompt.ts +11 -8
- package/src/planning/validate.ts +84 -0
- package/src/platform/omp.ts +15 -2
- package/src/platform/system-prompt.ts +37 -0
- package/src/platform/test-utils.ts +3 -0
- package/src/platform/types.ts +6 -1
- package/src/qa/config.ts +12 -6
- package/src/qa/detect-app-type.ts +13 -6
- package/src/qa/matrix.ts +12 -6
- package/src/qa/prompt-builder.ts +28 -30
- package/src/qa/scripts/dev-server-utils.ts +72 -0
- package/src/qa/scripts/run-e2e-tests.ts +226 -0
- package/src/qa/scripts/start-dev-server.ts +138 -0
- package/src/qa/scripts/stop-dev-server.ts +77 -0
- package/src/qa/session.ts +13 -7
- package/src/quality/ai-setup.ts +27 -25
- package/src/quality/contracts.ts +34 -0
- package/src/quality/gates/ai-review.ts +20 -58
- package/src/quality/gates/command.ts +249 -46
- package/src/quality/review-gates.ts +18 -2
- package/src/quality/runner.ts +63 -22
- package/src/quality/schemas.ts +37 -2
- package/src/quality/setup.ts +96 -16
- package/src/release/changelog.ts +1 -1
- package/src/release/channels/custom.ts +13 -3
- package/src/release/channels/types.ts +5 -0
- package/src/release/contracts.ts +90 -0
- package/src/release/executor.ts +122 -45
- package/src/release/prompt.ts +18 -2
- package/src/release/targets.ts +86 -0
- package/src/release/version.ts +96 -71
- package/src/review/agent-loader.ts +221 -109
- package/src/review/fixer.ts +10 -6
- package/src/review/multi-agent-runner.ts +114 -13
- package/src/review/output.ts +12 -139
- package/src/review/runner.ts +12 -6
- package/src/review/scope.ts +144 -24
- package/src/review/types.ts +1 -20
- package/src/review/validator.ts +12 -6
- package/src/storage/fix-pr-sessions.ts +21 -14
- package/src/storage/plans.ts +14 -5
- package/src/storage/qa-sessions.ts +25 -19
- package/src/storage/reliability-metrics.ts +180 -0
- package/src/storage/reports.ts +8 -7
- package/src/storage/review-sessions.ts +55 -20
- package/src/tool-catalog/active-tool-controller.ts +164 -0
- package/src/tool-catalog/active-tool-planner.ts +212 -0
- package/src/tool-catalog/tool-groups.ts +102 -0
- package/src/types.ts +1399 -5
- package/src/ui-design/backend-adapter.ts +78 -0
- package/src/ui-design/backends/local-html.ts +82 -0
- package/src/ui-design/backends/pencil-mcp.ts +111 -0
- package/src/ui-design/components-scanner.ts +124 -0
- package/src/ui-design/config.ts +55 -0
- package/src/ui-design/pen-scanner.ts +95 -0
- package/src/ui-design/pen-selector.ts +72 -0
- package/src/ui-design/prompt-builder.ts +73 -0
- package/src/ui-design/scanner.ts +136 -0
- package/src/ui-design/session.ts +974 -0
- package/src/ui-design/system-prompt.ts +312 -0
- package/src/ui-design/tokens-scanner.ts +181 -0
- package/src/ui-design/types.ts +96 -0
- package/src/ultraplan/agent-catalog.ts +522 -0
- package/src/ultraplan/authoring/agent-catalog.ts +310 -0
- package/src/ultraplan/authoring/authoring-tools.ts +552 -0
- package/src/ultraplan/authoring/command-handlers.ts +339 -0
- package/src/ultraplan/authoring/markdown.ts +510 -0
- package/src/ultraplan/authoring/model.ts +162 -0
- package/src/ultraplan/authoring/pipeline.ts +319 -0
- package/src/ultraplan/authoring/stage-runner.ts +141 -0
- package/src/ultraplan/authoring/stages/approve.ts +249 -0
- package/src/ultraplan/authoring/stages/discover.ts +289 -0
- package/src/ultraplan/authoring/stages/intake.ts +203 -0
- package/src/ultraplan/authoring/stages/research.ts +399 -0
- package/src/ultraplan/authoring/stages/review.ts +333 -0
- package/src/ultraplan/authoring/stages/scout.ts +188 -0
- package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
- package/src/ultraplan/authoring/storage.ts +594 -0
- package/src/ultraplan/authoring/synth-gate.ts +165 -0
- package/src/ultraplan/authoring-draft.ts +653 -0
- package/src/ultraplan/authoring-persist.ts +180 -0
- package/src/ultraplan/authoring-tool.ts +608 -0
- package/src/ultraplan/authoring-wizard.ts +587 -0
- package/src/ultraplan/batch/merge.ts +98 -0
- package/src/ultraplan/batch/planner.ts +150 -0
- package/src/ultraplan/batch/presenter.ts +97 -0
- package/src/ultraplan/batch/storage.ts +420 -0
- package/src/ultraplan/batch/supervisor.ts +317 -0
- package/src/ultraplan/batch/worker.ts +26 -0
- package/src/ultraplan/batch/worktree.ts +110 -0
- package/src/ultraplan/contracts.ts +1593 -0
- package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
- package/src/ultraplan/default-agents/authoring/intake.md +12 -0
- package/src/ultraplan/default-agents/authoring/planner.md +12 -0
- package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
- package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/scout.md +12 -0
- package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
- package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-executor.md +10 -0
- package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-tester.md +10 -0
- package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-executor.md +10 -0
- package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-tester.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
- package/src/ultraplan/execution/contract.ts +71 -0
- package/src/ultraplan/execution/policy.ts +217 -0
- package/src/ultraplan/execution/runtime-tools.ts +107 -0
- package/src/ultraplan/execution/session-runner.ts +281 -0
- package/src/ultraplan/next-router.ts +85 -0
- package/src/ultraplan/presenter.ts +359 -0
- package/src/ultraplan/project-paths.ts +342 -0
- package/src/ultraplan/runtime/active-execution.ts +72 -0
- package/src/ultraplan/runtime/apply-mutation.ts +416 -0
- package/src/ultraplan/runtime/blockers.ts +243 -0
- package/src/ultraplan/runtime/hook-bridge.ts +486 -0
- package/src/ultraplan/runtime/launch-context.ts +207 -0
- package/src/ultraplan/runtime/migration.ts +524 -0
- package/src/ultraplan/runtime/normalize.ts +281 -0
- package/src/ultraplan/runtime/proof.ts +260 -0
- package/src/ultraplan/runtime/reducer.ts +416 -0
- package/src/ultraplan/runtime/repair.ts +251 -0
- package/src/ultraplan/runtime/tracker-storage.ts +368 -0
- package/src/ultraplan/session-selection.ts +291 -0
- package/src/ultraplan/storage.ts +374 -0
- package/src/utils/editor.ts +38 -0
- package/src/utils/executable.ts +80 -0
- package/src/utils/paths.ts +1 -20
- package/src/utils/shell.ts +31 -0
- package/src/visual/companion.ts +2 -1
- package/src/visual/scripts/frame-template.html +60 -0
- package/src/visual/scripts/index.js +59 -13
- package/src/visual/scripts/package.json +3 -0
- package/src/visual/start-server.ts +2 -1
- package/src/workspace/git-scope.ts +64 -0
- package/src/workspace/locks.ts +23 -0
- package/src/workspace/package-manager.ts +117 -0
- package/src/workspace/path-mapping.ts +75 -0
- package/src/workspace/project-slug.ts +92 -0
- package/src/workspace/repo-root.ts +137 -0
- package/src/workspace/selector.ts +115 -0
- package/src/workspace/state-paths.ts +118 -0
- package/src/workspace/targets.ts +313 -0
- package/src/fix-pr/scripts/diff-comments.sh +0 -33
- package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
- package/src/fix-pr/scripts/trigger-review.sh +0 -36
- package/src/fix-pr/scripts/wait-and-check.sh +0 -37
- package/src/qa/scripts/detect-app-type.sh +0 -68
- package/src/qa/scripts/discover-routes.sh +0 -143
- package/src/qa/scripts/run-e2e-tests.sh +0 -131
- package/src/qa/scripts/start-dev-server.sh +0 -46
- package/src/qa/scripts/stop-dev-server.sh +0 -36
- package/src/review/prompts/fix-output-schema.md +0 -18
- package/src/review/prompts/review-output-schema.md +0 -38
- package/src/review/template.ts +0 -15
- /package/src/{review → ai}/prompts/invalid-output-retry.md +0 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DESIGN stage runner.
|
|
3
|
+
*
|
|
4
|
+
* Reads the discover + research artifacts and produces `<session>/design-spec.md` plus
|
|
5
|
+
* `<session>/decisions.jsonl`. The interactive Q&A flow lives in the command handler
|
|
6
|
+
* (it owns `planning_ask`); the stage runner builds the spec deterministically from a
|
|
7
|
+
* `HarnessDesignSpec` object the handler hands in.
|
|
8
|
+
*
|
|
9
|
+
* Why split this way? Mirrors `src/planning/approval-flow.ts`: stage runners are pure
|
|
10
|
+
* functions of the inputs on disk, while the interactive UI sits in the command layer.
|
|
11
|
+
* That makes the stage runner trivially testable.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
type HarnessStageRunResult,
|
|
16
|
+
type HarnessStageRunner,
|
|
17
|
+
type HarnessStageRunnerContext,
|
|
18
|
+
nowIso,
|
|
19
|
+
} from "../stage-runner.js";
|
|
20
|
+
import {
|
|
21
|
+
appendHarnessDecision,
|
|
22
|
+
loadHarnessDiscover,
|
|
23
|
+
loadHarnessDesignSpec,
|
|
24
|
+
saveHarnessDesignSpec,
|
|
25
|
+
saveHarnessDesignSpecJson,
|
|
26
|
+
} from "../storage.js";
|
|
27
|
+
import type {
|
|
28
|
+
HarnessCiConfig,
|
|
29
|
+
HarnessDesignSpec,
|
|
30
|
+
HarnessDiscoverArtifact,
|
|
31
|
+
HarnessQualityGate,
|
|
32
|
+
} from "../../types.js";
|
|
33
|
+
import { DEFAULT_HARNESS_HOOK_CONFIG } from "../hooks/register.js";
|
|
34
|
+
|
|
35
|
+
function mdCell(value: string | null): string {
|
|
36
|
+
return (value ?? "—").replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function hasText(value: unknown): value is string {
|
|
40
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function packageCommand(discover: HarnessDiscoverArtifact, script: string): string {
|
|
44
|
+
if (discover.packageManagers.includes("bun")) return `bun run ${script}`;
|
|
45
|
+
if (discover.packageManagers.includes("pnpm")) return `pnpm ${script}`;
|
|
46
|
+
if (discover.packageManagers.includes("yarn")) return `yarn ${script}`;
|
|
47
|
+
return `npm run ${script}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function defaultCiConfigFromDiscover(discover: HarnessDiscoverArtifact): HarnessCiConfig {
|
|
51
|
+
const manager = discover.packageManagers[0];
|
|
52
|
+
const localCommand = manager === "pnpm"
|
|
53
|
+
? "pnpm harness:quality"
|
|
54
|
+
: manager === "yarn"
|
|
55
|
+
? "yarn harness:quality"
|
|
56
|
+
: manager === "npm"
|
|
57
|
+
? "npm run harness:quality"
|
|
58
|
+
: "bun run harness:quality";
|
|
59
|
+
return {
|
|
60
|
+
provider: "github-actions",
|
|
61
|
+
trigger: { mode: "branches", branches: ["dev", "main"] },
|
|
62
|
+
localCommand,
|
|
63
|
+
workflowPath: ".github/workflows/harness-quality.yml",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export function defaultValidationGatesFromDiscover(discover: HarnessDiscoverArtifact): HarnessQualityGate[] {
|
|
69
|
+
const gates: HarnessQualityGate[] = [];
|
|
70
|
+
const lintTool = discover.lintTools[0];
|
|
71
|
+
if (lintTool) {
|
|
72
|
+
gates.push({
|
|
73
|
+
name: "lint",
|
|
74
|
+
invariant: "Source code should satisfy the repository's configured mechanical style and static lint rules before review.",
|
|
75
|
+
command: packageCommand(discover, "lint"),
|
|
76
|
+
proves: `${lintTool} accepts the files covered by the configured lint target.`,
|
|
77
|
+
doesNotProve: "Runtime behavior, type soundness, accessibility, and architecture boundaries are outside this proof.",
|
|
78
|
+
runsAt: "local command and CI when wired",
|
|
79
|
+
blocksOn: "non-zero exit code from the configured lint command",
|
|
80
|
+
artifact: "terminal output or CI log",
|
|
81
|
+
failSafe: "If no lint script exists, the design must either add one or remove this gate explicitly.",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (discover.languages.some((lang) => lang === "typescript" || lang === "tsx" || lang === "javascript")) {
|
|
86
|
+
gates.push({
|
|
87
|
+
name: "typecheck",
|
|
88
|
+
invariant: "Compile-time contracts must stay coherent before generated harness artifacts claim the repo is safe to edit.",
|
|
89
|
+
command: packageCommand(discover, "typecheck"),
|
|
90
|
+
proves: "The configured type checker accepts the current source and declaration graph.",
|
|
91
|
+
doesNotProve: "Runtime data shapes, third-party responses, and user workflows are not executed.",
|
|
92
|
+
runsAt: "local command and CI when wired",
|
|
93
|
+
blocksOn: "non-zero exit code from the typecheck command",
|
|
94
|
+
artifact: "terminal output or CI log",
|
|
95
|
+
failSafe: "If the command is unavailable, the gate fails until the design names the repository's actual type proof.",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const testTool = discover.testTools[0];
|
|
100
|
+
if (testTool) {
|
|
101
|
+
gates.push({
|
|
102
|
+
name: "test",
|
|
103
|
+
invariant: "Implemented behavior should keep the repository's focused unit and integration checks passing.",
|
|
104
|
+
command: packageCommand(discover, "test"),
|
|
105
|
+
proves: `${testTool} passes for the tests selected by the repository's test script.`,
|
|
106
|
+
doesNotProve: "Untested workflows, production integrations, and visual/accessibility regressions remain possible.",
|
|
107
|
+
runsAt: "local command and CI when wired",
|
|
108
|
+
blocksOn: "non-zero exit code from the test command",
|
|
109
|
+
artifact: "terminal output or CI log",
|
|
110
|
+
failSafe: "If deterministic test dependencies are missing, add fixtures or documented test-safe fallbacks before accepting the gate.",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
gates.push({
|
|
115
|
+
name: "anti-slop-scan",
|
|
116
|
+
invariant: "New harness work must not introduce unresolved duplicate, dead-code, or architecture-drift findings without queue visibility.",
|
|
117
|
+
command: null,
|
|
118
|
+
proves: `${discover.recommendedBackend} scan results were merged into the harness slop queue and scorecard.`,
|
|
119
|
+
doesNotProve: "Semantic correctness, product behavior, and findings hidden from the selected backend are outside this proof.",
|
|
120
|
+
runsAt: "/supi:harness validate and optional /supi:checks wiring",
|
|
121
|
+
blocksOn: "adapter error, strict score floor failure, or release-blocking score-floor policy when enabled",
|
|
122
|
+
artifact: "validate-report.json, queue.jsonl, score.json",
|
|
123
|
+
failSafe: "Missing optional external backends soft-fail with a warning; configured adapter errors block validation.",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return gates;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Render a HarnessDesignSpec into the markdown that lands at `<session>/design-spec.md`.
|
|
131
|
+
* Pure function for testability.
|
|
132
|
+
*/
|
|
133
|
+
export function renderDesignSpec(spec: HarnessDesignSpec): string {
|
|
134
|
+
const lines: string[] = [];
|
|
135
|
+
lines.push("---");
|
|
136
|
+
lines.push(`sessionId: ${spec.sessionId}`);
|
|
137
|
+
lines.push(`recordedAt: ${spec.recordedAt}`);
|
|
138
|
+
lines.push(`backend: ${spec.antiSlop.backend}`);
|
|
139
|
+
lines.push("---");
|
|
140
|
+
lines.push("");
|
|
141
|
+
lines.push("# Harness Design Spec");
|
|
142
|
+
lines.push("");
|
|
143
|
+
lines.push("## 1. Layered architecture");
|
|
144
|
+
lines.push("");
|
|
145
|
+
if (spec.layerRules.length === 0) {
|
|
146
|
+
lines.push("_No layered rules — single-bucket repo._");
|
|
147
|
+
} else {
|
|
148
|
+
lines.push("| Layer | Files | Allowed | Forbidden | Notes |");
|
|
149
|
+
lines.push("|---|---|---|---|---|");
|
|
150
|
+
for (const rule of spec.layerRules) {
|
|
151
|
+
const allowed = rule.allowedImports.length > 0 ? rule.allowedImports.join(", ") : "—";
|
|
152
|
+
const forbidden = rule.forbiddenImports.length > 0 ? rule.forbiddenImports.join(", ") : "—";
|
|
153
|
+
const notes = rule.description ?? "—";
|
|
154
|
+
const files = rule.globs.map((g) => `\`${g}\``).join(", ");
|
|
155
|
+
lines.push(`| ${rule.layer} | ${files} | ${allowed} | ${forbidden} | ${notes} |`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
lines.push("");
|
|
159
|
+
lines.push("## 2. Taste invariants");
|
|
160
|
+
lines.push("");
|
|
161
|
+
for (const inv of spec.tasteInvariants) lines.push(`- ${inv}`);
|
|
162
|
+
if (spec.tasteInvariants.length === 0) lines.push("_None recorded._");
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push("## 3. Tooling choices");
|
|
165
|
+
lines.push("");
|
|
166
|
+
lines.push(`- Lint: ${spec.tooling.lint ?? "(none)"}`);
|
|
167
|
+
lines.push(`- Structural test: ${spec.tooling.structuralTest ?? "(none)"}`);
|
|
168
|
+
lines.push(`- Eval framework: ${spec.tooling.eval ?? "(none)"}`);
|
|
169
|
+
lines.push("");
|
|
170
|
+
lines.push("## 4. Golden principles");
|
|
171
|
+
lines.push("");
|
|
172
|
+
for (let i = 0; i < spec.goldenPrinciples.length; i += 1) {
|
|
173
|
+
lines.push(`${i + 1}. ${spec.goldenPrinciples[i]}`);
|
|
174
|
+
}
|
|
175
|
+
if (spec.goldenPrinciples.length === 0) lines.push("_None recorded._");
|
|
176
|
+
lines.push("");
|
|
177
|
+
lines.push("## 5. Documentation tree");
|
|
178
|
+
lines.push("");
|
|
179
|
+
for (const doc of spec.docsTree) lines.push(`- \`${doc}\``);
|
|
180
|
+
if (spec.docsTree.length === 0) lines.push("_None recorded._");
|
|
181
|
+
lines.push("");
|
|
182
|
+
lines.push("## 6. Validation gates");
|
|
183
|
+
lines.push("");
|
|
184
|
+
if (spec.validationGates.length === 0) {
|
|
185
|
+
lines.push("_None recorded._");
|
|
186
|
+
} else {
|
|
187
|
+
lines.push("| Gate | Invariant | Command | Proves | Does not prove | Runs at | Blocks on | Artifact | Fail-safe |");
|
|
188
|
+
lines.push("|---|---|---|---|---|---|---|---|---|");
|
|
189
|
+
for (const gate of spec.validationGates) {
|
|
190
|
+
lines.push(
|
|
191
|
+
`| ${mdCell(gate.name)} | ${mdCell(gate.invariant)} | ${mdCell(gate.command)} | ${mdCell(gate.proves)} | ${mdCell(gate.doesNotProve)} | ${mdCell(gate.runsAt)} | ${mdCell(gate.blocksOn)} | ${mdCell(gate.artifact)} | ${mdCell(gate.failSafe)} |`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
lines.push("");
|
|
196
|
+
lines.push("## 7. CI and local quality command");
|
|
197
|
+
lines.push("");
|
|
198
|
+
lines.push(`- Provider: ${spec.ci.provider}`);
|
|
199
|
+
lines.push(`- PR trigger: ${
|
|
200
|
+
spec.ci.trigger.mode === "all-prs" ? "all PRs" : `PRs targeting ${spec.ci.trigger.branches.join(", ")}`
|
|
201
|
+
}`);
|
|
202
|
+
lines.push(`- Local command: \`${spec.ci.localCommand}\``);
|
|
203
|
+
lines.push(`- Workflow path: \`${spec.ci.workflowPath}\``);
|
|
204
|
+
lines.push("");
|
|
205
|
+
lines.push("## 8. Supipowers wiring");
|
|
206
|
+
lines.push("");
|
|
207
|
+
lines.push(`- Add review agent (\`harness-architecture\`): ${spec.supipowersWiring.addReviewAgent ? "yes" : "no"}`);
|
|
208
|
+
lines.push(`- Wire into \`/supi:checks\` as a gate: ${spec.supipowersWiring.wireChecksGate ? "yes" : "no"}`);
|
|
209
|
+
lines.push("");
|
|
210
|
+
lines.push("## 9. Anti-slop guardrails");
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push(`- Backend: \`${spec.antiSlop.backend}\``);
|
|
213
|
+
lines.push(`- Pre-edit dupe probe: ${spec.antiSlop.hooks.pre_edit_dupe_probe.enabled ? "enabled" : "disabled"}`);
|
|
214
|
+
lines.push(`- Post-session sweep: ${spec.antiSlop.hooks.post_session_sweep.enabled ? "enabled" : "disabled"}`);
|
|
215
|
+
lines.push(`- Layer-context inject: ${spec.antiSlop.hooks.layer_context_inject.enabled ? "enabled" : "disabled"}`);
|
|
216
|
+
lines.push(
|
|
217
|
+
`- Score floor: strict ≥${spec.antiSlop.hooks.score_floor.strict}, lenient ≥${spec.antiSlop.hooks.score_floor.lenient} (release-blocking: ${
|
|
218
|
+
spec.antiSlop.hooks.score_floor.release_blocking ? "yes" : "no"
|
|
219
|
+
})`,
|
|
220
|
+
);
|
|
221
|
+
lines.push(`- Agent-skill distribution targets: ${spec.antiSlop.skillTargets.length > 0 ? spec.antiSlop.skillTargets.join(", ") : "(none)"}`);
|
|
222
|
+
lines.push("");
|
|
223
|
+
return lines.join("\n");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Schema-level validator for a design spec. Returns error messages (empty when valid).
|
|
228
|
+
* The plan calls for a "spec-reviewer sub-agent" — that's a separate downstream step;
|
|
229
|
+
* this validator catches mechanical issues (missing sections, malformed scores) early.
|
|
230
|
+
*/
|
|
231
|
+
export function validateDesignSpec(spec: HarnessDesignSpec): string[] {
|
|
232
|
+
const errors: string[] = [];
|
|
233
|
+
const validBackends = new Set(["fallow", "desloppify", "supi-native", "hybrid"]);
|
|
234
|
+
if (!validBackends.has(spec.antiSlop.backend)) {
|
|
235
|
+
errors.push(`anti-slop backend must be one of fallow|desloppify|supi-native|hybrid (got "${spec.antiSlop.backend}")`);
|
|
236
|
+
}
|
|
237
|
+
if (spec.antiSlop.hooks.score_floor.strict < 0 || spec.antiSlop.hooks.score_floor.strict > 100) {
|
|
238
|
+
errors.push("score_floor.strict must be in 0..100");
|
|
239
|
+
}
|
|
240
|
+
if (spec.antiSlop.hooks.score_floor.lenient < 0 || spec.antiSlop.hooks.score_floor.lenient > 100) {
|
|
241
|
+
errors.push("score_floor.lenient must be in 0..100");
|
|
242
|
+
}
|
|
243
|
+
if (spec.antiSlop.hooks.pre_edit_dupe_probe.threshold < 0 || spec.antiSlop.hooks.pre_edit_dupe_probe.threshold > 1) {
|
|
244
|
+
errors.push("pre_edit_dupe_probe.threshold must be in 0..1");
|
|
245
|
+
}
|
|
246
|
+
if (spec.antiSlop.hooks.layer_context_inject.addendum_max_chars < 0) {
|
|
247
|
+
errors.push("layer_context_inject.addendum_max_chars must be ≥0");
|
|
248
|
+
}
|
|
249
|
+
for (const [index, gate] of spec.validationGates.entries()) {
|
|
250
|
+
const prefix = `validationGates[${index}]`;
|
|
251
|
+
for (const field of ["name", "invariant", "proves", "doesNotProve", "runsAt", "blocksOn", "artifact", "failSafe"] as const) {
|
|
252
|
+
if (!hasText(gate[field])) errors.push(`${prefix}.${field} must be non-empty`);
|
|
253
|
+
}
|
|
254
|
+
if (gate.command !== null && !hasText(gate.command)) {
|
|
255
|
+
errors.push(`${prefix}.command must be non-empty or null`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (spec.ci.provider !== "github-actions") {
|
|
259
|
+
errors.push("ci.provider must be github-actions");
|
|
260
|
+
}
|
|
261
|
+
if (!hasText(spec.ci.localCommand)) {
|
|
262
|
+
errors.push("ci.localCommand must be non-empty");
|
|
263
|
+
}
|
|
264
|
+
if (!hasText(spec.ci.workflowPath)) {
|
|
265
|
+
errors.push("ci.workflowPath must be non-empty");
|
|
266
|
+
}
|
|
267
|
+
if (spec.ci.trigger.mode === "branches" && spec.ci.trigger.branches.filter((b) => b.trim().length > 0).length === 0) {
|
|
268
|
+
errors.push("ci.trigger.branches must contain at least one branch when mode is branches");
|
|
269
|
+
}
|
|
270
|
+
return errors;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Build a sensible default `HarnessDesignSpec` from a Discover artifact. Used by the
|
|
275
|
+
* per-stage `/supi:harness design` subcommand when the user has not already authored a
|
|
276
|
+
* structured spec; lets the pipeline run end-to-end without an interactive Q&A.
|
|
277
|
+
*
|
|
278
|
+
* The spec is intentionally conservative — it picks the first discovered tool per
|
|
279
|
+
* category, leaves layer rules / golden principles empty, and inherits the discover
|
|
280
|
+
* artifact's recommended anti-slop backend.
|
|
281
|
+
*/
|
|
282
|
+
export function defaultDesignSpecFromDiscover(
|
|
283
|
+
discover: HarnessDiscoverArtifact,
|
|
284
|
+
sessionId: string,
|
|
285
|
+
recordedAt: string,
|
|
286
|
+
): HarnessDesignSpec {
|
|
287
|
+
const lint = discover.lintTools[0] ?? null;
|
|
288
|
+
const structuralTest = discover.testTools[0] ?? null;
|
|
289
|
+
return {
|
|
290
|
+
sessionId,
|
|
291
|
+
recordedAt,
|
|
292
|
+
layerRules: [],
|
|
293
|
+
tasteInvariants: [],
|
|
294
|
+
tooling: {
|
|
295
|
+
lint,
|
|
296
|
+
structuralTest,
|
|
297
|
+
eval: null,
|
|
298
|
+
},
|
|
299
|
+
goldenPrinciples: [],
|
|
300
|
+
docsTree: ["docs/architecture.md", "docs/golden-principles.md"],
|
|
301
|
+
validationGates: defaultValidationGatesFromDiscover(discover),
|
|
302
|
+
ci: defaultCiConfigFromDiscover(discover),
|
|
303
|
+
supipowersWiring: { addReviewAgent: true, wireChecksGate: false },
|
|
304
|
+
antiSlop: {
|
|
305
|
+
backend: discover.recommendedBackend,
|
|
306
|
+
hooks: DEFAULT_HARNESS_HOOK_CONFIG,
|
|
307
|
+
skillTargets: [],
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface DesignStageInput {
|
|
313
|
+
/** Pre-built spec, typically composed by the command handler from interactive Q&A. */
|
|
314
|
+
spec: HarnessDesignSpec;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export class HarnessDesignStage implements HarnessStageRunner {
|
|
318
|
+
readonly stage = "design" as const;
|
|
319
|
+
|
|
320
|
+
constructor(private readonly input: DesignStageInput) {}
|
|
321
|
+
|
|
322
|
+
async isReady(ctx: HarnessStageRunnerContext): Promise<boolean> {
|
|
323
|
+
return loadHarnessDiscover(ctx.paths, ctx.cwd, ctx.sessionId).ok;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async isComplete(ctx: HarnessStageRunnerContext): Promise<boolean> {
|
|
327
|
+
return loadHarnessDesignSpec(ctx.paths, ctx.cwd, ctx.sessionId).ok;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async run(ctx: HarnessStageRunnerContext): Promise<HarnessStageRunResult> {
|
|
331
|
+
const errors = validateDesignSpec(this.input.spec);
|
|
332
|
+
if (errors.length > 0) {
|
|
333
|
+
return {
|
|
334
|
+
status: "blocked",
|
|
335
|
+
stage: this.stage,
|
|
336
|
+
artifactPaths: [],
|
|
337
|
+
blocker: {
|
|
338
|
+
code: "design-spec-invalid",
|
|
339
|
+
message: `design spec validation failed: ${errors.join("; ")}`,
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const recordedAt = nowIso(ctx);
|
|
345
|
+
const specWithTimestamp: HarnessDesignSpec = { ...this.input.spec, recordedAt };
|
|
346
|
+
const markdown = renderDesignSpec(specWithTimestamp);
|
|
347
|
+
const persisted = saveHarnessDesignSpec(ctx.paths, ctx.cwd, ctx.sessionId, markdown);
|
|
348
|
+
if (!persisted.ok) {
|
|
349
|
+
return {
|
|
350
|
+
status: "failed",
|
|
351
|
+
stage: this.stage,
|
|
352
|
+
artifactPaths: [],
|
|
353
|
+
error: `failed to persist design spec: ${persisted.error.message}`,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const persistedJson = saveHarnessDesignSpecJson(
|
|
357
|
+
ctx.paths,
|
|
358
|
+
ctx.cwd,
|
|
359
|
+
ctx.sessionId,
|
|
360
|
+
specWithTimestamp,
|
|
361
|
+
);
|
|
362
|
+
if (!persistedJson.ok) {
|
|
363
|
+
return {
|
|
364
|
+
status: "failed",
|
|
365
|
+
stage: this.stage,
|
|
366
|
+
artifactPaths: [persisted.value],
|
|
367
|
+
error: `failed to persist design spec JSON: ${persistedJson.error.message}`,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
appendHarnessDecision(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
371
|
+
recordedAt,
|
|
372
|
+
area: "design-spec-saved",
|
|
373
|
+
question: "design spec persisted",
|
|
374
|
+
decision: persisted.value,
|
|
375
|
+
});
|
|
376
|
+
return {
|
|
377
|
+
status: "awaiting-user",
|
|
378
|
+
stage: this.stage,
|
|
379
|
+
artifactPaths: ["design-spec.md", "design-spec.json"],
|
|
380
|
+
details: {
|
|
381
|
+
backend: specWithTimestamp.antiSlop.backend,
|
|
382
|
+
layerCount: specWithTimestamp.layerRules.length,
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|