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,274 @@
|
|
|
1
|
+
// src/ai/structured-output.ts
|
|
2
|
+
//
|
|
3
|
+
// Canonical schema-backed AI output path. Every AI-heavy workflow (review,
|
|
4
|
+
// planning, commit, docs-drift, AI review gate, fix-pr, release) must flow
|
|
5
|
+
// through this module for:
|
|
6
|
+
// - final assistant message extraction (via ./final-message.ts)
|
|
7
|
+
// - JSON-fence stripping + schema-checked parsing
|
|
8
|
+
// - retry with a validator-feedback prompt until maxAttempts exhausts
|
|
9
|
+
// - explicit blocked result when parsing never succeeds
|
|
10
|
+
//
|
|
11
|
+
// One canonical retry template lives in `./prompts/invalid-output-retry.md`.
|
|
12
|
+
// One canonical renderer lives in `./template.ts`. Neither has a review-
|
|
13
|
+
// specific name any more.
|
|
14
|
+
|
|
15
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
16
|
+
import { Value } from "@sinclair/typebox/value";
|
|
17
|
+
import invalidOutputRetryPrompt from "./prompts/invalid-output-retry.md" with { type: "text" };
|
|
18
|
+
import { runStructuredAgentSession } from "./final-message.js";
|
|
19
|
+
import { renderTemplate } from "./template.js";
|
|
20
|
+
import { stripMarkdownCodeFence } from "../text.js";
|
|
21
|
+
import type { GateExecutionContext, ReliabilityOutcome, ValidationError } from "../types.js";
|
|
22
|
+
import type { PlatformPaths } from "../platform/types.js";
|
|
23
|
+
import { appendReliabilityRecord } from "../storage/reliability-metrics.js";
|
|
24
|
+
|
|
25
|
+
export interface StructuredParseResult<T> {
|
|
26
|
+
output: T | null;
|
|
27
|
+
error: string | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface StructuredOutputRunOptions<T> {
|
|
31
|
+
cwd: string;
|
|
32
|
+
prompt: string;
|
|
33
|
+
/**
|
|
34
|
+
* Prompt-visible schema text, produced by schema-text.ts. Injected into
|
|
35
|
+
* the retry prompt so the model can self-correct on invalid output.
|
|
36
|
+
*/
|
|
37
|
+
schema: string;
|
|
38
|
+
/**
|
|
39
|
+
* Parse raw model text into T. Implementations typically delegate to
|
|
40
|
+
* `parseStructuredOutput(raw, SomeSchema)`.
|
|
41
|
+
*/
|
|
42
|
+
parse: (raw: string) => StructuredParseResult<T>;
|
|
43
|
+
model?: string;
|
|
44
|
+
thinkingLevel?: string | null;
|
|
45
|
+
agentId?: string;
|
|
46
|
+
agentDisplayName?: string;
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
/** Default: 3. Clamped to >=1 at runtime. */
|
|
49
|
+
maxAttempts?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Optional reliability reporter. When supplied, the runner appends one
|
|
52
|
+
* ReliabilityRecord per final outcome (ok / retry-exhausted / agent-error)
|
|
53
|
+
* to the cwd-local reliability events log. No-op when omitted.
|
|
54
|
+
*/
|
|
55
|
+
reliability?: ReliabilityReporter;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Describes how to report the outcome of a runWithOutputValidation call to
|
|
60
|
+
* the per-cwd reliability log. Every AI-heavy production call site supplies
|
|
61
|
+
* one of these; the helper itself emits exactly one record per final outcome.
|
|
62
|
+
*
|
|
63
|
+
* Emission is best-effort: failures are swallowed (metrics must never crash
|
|
64
|
+
* the workflow they observe).
|
|
65
|
+
*/
|
|
66
|
+
export interface ReliabilityReporter {
|
|
67
|
+
paths: PlatformPaths;
|
|
68
|
+
cwd: string;
|
|
69
|
+
/** Logical command name (e.g. "plan", "commit", "review"). */
|
|
70
|
+
command: string;
|
|
71
|
+
/** Optional sub-operation (e.g. "commit-plan", "note-polish"). */
|
|
72
|
+
operation?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type StructuredOutputResult<T> =
|
|
76
|
+
| {
|
|
77
|
+
status: "ok";
|
|
78
|
+
output: T;
|
|
79
|
+
rawOutput: string;
|
|
80
|
+
attempts: number;
|
|
81
|
+
}
|
|
82
|
+
| {
|
|
83
|
+
status: "blocked";
|
|
84
|
+
error: string;
|
|
85
|
+
rawOutputs: string[];
|
|
86
|
+
attempts: number;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
function truncateForPrompt(text: string, maxLength = 1200): string {
|
|
90
|
+
const normalized = text.trim();
|
|
91
|
+
if (normalized.length <= maxLength) {
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
94
|
+
return `${normalized.slice(0, maxLength - 1)}…`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function normalizeErrorPath(path: string): string {
|
|
98
|
+
return path.replace(/^\//, "").replace(/\//g, ".") || "(root)";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Collect schema validation errors for a TypeBox schema in a stable
|
|
103
|
+
* {path, message} shape. Used by parseStructuredOutput and by any code that
|
|
104
|
+
* needs to format schema-check failures for humans or prompts.
|
|
105
|
+
*/
|
|
106
|
+
export function collectValidationErrors(schema: TSchema, data: unknown): ValidationError[] {
|
|
107
|
+
return [...Value.Errors(schema, data)].map((error) => ({
|
|
108
|
+
path: normalizeErrorPath(error.path),
|
|
109
|
+
message: error.message,
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Render validation errors as `path: message` lines.
|
|
115
|
+
*/
|
|
116
|
+
export function formatValidationErrors(errors: ValidationError[]): string[] {
|
|
117
|
+
return errors.map((error) => `${error.path}: ${error.message}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Strip markdown fences, JSON-parse, and schema-check against a TypeBox.
|
|
122
|
+
* Returns {output: T, error: null} on success; {output: null, error: string}
|
|
123
|
+
* on failure with a human-readable error suitable for retry prompts.
|
|
124
|
+
*/
|
|
125
|
+
export function parseStructuredOutput<T>(raw: string, schema: TSchema): StructuredParseResult<T> {
|
|
126
|
+
let parsed: unknown;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
parsed = JSON.parse(stripMarkdownCodeFence(raw));
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return {
|
|
132
|
+
output: null,
|
|
133
|
+
error: error instanceof Error ? `Invalid JSON: ${error.message}` : "Invalid JSON.",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!Value.Check(schema, parsed)) {
|
|
138
|
+
const errors = formatValidationErrors(collectValidationErrors(schema, parsed));
|
|
139
|
+
return {
|
|
140
|
+
output: null,
|
|
141
|
+
error: errors.length > 0 ? errors.join("; ") : "Output does not match the required schema.",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
output: parsed as T,
|
|
147
|
+
error: null,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Run a schema-backed AI session with retry-on-invalid-output. On every
|
|
153
|
+
* retry, the original prompt is wrapped with the invalid-output-retry
|
|
154
|
+
* template so the model sees the validation error and its previous output.
|
|
155
|
+
*
|
|
156
|
+
* Returns `status: "ok"` on first successful schema-valid parse. Returns
|
|
157
|
+
* `status: "blocked"` when maxAttempts exhausts, when the underlying agent
|
|
158
|
+
* session errors, or when no final assistant text is produced.
|
|
159
|
+
*/
|
|
160
|
+
export async function runWithOutputValidation<T>(
|
|
161
|
+
createAgentSession: GateExecutionContext["createAgentSession"],
|
|
162
|
+
options: StructuredOutputRunOptions<T>,
|
|
163
|
+
): Promise<StructuredOutputResult<T>> {
|
|
164
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 3);
|
|
165
|
+
const rawOutputs: string[] = [];
|
|
166
|
+
let prompt = options.prompt;
|
|
167
|
+
let attempt = 0;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
for (attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
171
|
+
const result = await runStructuredAgentSession(createAgentSession, {
|
|
172
|
+
cwd: options.cwd,
|
|
173
|
+
prompt,
|
|
174
|
+
model: options.model,
|
|
175
|
+
thinkingLevel: options.thinkingLevel ?? null,
|
|
176
|
+
agentId: options.agentId,
|
|
177
|
+
agentDisplayName: options.agentDisplayName,
|
|
178
|
+
timeoutMs: options.timeoutMs,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (result.status !== "ok") {
|
|
182
|
+
emitReliabilityOutcome(options.reliability, "agent-error", attempt, result.error);
|
|
183
|
+
return {
|
|
184
|
+
status: "blocked",
|
|
185
|
+
error: result.error,
|
|
186
|
+
rawOutputs,
|
|
187
|
+
attempts: attempt,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
rawOutputs.push(result.finalText);
|
|
192
|
+
const parsed = options.parse(result.finalText);
|
|
193
|
+
if (parsed.output) {
|
|
194
|
+
emitReliabilityOutcome(options.reliability, "ok", attempt);
|
|
195
|
+
return {
|
|
196
|
+
status: "ok",
|
|
197
|
+
output: parsed.output,
|
|
198
|
+
rawOutput: result.finalText,
|
|
199
|
+
attempts: attempt,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (attempt === maxAttempts) {
|
|
204
|
+
const reason = parsed.error ?? "Agent output was invalid.";
|
|
205
|
+
emitReliabilityOutcome(options.reliability, "retry-exhausted", attempt, reason);
|
|
206
|
+
return {
|
|
207
|
+
status: "blocked",
|
|
208
|
+
error: reason,
|
|
209
|
+
rawOutputs,
|
|
210
|
+
attempts: attempt,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
prompt = renderTemplate(invalidOutputRetryPrompt, {
|
|
215
|
+
prompt: options.prompt,
|
|
216
|
+
error: parsed.error ?? "Agent output was invalid.",
|
|
217
|
+
previousOutput: truncateForPrompt(result.finalText),
|
|
218
|
+
schema: options.schema,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
// createAgentSession (or anything else) threw before completing a final
|
|
223
|
+
// outcome — record as agent-error and re-raise so callers keep their
|
|
224
|
+
// existing error semantics.
|
|
225
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
226
|
+
emitReliabilityOutcome(
|
|
227
|
+
options.reliability,
|
|
228
|
+
"agent-error",
|
|
229
|
+
Math.max(1, attempt),
|
|
230
|
+
reason,
|
|
231
|
+
);
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Fallthrough: loop exhausted without a final outcome. Treat as retry-
|
|
236
|
+
// exhausted for the record, and return blocked so callers see the same
|
|
237
|
+
// shape they used to.
|
|
238
|
+
emitReliabilityOutcome(
|
|
239
|
+
options.reliability,
|
|
240
|
+
"retry-exhausted",
|
|
241
|
+
maxAttempts,
|
|
242
|
+
"Output validation exhausted without producing a valid result.",
|
|
243
|
+
);
|
|
244
|
+
return {
|
|
245
|
+
status: "blocked",
|
|
246
|
+
error: "Output validation exhausted without producing a valid result.",
|
|
247
|
+
rawOutputs,
|
|
248
|
+
attempts: maxAttempts,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function emitReliabilityOutcome(
|
|
253
|
+
reporter: ReliabilityReporter | undefined,
|
|
254
|
+
outcome: ReliabilityOutcome,
|
|
255
|
+
attempts: number,
|
|
256
|
+
reason?: string,
|
|
257
|
+
): void {
|
|
258
|
+
if (!reporter) return;
|
|
259
|
+
try {
|
|
260
|
+
appendReliabilityRecord(reporter.paths, reporter.cwd, {
|
|
261
|
+
ts: new Date().toISOString(),
|
|
262
|
+
command: reporter.command,
|
|
263
|
+
operation: reporter.operation,
|
|
264
|
+
outcome,
|
|
265
|
+
attempts,
|
|
266
|
+
reason,
|
|
267
|
+
cwd: reporter.cwd,
|
|
268
|
+
});
|
|
269
|
+
} catch {
|
|
270
|
+
// Defensive: appendReliabilityRecord already swallows its own errors,
|
|
271
|
+
// but we double-guard so a reporter misconfiguration never crashes the
|
|
272
|
+
// workflow it observes.
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/ai/template.ts
|
|
2
|
+
//
|
|
3
|
+
// Generic Handlebars-based template renderer. Used by every AI prompt that
|
|
4
|
+
// needs structured interpolation. Lives under src/ai/ because it is generic
|
|
5
|
+
// and was previously duplicated under src/review/template.ts.
|
|
6
|
+
//
|
|
7
|
+
// Helpers:
|
|
8
|
+
// - {{json value}} → JSON.stringify(value, null, 2)
|
|
9
|
+
// - {{joinLines lines}} → array joined by newline
|
|
10
|
+
//
|
|
11
|
+
// Add new helpers here only when at least two unrelated callers need them.
|
|
12
|
+
|
|
13
|
+
import Handlebars from "handlebars";
|
|
14
|
+
|
|
15
|
+
const handlebars = Handlebars.create();
|
|
16
|
+
|
|
17
|
+
handlebars.registerHelper("json", (value: unknown): string => JSON.stringify(value, null, 2));
|
|
18
|
+
handlebars.registerHelper("joinLines", (value: unknown): string => {
|
|
19
|
+
if (!Array.isArray(value)) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
return value.join("\n");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export function renderTemplate(template: string, context: Record<string, unknown> = {}): string {
|
|
26
|
+
return handlebars.compile(template, { noEscape: true })(context);
|
|
27
|
+
}
|
package/src/bootstrap.ts
CHANGED
|
@@ -19,18 +19,37 @@ import { executeManagerAction } from "./mcp/manager-tool.js";
|
|
|
19
19
|
import { registerFixPrCommand } from "./commands/fix-pr.js";
|
|
20
20
|
import { registerContextCommand, handleContext } from "./commands/context.js";
|
|
21
21
|
import { registerOptimizeContextCommand, handleOptimizeContext } from "./commands/optimize-context.js";
|
|
22
|
+
import { registerClearCommand, handleClear } from "./commands/clear.js";
|
|
22
23
|
import { registerCommitCommand, handleCommit } from "./commands/commit.js";
|
|
23
24
|
import { registerGenerateCommand } from "./commands/generate.js";
|
|
24
25
|
import { registerAgentsCommand, handleAgents } from "./commands/agents.js";
|
|
26
|
+
import { registerMemoryCommand, handleMemory } from "./commands/memory.js";
|
|
27
|
+
import { registerUltraplanCommand, handleUltraplan } from "./commands/ultraplan.js";
|
|
28
|
+
import { registerHarnessCommand, handleHarness } from "./harness/command.js";
|
|
29
|
+
import { registerHarnessPipelineTools } from "./harness/tools.js";
|
|
30
|
+
import { registerHarnessHooks } from "./harness/hooks/register.js";
|
|
25
31
|
import { loadConfig } from "./config/loader.js";
|
|
26
32
|
import { registerContextModeHooks } from "./context-mode/hooks.js";
|
|
27
33
|
import { loadMcpRegistry } from "./mcp/config.js";
|
|
28
34
|
import { McpcClient } from "./mcp/mcpc.js";
|
|
29
|
-
import { parseTags
|
|
35
|
+
import { parseTags } from "./mcp/activation.js";
|
|
30
36
|
import { initializeMcpServers, shutdownMcpServers } from "./mcp/lifecycle.js";
|
|
31
37
|
import { registerPlanApprovalHook } from "./planning/approval-flow.js";
|
|
32
38
|
import { registerPlanningSystemPromptHook } from "./planning/system-prompt.js";
|
|
33
|
-
import { registerPlanningAskTool } from "./planning/planning-ask-tool.js";
|
|
39
|
+
import { registerPlanningAskTool, registerPlanningAskToolGuard } from "./planning/planning-ask-tool.js";
|
|
40
|
+
import { registerUiDesignCommand } from "./commands/ui-design.js";
|
|
41
|
+
import { registerUiDesignSystemPromptHook } from "./ui-design/system-prompt.js";
|
|
42
|
+
import {
|
|
43
|
+
registerUiDesignApprovalHook,
|
|
44
|
+
registerUiDesignToolGuard,
|
|
45
|
+
stopActiveUiDesignSession,
|
|
46
|
+
} from "./ui-design/session.js";
|
|
47
|
+
import { registerUltraPlanRuntimeTools } from "./ultraplan/execution/runtime-tools.js";
|
|
48
|
+
import { registerUltraPlanAuthoringTool } from "./ultraplan/authoring-tool.js";
|
|
49
|
+
import { registerUltraPlanAuthoringPipelineTools } from "./ultraplan/authoring/authoring-tools.js";
|
|
50
|
+
import { registerActiveToolController } from "./tool-catalog/active-tool-controller.js";
|
|
51
|
+
import { registerMempalaceHooks } from "./mempalace/hooks.js";
|
|
52
|
+
import { registerMempalaceTool } from "./mempalace/tool.js";
|
|
34
53
|
|
|
35
54
|
// TUI-only commands — intercepted at the input level to prevent
|
|
36
55
|
// message submission and "Working..." indicator
|
|
@@ -38,17 +57,21 @@ const TUI_COMMANDS: Record<string, (platform: Platform, ctx: any, args?: string)
|
|
|
38
57
|
"supi": (platform, ctx) => handleSupi(platform, ctx),
|
|
39
58
|
"supi:config": (platform, ctx) => handleConfig(platform, ctx),
|
|
40
59
|
"supi:status": (platform, ctx) => handleStatus(platform, ctx),
|
|
41
|
-
"supi:review": (platform, ctx) => handleAiReview(platform, ctx),
|
|
60
|
+
"supi:review": (platform, ctx, args) => handleAiReview(platform, ctx, args),
|
|
42
61
|
"supi:update": (platform, ctx) => handleUpdate(platform, ctx),
|
|
43
62
|
"supi:doctor": (platform, ctx) => handleDoctor(platform, ctx),
|
|
44
63
|
"supi:mcp": (platform, ctx) => handleMcp(platform, ctx),
|
|
45
64
|
"supi:model": (platform, ctx) => handleModel(platform, ctx),
|
|
46
65
|
"supi:context": (platform, ctx) => handleContext(platform, ctx),
|
|
47
|
-
"supi:optimize-context": (platform, ctx) => handleOptimizeContext(platform, ctx),
|
|
66
|
+
"supi:optimize-context": (platform, ctx, args) => handleOptimizeContext(platform, ctx, args),
|
|
67
|
+
"supi:clear": (platform, ctx, args) => handleClear(platform, ctx, args),
|
|
48
68
|
"supi:commit": (platform, ctx, args) => handleCommit(platform, ctx, args),
|
|
49
69
|
"supi:release": (platform, ctx, args) => handleRelease(platform, ctx, args),
|
|
50
70
|
"supi:checks": (platform, ctx, args) => handleChecksCommand(platform, ctx, args),
|
|
51
71
|
"supi:agents": (platform, ctx, args) => handleAgents(platform, ctx, args),
|
|
72
|
+
"supi:ultraplan": (platform, ctx, args) => handleUltraplan(platform, ctx, args),
|
|
73
|
+
"supi:harness": (platform, ctx, args) => { void handleHarness(platform, ctx, args); },
|
|
74
|
+
"supi:memory": (platform, ctx, args) => handleMemory(platform, ctx, args),
|
|
52
75
|
};
|
|
53
76
|
|
|
54
77
|
let pendingTags: string[] = [];
|
|
@@ -80,15 +103,29 @@ export function bootstrap(platform: Platform): void {
|
|
|
80
103
|
registerModelCommand(platform);
|
|
81
104
|
registerContextCommand(platform);
|
|
82
105
|
registerOptimizeContextCommand(platform);
|
|
106
|
+
registerClearCommand(platform);
|
|
83
107
|
registerCommitCommand(platform);
|
|
84
108
|
registerGenerateCommand(platform);
|
|
85
109
|
registerAgentsCommand(platform);
|
|
110
|
+
registerUiDesignCommand(platform);
|
|
111
|
+
registerUltraplanCommand(platform);
|
|
112
|
+
registerHarnessCommand(platform);
|
|
113
|
+
registerMemoryCommand(platform);
|
|
86
114
|
|
|
87
115
|
|
|
116
|
+
registerUltraPlanRuntimeTools(platform);
|
|
117
|
+
registerUltraPlanAuthoringTool(platform);
|
|
118
|
+
registerUltraPlanAuthoringPipelineTools(platform);
|
|
119
|
+
registerHarnessPipelineTools(platform);
|
|
120
|
+
|
|
88
121
|
// Register plan approval flow (agent_end hook for plan approval UI)
|
|
89
122
|
registerPlanApprovalHook(platform);
|
|
90
123
|
registerPlanningAskTool(platform);
|
|
124
|
+
registerPlanningAskToolGuard(platform);
|
|
91
125
|
|
|
126
|
+
// Register ui-design approval flow + runtime write-scope guard
|
|
127
|
+
registerUiDesignApprovalHook(platform);
|
|
128
|
+
registerUiDesignToolGuard(platform);
|
|
92
129
|
|
|
93
130
|
// Intercept TUI-only commands at the input level — this runs BEFORE
|
|
94
131
|
// message submission, so no chat message appears and no "Working..." indicator
|
|
@@ -120,35 +157,28 @@ export function bootstrap(platform: Platform): void {
|
|
|
120
157
|
|
|
121
158
|
// Context-mode integration
|
|
122
159
|
const config = loadConfig(platform.paths, process.cwd());
|
|
160
|
+
registerActiveToolController(platform, config, {
|
|
161
|
+
loadMcpRegistryForCwd: (cwd: string) => loadMcpRegistry(platform.paths, cwd),
|
|
162
|
+
consumePendingTags: () => {
|
|
163
|
+
const tags = pendingTags;
|
|
164
|
+
pendingTags = [];
|
|
165
|
+
return tags;
|
|
166
|
+
},
|
|
167
|
+
});
|
|
123
168
|
registerContextModeHooks(platform, config);
|
|
169
|
+
registerMempalaceTool(platform, config);
|
|
170
|
+
registerMempalaceHooks(platform, config);
|
|
124
171
|
|
|
125
|
-
|
|
126
|
-
// Planning-mode prompt override — registered after context-mode so it wins
|
|
172
|
+
// Planning-mode prompt override — registered after context-mode and MemPalace so it wins
|
|
127
173
|
// when /supi:plan is active and otherwise stays dormant.
|
|
128
174
|
registerPlanningSystemPromptHook(platform);
|
|
175
|
+
registerUiDesignSystemPromptHook(platform);
|
|
129
176
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
pendingTags = [];
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
177
|
+
// Register harness anti-slop hooks (gated by per-repo marker file at session start).
|
|
178
|
+
// Idempotent — safe to call once per process. The hooks themselves no-op on every
|
|
179
|
+
// event when the marker is missing, so other repos see no behavior change.
|
|
180
|
+
registerHarnessHooks(platform);
|
|
137
181
|
|
|
138
|
-
const message = typeof event.message?.content === "string" ? event.message.content : "";
|
|
139
|
-
const active = computeActiveServers(registry.servers, message, pendingTags);
|
|
140
|
-
|
|
141
|
-
const activeToolNames = active.map((name) => `mcpc_${name}`);
|
|
142
|
-
activeToolNames.push("mcpc_manager");
|
|
143
|
-
|
|
144
|
-
if (platform.setActiveTools) {
|
|
145
|
-
const currentTools = platform.getActiveTools();
|
|
146
|
-
const nonMcpTools = currentTools.filter((t: string) => !t.startsWith("mcpc_"));
|
|
147
|
-
platform.setActiveTools([...nonMcpTools, ...activeToolNames]);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
pendingTags = [];
|
|
151
|
-
});
|
|
152
182
|
|
|
153
183
|
// Session start
|
|
154
184
|
platform.on("session_start", async (_event, ctx) => {
|
|
@@ -159,6 +189,9 @@ export function bootstrap(platform: Platform): void {
|
|
|
159
189
|
setActiveVisualSessionDir(null);
|
|
160
190
|
}
|
|
161
191
|
|
|
192
|
+
// Clean up any leftover ui-design companion from a previous session
|
|
193
|
+
await stopActiveUiDesignSession();
|
|
194
|
+
|
|
162
195
|
// Clear leftover model-override status from a previous session.
|
|
163
196
|
// OMP's StatusLine never clears hook statuses on /new, so extensions must do it.
|
|
164
197
|
ctx.ui?.setStatus?.("supi-model", undefined);
|
|
@@ -200,8 +233,10 @@ export function bootstrap(platform: Platform): void {
|
|
|
200
233
|
});
|
|
201
234
|
});
|
|
202
235
|
|
|
203
|
-
//
|
|
236
|
+
// Session shutdown
|
|
204
237
|
platform.on("session_shutdown", async (_event, ctx) => {
|
|
238
|
+
await stopActiveUiDesignSession();
|
|
239
|
+
|
|
205
240
|
const mcpConfig = loadConfig(platform.paths, ctx.cwd ?? process.cwd());
|
|
206
241
|
if (!mcpConfig.mcp?.closeSessionsOnExit) return;
|
|
207
242
|
|