@rosenfan/matrix 0.1.2 → 0.1.4
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/.claude/skills/matrix/SKILL.md +59 -62
- package/.claude/skills/matrix/scripts/matrix_claude.py +11 -11
- package/.claude/skills/matrix/scripts/matrix_state.py +53 -53
- package/.claude/skills/matrix-archive/SKILL.md +36 -33
- package/.claude/skills/matrix-build/SKILL.md +28 -23
- package/.claude/skills/matrix-claude/SKILL.md +13 -11
- package/.claude/skills/matrix-design/SKILL.md +32 -26
- package/.claude/skills/matrix-hotfix/SKILL.md +1 -1
- package/.claude/skills/matrix-open/SKILL.md +27 -15
- package/.claude/skills/matrix-status/SKILL.md +5 -5
- package/.claude/skills/matrix-tweak/SKILL.md +1 -1
- package/.claude/skills/matrix-verify/SKILL.md +35 -17
- package/README.md +131 -96
- package/README.zh-CN.md +127 -92
- package/assets/skills-zh-CN/matrix/SKILL.md +75 -72
- package/assets/skills-zh-CN/matrix-archive/SKILL.md +36 -33
- package/assets/skills-zh-CN/matrix-build/SKILL.md +41 -37
- package/assets/skills-zh-CN/matrix-claude/SKILL.md +33 -31
- package/assets/skills-zh-CN/matrix-design/SKILL.md +13 -7
- package/assets/skills-zh-CN/matrix-hotfix/SKILL.md +1 -1
- package/assets/skills-zh-CN/matrix-open/SKILL.md +18 -6
- package/assets/skills-zh-CN/matrix-status/SKILL.md +5 -5
- package/assets/skills-zh-CN/matrix-tweak/SKILL.md +1 -1
- package/assets/skills-zh-CN/matrix-verify/SKILL.md +27 -9
- package/package.json +2 -2
- package/src/catalog.js +29 -18
- package/src/cli.js +150 -39
- package/src/distribution.js +268 -114
- package/src/installer.js +10 -10
- package/src/matt-catalog.mjs +67 -0
- package/src/matt.js +115 -33
- package/src/messages.js +18 -14
- package/src/runtime-resolver.js +76 -0
- package/src/self-update.js +81 -0
- package/src/ui.js +1 -1
- package/src/workflow-transaction.js +622 -618
- package/src/workflow.js +949 -464
package/src/cli.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { PLATFORMS } from "./catalog.js";
|
|
5
|
-
import { createDistribution } from "./distribution.js";
|
|
5
|
+
import { PLATFORMS } from "./catalog.js";
|
|
6
|
+
import { createDistribution, installedIntent } from "./distribution.js";
|
|
7
|
+
import { createMattAdapter, inspectMattInstallation } from "./matt.js";
|
|
6
8
|
import { text } from "./messages.js";
|
|
7
9
|
import { createUi } from "./ui.js";
|
|
8
10
|
import { invoke } from "./workflow.js";
|
|
11
|
+
import { compareVersions, globalBinPath, latestVersion, selfUpdate } from "./self-update.js";
|
|
12
|
+
import { resolveProjectRuntime } from "./runtime-resolver.js";
|
|
13
|
+
import { MATT_COMPATIBILITY } from "./matt-catalog.mjs";
|
|
9
14
|
|
|
10
15
|
const packagePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
11
|
-
const version = JSON.parse(fs.readFileSync(packagePath, "utf8")).version;
|
|
12
|
-
const HELP = `Matrix ${version}\n\nUsage: matrix init [directory] [options]\n matrix doctor [directory] [options]\n\nOptions:\n --language <en|zh-CN>\n --scope <project|global>\n --platform <claude-code|codex> (repeatable)\n --mode <copy|symlink>\n --with-mattpocock | --without-mattpocock\n --default-orchestration <prim|arch>\n --force --yes, -y --dry-run --json --no-color`;
|
|
16
|
+
const version = JSON.parse(fs.readFileSync(packagePath, "utf8")).version;
|
|
17
|
+
const HELP = `Matrix ${version}\n\nUsage: matrix init [directory] [options]\n matrix update [directory] [options]\n matrix doctor [directory] [options]\n\nOptions:\n --language <en|zh-CN>\n --scope <project|global>\n --platform <claude-code|codex> (repeatable)\n --mode <copy|symlink>\n --with-mattpocock | --without-mattpocock\n --force-matt\n --default-orchestration <prim|arch>\n --skip-self-update --force --yes, -y --dry-run --json --no-color`;
|
|
13
18
|
|
|
14
|
-
function parse(argv) {
|
|
15
|
-
const result = { command: null, directory: null, scope: null, language: null, platforms: [], mode: "copy", matt: null, defaultOrchestration: null, matrixPolicy: "safe", yes: false, dryRun: false, json: false, color: true };
|
|
19
|
+
function parse(argv) {
|
|
20
|
+
const result = { command: null, directory: null, scope: null, language: null, platforms: [], mode: "copy", matt: null, mattPolicy: "preserve", defaultOrchestration: null, matrixPolicy: "safe", yes: false, dryRun: false, json: false, color: true, skipSelfUpdate: false, reexec: false };
|
|
16
21
|
const values = [...argv];
|
|
17
22
|
if (values[0] && !values[0].startsWith("-")) result.command = values.shift();
|
|
18
23
|
while (values.length) {
|
|
@@ -24,10 +29,13 @@ function parse(argv) {
|
|
|
24
29
|
else if (token === "--mode") result.mode = values.shift();
|
|
25
30
|
else if (token === "--with-mattpocock") result.matt = "missing";
|
|
26
31
|
else if (token === "--without-mattpocock") result.matt = "none";
|
|
27
|
-
else if (token === "--
|
|
32
|
+
else if (token === "--force-matt") result.mattPolicy = "replace";
|
|
33
|
+
else if (token === "--default-orchestration") result.defaultOrchestration = values.shift();
|
|
28
34
|
else if (token === "--force") result.matrixPolicy = "replace";
|
|
29
35
|
else if (["--yes", "-y"].includes(token)) result.yes = true;
|
|
30
36
|
else if (token === "--dry-run") result.dryRun = true;
|
|
37
|
+
else if (token === "--skip-self-update") result.skipSelfUpdate = true;
|
|
38
|
+
else if (token === "--_reexec") result.reexec = true;
|
|
31
39
|
else if (token === "--json") result.json = true;
|
|
32
40
|
else if (token === "--no-color") result.color = false;
|
|
33
41
|
else if (["--help", "-h"].includes(token)) result.help = true;
|
|
@@ -45,8 +53,8 @@ function projectRoot(directory) {
|
|
|
45
53
|
|
|
46
54
|
function labelsFor(language) { return { yes: text(language, "yes"), no: text(language, "no") }; }
|
|
47
55
|
|
|
48
|
-
function localizedState(language, state) {
|
|
49
|
-
return text(language, ({ missing: "stateMissing", matching: "stateMatching", complete: "stateComplete", "user-modified": "stateUserModified", partial: "statePartial", damaged: "statePartial", newer: "stateMatching", "outdated-unchanged": "stateOutdated" })[state] ?? state);
|
|
56
|
+
function localizedState(language, state) {
|
|
57
|
+
return text(language, ({ missing: "stateMissing", matching: "stateMatching", complete: "stateComplete", "user-modified": "stateUserModified", partial: "statePartial", damaged: "statePartial", newer: "stateMatching", "outdated-unchanged": "stateOutdated", "safe-update": "stateSafeUpdate", adoptable: "stateAdoptable", unreadable: "stateUnreadable", compatible: "stateCompatible", "update-required": "stateUpdateRequired", "unsupported-newer": "stateUnsupportedNewer", unverified: "stateUnverified", unknown: "stateUnknown", incomplete: "statePartial" })[state] ?? state);
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
function localizedAction(language, action) {
|
|
@@ -58,57 +66,159 @@ async function intentFrom(options, ui) {
|
|
|
58
66
|
const language = options.language ?? (options.yes ? "en" : await ui.select("Language / 语言", [{ label: "English", value: "en" }, { label: "中文", value: "zh-CN" }]));
|
|
59
67
|
const scope = options.scope ?? (options.yes ? "project" : await ui.select(text(language, "scopeQuestion"), [{ label: text(language, "project"), value: "project" }, { label: text(language, "global"), value: "global" }]));
|
|
60
68
|
let platforms = options.platforms;
|
|
61
|
-
if (!platforms.length && interactive && !options.yes) platforms = await ui.selectMany(text(language, "platformsQuestion"), [{ label: "Claude Code", value: "claude-code" }, { label: "Codex", value: "codex" }]);
|
|
62
|
-
const matt = options.matt ?? (interactive && !options.yes ? (await ui.confirm(text(language, "mattQuestion"), true, labelsFor(language)) ? "missing" : "none") : "missing");
|
|
63
|
-
const defaultOrchestration = options.defaultOrchestration ?? (interactive && !options.yes && matt === "missing"
|
|
64
|
-
? await ui.select(text(language, "orchestrationQuestion"), [{ label: "Arch", value: "arch" }, { label: "Prim", value: "prim" }])
|
|
65
|
-
: null);
|
|
66
|
-
return { projectRoot: projectRoot(options.directory), language, scope, platforms, mode: options.mode, matt, defaultOrchestration, nonInteractive: options.yes || !interactive, matrixPolicy: options.matrixPolicy, dryRun: options.dryRun };
|
|
69
|
+
if (!platforms.length && interactive && !options.yes) platforms = await ui.selectMany(text(language, "platformsQuestion"), [{ label: "Claude Code", value: "claude-code" }, { label: "Codex", value: "codex" }]);
|
|
70
|
+
const matt = options.matt ?? (interactive && !options.yes ? (await ui.confirm(text(language, "mattQuestion"), true, labelsFor(language)) ? "missing" : "none") : "missing");
|
|
71
|
+
const defaultOrchestration = options.defaultOrchestration ?? (interactive && !options.yes && matt === "missing"
|
|
72
|
+
? await ui.select(text(language, "orchestrationQuestion"), [{ label: "Arch", value: "arch" }, { label: "Prim", value: "prim" }])
|
|
73
|
+
: null);
|
|
74
|
+
return { projectRoot: projectRoot(options.directory), language, scope, platforms, mode: options.mode, matt, mattPolicy: options.mattPolicy, defaultOrchestration, nonInteractive: options.yes || !interactive, matrixPolicy: options.matrixPolicy, dryRun: options.dryRun };
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
function render(ui, evaluation) {
|
|
70
78
|
const language = evaluation.intent?.language ?? "en";
|
|
71
|
-
const actions = (evaluation.actions ?? []).map((item) => `${item.platform}: ${localizedAction(language, item.matrix)}`).join(", ");
|
|
72
|
-
ui.info(actions ? `${text(language, "preview")}: ${actions}` : evaluation.code);
|
|
73
|
-
if (evaluation.intent?.defaultOrchestration) ui.muted(
|
|
74
|
-
for (const item of evaluation.observations ?? [])
|
|
79
|
+
const actions = (evaluation.actions ?? []).map((item) => `${item.platform}: ${localizedAction(language, item.matrix)}`).join(", ");
|
|
80
|
+
ui.info(actions ? `${text(language, "preview")}: ${actions}` : evaluation.code);
|
|
81
|
+
if (evaluation.intent?.defaultOrchestration) ui.muted(`${text(language, "defaultOrchestration")}: ${evaluation.intent.defaultOrchestration}`);
|
|
82
|
+
for (const item of evaluation.observations ?? []) {
|
|
83
|
+
const mattStates = Object.entries(item.matt.classificationCounts ?? {}).map(([state, count]) => `${localizedState(language, state)}=${count}`).join(", ");
|
|
84
|
+
ui.muted(`${item.name}: ${text(language, "matrix")} ${localizedState(language, item.matrix)};${text(language, "matt")} ${localizedState(language, item.matt.state)}${mattStates ? ` (${mattStates})` : ""}`);
|
|
85
|
+
}
|
|
75
86
|
for (const item of evaluation.diagnostics ?? []) ui.warn(item.code === "USER_MODIFIED_BLOCKED" ? text(language, "replaceQuestion") : item.message ?? item.code);
|
|
76
|
-
for (const item of evaluation.diagnosis ?? []) (item.code === "
|
|
87
|
+
for (const item of evaluation.diagnosis ?? []) (item.code === "MATT_GLOBAL_IGNORED" ? ui.muted : ui.warn)(item.message ?? item.code);
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
async function init(options) {
|
|
80
91
|
const ui = createUi({ color: options.color && !options.json });
|
|
81
92
|
if (!options.json) await ui.banner();
|
|
82
93
|
const intent = await intentFrom(options, ui);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
return refresh(intent, options, ui);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function refresh(intent, options, ui) {
|
|
98
|
+
const distribution = createDistribution({ mattAdapter: createMattAdapter({ stdio: options.json ? "pipe" : "inherit" }) });
|
|
99
|
+
let evaluation = distribution.evaluate(intent);
|
|
100
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY && !options.json);
|
|
101
|
+
let reevaluated = false;
|
|
102
|
+
if (!options.json) render(ui, evaluation);
|
|
103
|
+
if (!evaluation.ok && evaluation.code === "USER_MODIFIED_BLOCKED" && interactive && !options.yes && await ui.confirm(text(intent.language, "replaceQuestion"), false, labelsFor(intent.language))) {
|
|
104
|
+
evaluation = distribution.evaluate({ ...intent, matrixPolicy: "replace" }); reevaluated = true;
|
|
105
|
+
}
|
|
106
|
+
if (!evaluation.ok && evaluation.code === "MATT_USER_MODIFIED" && interactive && !options.yes
|
|
107
|
+
&& await ui.confirm(text(intent.language, "mattReplaceQuestion"), false, labelsFor(intent.language))) {
|
|
108
|
+
evaluation = distribution.evaluate({ ...intent, mattPolicy: "replace" }); reevaluated = true;
|
|
109
|
+
}
|
|
110
|
+
if (options.json) {
|
|
111
|
+
if (!evaluation.ok || options.dryRun) {
|
|
112
|
+
const output = options.updateMode ? { ...evaluation, matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms }) } : evaluation;
|
|
113
|
+
console.log(JSON.stringify(output)); return evaluation.ok ? 0 : 2;
|
|
114
|
+
}
|
|
115
|
+
const result = distribution.commit(evaluation.plan);
|
|
116
|
+
const output = { ...evaluation, ...result, intent: evaluation.intent, observations: evaluation.observations, actions: evaluation.actions,
|
|
117
|
+
...(options.updateMode ? { matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms }) } : {}) };
|
|
118
|
+
console.log(JSON.stringify(output));
|
|
119
|
+
return !result.ok ? 2 : result.code === "PARTIAL" ? 1 : 0;
|
|
120
|
+
}
|
|
121
|
+
if (reevaluated) render(ui, evaluation);
|
|
89
122
|
if (!evaluation.ok) return 2;
|
|
90
123
|
if (!options.yes && interactive && !options.dryRun && !await ui.confirm(text(intent.language, "confirm"), true, labelsFor(intent.language))) return 0;
|
|
91
|
-
const result = distribution.commit(evaluation.plan);
|
|
124
|
+
const result = distribution.commit(evaluation.plan);
|
|
92
125
|
if (!result.ok) { ui.warn(result.error ?? result.code); return 2; }
|
|
93
126
|
if (result.code === "PARTIAL") { ui.warn(result.recovery); return 1; }
|
|
94
|
-
ui.success(options.dryRun ? text(intent.language, "dryRunComplete") : text(intent.language, "ready"));
|
|
127
|
+
ui.success(options.dryRun ? text(intent.language, "dryRunComplete") : text(intent.language, "ready"));
|
|
128
|
+
if (!options.updateMode && intent.matt === "missing" && !options.dryRun) ui.muted(text(intent.language, "mattSetupHint").replace("{release}", MATT_COMPATIBILITY.release));
|
|
129
|
+
if (options.updateMode) {
|
|
130
|
+
const matt = inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms });
|
|
131
|
+
ui.muted(`${text(intent.language, "mattCompatibilityStatus").replace("{release}", matt.supported.release).replace("{status}", localizedState(intent.language, matt.status))}${matt.action ? `; ${matt.action}` : ""}`);
|
|
132
|
+
}
|
|
95
133
|
ui.muted(evaluation.intent.platforms.map((id) => `${PLATFORMS[id].name}: $matrix <request>`).join("\n"));
|
|
96
134
|
return 0;
|
|
97
135
|
}
|
|
98
136
|
|
|
99
|
-
async function
|
|
137
|
+
async function update(options) {
|
|
100
138
|
const ui = createUi({ color: options.color && !options.json });
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
const root = projectRoot(options.directory);
|
|
140
|
+
const installed = installedIntent({ projectRoot: root });
|
|
141
|
+
if (!installed.ok) {
|
|
142
|
+
const result = { ok: false, code: installed.code, message: "No trusted Matrix installation manifest was found. Run matrix init first." };
|
|
143
|
+
if (options.json) console.log(JSON.stringify(result)); else ui.warn(result.message);
|
|
144
|
+
return 2;
|
|
145
|
+
}
|
|
146
|
+
const forbidden = options.language || options.scope || options.platforms.length || options.matt || options.mattPolicy === "replace" || options.defaultOrchestration || options.mode !== "copy";
|
|
147
|
+
if (forbidden) throw new Error("matrix update inherits installation settings. Use matrix init to change language, scope, platform, mode, Matt skills, or orchestration.");
|
|
148
|
+
const intent = { ...installed.intent, dryRun: options.dryRun };
|
|
149
|
+
let npm = { status: "skipped", current: version, target: version, reason: options.skipSelfUpdate ? "disabled by --skip-self-update" : null };
|
|
150
|
+
if (!options.skipSelfUpdate && !options.reexec) {
|
|
151
|
+
try {
|
|
152
|
+
const target = await latestVersion(); const comparison = compareVersions(target, version);
|
|
153
|
+
if (comparison === null) throw new Error("unable to compare registry version");
|
|
154
|
+
npm = comparison > 0 ? { status: "available", current: version, target } : { status: "skipped", current: version, target, reason: comparison === 0 ? "already latest" : "registry version is older" };
|
|
155
|
+
} catch (error) {
|
|
156
|
+
const result = { ok: false, code: "SELF_UPDATE_CHECK_FAILED", npm: { status: "failed", current: version, reason: error.message }, recovery_command: "matrix update --skip-self-update" };
|
|
157
|
+
if (options.json) console.log(JSON.stringify(result)); else ui.warn(`${result.code}: ${error.message}\nRun ${result.recovery_command} to refresh assets without npm.`);
|
|
158
|
+
return 2;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (options.json && options.dryRun) { console.log(JSON.stringify({ ok: true, code: "DRY_RUN", npm, intent, matt: inspectMattInstallation({ projectRoot: root, home: intent.home, platforms: intent.platforms }) })); return 0; }
|
|
162
|
+
if (!options.json) {
|
|
163
|
+
await ui.banner(); ui.info(`Matrix update: CLI ${npm.current}${npm.status === "available" ? ` → ${npm.target}` : ""}`);
|
|
164
|
+
ui.muted(`Assets: ${intent.scope}, ${intent.language}, ${intent.platforms.join(", ")}`);
|
|
165
|
+
}
|
|
166
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY && !options.json);
|
|
167
|
+
if (npm.status === "available") {
|
|
168
|
+
if (!options.yes && interactive && !await ui.confirm(`Upgrade Matrix CLI ${npm.current} → ${npm.target} and then refresh these assets?`, true, labelsFor(intent.language))) return 0;
|
|
169
|
+
if (options.dryRun) { if (options.json) console.log(JSON.stringify({ ok: true, code: "DRY_RUN", npm, intent, matt: inspectMattInstallation({ projectRoot: root, home: intent.home, platforms: intent.platforms }) })); else ui.success(text(intent.language, "dryRunComplete")); return 0; }
|
|
170
|
+
const updated = selfUpdate(version, npm.target);
|
|
171
|
+
if (!updated.ok) { const result = { ok: false, code: "SELF_UPDATE_FAILED", npm: { ...npm, status: "failed", reason: updated.reason }, recovery_command: "matrix update --skip-self-update" }; if (options.json) console.log(JSON.stringify(result)); else ui.warn(`${result.code}: ${updated.reason}`); return 2; }
|
|
172
|
+
const args = [globalBinPath(), "update", root, "--skip-self-update", "--_reexec", "--yes"];
|
|
173
|
+
if (options.matrixPolicy === "replace") args.push("--force"); if (options.json) args.push("--json"); if (!options.color) args.push("--no-color");
|
|
174
|
+
const rerun = spawnSync(process.execPath, args, { stdio: "inherit" });
|
|
175
|
+
return Number.isInteger(rerun.status) ? rerun.status : 2;
|
|
176
|
+
}
|
|
177
|
+
if (options.json) return refresh(intent, { ...options, yes: true, updateMode: true }, ui);
|
|
178
|
+
return refresh(intent, { ...options, updateMode: true }, ui);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function recoveryArgument(value) {
|
|
182
|
+
const argument = String(value);
|
|
183
|
+
if (/^[A-Za-z0-9_./:@=-]+$/.test(argument)) return argument;
|
|
184
|
+
if (process.platform === "win32") return `"${argument.replaceAll('"', '\\"')}"`;
|
|
185
|
+
return `'${argument.replaceAll("'", "'\\''")}'`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function runtimeRecovery(projectRuntime, argv) {
|
|
189
|
+
const argumentsWithoutJson = argv.slice(1).filter((value) => value !== "--json");
|
|
190
|
+
return { ...projectRuntime, recovery_command: [projectRuntime.recovery_command, ...argumentsWithoutJson.map(recoveryArgument)].join(" ") };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function doctor(options) {
|
|
194
|
+
const ui = createUi({ color: options.color && !options.json });
|
|
195
|
+
const root = projectRoot(options.directory);
|
|
196
|
+
const installed = installedIntent({ projectRoot: root });
|
|
197
|
+
const intent = installed.ok
|
|
198
|
+
? { ...installed.intent, dryRun: true }
|
|
199
|
+
: await intentFrom({ ...options, directory: root, yes: true }, ui);
|
|
200
|
+
const evaluation = createDistribution().diagnose(intent);
|
|
201
|
+
const matt = inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms });
|
|
202
|
+
if (options.json) console.log(JSON.stringify({ ...evaluation, matt }));
|
|
203
|
+
else { await ui.banner(); ui.info(text(intent.language, "doctor")); render(ui, evaluation); ui.muted(`${text(intent.language, "mattCompatibilityStatus").replace("{release}", matt.supported.release).replace("{status}", localizedState(intent.language, matt.status))}${matt.action ? `; ${matt.action}` : ""}`); }
|
|
204
|
+
return evaluation.ok ? 0 : 2;
|
|
205
|
+
}
|
|
107
206
|
|
|
108
|
-
export async function main(argv) {
|
|
109
|
-
if (argv[0] === "workflow") {
|
|
110
|
-
const json = argv.includes("--json");
|
|
111
|
-
const
|
|
207
|
+
export async function main(argv) {
|
|
208
|
+
if (argv[0] === "workflow") {
|
|
209
|
+
const json = argv.includes("--json");
|
|
210
|
+
const projectRuntime = resolveProjectRuntime({ projectRoot: process.cwd() });
|
|
211
|
+
if (!projectRuntime.ok) {
|
|
212
|
+
const failure = projectRuntime.recovery_command ? runtimeRecovery(projectRuntime, argv) : projectRuntime;
|
|
213
|
+
if (json) console.log(JSON.stringify(failure));
|
|
214
|
+
else console.log(`MATRIX ERROR [${failure.code}]: ${failure.message}${failure.recovery_command ? `\nRun ${failure.recovery_command}` : ""}`);
|
|
215
|
+
return 2;
|
|
216
|
+
}
|
|
217
|
+
if (projectRuntime.runtime) {
|
|
218
|
+
const delegated = spawnSync(process.execPath, [projectRuntime.runtime, ...argv.slice(1).filter((value) => value !== "--json")], { stdio: "inherit" });
|
|
219
|
+
return Number.isInteger(delegated.status) ? delegated.status : 2;
|
|
220
|
+
}
|
|
221
|
+
const result = invoke(argv.slice(1).filter((value) => value !== "--json"));
|
|
112
222
|
if (json) console.log(JSON.stringify(result));
|
|
113
223
|
else console.log(result.ok ? JSON.stringify(result, null, 2) : `MATRIX ERROR [${result.code}]: ${result.message}`);
|
|
114
224
|
return result.ok ? 0 : 2;
|
|
@@ -117,6 +227,7 @@ export async function main(argv) {
|
|
|
117
227
|
if (options.version) { console.log(version); return 0; }
|
|
118
228
|
if (options.help || !options.command) { console.log(HELP); return 0; }
|
|
119
229
|
if (options.command === "init") return init(options);
|
|
230
|
+
if (options.command === "update") return update(options);
|
|
120
231
|
if (options.command === "doctor") return doctor(options);
|
|
121
232
|
throw new Error(`Unknown command: ${options.command}. Run matrix --help.`);
|
|
122
233
|
}
|