supipowers 1.5.3 → 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 +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 +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 +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,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline driver for the multi-stage authoring flow.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the next stage to run from the manifest's `authoring` block, executes it via the
|
|
5
|
+
* stage's runner, and either advances or surfaces a gate decision to the caller. The driver
|
|
6
|
+
* is intentionally pure orchestration \u2014 every disk write goes through `authoring/storage`.
|
|
7
|
+
*
|
|
8
|
+
* Three gate modes:
|
|
9
|
+
* - `default`: gates at discover, synthesize, approve.
|
|
10
|
+
* - `auto`: no user gates; runs end-to-end. Synthesize still produces a draft and the
|
|
11
|
+
* approve stage promotes it without a user confirmation.
|
|
12
|
+
* - `manual`: every stage waits for explicit advance commands.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as fs from "node:fs";
|
|
16
|
+
|
|
17
|
+
import type { Platform, PlatformPaths } from "../../platform/types.js";
|
|
18
|
+
import type {
|
|
19
|
+
ModelConfig,
|
|
20
|
+
UltraPlanAuthoringStage,
|
|
21
|
+
} from "../../types.js";
|
|
22
|
+
|
|
23
|
+
import { ApproveStage } from "./stages/approve.js";
|
|
24
|
+
import { DiscoverStage } from "./stages/discover.js";
|
|
25
|
+
import { IntakeStage } from "./stages/intake.js";
|
|
26
|
+
import { ResearchStage } from "./stages/research.js";
|
|
27
|
+
import { ReviewStage } from "./stages/review.js";
|
|
28
|
+
import { ScoutStage } from "./stages/scout.js";
|
|
29
|
+
import { SynthesizeStage } from "./stages/synthesize.js";
|
|
30
|
+
import {
|
|
31
|
+
loadAuthoringState,
|
|
32
|
+
} from "./storage.js";
|
|
33
|
+
import type {
|
|
34
|
+
StageRunResult,
|
|
35
|
+
StageRunner,
|
|
36
|
+
StageRunnerContext,
|
|
37
|
+
} from "./stage-runner.js";
|
|
38
|
+
import { runSynthGateLoop } from "./synth-gate.js";
|
|
39
|
+
import {
|
|
40
|
+
getUltraplanAuthoringDecisionsPath,
|
|
41
|
+
getUltraplanAuthoringDir,
|
|
42
|
+
getUltraplanAuthoringIntakePath,
|
|
43
|
+
getUltraplanAuthoringResearchSummaryPath,
|
|
44
|
+
getUltraplanAuthoringScoutPath,
|
|
45
|
+
} from "../project-paths.js";
|
|
46
|
+
|
|
47
|
+
export type PipelineGateMode = "default" | "auto" | "manual";
|
|
48
|
+
|
|
49
|
+
const GATE_STAGES_DEFAULT = new Set<UltraPlanAuthoringStage>(["discover", "synthesize", "approve"]);
|
|
50
|
+
const GATE_STAGES_MANUAL = new Set<UltraPlanAuthoringStage>([
|
|
51
|
+
"intake",
|
|
52
|
+
"scout",
|
|
53
|
+
"discover",
|
|
54
|
+
"research",
|
|
55
|
+
"synthesize",
|
|
56
|
+
"review",
|
|
57
|
+
"approve",
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
export interface PipelineDriverInput {
|
|
61
|
+
platform: Platform;
|
|
62
|
+
paths: PlatformPaths;
|
|
63
|
+
cwd: string;
|
|
64
|
+
sessionId: string;
|
|
65
|
+
modelConfig: ModelConfig;
|
|
66
|
+
/** Required for INTAKE stage; ignored once intake artifact exists. */
|
|
67
|
+
seedPrompt: string;
|
|
68
|
+
gates: PipelineGateMode;
|
|
69
|
+
/** Iteration to use for review/approve. Defaults to 1. */
|
|
70
|
+
iteration?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface PipelineRunOutcome {
|
|
74
|
+
/** Final stage that was executed (or attempted). */
|
|
75
|
+
stage: UltraPlanAuthoringStage;
|
|
76
|
+
status: StageRunResult["status"];
|
|
77
|
+
/** True when the pipeline reached APPROVE successfully. */
|
|
78
|
+
promoted: boolean;
|
|
79
|
+
/** Error or blocker message, when status is failed/blocked. */
|
|
80
|
+
message?: string;
|
|
81
|
+
/** Human-readable summary of every stage that ran. */
|
|
82
|
+
trace: { stage: UltraPlanAuthoringStage; status: StageRunResult["status"] }[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface ResolvedNextStage {
|
|
86
|
+
stage: UltraPlanAuthoringStage;
|
|
87
|
+
reason: "fresh-start" | "next-after-completed" | "resume-incomplete";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Find the stage that should run next for a session. Reads the manifest's `authoring` block;
|
|
92
|
+
* falls back to disk artifact existence for sessions that were started by a different driver
|
|
93
|
+
* version that didn't persist the manifest block.
|
|
94
|
+
*/
|
|
95
|
+
export function resolveNextStage(
|
|
96
|
+
paths: PlatformPaths,
|
|
97
|
+
cwd: string,
|
|
98
|
+
sessionId: string,
|
|
99
|
+
): ResolvedNextStage {
|
|
100
|
+
const stateResult = loadAuthoringState(paths, cwd, sessionId);
|
|
101
|
+
if (stateResult.ok && stateResult.value) {
|
|
102
|
+
const state = stateResult.value;
|
|
103
|
+
if (state.stageStatus === "running") {
|
|
104
|
+
return { stage: state.stage, reason: "resume-incomplete" };
|
|
105
|
+
}
|
|
106
|
+
if (state.stageStatus === "blocked" || state.stageStatus === "awaiting-user") {
|
|
107
|
+
return { stage: state.stage, reason: "resume-incomplete" };
|
|
108
|
+
}
|
|
109
|
+
// status === "done" \u2014 advance to the next stage.
|
|
110
|
+
const next = nextStageOf(state.stage);
|
|
111
|
+
if (next) return { stage: next, reason: "next-after-completed" };
|
|
112
|
+
return { stage: "approve", reason: "next-after-completed" };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Fall back to disk artifact existence.
|
|
116
|
+
if (!fs.existsSync(getUltraplanAuthoringIntakePath(paths, cwd, sessionId))) {
|
|
117
|
+
return { stage: "intake", reason: "fresh-start" };
|
|
118
|
+
}
|
|
119
|
+
if (!fs.existsSync(getUltraplanAuthoringScoutPath(paths, cwd, sessionId))) {
|
|
120
|
+
return { stage: "scout", reason: "resume-incomplete" };
|
|
121
|
+
}
|
|
122
|
+
if (!fs.existsSync(getUltraplanAuthoringDecisionsPath(paths, cwd, sessionId))) {
|
|
123
|
+
return { stage: "discover", reason: "resume-incomplete" };
|
|
124
|
+
}
|
|
125
|
+
if (!fs.existsSync(getUltraplanAuthoringResearchSummaryPath(paths, cwd, sessionId))) {
|
|
126
|
+
return { stage: "research", reason: "resume-incomplete" };
|
|
127
|
+
}
|
|
128
|
+
return { stage: "synthesize", reason: "resume-incomplete" };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function nextStageOf(stage: UltraPlanAuthoringStage): UltraPlanAuthoringStage | null {
|
|
132
|
+
switch (stage) {
|
|
133
|
+
case "intake":
|
|
134
|
+
return "scout";
|
|
135
|
+
case "scout":
|
|
136
|
+
return "discover";
|
|
137
|
+
case "discover":
|
|
138
|
+
return "research";
|
|
139
|
+
case "research":
|
|
140
|
+
return "synthesize";
|
|
141
|
+
case "synthesize":
|
|
142
|
+
return "review";
|
|
143
|
+
case "review":
|
|
144
|
+
return "approve";
|
|
145
|
+
case "approve":
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Run a single stage by name. Used both by the full driver and by the per-stage CLI
|
|
152
|
+
* subcommands (`/supi:ultraplan discover`, `/supi:ultraplan research`, etc).
|
|
153
|
+
*/
|
|
154
|
+
export async function runStage(
|
|
155
|
+
stage: UltraPlanAuthoringStage,
|
|
156
|
+
input: Omit<PipelineDriverInput, "gates">,
|
|
157
|
+
): Promise<StageRunResult> {
|
|
158
|
+
const ctx: StageRunnerContext = {
|
|
159
|
+
platform: input.platform,
|
|
160
|
+
paths: input.paths,
|
|
161
|
+
cwd: input.cwd,
|
|
162
|
+
sessionId: input.sessionId,
|
|
163
|
+
modelConfig: input.modelConfig,
|
|
164
|
+
};
|
|
165
|
+
const runner = buildRunner(stage, input);
|
|
166
|
+
return runner.run(ctx);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function buildRunner(
|
|
170
|
+
stage: UltraPlanAuthoringStage,
|
|
171
|
+
input: Omit<PipelineDriverInput, "gates">,
|
|
172
|
+
): StageRunner {
|
|
173
|
+
switch (stage) {
|
|
174
|
+
case "intake":
|
|
175
|
+
return new IntakeStage({ seedPrompt: input.seedPrompt });
|
|
176
|
+
case "scout":
|
|
177
|
+
return new ScoutStage();
|
|
178
|
+
case "discover":
|
|
179
|
+
return new DiscoverStage();
|
|
180
|
+
case "research":
|
|
181
|
+
return new ResearchStage();
|
|
182
|
+
case "synthesize":
|
|
183
|
+
return new SynthesizeStage();
|
|
184
|
+
case "review":
|
|
185
|
+
return new ReviewStage({ iteration: input.iteration ?? 1 });
|
|
186
|
+
case "approve":
|
|
187
|
+
return new ApproveStage({ iteration: input.iteration ?? 1 });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function gateStagesFor(mode: PipelineGateMode): Set<UltraPlanAuthoringStage> {
|
|
192
|
+
switch (mode) {
|
|
193
|
+
case "default":
|
|
194
|
+
return GATE_STAGES_DEFAULT;
|
|
195
|
+
case "auto":
|
|
196
|
+
return new Set();
|
|
197
|
+
case "manual":
|
|
198
|
+
return GATE_STAGES_MANUAL;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Run the pipeline forward until either (a) it completes through APPROVE, (b) it lands at a
|
|
204
|
+
* gate stage, or (c) a stage returns `failed`/`blocked`. Synth-stage gating includes the
|
|
205
|
+
* `$EDITOR` round-trip via `runSynthGateLoop`.
|
|
206
|
+
*
|
|
207
|
+
* The driver does **not** run interactive UI prompts on its own \u2014 the calling command
|
|
208
|
+
* orchestrator wraps the call and presents `ctx.ui.select` / `ctx.ui.confirm` between
|
|
209
|
+
* driver invocations.
|
|
210
|
+
*/
|
|
211
|
+
export async function runPipelineUntilGate(input: PipelineDriverInput): Promise<PipelineRunOutcome> {
|
|
212
|
+
const trace: { stage: UltraPlanAuthoringStage; status: StageRunResult["status"] }[] = [];
|
|
213
|
+
const gateStages = gateStagesFor(input.gates);
|
|
214
|
+
|
|
215
|
+
let safety = 0;
|
|
216
|
+
// Hard cap to prevent runaway loops if a runner ever returns `completed` without advancing
|
|
217
|
+
// its on-disk state. We've sized this to handle the longest legitimate path (intake \u2192 scout
|
|
218
|
+
// \u2192 discover \u2192 research \u2192 synthesize \u2192 review \u2192 approve = 7) plus a margin.
|
|
219
|
+
while (safety < 16) {
|
|
220
|
+
safety += 1;
|
|
221
|
+
const next = resolveNextStage(input.paths, input.cwd, input.sessionId);
|
|
222
|
+
const runner = buildRunner(next.stage, input);
|
|
223
|
+
const ctx: StageRunnerContext = {
|
|
224
|
+
platform: input.platform,
|
|
225
|
+
paths: input.paths,
|
|
226
|
+
cwd: input.cwd,
|
|
227
|
+
sessionId: input.sessionId,
|
|
228
|
+
modelConfig: input.modelConfig,
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const result = await runner.run(ctx);
|
|
232
|
+
trace.push({ stage: next.stage, status: result.status });
|
|
233
|
+
|
|
234
|
+
if (result.status === "failed" || result.status === "blocked") {
|
|
235
|
+
return {
|
|
236
|
+
stage: next.stage,
|
|
237
|
+
status: result.status,
|
|
238
|
+
promoted: false,
|
|
239
|
+
message: result.error ?? result.blocker?.message,
|
|
240
|
+
trace,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Synth-stage editor round-trip when in non-manual modes. After the planner draft is
|
|
245
|
+
// persisted, run the editor gate; on save, the driver continues to review.
|
|
246
|
+
if (next.stage === "synthesize" && result.status === "awaiting-user" && input.gates !== "manual") {
|
|
247
|
+
const gate = await runSynthGateLoop({
|
|
248
|
+
platform: input.platform,
|
|
249
|
+
paths: input.paths,
|
|
250
|
+
cwd: input.cwd,
|
|
251
|
+
sessionId: input.sessionId,
|
|
252
|
+
iteration: input.iteration ?? 1,
|
|
253
|
+
});
|
|
254
|
+
if (gate.status === "io-error" || gate.status === "parse-failed") {
|
|
255
|
+
return {
|
|
256
|
+
stage: next.stage,
|
|
257
|
+
status: "blocked",
|
|
258
|
+
promoted: false,
|
|
259
|
+
message: gate.status === "parse-failed"
|
|
260
|
+
? `Synth gate parse-failed after retries: ${gate.errors.map((e) => e.message).join("; ")}`
|
|
261
|
+
: gate.message,
|
|
262
|
+
trace,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (gateStages.has(next.stage) && result.status !== "skipped") {
|
|
268
|
+
// Awaiting user gate: caller orchestrates the prompt and re-invokes the driver.
|
|
269
|
+
return {
|
|
270
|
+
stage: next.stage,
|
|
271
|
+
status: "awaiting-user",
|
|
272
|
+
promoted: false,
|
|
273
|
+
trace,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (next.stage === "approve" && (result.status === "completed" || result.status === "skipped")) {
|
|
278
|
+
return {
|
|
279
|
+
stage: "approve",
|
|
280
|
+
status: result.status,
|
|
281
|
+
promoted: true,
|
|
282
|
+
trace,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
stage: "approve",
|
|
289
|
+
status: "failed",
|
|
290
|
+
promoted: false,
|
|
291
|
+
message: "Pipeline driver exceeded its safety cap; check the manifest's authoring block for inconsistency.",
|
|
292
|
+
trace,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Detect every in-flight authoring session for the picker. Returns sessions whose manifest
|
|
298
|
+
* has an `authoring` block AND whose canonical authored.json doesn't exist yet (i.e. they
|
|
299
|
+
* haven't been promoted).
|
|
300
|
+
*/
|
|
301
|
+
export function listInFlightAuthoringSessions(
|
|
302
|
+
paths: PlatformPaths,
|
|
303
|
+
cwd: string,
|
|
304
|
+
sessionIds: string[],
|
|
305
|
+
): { sessionId: string; stage: UltraPlanAuthoringStage; status: string }[] {
|
|
306
|
+
const inFlight = [];
|
|
307
|
+
for (const sessionId of sessionIds) {
|
|
308
|
+
const dir = getUltraplanAuthoringDir(paths, cwd, sessionId);
|
|
309
|
+
if (!fs.existsSync(dir)) continue;
|
|
310
|
+
const stateResult = loadAuthoringState(paths, cwd, sessionId);
|
|
311
|
+
if (!stateResult.ok || !stateResult.value) continue;
|
|
312
|
+
inFlight.push({
|
|
313
|
+
sessionId,
|
|
314
|
+
stage: stateResult.value.stage,
|
|
315
|
+
status: stateResult.value.stageStatus,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return inFlight;
|
|
319
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage runner abstraction for the multi-stage authoring pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Every stage runs as a fresh `platform.createAgentSession`. The stage runner is the thin
|
|
5
|
+
* wrapper that:
|
|
6
|
+
* - resolves the model + agent prompt for the stage,
|
|
7
|
+
* - builds the assignment prompt deterministically from prior artifacts,
|
|
8
|
+
* - spawns the session and awaits its completion (the agent calls one or more
|
|
9
|
+
* `ultraplan_*` tools, which the hook bridge translates into atomic disk writes),
|
|
10
|
+
* - transitions the manifest's `authoring` block on success.
|
|
11
|
+
*
|
|
12
|
+
* This file owns the abstract interface only. Concrete stages live under `stages/`.
|
|
13
|
+
*
|
|
14
|
+
* Design notes:
|
|
15
|
+
* - Stages do not share state in memory. The disk artifacts under `<session>/authoring/`
|
|
16
|
+
* are the source of truth. `resume` is just `run` with the same inputs — which means
|
|
17
|
+
* we always re-derive prompts from disk, never from in-memory variables.
|
|
18
|
+
* - Each stage owns its own pre-flight check (`isReady`) and post-condition
|
|
19
|
+
* (`isComplete`). The pipeline driver uses these to decide whether to skip, run,
|
|
20
|
+
* or block.
|
|
21
|
+
* - Errors propagate as `StageRunResult` discriminated unions. Stage runners never throw
|
|
22
|
+
* on user-visible failures (validation, missing prerequisites, agent abort). They throw
|
|
23
|
+
* only on programming errors (malformed config, etc.).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { Platform } from "../../platform/types.js";
|
|
27
|
+
import type { PlatformPaths } from "../../platform/types.js";
|
|
28
|
+
import type {
|
|
29
|
+
ModelConfig,
|
|
30
|
+
UltraPlanAuthoringStage,
|
|
31
|
+
UltraPlanAuthoringStageStatus,
|
|
32
|
+
UltraPlanBlocker,
|
|
33
|
+
} from "../../types.js";
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Public types
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Inputs available to every stage runner. The runner reads from disk inside `run` rather
|
|
41
|
+
* than capturing state at construction time, which keeps `resume` semantics trivial.
|
|
42
|
+
*/
|
|
43
|
+
export interface StageRunnerContext {
|
|
44
|
+
platform: Platform;
|
|
45
|
+
paths: PlatformPaths;
|
|
46
|
+
cwd: string;
|
|
47
|
+
sessionId: string;
|
|
48
|
+
/** Loaded once at the start of the pipeline; passed in for model resolution. */
|
|
49
|
+
modelConfig: ModelConfig;
|
|
50
|
+
/**
|
|
51
|
+
* Optional override for `now()` so tests can produce deterministic timestamps. Production
|
|
52
|
+
* code defaults to `Date.now()` via `() => new Date().toISOString()`.
|
|
53
|
+
*/
|
|
54
|
+
now?: () => string;
|
|
55
|
+
/** Optional override for the agent session model. Tests use this to bypass resolution. */
|
|
56
|
+
modelOverride?: { model: string; thinkingLevel: string | null };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type StageRunStatus =
|
|
60
|
+
| "completed" // The stage ran to completion and persisted its artifact.
|
|
61
|
+
| "skipped" // Pre-conditions said the stage was already done; no work performed.
|
|
62
|
+
| "blocked" // The stage hit a structured blocker; manifest's `authoring.blocker` set.
|
|
63
|
+
| "awaiting-user" // The stage produced output but needs a user gate before advancing.
|
|
64
|
+
| "failed"; // Programming-level failure; surfaced for the operator with `error`.
|
|
65
|
+
|
|
66
|
+
export interface StageRunResult {
|
|
67
|
+
status: StageRunStatus;
|
|
68
|
+
stage: UltraPlanAuthoringStage;
|
|
69
|
+
/** Artifacts touched by this run (relative to `<session>/authoring/`). */
|
|
70
|
+
artifactPaths: string[];
|
|
71
|
+
/** Set when status is `blocked`. */
|
|
72
|
+
blocker?: UltraPlanBlocker;
|
|
73
|
+
/** Set when status is `failed`. */
|
|
74
|
+
error?: string;
|
|
75
|
+
/** Free-form structured details for `pipeline-log.jsonl`. */
|
|
76
|
+
details?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface StageRunner {
|
|
80
|
+
/** The stage this runner advances. Constant per runner. */
|
|
81
|
+
readonly stage: UltraPlanAuthoringStage;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Cheap existence check: are the upstream artifacts the stage needs available on disk?
|
|
85
|
+
* The pipeline driver calls this before `run` to bucket sessions in the resume picker.
|
|
86
|
+
*/
|
|
87
|
+
isReady(ctx: StageRunnerContext): Promise<boolean>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Has this stage already been completed for the given session? Used by `resume` to
|
|
91
|
+
* decide whether to re-run or skip. Returns `true` if the stage's primary artifact
|
|
92
|
+
* exists on disk and passes its schema validation.
|
|
93
|
+
*/
|
|
94
|
+
isComplete(ctx: StageRunnerContext): Promise<boolean>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Execute the stage. Idempotent: if `isComplete` returns true, the runner returns
|
|
98
|
+
* `status: "skipped"` without spawning an agent. Otherwise it runs the agent, awaits
|
|
99
|
+
* completion, validates the produced artifact, and updates the manifest's
|
|
100
|
+
* `authoring.stage` / `stageStatus` fields atomically.
|
|
101
|
+
*/
|
|
102
|
+
run(ctx: StageRunnerContext): Promise<StageRunResult>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Convenience helpers shared by concrete stages
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
export function nowIso(ctx: StageRunnerContext): string {
|
|
110
|
+
return (ctx.now ?? (() => new Date().toISOString()))();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Build a deterministic agent display name for the spawned `createAgentSession`. The
|
|
115
|
+
* convention `ultraplan-authoring-<stage>[/<discriminator>]` lets the picker and logs
|
|
116
|
+
* correlate sessions to stages without parsing prompts.
|
|
117
|
+
*/
|
|
118
|
+
export function buildAgentDisplayName(
|
|
119
|
+
stage: UltraPlanAuthoringStage,
|
|
120
|
+
discriminator?: string,
|
|
121
|
+
): string {
|
|
122
|
+
return discriminator ? `ultraplan-authoring-${stage}/${discriminator}` : `ultraplan-authoring-${stage}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Translate a `StageRunStatus` to the manifest's `stageStatus` value for the same stage.
|
|
127
|
+
*/
|
|
128
|
+
export function toManifestStageStatus(status: StageRunStatus): UltraPlanAuthoringStageStatus {
|
|
129
|
+
switch (status) {
|
|
130
|
+
case "completed":
|
|
131
|
+
return "done";
|
|
132
|
+
case "skipped":
|
|
133
|
+
return "done";
|
|
134
|
+
case "blocked":
|
|
135
|
+
return "blocked";
|
|
136
|
+
case "awaiting-user":
|
|
137
|
+
return "awaiting-user";
|
|
138
|
+
case "failed":
|
|
139
|
+
return "blocked";
|
|
140
|
+
}
|
|
141
|
+
}
|