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.
- 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 +149 -45
- 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 +19 -9
- 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 +129 -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 +264 -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 +298 -127
- package/src/review/fixer.ts +10 -6
- package/src/review/multi-agent-runner.ts +115 -14
- 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 +11 -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 +1401 -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,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REVIEW stage runner.
|
|
3
|
+
*
|
|
4
|
+
* Spawns three checker agents in parallel — `structure-checker`, `scope-checker`,
|
|
5
|
+
* `tdd-checker` — against a synthesized draft. Each checker calls
|
|
6
|
+
* `ultraplan_review_finding` zero or more times; the tool accumulates findings into
|
|
7
|
+
* `drafts/iteration-N/findings.json`.
|
|
8
|
+
*
|
|
9
|
+
* If no checker calls the tool (zero findings — a valid converged state), the stage
|
|
10
|
+
* runner writes an empty findings artifact so `isComplete` is satisfied.
|
|
11
|
+
*
|
|
12
|
+
* Resume semantics: skipped when findings.json exists and validates for the iteration.
|
|
13
|
+
* Future iterations re-run the same stage against their own iteration directory.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import * as fs from "node:fs";
|
|
17
|
+
|
|
18
|
+
import { resolveAuthoringSlot } from "../agent-catalog.js";
|
|
19
|
+
import { resolveAuthoringSlotModel } from "../model.js";
|
|
20
|
+
import { modelRegistry } from "../../../config/model-registry-instance.js";
|
|
21
|
+
import {
|
|
22
|
+
appendPipelineLog,
|
|
23
|
+
loadDraftAuthoredJson,
|
|
24
|
+
loadFindingsArtifact,
|
|
25
|
+
loadResearchSummary,
|
|
26
|
+
saveAuthoringState,
|
|
27
|
+
saveFindingsArtifact,
|
|
28
|
+
} from "../storage.js";
|
|
29
|
+
import {
|
|
30
|
+
buildAgentDisplayName,
|
|
31
|
+
nowIso,
|
|
32
|
+
toManifestStageStatus,
|
|
33
|
+
type StageRunResult,
|
|
34
|
+
type StageRunner,
|
|
35
|
+
type StageRunnerContext,
|
|
36
|
+
} from "../stage-runner.js";
|
|
37
|
+
import {
|
|
38
|
+
getUltraplanAuthoringDecisionsPath,
|
|
39
|
+
getUltraplanAuthoringDraftAuthoredJsonPath,
|
|
40
|
+
getUltraplanAuthoringDraftFindingsPath,
|
|
41
|
+
} from "../../project-paths.js";
|
|
42
|
+
import type { UltraPlanAuthoringSlotName } from "../../../types.js";
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Checker slot constants
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
const CHECKER_SLOTS = ["structure-checker", "scope-checker", "tdd-checker"] as const satisfies readonly UltraPlanAuthoringSlotName[];
|
|
49
|
+
type CheckerSlot = (typeof CHECKER_SLOTS)[number];
|
|
50
|
+
|
|
51
|
+
const CHECKER_FOCUS: Record<CheckerSlot, string> = {
|
|
52
|
+
"structure-checker":
|
|
53
|
+
"Verify that the authored.json structure is internally consistent: domains reference valid stacks, scenario ids are unique and kebab-case, all required fields are present and non-empty, and the stacks/domains/scenarios hierarchy is coherent.",
|
|
54
|
+
"scope-checker":
|
|
55
|
+
"Verify that the scope is bounded: no single scenario conflates multiple jobs, every domain aligns with the stated goal, nothing from the deferred-ideas list has crept back in, and no gaps exist between the goal and the domain coverage.",
|
|
56
|
+
"tdd-checker":
|
|
57
|
+
"Verify that every scenario has testable acceptance criteria (unit, integration, or e2e as appropriate), that the described test patterns are consistent with the project's existing test conventions identified by scout, and that no scenario is only verifiable by manual inspection.",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Public types
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
/** Inputs unique to REVIEW: which draft iteration to review (default 1). */
|
|
65
|
+
export interface ReviewStageInput {
|
|
66
|
+
iteration?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Assignment builder
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
function buildCheckerAssignment(
|
|
74
|
+
ctx: StageRunnerContext,
|
|
75
|
+
slot: CheckerSlot,
|
|
76
|
+
iteration: number,
|
|
77
|
+
draft: unknown,
|
|
78
|
+
researchSummary: string | null,
|
|
79
|
+
decisions: string | null,
|
|
80
|
+
): string {
|
|
81
|
+
const parts: string[] = [
|
|
82
|
+
`# UltraPlan authoring · review (${slot})`,
|
|
83
|
+
``,
|
|
84
|
+
`Session id: ${ctx.sessionId}`,
|
|
85
|
+
`cwd: ${ctx.cwd}`,
|
|
86
|
+
`Iteration: ${iteration}`,
|
|
87
|
+
``,
|
|
88
|
+
`## Focus area`,
|
|
89
|
+
``,
|
|
90
|
+
CHECKER_FOCUS[slot],
|
|
91
|
+
``,
|
|
92
|
+
`## Draft authored.json (iteration ${iteration})`,
|
|
93
|
+
"```json",
|
|
94
|
+
JSON.stringify(draft, null, 2),
|
|
95
|
+
"```",
|
|
96
|
+
``,
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
if (researchSummary) {
|
|
100
|
+
parts.push(
|
|
101
|
+
`## Research summary`,
|
|
102
|
+
"```",
|
|
103
|
+
researchSummary,
|
|
104
|
+
"```",
|
|
105
|
+
``,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (decisions) {
|
|
110
|
+
parts.push(
|
|
111
|
+
`## Discover decisions (decisions.jsonl — JSONL, one record per line)`,
|
|
112
|
+
"```",
|
|
113
|
+
decisions,
|
|
114
|
+
"```",
|
|
115
|
+
``,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
parts.push(
|
|
120
|
+
`## Your task`,
|
|
121
|
+
``,
|
|
122
|
+
`Review the draft with your focus area above. Call \`ultraplan_review_finding\` for each issue you identify. You MAY call it zero times if the draft is clean in your area — zero findings is a valid and desirable outcome.`,
|
|
123
|
+
``,
|
|
124
|
+
`Required fields for each call:`,
|
|
125
|
+
`- sessionId: ${JSON.stringify(ctx.sessionId)}`,
|
|
126
|
+
`- iteration: ${iteration}`,
|
|
127
|
+
`- id: stable kebab-case id (unique across all findings)`,
|
|
128
|
+
`- severity: BLOCKER | WARNING`,
|
|
129
|
+
`- source: ${slot}`,
|
|
130
|
+
`- target: { stack, domainId, scenarioId } — use null for fields that do not apply`,
|
|
131
|
+
`- message: concise description of the issue`,
|
|
132
|
+
`- recommendation: actionable fix suggestion`,
|
|
133
|
+
``,
|
|
134
|
+
`Return after all calls. Do not append a chat summary.`,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return parts.join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// Stage runner
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
export class ReviewStage implements StageRunner {
|
|
145
|
+
readonly stage = "review" as const;
|
|
146
|
+
|
|
147
|
+
private readonly iteration: number;
|
|
148
|
+
|
|
149
|
+
constructor(input: ReviewStageInput = {}) {
|
|
150
|
+
this.iteration = input.iteration ?? 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async isReady(ctx: StageRunnerContext): Promise<boolean> {
|
|
154
|
+
return fs.existsSync(
|
|
155
|
+
getUltraplanAuthoringDraftAuthoredJsonPath(ctx.paths, ctx.cwd, ctx.sessionId, this.iteration),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async isComplete(ctx: StageRunnerContext): Promise<boolean> {
|
|
160
|
+
const artifactPath = getUltraplanAuthoringDraftFindingsPath(
|
|
161
|
+
ctx.paths,
|
|
162
|
+
ctx.cwd,
|
|
163
|
+
ctx.sessionId,
|
|
164
|
+
this.iteration,
|
|
165
|
+
);
|
|
166
|
+
if (!fs.existsSync(artifactPath)) return false;
|
|
167
|
+
const loaded = loadFindingsArtifact(ctx.paths, ctx.cwd, ctx.sessionId, this.iteration);
|
|
168
|
+
return loaded.ok;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async run(ctx: StageRunnerContext): Promise<StageRunResult> {
|
|
172
|
+
if (!(await this.isReady(ctx))) {
|
|
173
|
+
return {
|
|
174
|
+
status: "failed",
|
|
175
|
+
stage: this.stage,
|
|
176
|
+
artifactPaths: [],
|
|
177
|
+
error: `REVIEW requires drafts/iteration-${this.iteration}/authored.json; run the synthesize stage first.`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (await this.isComplete(ctx)) {
|
|
182
|
+
return {
|
|
183
|
+
status: "skipped",
|
|
184
|
+
stage: this.stage,
|
|
185
|
+
artifactPaths: [`authoring/drafts/iteration-${this.iteration}/findings.json`],
|
|
186
|
+
details: { reason: `findings artifact already exists for iteration ${this.iteration}` },
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Load the draft as context for all checkers.
|
|
191
|
+
const draftResult = loadDraftAuthoredJson(ctx.paths, ctx.cwd, ctx.sessionId, this.iteration);
|
|
192
|
+
if (!draftResult.ok) {
|
|
193
|
+
return {
|
|
194
|
+
status: "failed",
|
|
195
|
+
stage: this.stage,
|
|
196
|
+
artifactPaths: [],
|
|
197
|
+
error: `REVIEW could not read draft authored.json: ${draftResult.error.message}`,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Load optional upstream artifacts for richer context; missing is non-fatal.
|
|
202
|
+
const summaryResult = loadResearchSummary(ctx.paths, ctx.cwd, ctx.sessionId);
|
|
203
|
+
const researchSummary = summaryResult.ok ? summaryResult.value : null;
|
|
204
|
+
|
|
205
|
+
const decisionsPath = getUltraplanAuthoringDecisionsPath(ctx.paths, ctx.cwd, ctx.sessionId);
|
|
206
|
+
const decisions = fs.existsSync(decisionsPath)
|
|
207
|
+
? fs.readFileSync(decisionsPath, "utf8")
|
|
208
|
+
: null;
|
|
209
|
+
|
|
210
|
+
// Mark the stage running before spawning agents so resume can find it mid-flight.
|
|
211
|
+
saveAuthoringState(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
212
|
+
pipeline: "multi-stage",
|
|
213
|
+
stage: this.stage,
|
|
214
|
+
stageStatus: "running",
|
|
215
|
+
iteration: this.iteration,
|
|
216
|
+
stallReentryCount: 0,
|
|
217
|
+
artifacts: {},
|
|
218
|
+
blocker: null,
|
|
219
|
+
startedAt: nowIso(ctx),
|
|
220
|
+
updatedAt: nowIso(ctx),
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Spawn all three checkers concurrently.
|
|
224
|
+
await Promise.all(
|
|
225
|
+
CHECKER_SLOTS.map(async (slot) => {
|
|
226
|
+
const resolvedModel =
|
|
227
|
+
ctx.modelOverride ??
|
|
228
|
+
resolveAuthoringSlotModel(
|
|
229
|
+
slot,
|
|
230
|
+
null,
|
|
231
|
+
ctx.modelConfig,
|
|
232
|
+
modelRegistry,
|
|
233
|
+
{
|
|
234
|
+
getModelForRole: (role) => ctx.platform.getModelForRole?.(role) ?? null,
|
|
235
|
+
getCurrentModel: () => ctx.platform.getCurrentModel?.() ?? "unknown",
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const slotBinding = resolveAuthoringSlot(slot, ctx.paths, ctx.cwd);
|
|
240
|
+
|
|
241
|
+
const sessionOpts: Record<string, unknown> = {
|
|
242
|
+
cwd: ctx.cwd,
|
|
243
|
+
agentDisplayName: buildAgentDisplayName(this.stage, slot),
|
|
244
|
+
agentId: `ultraplan-authoring-${this.stage}-${slot}-${ctx.sessionId}`,
|
|
245
|
+
};
|
|
246
|
+
if (resolvedModel.model) sessionOpts.model = resolvedModel.model;
|
|
247
|
+
if (resolvedModel.thinkingLevel) sessionOpts.thinkingLevel = resolvedModel.thinkingLevel;
|
|
248
|
+
|
|
249
|
+
const agentSession = await ctx.platform.createAgentSession(sessionOpts as never);
|
|
250
|
+
const assignment = [
|
|
251
|
+
slotBinding.definition.prompt.trim(),
|
|
252
|
+
"",
|
|
253
|
+
buildCheckerAssignment(
|
|
254
|
+
ctx,
|
|
255
|
+
slot,
|
|
256
|
+
this.iteration,
|
|
257
|
+
draftResult.value,
|
|
258
|
+
researchSummary,
|
|
259
|
+
decisions,
|
|
260
|
+
),
|
|
261
|
+
].join("\n");
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
await agentSession.prompt(assignment, { expandPromptTemplates: false });
|
|
265
|
+
} finally {
|
|
266
|
+
await agentSession.dispose();
|
|
267
|
+
}
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
// If no checker called ultraplan_review_finding, write an empty findings artifact
|
|
272
|
+
// so isComplete is satisfied (zero findings is a valid converged state).
|
|
273
|
+
const findingsPath = getUltraplanAuthoringDraftFindingsPath(
|
|
274
|
+
ctx.paths,
|
|
275
|
+
ctx.cwd,
|
|
276
|
+
ctx.sessionId,
|
|
277
|
+
this.iteration,
|
|
278
|
+
);
|
|
279
|
+
if (!fs.existsSync(findingsPath)) {
|
|
280
|
+
const emptyArtifact = {
|
|
281
|
+
iteration: this.iteration,
|
|
282
|
+
draftRef: `drafts/iteration-${this.iteration}/authored.json`,
|
|
283
|
+
recordedAt: nowIso(ctx),
|
|
284
|
+
findings: [],
|
|
285
|
+
};
|
|
286
|
+
const saved = saveFindingsArtifact(
|
|
287
|
+
ctx.paths,
|
|
288
|
+
ctx.cwd,
|
|
289
|
+
ctx.sessionId,
|
|
290
|
+
this.iteration,
|
|
291
|
+
emptyArtifact,
|
|
292
|
+
);
|
|
293
|
+
if (!saved.ok) {
|
|
294
|
+
return {
|
|
295
|
+
status: "failed",
|
|
296
|
+
stage: this.stage,
|
|
297
|
+
artifactPaths: [],
|
|
298
|
+
error: `REVIEW could not write empty findings artifact: ${saved.error.message}`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const findingsRelPath = `authoring/drafts/iteration-${this.iteration}/findings.json`;
|
|
304
|
+
|
|
305
|
+
appendPipelineLog(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
306
|
+
recordedAt: nowIso(ctx),
|
|
307
|
+
stage: this.stage,
|
|
308
|
+
stageStatus: toManifestStageStatus("completed"),
|
|
309
|
+
iteration: this.iteration,
|
|
310
|
+
summary: `review complete for iteration ${this.iteration}`,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
saveAuthoringState(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
314
|
+
pipeline: "multi-stage",
|
|
315
|
+
stage: this.stage,
|
|
316
|
+
stageStatus: "done",
|
|
317
|
+
iteration: this.iteration,
|
|
318
|
+
stallReentryCount: 0,
|
|
319
|
+
artifacts: {
|
|
320
|
+
findings: findingsRelPath,
|
|
321
|
+
},
|
|
322
|
+
blocker: null,
|
|
323
|
+
startedAt: nowIso(ctx),
|
|
324
|
+
updatedAt: nowIso(ctx),
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
status: "completed",
|
|
329
|
+
stage: this.stage,
|
|
330
|
+
artifactPaths: [findingsRelPath],
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCOUT stage runner.
|
|
3
|
+
*
|
|
4
|
+
* Spawns a single `createAgentSession` running the `scout` slot agent. The agent reads the
|
|
5
|
+
* intake artifact and the repository, then calls `ultraplan_scout_record` exactly once with
|
|
6
|
+
* structured codebase reconnaissance: reusable assets, integration points, conventions per
|
|
7
|
+
* applicable stack, existing test patterns.
|
|
8
|
+
*
|
|
9
|
+
* Resume semantics: skipped when scout artifact exists and validates.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
|
|
14
|
+
import { resolveAuthoringSlot } from "../agent-catalog.js";
|
|
15
|
+
import { resolveAuthoringSlotModel } from "../model.js";
|
|
16
|
+
import { modelRegistry } from "../../../config/model-registry-instance.js";
|
|
17
|
+
import {
|
|
18
|
+
appendPipelineLog,
|
|
19
|
+
loadIntakeArtifact,
|
|
20
|
+
loadScoutArtifact,
|
|
21
|
+
saveAuthoringState,
|
|
22
|
+
} from "../storage.js";
|
|
23
|
+
import {
|
|
24
|
+
buildAgentDisplayName,
|
|
25
|
+
nowIso,
|
|
26
|
+
toManifestStageStatus,
|
|
27
|
+
type StageRunResult,
|
|
28
|
+
type StageRunner,
|
|
29
|
+
type StageRunnerContext,
|
|
30
|
+
} from "../stage-runner.js";
|
|
31
|
+
import {
|
|
32
|
+
getUltraplanAuthoringIntakePath,
|
|
33
|
+
getUltraplanAuthoringScoutPath,
|
|
34
|
+
} from "../../project-paths.js";
|
|
35
|
+
|
|
36
|
+
function buildScoutAssignment(ctx: StageRunnerContext, intake: unknown): string {
|
|
37
|
+
return [
|
|
38
|
+
`# UltraPlan authoring \u00b7 scout`,
|
|
39
|
+
``,
|
|
40
|
+
`Session id: ${ctx.sessionId}`,
|
|
41
|
+
`cwd: ${ctx.cwd}`,
|
|
42
|
+
``,
|
|
43
|
+
`## Intake artifact (verbatim)`,
|
|
44
|
+
"```json",
|
|
45
|
+
JSON.stringify(intake, null, 2),
|
|
46
|
+
"```",
|
|
47
|
+
``,
|
|
48
|
+
`## Your task`,
|
|
49
|
+
`Survey the repository to surface what already exists. Use parallel \`task\` / \`search\` / \`find\` calls. Do not pick libraries; that is the researcher's job.`,
|
|
50
|
+
``,
|
|
51
|
+
`Call \`ultraplan_scout_record\` exactly once with sessionId=${JSON.stringify(ctx.sessionId)} and these fields:`,
|
|
52
|
+
`- reusableAssets: list of { kind, path, note } for files/symbols the implementation can reuse`,
|
|
53
|
+
`- integrationPoints: list of { path, note } for existing modules the new work must integrate with`,
|
|
54
|
+
`- conventionsByStack: { frontend?: string[], backend?: string[], infrastructure?: string[] } \u2014 short imperative bullets for each applicable stack`,
|
|
55
|
+
`- existingTests: file paths of existing tests that establish the project's test patterns`,
|
|
56
|
+
``,
|
|
57
|
+
`Only include sections for stacks the intake marked applicable. Return after the tool call.`,
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class ScoutStage implements StageRunner {
|
|
62
|
+
readonly stage = "scout" as const;
|
|
63
|
+
|
|
64
|
+
async isReady(ctx: StageRunnerContext): Promise<boolean> {
|
|
65
|
+
return fs.existsSync(getUltraplanAuthoringIntakePath(ctx.paths, ctx.cwd, ctx.sessionId));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async isComplete(ctx: StageRunnerContext): Promise<boolean> {
|
|
69
|
+
const artifactPath = getUltraplanAuthoringScoutPath(ctx.paths, ctx.cwd, ctx.sessionId);
|
|
70
|
+
if (!fs.existsSync(artifactPath)) return false;
|
|
71
|
+
const loaded = loadScoutArtifact(ctx.paths, ctx.cwd, ctx.sessionId);
|
|
72
|
+
return loaded.ok;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async run(ctx: StageRunnerContext): Promise<StageRunResult> {
|
|
76
|
+
if (!(await this.isReady(ctx))) {
|
|
77
|
+
return {
|
|
78
|
+
status: "failed",
|
|
79
|
+
stage: this.stage,
|
|
80
|
+
artifactPaths: [],
|
|
81
|
+
error: "SCOUT requires the intake artifact; run the intake stage first.",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (await this.isComplete(ctx)) {
|
|
86
|
+
return {
|
|
87
|
+
status: "skipped",
|
|
88
|
+
stage: this.stage,
|
|
89
|
+
artifactPaths: ["authoring/scout.json"],
|
|
90
|
+
details: { reason: "scout artifact already exists" },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const intakeResult = loadIntakeArtifact(ctx.paths, ctx.cwd, ctx.sessionId);
|
|
95
|
+
if (!intakeResult.ok) {
|
|
96
|
+
return {
|
|
97
|
+
status: "failed",
|
|
98
|
+
stage: this.stage,
|
|
99
|
+
artifactPaths: [],
|
|
100
|
+
error: `SCOUT could not read intake artifact: ${intakeResult.error.message}`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const slotBinding = resolveAuthoringSlot("scout", ctx.paths, ctx.cwd);
|
|
105
|
+
const resolvedModel =
|
|
106
|
+
ctx.modelOverride ?? resolveAuthoringSlotModel(
|
|
107
|
+
"scout",
|
|
108
|
+
null,
|
|
109
|
+
ctx.modelConfig,
|
|
110
|
+
modelRegistry,
|
|
111
|
+
{
|
|
112
|
+
getModelForRole: (role) => ctx.platform.getModelForRole?.(role) ?? null,
|
|
113
|
+
getCurrentModel: () => ctx.platform.getCurrentModel?.() ?? "unknown",
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
saveAuthoringState(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
118
|
+
pipeline: "multi-stage",
|
|
119
|
+
stage: this.stage,
|
|
120
|
+
stageStatus: "running",
|
|
121
|
+
iteration: 1,
|
|
122
|
+
stallReentryCount: 0,
|
|
123
|
+
artifacts: { intake: "authoring/intake.json" },
|
|
124
|
+
blocker: null,
|
|
125
|
+
startedAt: nowIso(ctx),
|
|
126
|
+
updatedAt: nowIso(ctx),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const sessionOpts: Record<string, unknown> = {
|
|
130
|
+
cwd: ctx.cwd,
|
|
131
|
+
agentDisplayName: buildAgentDisplayName(this.stage),
|
|
132
|
+
agentId: `ultraplan-authoring-${this.stage}-${ctx.sessionId}`,
|
|
133
|
+
};
|
|
134
|
+
if (resolvedModel.model) sessionOpts.model = resolvedModel.model;
|
|
135
|
+
if (resolvedModel.thinkingLevel) sessionOpts.thinkingLevel = resolvedModel.thinkingLevel;
|
|
136
|
+
|
|
137
|
+
const agentSession = await ctx.platform.createAgentSession(sessionOpts as never);
|
|
138
|
+
const assignment = [
|
|
139
|
+
slotBinding.definition.prompt.trim(),
|
|
140
|
+
"",
|
|
141
|
+
buildScoutAssignment(ctx, intakeResult.value),
|
|
142
|
+
].join("\n");
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
await agentSession.prompt(assignment, { expandPromptTemplates: false });
|
|
146
|
+
} finally {
|
|
147
|
+
await agentSession.dispose();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const verified = await this.isComplete(ctx);
|
|
151
|
+
if (!verified) {
|
|
152
|
+
return {
|
|
153
|
+
status: "failed",
|
|
154
|
+
stage: this.stage,
|
|
155
|
+
artifactPaths: [],
|
|
156
|
+
error: "SCOUT agent finished without persisting a scout artifact (ultraplan_scout_record was not called).",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
appendPipelineLog(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
161
|
+
recordedAt: nowIso(ctx),
|
|
162
|
+
stage: this.stage,
|
|
163
|
+
stageStatus: toManifestStageStatus("completed"),
|
|
164
|
+
iteration: 1,
|
|
165
|
+
summary: "scout artifact recorded",
|
|
166
|
+
details: { model: resolvedModel.model ?? null },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
saveAuthoringState(ctx.paths, ctx.cwd, ctx.sessionId, {
|
|
170
|
+
pipeline: "multi-stage",
|
|
171
|
+
stage: this.stage,
|
|
172
|
+
stageStatus: "done",
|
|
173
|
+
iteration: 1,
|
|
174
|
+
stallReentryCount: 0,
|
|
175
|
+
artifacts: { intake: "authoring/intake.json", scout: "authoring/scout.json" },
|
|
176
|
+
blocker: null,
|
|
177
|
+
startedAt: nowIso(ctx),
|
|
178
|
+
updatedAt: nowIso(ctx),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
status: "completed",
|
|
183
|
+
stage: this.stage,
|
|
184
|
+
artifactPaths: ["authoring/scout.json"],
|
|
185
|
+
details: { model: resolvedModel.model ?? null },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|