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
package/src/commands/qa.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import type { Platform } from "../platform/types.js";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { loadModelConfig } from "../config/model-config.js";
|
|
5
|
+
import { modelRegistry } from "../config/model-registry-instance.js";
|
|
6
|
+
import { applyModelOverride, createModelBridge, resolveModelForAction } from "../config/model-resolver.js";
|
|
7
|
+
import { notifyError, notifyInfo } from "../notifications/renderer.js";
|
|
8
|
+
import { DEFAULT_E2E_QA_CONFIG, loadE2eQaConfig, saveE2eQaConfig } from "../qa/config.js";
|
|
9
|
+
import { detectAppType } from "../qa/detect-app-type.js";
|
|
10
|
+
import { discoverRoutes, type DiscoveredRoute } from "../qa/discover-routes.js";
|
|
7
11
|
import { loadE2eMatrix } from "../qa/matrix.js";
|
|
8
|
-
import { createNewE2eSession } from "../qa/session.js";
|
|
9
12
|
import { buildE2eOrchestratorPrompt } from "../qa/prompt-builder.js";
|
|
13
|
+
import { createNewE2eSession } from "../qa/session.js";
|
|
14
|
+
import type { AppType, E2eQaConfig, E2eRegression } from "../qa/types.js";
|
|
15
|
+
import type { WorkspaceTarget } from "../types.js";
|
|
10
16
|
import { findActiveSession, getSessionDir } from "../storage/qa-sessions.js";
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
import { moduleDir } from "../utils/paths.js";
|
|
18
|
+
import { resolvePackageManager } from "../workspace/package-manager.js";
|
|
19
|
+
import { resolveRepoRoot } from "../workspace/repo-root.js";
|
|
20
|
+
import {
|
|
21
|
+
buildWorkspaceTargetOptionLabel,
|
|
22
|
+
parseTargetArg,
|
|
23
|
+
selectWorkspaceTarget,
|
|
24
|
+
type WorkspaceTargetOption,
|
|
25
|
+
} from "../workspace/selector.js";
|
|
26
|
+
import { discoverWorkspaceTargets } from "../workspace/targets.js";
|
|
17
27
|
|
|
18
28
|
modelRegistry.register({
|
|
19
29
|
id: "qa",
|
|
@@ -22,8 +32,48 @@ modelRegistry.register({
|
|
|
22
32
|
harnessRoleHint: "slow",
|
|
23
33
|
});
|
|
24
34
|
|
|
35
|
+
export interface QaCommandDependencies {
|
|
36
|
+
loadModelConfig: typeof loadModelConfig;
|
|
37
|
+
createModelBridge: typeof createModelBridge;
|
|
38
|
+
resolveModelForAction: typeof resolveModelForAction;
|
|
39
|
+
applyModelOverride: typeof applyModelOverride;
|
|
40
|
+
resolvePackageManager: typeof resolvePackageManager;
|
|
41
|
+
discoverWorkspaceTargets: typeof discoverWorkspaceTargets;
|
|
42
|
+
selectWorkspaceTarget: typeof selectWorkspaceTarget;
|
|
43
|
+
loadE2eQaConfig: typeof loadE2eQaConfig;
|
|
44
|
+
saveE2eQaConfig: typeof saveE2eQaConfig;
|
|
45
|
+
loadE2eMatrix: typeof loadE2eMatrix;
|
|
46
|
+
createNewE2eSession: typeof createNewE2eSession;
|
|
47
|
+
findActiveSession: typeof findActiveSession;
|
|
48
|
+
getSessionDir: typeof getSessionDir;
|
|
49
|
+
detectAppType: typeof detectAppType;
|
|
50
|
+
discoverRoutes: typeof discoverRoutes;
|
|
51
|
+
notifyError: typeof notifyError;
|
|
52
|
+
notifyInfo: typeof notifyInfo;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const QA_COMMAND_DEPENDENCIES: QaCommandDependencies = {
|
|
56
|
+
loadModelConfig,
|
|
57
|
+
createModelBridge,
|
|
58
|
+
resolveModelForAction,
|
|
59
|
+
applyModelOverride,
|
|
60
|
+
resolvePackageManager,
|
|
61
|
+
discoverWorkspaceTargets,
|
|
62
|
+
selectWorkspaceTarget,
|
|
63
|
+
loadE2eQaConfig,
|
|
64
|
+
saveE2eQaConfig,
|
|
65
|
+
loadE2eMatrix,
|
|
66
|
+
createNewE2eSession,
|
|
67
|
+
findActiveSession,
|
|
68
|
+
getSessionDir,
|
|
69
|
+
detectAppType,
|
|
70
|
+
discoverRoutes,
|
|
71
|
+
notifyError,
|
|
72
|
+
notifyInfo,
|
|
73
|
+
};
|
|
74
|
+
|
|
25
75
|
function getScriptsDir(): string {
|
|
26
|
-
return
|
|
76
|
+
return path.join(moduleDir(import.meta.url), "..", "qa", "scripts");
|
|
27
77
|
}
|
|
28
78
|
|
|
29
79
|
function findSkillPath(skillName: string): string | null {
|
|
@@ -52,13 +102,69 @@ const RETRY_OPTIONS = [
|
|
|
52
102
|
"3",
|
|
53
103
|
];
|
|
54
104
|
|
|
105
|
+
function buildQaTargetOptionLabel(option: WorkspaceTargetOption<WorkspaceTarget>): string {
|
|
106
|
+
return buildWorkspaceTargetOptionLabel(option, [option.target.kind === "root" ? "repo root" : "workspace package"]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function describeTarget(target: WorkspaceTarget): string {
|
|
110
|
+
return target.kind === "root" ? target.name : `${target.name} (${target.relativeDir})`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface QaTargetInspection {
|
|
114
|
+
detectedType: AppType | null;
|
|
115
|
+
detectedDevCommand: string | null;
|
|
116
|
+
detectedPort: number | null;
|
|
117
|
+
detectedIsLikelyApp: boolean;
|
|
118
|
+
preliminaryRoutes: DiscoveredRoute[];
|
|
119
|
+
isRunnable: boolean;
|
|
120
|
+
isRunnableForPrefilter: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function inspectQaTarget(target: WorkspaceTarget, deps: QaCommandDependencies): QaTargetInspection {
|
|
124
|
+
let detectedType: AppType | null = null;
|
|
125
|
+
let detectedDevCommand: string | null = null;
|
|
126
|
+
let detectedPort: number | null = null;
|
|
127
|
+
let detectedIsLikelyApp = false;
|
|
128
|
+
let preliminaryRoutes: DiscoveredRoute[] = [];
|
|
129
|
+
let detectionFailed = false;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const detected = deps.detectAppType(target.packageDir);
|
|
133
|
+
detectedType = detected.type;
|
|
134
|
+
detectedDevCommand = detected.devCommand;
|
|
135
|
+
detectedPort = detected.port;
|
|
136
|
+
detectedIsLikelyApp = detected.isLikelyApp;
|
|
137
|
+
} catch {
|
|
138
|
+
detectionFailed = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!detectionFailed && detectedType) {
|
|
142
|
+
try {
|
|
143
|
+
preliminaryRoutes = deps.discoverRoutes(target.packageDir, detectedType);
|
|
144
|
+
} catch {
|
|
145
|
+
detectionFailed = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const isRunnable = detectedIsLikelyApp || preliminaryRoutes.length > 0;
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
detectedType,
|
|
153
|
+
detectedDevCommand,
|
|
154
|
+
detectedPort,
|
|
155
|
+
detectedIsLikelyApp,
|
|
156
|
+
preliminaryRoutes,
|
|
157
|
+
isRunnable,
|
|
158
|
+
isRunnableForPrefilter: !detectionFailed && isRunnable,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
55
162
|
async function runSetupWizard(
|
|
56
163
|
ctx: any,
|
|
57
164
|
detectedAppType: string | null,
|
|
58
165
|
detectedDevCommand: string | null,
|
|
59
166
|
detectedPort: number | null,
|
|
60
167
|
): Promise<E2eQaConfig | null> {
|
|
61
|
-
// 1. App type
|
|
62
168
|
const appTypeChoice = await ctx.ui.select(
|
|
63
169
|
"App type",
|
|
64
170
|
APP_TYPE_OPTIONS,
|
|
@@ -67,7 +173,6 @@ async function runSetupWizard(
|
|
|
67
173
|
if (!appTypeChoice) return null;
|
|
68
174
|
const appType = appTypeChoice.split(" ")[0] as AppType;
|
|
69
175
|
|
|
70
|
-
// 2. Dev command
|
|
71
176
|
const defaultDev = detectedDevCommand || "npm run dev";
|
|
72
177
|
const devCommand = await ctx.ui.input(
|
|
73
178
|
"Dev server command",
|
|
@@ -76,7 +181,6 @@ async function runSetupWizard(
|
|
|
76
181
|
);
|
|
77
182
|
if (devCommand === undefined) return null;
|
|
78
183
|
|
|
79
|
-
// 3. Port
|
|
80
184
|
const defaultPort = String(detectedPort || 3000);
|
|
81
185
|
const portStr = await ctx.ui.input(
|
|
82
186
|
"Dev server port",
|
|
@@ -86,7 +190,6 @@ async function runSetupWizard(
|
|
|
86
190
|
if (portStr === undefined) return null;
|
|
87
191
|
const port = parseInt(portStr, 10) || 3000;
|
|
88
192
|
|
|
89
|
-
// 4. Max retries
|
|
90
193
|
const retryChoice = await ctx.ui.select(
|
|
91
194
|
"Max test retries",
|
|
92
195
|
RETRY_OPTIONS,
|
|
@@ -113,134 +216,206 @@ async function runSetupWizard(
|
|
|
113
216
|
};
|
|
114
217
|
}
|
|
115
218
|
|
|
116
|
-
export function
|
|
117
|
-
platform
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// ── Step 1: Detect app type ─────────────────────────────────────
|
|
128
|
-
let detectedType: string | null = null;
|
|
129
|
-
let detectedDevCommand: string | null = null;
|
|
130
|
-
let detectedPort: number | null = null;
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const detected = detectAppType(ctx.cwd);
|
|
134
|
-
detectedType = detected.type;
|
|
135
|
-
detectedDevCommand = detected.devCommand;
|
|
136
|
-
detectedPort = detected.port;
|
|
137
|
-
} catch { /* proceed without detection */ }
|
|
138
|
-
|
|
139
|
-
// ── Step 2: Load or create config ────────────────────────────────
|
|
140
|
-
let config = loadE2eQaConfig(platform.paths, ctx.cwd);
|
|
141
|
-
|
|
142
|
-
if (!config && ctx.hasUI) {
|
|
143
|
-
config = await runSetupWizard(ctx, detectedType, detectedDevCommand, detectedPort);
|
|
144
|
-
if (!config) return; // user cancelled
|
|
145
|
-
saveE2eQaConfig(platform.paths, ctx.cwd, config);
|
|
146
|
-
ctx.ui.notify(`E2E QA config saved to ${platform.paths.dotDirDisplay}/supipowers/e2e-qa.json`, "info");
|
|
147
|
-
}
|
|
219
|
+
export async function handleQa(
|
|
220
|
+
platform: Platform,
|
|
221
|
+
ctx: any,
|
|
222
|
+
args: string | undefined,
|
|
223
|
+
deps: QaCommandDependencies = QA_COMMAND_DEPENDENCIES,
|
|
224
|
+
): Promise<void> {
|
|
225
|
+
const modelCfg = deps.loadModelConfig(platform.paths, ctx.cwd);
|
|
226
|
+
const bridge = deps.createModelBridge(platform);
|
|
227
|
+
const resolved = deps.resolveModelForAction("qa", modelRegistry, modelCfg, bridge);
|
|
228
|
+
await deps.applyModelOverride(platform, ctx, "qa", resolved);
|
|
148
229
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
port: detectedPort || 3000,
|
|
157
|
-
baseUrl: `http://localhost:${detectedPort || 3000}`,
|
|
158
|
-
},
|
|
159
|
-
};
|
|
160
|
-
}
|
|
230
|
+
const repoRoot = await resolveRepoRoot(platform, ctx.cwd);
|
|
231
|
+
const packageManager = deps.resolvePackageManager(repoRoot);
|
|
232
|
+
const targets = deps.discoverWorkspaceTargets(repoRoot, packageManager.id);
|
|
233
|
+
if (targets.length === 0) {
|
|
234
|
+
deps.notifyError(ctx, "QA target not found", "Create a package.json with name and version before running /supi:qa.");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
161
237
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
for (const regression of unresolvedRegressions) {
|
|
168
|
-
const choice = await ctx.ui.select(
|
|
169
|
-
`Regression: ${regression.flowName}`,
|
|
170
|
-
[
|
|
171
|
-
"This is a bug — needs fixing",
|
|
172
|
-
"Behavior changed intentionally — update the test",
|
|
173
|
-
"Skip for now",
|
|
174
|
-
],
|
|
175
|
-
{ helpText: `Was passing, now fails: ${regression.error}` },
|
|
176
|
-
);
|
|
177
|
-
if (!choice) continue;
|
|
178
|
-
if (choice.startsWith("This is a bug")) regression.resolution = "bug";
|
|
179
|
-
else if (choice.startsWith("Behavior changed")) regression.resolution = "intentional-change";
|
|
180
|
-
else regression.resolution = "skipped";
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
238
|
+
const requestedTarget = parseTargetArg(args);
|
|
239
|
+
const targetInspections = new Map<string, QaTargetInspection>();
|
|
240
|
+
const getTargetInspection = (target: WorkspaceTarget): QaTargetInspection => {
|
|
241
|
+
const existing = targetInspections.get(target.id);
|
|
242
|
+
if (existing) return existing;
|
|
184
243
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
244
|
+
const inspection = inspectQaTarget(target, deps);
|
|
245
|
+
targetInspections.set(target.id, inspection);
|
|
246
|
+
return inspection;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
let selectedTarget: WorkspaceTarget | null = null;
|
|
250
|
+
let selectedInspection: QaTargetInspection | null = null;
|
|
251
|
+
|
|
252
|
+
if (!ctx.hasUI && !requestedTarget && targets.length > 1) {
|
|
253
|
+
const runnableTargets = targets
|
|
254
|
+
.map((target) => ({ target, inspection: getTargetInspection(target) }))
|
|
255
|
+
.filter(({ inspection }) => inspection.isRunnableForPrefilter);
|
|
197
256
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
257
|
+
if (runnableTargets.length === 1) {
|
|
258
|
+
selectedTarget = runnableTargets[0]!.target;
|
|
259
|
+
selectedInspection = runnableTargets[0]!.inspection;
|
|
260
|
+
} else {
|
|
261
|
+
deps.notifyError(ctx, "QA target required", "Pass --target <package> when running /supi:qa outside interactive mode.");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!selectedTarget) {
|
|
267
|
+
selectedTarget = await deps.selectWorkspaceTarget(
|
|
268
|
+
ctx,
|
|
269
|
+
targets.map((target) => ({ target, changed: false, label: buildQaTargetOptionLabel({ target, changed: false }) })),
|
|
270
|
+
requestedTarget,
|
|
271
|
+
{
|
|
272
|
+
title: "QA target",
|
|
273
|
+
helpText: "Pick one app package to test. QA runs only within the selected target.",
|
|
274
|
+
},
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
if (requestedTarget && !selectedTarget) {
|
|
278
|
+
deps.notifyError(ctx, "QA target not found", requestedTarget);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (!selectedTarget) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
selectedInspection ??= getTargetInspection(selectedTarget);
|
|
286
|
+
|
|
287
|
+
const scriptsDir = getScriptsDir();
|
|
288
|
+
const targetDir = selectedTarget.packageDir;
|
|
289
|
+
const targetLabel = describeTarget(selectedTarget);
|
|
290
|
+
|
|
291
|
+
const {
|
|
292
|
+
detectedType,
|
|
293
|
+
detectedDevCommand,
|
|
294
|
+
detectedPort,
|
|
295
|
+
detectedIsLikelyApp,
|
|
296
|
+
preliminaryRoutes,
|
|
297
|
+
} = selectedInspection;
|
|
298
|
+
|
|
299
|
+
if (!detectedIsLikelyApp && preliminaryRoutes.length === 0) {
|
|
300
|
+
deps.notifyError(
|
|
301
|
+
ctx,
|
|
302
|
+
"Selected target is not a runnable app",
|
|
303
|
+
`${targetLabel} has no detectable app framework, routes, or dev/start script. Pick an app package instead.`,
|
|
304
|
+
);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let config = deps.loadE2eQaConfig(platform.paths, ctx.cwd, selectedTarget);
|
|
309
|
+
|
|
310
|
+
if (!config && ctx.hasUI) {
|
|
311
|
+
config = await runSetupWizard(ctx, detectedType, detectedDevCommand, detectedPort);
|
|
312
|
+
if (!config) return;
|
|
313
|
+
deps.saveE2eQaConfig(platform.paths, ctx.cwd, config, selectedTarget);
|
|
314
|
+
ctx.ui.notify(`E2E QA config saved for ${targetLabel}`, "info");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!config) {
|
|
318
|
+
config = {
|
|
319
|
+
...DEFAULT_E2E_QA_CONFIG,
|
|
320
|
+
app: {
|
|
321
|
+
type: (detectedType as AppType) || "generic",
|
|
322
|
+
devCommand: detectedDevCommand || "npm run dev",
|
|
323
|
+
port: detectedPort || 3000,
|
|
324
|
+
baseUrl: `http://localhost:${detectedPort || 3000}`,
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const activeSession = deps.findActiveSession(platform.paths, ctx.cwd, selectedTarget);
|
|
330
|
+
if (activeSession && activeSession.regressions.length > 0 && ctx.hasUI) {
|
|
331
|
+
const unresolvedRegressions = activeSession.regressions.filter((r: E2eRegression) => !r.resolution);
|
|
332
|
+
if (unresolvedRegressions.length > 0) {
|
|
333
|
+
for (const regression of unresolvedRegressions) {
|
|
334
|
+
const choice = await ctx.ui.select(
|
|
335
|
+
`Regression: ${regression.flowName}`,
|
|
336
|
+
[
|
|
337
|
+
"This is a bug — needs fixing",
|
|
338
|
+
"Behavior changed intentionally — update the test",
|
|
339
|
+
"Skip for now",
|
|
340
|
+
],
|
|
341
|
+
{ helpText: `Was passing, now fails: ${regression.error}` },
|
|
342
|
+
);
|
|
343
|
+
if (!choice) continue;
|
|
344
|
+
if (choice.startsWith("This is a bug")) regression.resolution = "bug";
|
|
345
|
+
else if (choice.startsWith("Behavior changed")) regression.resolution = "intentional-change";
|
|
346
|
+
else regression.resolution = "skipped";
|
|
213
347
|
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
214
350
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
351
|
+
let routes = preliminaryRoutes;
|
|
352
|
+
try {
|
|
353
|
+
if (config.app.type !== detectedType) {
|
|
354
|
+
routes = deps.discoverRoutes(targetDir, config.app.type);
|
|
355
|
+
}
|
|
356
|
+
} catch {
|
|
357
|
+
routes = [];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
let discoveredRoutes = "";
|
|
361
|
+
if (routes.length > 0) {
|
|
362
|
+
discoveredRoutes = routes.map((r) => JSON.stringify(r)).join("\n");
|
|
363
|
+
}
|
|
364
|
+
if (!discoveredRoutes) {
|
|
365
|
+
discoveredRoutes = '{"path": "/", "file": "unknown", "type": "page", "hasForm": false}';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const previousMatrix = deps.loadE2eMatrix(platform.paths, ctx.cwd, selectedTarget);
|
|
369
|
+
const matrixJson = previousMatrix ? JSON.stringify(previousMatrix, null, 2) : null;
|
|
370
|
+
|
|
371
|
+
const ledger = deps.createNewE2eSession(platform.paths, ctx.cwd, config, selectedTarget);
|
|
372
|
+
const sessionDir = deps.getSessionDir(platform.paths, ctx.cwd, ledger.id, selectedTarget);
|
|
373
|
+
|
|
374
|
+
let skillContent = "";
|
|
375
|
+
const skillPath = findSkillPath("qa-strategy");
|
|
376
|
+
if (skillPath) {
|
|
377
|
+
try {
|
|
378
|
+
skillContent = fs.readFileSync(skillPath, "utf-8");
|
|
379
|
+
} catch {
|
|
380
|
+
// proceed without skill content
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const routeCount = discoveredRoutes.split("\n").filter(Boolean).length;
|
|
385
|
+
|
|
386
|
+
const prompt = buildE2eOrchestratorPrompt({
|
|
387
|
+
cwd: targetDir,
|
|
388
|
+
appType: config.app,
|
|
389
|
+
sessionDir,
|
|
390
|
+
scriptsDir,
|
|
391
|
+
config,
|
|
392
|
+
discoveredRoutes,
|
|
393
|
+
previousMatrix: matrixJson,
|
|
394
|
+
skillContent,
|
|
395
|
+
dotDirDisplay: platform.paths.dotDirDisplay,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
platform.sendMessage(
|
|
399
|
+
{
|
|
400
|
+
customType: "supi-qa",
|
|
401
|
+
content: [{ type: "text", text: prompt }],
|
|
402
|
+
display: "none",
|
|
403
|
+
},
|
|
404
|
+
{ deliverAs: "steer", triggerTurn: true },
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
deps.notifyInfo(
|
|
408
|
+
ctx,
|
|
409
|
+
`E2E QA started: ${config.app.type}`,
|
|
410
|
+
`${routeCount} routes discovered | session ${ledger.id} | ${targetLabel}`,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function registerQaCommand(platform: Platform): void {
|
|
415
|
+
platform.registerCommand("supi:qa", {
|
|
416
|
+
description: "Run autonomous E2E product testing pipeline with playwright",
|
|
417
|
+
async handler(args: string | undefined, ctx: any) {
|
|
418
|
+
await handleQa(platform, ctx, args, QA_COMMAND_DEPENDENCIES);
|
|
244
419
|
},
|
|
245
420
|
});
|
|
246
421
|
}
|