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,565 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import type { ResolvedMempalaceConfig } from "./config.js";
|
|
6
|
+
import type { MempalaceAction, MempalaceParams } from "./schema.js";
|
|
7
|
+
|
|
8
|
+
export interface MempalaceRuntimeError {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
remediation?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type BridgePathResult =
|
|
16
|
+
| { ok: true; path: string }
|
|
17
|
+
| { ok: false; path: string; error: MempalaceRuntimeError };
|
|
18
|
+
|
|
19
|
+
export interface BridgePathOptions {
|
|
20
|
+
moduleUrl?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ProcessRunResult {
|
|
24
|
+
code: number;
|
|
25
|
+
stdout: string;
|
|
26
|
+
stderr: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type ProcessRunner = (
|
|
30
|
+
command: string,
|
|
31
|
+
args: string[],
|
|
32
|
+
options?: { cwd?: string; timeoutMs?: number; input?: string },
|
|
33
|
+
) => Promise<ProcessRunResult>;
|
|
34
|
+
|
|
35
|
+
export type MempalaceRuntimePlatform = "posix" | "win32";
|
|
36
|
+
|
|
37
|
+
export interface ManagedVenvPaths {
|
|
38
|
+
root: string;
|
|
39
|
+
python: string;
|
|
40
|
+
pip: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type DiscoverPythonResult =
|
|
44
|
+
| { ok: true; pythonPath: string; version: string }
|
|
45
|
+
| { ok: false; error: MempalaceRuntimeError };
|
|
46
|
+
|
|
47
|
+
export interface DiscoverPythonOptions {
|
|
48
|
+
configuredPython?: string | null;
|
|
49
|
+
candidates?: string[];
|
|
50
|
+
runner: ProcessRunner;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface MempalaceBridgeRequest {
|
|
54
|
+
action: string;
|
|
55
|
+
params: Record<string, unknown>;
|
|
56
|
+
options: Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type MempalaceBridgeJsonResponse =
|
|
60
|
+
| { ok: true; result?: unknown; diagnostics?: Record<string, unknown> }
|
|
61
|
+
| { ok: false; error: MempalaceRuntimeError; diagnostics?: Record<string, unknown> };
|
|
62
|
+
|
|
63
|
+
export type RunBridgeRequestResult =
|
|
64
|
+
| {
|
|
65
|
+
ok: true;
|
|
66
|
+
response: MempalaceBridgeJsonResponse;
|
|
67
|
+
stderr: string;
|
|
68
|
+
durationMs: number;
|
|
69
|
+
}
|
|
70
|
+
| {
|
|
71
|
+
ok: false;
|
|
72
|
+
error: MempalaceRuntimeError;
|
|
73
|
+
stdoutPreview: string;
|
|
74
|
+
stderrTail: string;
|
|
75
|
+
durationMs: number;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export interface RunBridgeRequestOptions {
|
|
79
|
+
pythonPath: string;
|
|
80
|
+
bridgeScriptPath: string;
|
|
81
|
+
request: MempalaceBridgeRequest;
|
|
82
|
+
timeoutMs: number;
|
|
83
|
+
runner?: ProcessRunner;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type SetupMempalaceRuntimeResult =
|
|
87
|
+
| {
|
|
88
|
+
ok: true;
|
|
89
|
+
details: {
|
|
90
|
+
uvPath: string;
|
|
91
|
+
uvVersion: string;
|
|
92
|
+
managedPython: string;
|
|
93
|
+
venvPath: string;
|
|
94
|
+
venvPython: string;
|
|
95
|
+
packageVersion: string;
|
|
96
|
+
version: unknown;
|
|
97
|
+
status: unknown;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
| {
|
|
101
|
+
ok: false;
|
|
102
|
+
error: MempalaceRuntimeError;
|
|
103
|
+
stderrTail?: string;
|
|
104
|
+
details?: Record<string, unknown>;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export interface SetupMempalaceRuntimeOptions {
|
|
108
|
+
cwd: string;
|
|
109
|
+
config: ResolvedMempalaceConfig;
|
|
110
|
+
bridgeScriptPath: string;
|
|
111
|
+
managedBinDir: string;
|
|
112
|
+
managedPythonVersion?: string;
|
|
113
|
+
runner?: ProcessRunner;
|
|
114
|
+
fetcher?: import("./uv.js").UvFetcher;
|
|
115
|
+
uvVersion?: string;
|
|
116
|
+
onProgress?: (message: string) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Filesystem side effects used to (re)create the managed venv. Tests stub
|
|
119
|
+
* these to keep the real `~/.omp/supipowers/mempalace-venv` untouched even
|
|
120
|
+
* when the runner is mocked. Defaults call `node:fs` directly.
|
|
121
|
+
*/
|
|
122
|
+
fs?: {
|
|
123
|
+
existsSync?: (path: string) => boolean;
|
|
124
|
+
rmSync?: (path: string, options?: { recursive?: boolean; force?: boolean }) => void;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
export function resolveBridgeScriptPath(options: BridgePathOptions = {}): BridgePathResult {
|
|
132
|
+
const moduleUrl = options.moduleUrl ?? import.meta.url;
|
|
133
|
+
const runtimePath = fileURLToPath(moduleUrl);
|
|
134
|
+
const bridgePath = path.join(path.dirname(runtimePath), "python", "mempalace_bridge.py");
|
|
135
|
+
|
|
136
|
+
if (!fs.existsSync(bridgePath)) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
path: bridgePath,
|
|
140
|
+
error: {
|
|
141
|
+
code: "bridge_not_found",
|
|
142
|
+
message: `Bundled MemPalace bridge not found at ${bridgePath}`,
|
|
143
|
+
remediation: "Reinstall supipowers or verify the package includes src/mempalace/python/mempalace_bridge.py.",
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { ok: true, path: bridgePath };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function resolveManagedVenvPaths(
|
|
152
|
+
venvPath: string,
|
|
153
|
+
platform: MempalaceRuntimePlatform = process.platform === "win32" ? "win32" : "posix",
|
|
154
|
+
): ManagedVenvPaths {
|
|
155
|
+
if (platform === "win32") {
|
|
156
|
+
return {
|
|
157
|
+
root: venvPath,
|
|
158
|
+
python: path.win32.join(venvPath, "Scripts", "python.exe"),
|
|
159
|
+
pip: path.win32.join(venvPath, "Scripts", "pip.exe"),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
root: venvPath,
|
|
165
|
+
python: path.join(venvPath, "bin", "python"),
|
|
166
|
+
pip: path.join(venvPath, "bin", "pip"),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function parsePythonVersion(output: string): string | null {
|
|
171
|
+
const match = /Python\s+(\d+)\.(\d+)\.(\d+)/.exec(output);
|
|
172
|
+
return match ? `${match[1]}.${match[2]}.${match[3]}` : null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function isSupportedPythonVersion(version: string): boolean {
|
|
176
|
+
const [majorRaw, minorRaw] = version.split(".");
|
|
177
|
+
const major = Number(majorRaw);
|
|
178
|
+
const minor = Number(minorRaw);
|
|
179
|
+
return major > 3 || (major === 3 && minor >= 9);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function unsupportedPython(version: string): DiscoverPythonResult {
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
error: {
|
|
186
|
+
code: "python_version_unsupported",
|
|
187
|
+
message: `MemPalace requires Python 3.9+, found Python ${version}.`,
|
|
188
|
+
remediation: "Install Python 3.9+ and configure mempalace.pythonPath or ensure python3 is on PATH.",
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function discoverPython(options: DiscoverPythonOptions): Promise<DiscoverPythonResult> {
|
|
194
|
+
const candidates = options.configuredPython
|
|
195
|
+
? [options.configuredPython]
|
|
196
|
+
: options.candidates ?? ["python3", "python"];
|
|
197
|
+
let unsupported: string | null = null;
|
|
198
|
+
|
|
199
|
+
for (const candidate of candidates) {
|
|
200
|
+
try {
|
|
201
|
+
const result = await options.runner(candidate, ["--version"]);
|
|
202
|
+
if (result.code !== 0) continue;
|
|
203
|
+
const version = parsePythonVersion(`${result.stdout}\n${result.stderr}`);
|
|
204
|
+
if (!version) continue;
|
|
205
|
+
if (isSupportedPythonVersion(version)) {
|
|
206
|
+
return { ok: true, pythonPath: candidate, version };
|
|
207
|
+
}
|
|
208
|
+
unsupported ??= version;
|
|
209
|
+
if (options.configuredPython) return unsupportedPython(version);
|
|
210
|
+
} catch {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (unsupported) return unsupportedPython(unsupported);
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
ok: false,
|
|
219
|
+
error: {
|
|
220
|
+
code: "python_missing",
|
|
221
|
+
message: "Unable to find a Python executable for MemPalace.",
|
|
222
|
+
remediation: "Install Python 3.9+ from python.org or your OS package manager, then run mempalace setup again.",
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function preview(value: string, maxChars = 1000): string {
|
|
228
|
+
return value.length <= maxChars ? value : `${value.slice(0, maxChars)}…`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function tail(value: string, maxChars = 4000): string {
|
|
232
|
+
return value.length <= maxChars ? value : `…${value.slice(-maxChars)}`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isBridgeResponse(value: unknown): value is MempalaceBridgeJsonResponse {
|
|
236
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
237
|
+
const record = value as Record<string, unknown>;
|
|
238
|
+
if (record.ok === true) return true;
|
|
239
|
+
if (record.ok !== false) return false;
|
|
240
|
+
const error = record.error;
|
|
241
|
+
return typeof error === "object" && error !== null && !Array.isArray(error)
|
|
242
|
+
&& typeof (error as Record<string, unknown>).code === "string"
|
|
243
|
+
&& typeof (error as Record<string, unknown>).message === "string";
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function defaultProcessRunner(
|
|
247
|
+
command: string,
|
|
248
|
+
args: string[],
|
|
249
|
+
options: { cwd?: string; timeoutMs?: number; input?: string } = {},
|
|
250
|
+
): Promise<ProcessRunResult> {
|
|
251
|
+
return await new Promise<ProcessRunResult>((resolve, reject) => {
|
|
252
|
+
const child = spawn(command, args, {
|
|
253
|
+
cwd: options.cwd,
|
|
254
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
255
|
+
windowsHide: true,
|
|
256
|
+
});
|
|
257
|
+
let stdout = "";
|
|
258
|
+
let stderr = "";
|
|
259
|
+
let settled = false;
|
|
260
|
+
const timeout = options.timeoutMs
|
|
261
|
+
? setTimeout(() => {
|
|
262
|
+
child.kill("SIGKILL");
|
|
263
|
+
}, options.timeoutMs)
|
|
264
|
+
: null;
|
|
265
|
+
|
|
266
|
+
child.stdout.setEncoding("utf8");
|
|
267
|
+
child.stderr.setEncoding("utf8");
|
|
268
|
+
child.stdout.on("data", (chunk) => { stdout += chunk; });
|
|
269
|
+
child.stderr.on("data", (chunk) => { stderr += chunk; });
|
|
270
|
+
child.on("error", (error) => {
|
|
271
|
+
if (timeout) clearTimeout(timeout);
|
|
272
|
+
if (!settled) {
|
|
273
|
+
settled = true;
|
|
274
|
+
reject(error);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
child.on("close", (code) => {
|
|
278
|
+
if (timeout) clearTimeout(timeout);
|
|
279
|
+
if (!settled) {
|
|
280
|
+
settled = true;
|
|
281
|
+
resolve({ code: code ?? -1, stdout, stderr });
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
if (options.input !== undefined) {
|
|
286
|
+
child.stdin.end(options.input);
|
|
287
|
+
} else {
|
|
288
|
+
child.stdin.end();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export async function runBridgeRequest(options: RunBridgeRequestOptions): Promise<RunBridgeRequestResult> {
|
|
294
|
+
const started = Date.now();
|
|
295
|
+
const input = JSON.stringify(options.request);
|
|
296
|
+
const runner = options.runner ?? defaultProcessRunner;
|
|
297
|
+
|
|
298
|
+
const timeout = new Promise<ProcessRunResult>((resolve) => {
|
|
299
|
+
setTimeout(() => resolve({
|
|
300
|
+
code: -1,
|
|
301
|
+
stdout: "",
|
|
302
|
+
stderr: "",
|
|
303
|
+
}), options.timeoutMs);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
let runResult: ProcessRunResult;
|
|
307
|
+
try {
|
|
308
|
+
runResult = await Promise.race([
|
|
309
|
+
runner(options.pythonPath, [options.bridgeScriptPath], { input, timeoutMs: options.timeoutMs }),
|
|
310
|
+
timeout,
|
|
311
|
+
]);
|
|
312
|
+
} catch (error) {
|
|
313
|
+
return {
|
|
314
|
+
ok: false,
|
|
315
|
+
error: {
|
|
316
|
+
code: "bridge_process_failed",
|
|
317
|
+
message: error instanceof Error ? error.message : "Failed to launch MemPalace bridge.",
|
|
318
|
+
remediation: "Run mempalace setup and verify the managed Python environment is usable.",
|
|
319
|
+
},
|
|
320
|
+
stdoutPreview: "",
|
|
321
|
+
stderrTail: "",
|
|
322
|
+
durationMs: Date.now() - started,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const durationMs = Date.now() - started;
|
|
327
|
+
if (runResult.code === -1 && runResult.stdout.length === 0 && runResult.stderr.length === 0 && durationMs >= options.timeoutMs) {
|
|
328
|
+
return {
|
|
329
|
+
ok: false,
|
|
330
|
+
error: {
|
|
331
|
+
code: "bridge_timeout",
|
|
332
|
+
message: `MemPalace bridge timed out after ${options.timeoutMs}ms.`,
|
|
333
|
+
remediation: "Retry with a narrower request or run mempalace(action=\"repair\") if the palace appears stuck.",
|
|
334
|
+
},
|
|
335
|
+
stdoutPreview: "",
|
|
336
|
+
stderrTail: "",
|
|
337
|
+
durationMs,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (runResult.code !== 0) {
|
|
342
|
+
return {
|
|
343
|
+
ok: false,
|
|
344
|
+
error: {
|
|
345
|
+
code: "bridge_process_failed",
|
|
346
|
+
message: `MemPalace bridge exited with code ${runResult.code}.`,
|
|
347
|
+
remediation: "Run mempalace(action=\"setup\") to verify the managed Python environment.",
|
|
348
|
+
},
|
|
349
|
+
stdoutPreview: preview(runResult.stdout),
|
|
350
|
+
stderrTail: tail(runResult.stderr),
|
|
351
|
+
durationMs,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let parsed: unknown;
|
|
356
|
+
try {
|
|
357
|
+
parsed = JSON.parse(runResult.stdout.trim());
|
|
358
|
+
} catch {
|
|
359
|
+
return {
|
|
360
|
+
ok: false,
|
|
361
|
+
error: {
|
|
362
|
+
code: "bridge_protocol_error",
|
|
363
|
+
message: "MemPalace bridge returned malformed JSON on stdout.",
|
|
364
|
+
remediation: "Run mempalace(action=\"setup\") to verify the bundled bridge and package version.",
|
|
365
|
+
},
|
|
366
|
+
stdoutPreview: preview(runResult.stdout),
|
|
367
|
+
stderrTail: tail(runResult.stderr),
|
|
368
|
+
durationMs,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!isBridgeResponse(parsed)) {
|
|
373
|
+
return {
|
|
374
|
+
ok: false,
|
|
375
|
+
error: {
|
|
376
|
+
code: "bridge_protocol_error",
|
|
377
|
+
message: "MemPalace bridge JSON did not match the expected response protocol.",
|
|
378
|
+
remediation: "Run mempalace(action=\"setup\") to verify the bundled bridge and package version.",
|
|
379
|
+
},
|
|
380
|
+
stdoutPreview: preview(runResult.stdout),
|
|
381
|
+
stderrTail: tail(runResult.stderr),
|
|
382
|
+
durationMs,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
ok: true,
|
|
388
|
+
response: parsed,
|
|
389
|
+
stderr: runResult.stderr,
|
|
390
|
+
durationMs,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const SETUP_REMEDIATION = "Run `/supi:memory setup` again, or check the displayed stderr for upstream details. The official MemPalace package is on PyPI as `mempalace`; uv (from astral-sh/uv on GitHub) is used solely to provision Python.";
|
|
395
|
+
|
|
396
|
+
function setupFailed(message: string, stderrTail?: string): SetupMempalaceRuntimeResult {
|
|
397
|
+
const fullMessage = stderrTail
|
|
398
|
+
? `${message}\n\n${stderrTail}`
|
|
399
|
+
: message;
|
|
400
|
+
return {
|
|
401
|
+
ok: false,
|
|
402
|
+
error: {
|
|
403
|
+
code: "setup_failed",
|
|
404
|
+
message: fullMessage,
|
|
405
|
+
remediation: SETUP_REMEDIATION,
|
|
406
|
+
},
|
|
407
|
+
stderrTail,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async function runSetupCommand(
|
|
412
|
+
runner: ProcessRunner,
|
|
413
|
+
command: string,
|
|
414
|
+
args: string[],
|
|
415
|
+
timeoutMs: number,
|
|
416
|
+
): Promise<ProcessRunResult> {
|
|
417
|
+
return await runner(command, args, { timeoutMs });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export async function setupMempalaceRuntime(
|
|
421
|
+
options: SetupMempalaceRuntimeOptions,
|
|
422
|
+
): Promise<SetupMempalaceRuntimeResult> {
|
|
423
|
+
const progress = (message: string) => options.onProgress?.(message);
|
|
424
|
+
const setupTimeout = options.config.timeouts.setupMs;
|
|
425
|
+
const packageSpec = `mempalace==${options.config.packageVersion}`;
|
|
426
|
+
const managedPythonVersion = options.managedPythonVersion ?? "3.12";
|
|
427
|
+
const runner = options.runner ?? defaultProcessRunner;
|
|
428
|
+
|
|
429
|
+
// 1. Ensure uv is available (download + verify if needed).
|
|
430
|
+
const { ensureUv } = await import("./uv.js");
|
|
431
|
+
const uv = await ensureUv({
|
|
432
|
+
managedBinDir: options.managedBinDir,
|
|
433
|
+
runner,
|
|
434
|
+
fetcher: options.fetcher,
|
|
435
|
+
version: options.uvVersion,
|
|
436
|
+
onProgress: progress,
|
|
437
|
+
});
|
|
438
|
+
if (!uv.ok) return { ok: false, error: uv.error };
|
|
439
|
+
|
|
440
|
+
// 2. Have uv install the managed Python interpreter (no-op if already installed).
|
|
441
|
+
progress(`Provisioning managed Python ${managedPythonVersion} via uv`);
|
|
442
|
+
const pythonInstall = await runSetupCommand(
|
|
443
|
+
runner,
|
|
444
|
+
uv.uvPath,
|
|
445
|
+
["python", "install", managedPythonVersion],
|
|
446
|
+
setupTimeout,
|
|
447
|
+
);
|
|
448
|
+
if (pythonInstall.code !== 0) {
|
|
449
|
+
return setupFailed(
|
|
450
|
+
`uv failed to install Python ${managedPythonVersion}.`,
|
|
451
|
+
tail(pythonInstall.stderr || pythonInstall.stdout),
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// 3. Create (or recreate) the managed virtual environment.
|
|
456
|
+
const fsImpl = {
|
|
457
|
+
existsSync: options.fs?.existsSync ?? fs.existsSync,
|
|
458
|
+
rmSync: options.fs?.rmSync ?? fs.rmSync,
|
|
459
|
+
};
|
|
460
|
+
if (fsImpl.existsSync(options.config.managedVenvPath)) {
|
|
461
|
+
fsImpl.rmSync(options.config.managedVenvPath, { recursive: true, force: true });
|
|
462
|
+
}
|
|
463
|
+
progress("Creating managed MemPalace virtual environment");
|
|
464
|
+
const createVenv = await runSetupCommand(
|
|
465
|
+
runner,
|
|
466
|
+
uv.uvPath,
|
|
467
|
+
["venv", options.config.managedVenvPath, "--python", managedPythonVersion],
|
|
468
|
+
setupTimeout,
|
|
469
|
+
);
|
|
470
|
+
if (createVenv.code !== 0) {
|
|
471
|
+
return setupFailed(
|
|
472
|
+
"Failed to create the managed MemPalace virtual environment.",
|
|
473
|
+
tail(createVenv.stderr || createVenv.stdout),
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const venv = resolveManagedVenvPaths(options.config.managedVenvPath);
|
|
478
|
+
|
|
479
|
+
// 4. Install MemPalace from PyPI into the managed venv.
|
|
480
|
+
progress(`Installing ${packageSpec} from PyPI`);
|
|
481
|
+
const installPackage = await runSetupCommand(
|
|
482
|
+
runner,
|
|
483
|
+
uv.uvPath,
|
|
484
|
+
["pip", "install", "--python", venv.python, packageSpec],
|
|
485
|
+
setupTimeout,
|
|
486
|
+
);
|
|
487
|
+
if (installPackage.code !== 0) {
|
|
488
|
+
return setupFailed(
|
|
489
|
+
`Failed to install ${packageSpec} from PyPI.`,
|
|
490
|
+
tail(installPackage.stderr || installPackage.stdout),
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// 5. Verify the bridge can import MemPalace and inspect the palace.
|
|
495
|
+
progress("Verifying MemPalace bridge");
|
|
496
|
+
const version = await runBridgeRequest({
|
|
497
|
+
pythonPath: venv.python,
|
|
498
|
+
bridgeScriptPath: options.bridgeScriptPath,
|
|
499
|
+
timeoutMs: options.config.timeouts.bridgeMs,
|
|
500
|
+
request: {
|
|
501
|
+
action: "version",
|
|
502
|
+
params: {},
|
|
503
|
+
options: {
|
|
504
|
+
cwd: options.cwd,
|
|
505
|
+
palacePath: options.config.palacePath,
|
|
506
|
+
agentName: options.config.defaultAgentName,
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
runner,
|
|
510
|
+
});
|
|
511
|
+
if (!version.ok) return { ok: false, error: version.error, stderrTail: version.stderrTail };
|
|
512
|
+
|
|
513
|
+
progress("Checking MemPalace palace status");
|
|
514
|
+
const status = await runBridgeRequest({
|
|
515
|
+
pythonPath: venv.python,
|
|
516
|
+
bridgeScriptPath: options.bridgeScriptPath,
|
|
517
|
+
timeoutMs: options.config.timeouts.bridgeMs,
|
|
518
|
+
request: {
|
|
519
|
+
action: "status",
|
|
520
|
+
params: {},
|
|
521
|
+
options: {
|
|
522
|
+
cwd: options.cwd,
|
|
523
|
+
palacePath: options.config.palacePath,
|
|
524
|
+
agentName: options.config.defaultAgentName,
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
runner,
|
|
528
|
+
});
|
|
529
|
+
if (!status.ok) return { ok: false, error: status.error, stderrTail: status.stderrTail };
|
|
530
|
+
|
|
531
|
+
return {
|
|
532
|
+
ok: true,
|
|
533
|
+
details: {
|
|
534
|
+
uvPath: uv.uvPath,
|
|
535
|
+
uvVersion: uv.version,
|
|
536
|
+
managedPython: managedPythonVersion,
|
|
537
|
+
venvPath: venv.root,
|
|
538
|
+
venvPython: venv.python,
|
|
539
|
+
packageVersion: options.config.packageVersion,
|
|
540
|
+
version: version.response.ok ? version.response.result : version.response.error,
|
|
541
|
+
status: status.response.ok ? status.response.result : status.response.error,
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export function buildMempalaceCliArgs(
|
|
547
|
+
action: Extract<MempalaceAction, "init" | "mine" | "split" | "repair">,
|
|
548
|
+
params: Partial<MempalaceParams>,
|
|
549
|
+
): string[] {
|
|
550
|
+
const args: string[] = [action];
|
|
551
|
+
if (action === "split") {
|
|
552
|
+
if (params.source_file) args.push(params.source_file);
|
|
553
|
+
} else if (params.dir) {
|
|
554
|
+
args.push(params.dir);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (typeof params.limit === "number") args.push("--limit", String(params.limit));
|
|
558
|
+
if (params.mode) args.push("--mode", params.mode);
|
|
559
|
+
if (params.extract) args.push("--extract");
|
|
560
|
+
if (params.dry_run) args.push("--dry-run");
|
|
561
|
+
if (params.include_ignored) args.push("--include-ignored");
|
|
562
|
+
if (params.no_gitignore) args.push("--no-gitignore");
|
|
563
|
+
if (params.yes) args.push("--yes");
|
|
564
|
+
return args;
|
|
565
|
+
}
|