@rosenfan/matrix 0.1.5 → 0.1.7
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 +22 -19
- package/README.zh-CN.md +21 -18
- package/assets/skills/matrix/SKILL.md +6 -5
- package/assets/skills/matrix-archive/SKILL.md +2 -0
- package/assets/skills/matrix-build/SKILL.md +1 -1
- package/assets/skills/matrix-design/SKILL.md +12 -6
- package/assets/skills/matrix-handoff/SKILL.md +89 -0
- package/assets/skills/matrix-handoff/agents/openai.yaml +4 -0
- package/assets/skills/matrix-open/SKILL.md +13 -2
- package/assets/skills/matrix-verify/SKILL.md +4 -4
- package/assets/skills-zh-CN/matrix/SKILL.md +84 -83
- package/assets/skills-zh-CN/matrix-archive/SKILL.md +2 -0
- package/assets/skills-zh-CN/matrix-build/SKILL.md +41 -41
- package/assets/skills-zh-CN/matrix-design/SKILL.md +41 -24
- package/assets/skills-zh-CN/matrix-handoff/SKILL.md +79 -0
- package/assets/skills-zh-CN/matrix-open/SKILL.md +40 -30
- package/package.json +1 -1
- package/src/catalog.js +10 -2
- package/src/cli.js +303 -233
- package/src/distribution.js +1 -1
- package/src/installer.js +45 -45
- package/src/matt-catalog.mjs +35 -33
- package/src/matt.js +122 -127
- package/src/messages.js +46 -37
- package/src/npm-invocation.js +23 -0
- package/src/project-index.js +43 -0
- package/src/runtime-resolver.js +76 -76
- package/src/self-update.js +8 -1
- package/src/ui.js +97 -89
- package/src/workflow.js +36 -4
- package/assets/skills/matrix-claude/SKILL.md +0 -98
- package/assets/skills/matrix-claude/agents/openai.yaml +0 -4
- package/assets/skills-zh-CN/matrix-claude/SKILL.md +0 -33
package/src/installer.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { createDistribution } from "./distribution.js";
|
|
4
|
-
import { MATRIX_SKILLS, MATT_SKILLS, PLATFORMS, sourceSkillsRoot } from "./catalog.js";
|
|
5
|
-
|
|
6
|
-
export { MATRIX_SKILLS, MATT_SKILLS, sourceSkillsRoot };
|
|
7
|
-
|
|
8
|
-
export function destinationFor({ scope, projectRoot, platform = "claude-code", home }) {
|
|
9
|
-
const base = scope === "global" ? (home ?? process.env.USERPROFILE ?? process.env.HOME) : projectRoot;
|
|
10
|
-
return PLATFORMS[platform].skillRoot(base);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function inspectInstallation(destination) {
|
|
14
|
-
const inspect = (names) => names.filter((skill) => {
|
|
15
|
-
try { return Boolean(destination) && requireExists(destination, skill); } catch { return false; }
|
|
16
|
-
});
|
|
17
|
-
const installed = inspect(MATRIX_SKILLS);
|
|
18
|
-
const mattInstalled = inspect(MATT_SKILLS);
|
|
19
|
-
return { installed, missing: MATRIX_SKILLS.filter((skill) => !installed.includes(skill)), mattInstalled, mattMissing: MATT_SKILLS.filter((skill) => !mattInstalled.includes(skill)) };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function requireExists(destination, skill) {
|
|
23
|
-
// Avoid exposing a second installation policy through this legacy helper.
|
|
24
|
-
return fs.existsSync(path.join(destination, skill, "SKILL.md"));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function installMatrix({ destination, mode = "copy", conflict = "error", dryRun = false }) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const distribution = createDistribution();
|
|
31
|
-
const evaluation = distribution.evaluate({ projectRoot, scope: "project", platforms: [platform], mode, matrixPolicy: conflict === "replace" ? "replace" : "safe", dryRun });
|
|
32
|
-
if (!evaluation.ok) throw new Error(evaluation.diagnostics?.[0]?.message ?? evaluation.code);
|
|
33
|
-
const result = distribution.commit(evaluation.plan);
|
|
34
|
-
if (!result.ok) throw new Error(result.error ?? result.code);
|
|
35
|
-
return { installed: result.committed ?? MATRIX_SKILLS, skipped: [], existing: [], backupRoot: result.backups?.[0] ? result.backups[0].backup : null };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function installMattSkills({ projectRoot, platforms = ["claude-code"], skills = MATT_SKILLS, global = false, timeout = 300_000 }) {
|
|
39
|
-
void projectRoot; void platforms; void skills; void global; void timeout;
|
|
40
|
-
const error = new Error("Direct Matt installation was retired; run matrix init --with-mattpocock so Distribution owns the complete Matrix/Matt transaction.");
|
|
41
|
-
error.code = "MATT_DIRECT_INSTALL_UNSUPPORTED";
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function findPython() { return null; }
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createDistribution } from "./distribution.js";
|
|
4
|
+
import { MATRIX_SKILLS, MATT_SKILLS, PLATFORMS, PLATFORM_IDS, sourceSkillsRoot } from "./catalog.js";
|
|
5
|
+
|
|
6
|
+
export { MATRIX_SKILLS, MATT_SKILLS, sourceSkillsRoot };
|
|
7
|
+
|
|
8
|
+
export function destinationFor({ scope, projectRoot, platform = "claude-code", home }) {
|
|
9
|
+
const base = scope === "global" ? (home ?? process.env.USERPROFILE ?? process.env.HOME) : projectRoot;
|
|
10
|
+
return PLATFORMS[platform].skillRoot(base);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function inspectInstallation(destination) {
|
|
14
|
+
const inspect = (names) => names.filter((skill) => {
|
|
15
|
+
try { return Boolean(destination) && requireExists(destination, skill); } catch { return false; }
|
|
16
|
+
});
|
|
17
|
+
const installed = inspect(MATRIX_SKILLS);
|
|
18
|
+
const mattInstalled = inspect(MATT_SKILLS);
|
|
19
|
+
return { installed, missing: MATRIX_SKILLS.filter((skill) => !installed.includes(skill)), mattInstalled, mattMissing: MATT_SKILLS.filter((skill) => !mattInstalled.includes(skill)) };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function requireExists(destination, skill) {
|
|
23
|
+
// Avoid exposing a second installation policy through this legacy helper.
|
|
24
|
+
return fs.existsSync(path.join(destination, skill, "SKILL.md"));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function installMatrix({ destination, mode = "copy", conflict = "error", dryRun = false }) {
|
|
28
|
+
const projectRoot = path.resolve(destination, "..", "..");
|
|
29
|
+
const platform = PLATFORM_IDS.find((id) => PLATFORMS[id].skillRoot(projectRoot) === path.resolve(destination)) ?? "claude-code";
|
|
30
|
+
const distribution = createDistribution();
|
|
31
|
+
const evaluation = distribution.evaluate({ projectRoot, scope: "project", platforms: [platform], mode, matrixPolicy: conflict === "replace" ? "replace" : "safe", dryRun });
|
|
32
|
+
if (!evaluation.ok) throw new Error(evaluation.diagnostics?.[0]?.message ?? evaluation.code);
|
|
33
|
+
const result = distribution.commit(evaluation.plan);
|
|
34
|
+
if (!result.ok) throw new Error(result.error ?? result.code);
|
|
35
|
+
return { installed: result.committed ?? MATRIX_SKILLS, skipped: [], existing: [], backupRoot: result.backups?.[0] ? result.backups[0].backup : null };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function installMattSkills({ projectRoot, platforms = ["claude-code"], skills = MATT_SKILLS, global = false, timeout = 300_000 }) {
|
|
39
|
+
void projectRoot; void platforms; void skills; void global; void timeout;
|
|
40
|
+
const error = new Error("Direct Matt installation was retired; run matrix init --with-mattpocock so Distribution owns the complete Matrix/Matt transaction.");
|
|
41
|
+
error.code = "MATT_DIRECT_INSTALL_UNSUPPORTED";
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function findPython() { return null; }
|
package/src/matt-catalog.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
|
|
3
3
|
export const MATT_COMPATIBILITY = Object.freeze({
|
|
4
|
-
matrixVersion: "0.1.
|
|
5
|
-
release: "v1.
|
|
6
|
-
commit: "
|
|
7
|
-
archive: "https://github.com/mattpocock/skills/archive/
|
|
8
|
-
skillsCli: "skills@1.
|
|
4
|
+
matrixVersion: "0.1.7",
|
|
5
|
+
release: "v1.3.1",
|
|
6
|
+
commit: "24fe0ef7737efae15c87225755e9f6f5965e4888",
|
|
7
|
+
archive: "https://github.com/mattpocock/skills/archive/24fe0ef7737efae15c87225755e9f6f5965e4888.tar.gz",
|
|
8
|
+
skillsCli: "skills@1.7.4"
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
export const MATT_ROLES = Object.freeze({
|
|
@@ -14,12 +14,12 @@ export const MATT_ROLES = Object.freeze({
|
|
|
14
14
|
"tdd", "diagnosing-bugs", "code-review", "wizard", "writing-for-agents"
|
|
15
15
|
]),
|
|
16
16
|
handoff: Object.freeze([
|
|
17
|
-
"setup-matt-pocock-skills", "improve-codebase-architecture", "wayfinder", "handoff", "to-questionnaire"
|
|
17
|
+
"setup-matt-pocock-skills", "improve-codebase-architecture", "wayfinder", "handoff", "to-questionnaire", "retro"
|
|
18
18
|
]),
|
|
19
19
|
standalone: Object.freeze([
|
|
20
|
-
"ask-matt", "grill-with-docs", "triage", "to-spec", "to-tickets", "grill-me", "teach", "wait-what"
|
|
20
|
+
"ask-matt", "grill-with-docs", "triage", "to-spec", "to-tickets", "grill-me", "teach", "wait-what", "pr"
|
|
21
21
|
]),
|
|
22
|
-
incompatible: Object.freeze(["implement", "
|
|
22
|
+
incompatible: Object.freeze(["implement", "implement-spec"])
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export const MATT_AUTOMATIC_SKILLS = MATT_ROLES.automatic;
|
|
@@ -29,35 +29,37 @@ export const MATT_INSTALLABLE_SKILLS = Object.freeze([
|
|
|
29
29
|
...MATT_ROLES.standalone
|
|
30
30
|
]);
|
|
31
31
|
export const MATT_OFFICIAL_SKILLS = Object.freeze(Object.values(MATT_ROLES).flat());
|
|
32
|
-
// Content identities produced by skills@1.
|
|
32
|
+
// Content identities produced by skills@1.7.4 --copy from the exact v1.3.1 archive.
|
|
33
33
|
// They let init classify existing project files before any target mutation without
|
|
34
34
|
// bundling or redistributing Matt's Skill contents.
|
|
35
35
|
export const MATT_CONTENT_HASHES = Object.freeze({
|
|
36
|
-
"grilling": "
|
|
37
|
-
"domain-modeling": "
|
|
38
|
-
"research": "
|
|
39
|
-
"prototype": "
|
|
40
|
-
"codebase-design": "
|
|
41
|
-
"tdd": "
|
|
42
|
-
"diagnosing-bugs": "
|
|
43
|
-
"code-review": "
|
|
44
|
-
"wizard": "
|
|
45
|
-
"writing-for-agents": "
|
|
46
|
-
"setup-matt-pocock-skills": "
|
|
47
|
-
"improve-codebase-architecture": "
|
|
48
|
-
"wayfinder": "
|
|
49
|
-
"handoff": "
|
|
50
|
-
"to-questionnaire": "
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"to-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
36
|
+
"grilling": "229e9190ddcdf65fcfa68aeebe6edfcf3b039967e4d5321c48325ea197836b88",
|
|
37
|
+
"domain-modeling": "332c4e23360e692a488fa25fe878596f91e4eaf125f48ea280dca151f3798eaa",
|
|
38
|
+
"research": "8766e592808cb8e6951dd8e4d414f4fef3ee9dde1c487b2e5af7461027f794e2",
|
|
39
|
+
"prototype": "5fc3162feb286bc773e21c208c440de81f66ef36e6ae2fd2189a54756af4468c",
|
|
40
|
+
"codebase-design": "17a6a1ab67eff070a38564834d6e3ff82bc2d46cdc888a57f6bc18c3efe6442b",
|
|
41
|
+
"tdd": "cf0a63fd20988baef0a31d2d8467e70319fdc75d5bb3eaa60620abcedb97574c",
|
|
42
|
+
"diagnosing-bugs": "bc1ade4a8b7e988aed02c251d3d0d8cdbedc74ce3361a244e2cf12cbb6744d74",
|
|
43
|
+
"code-review": "9a883c4392f27b6d45c6a51d12d168897ba7707a5e70f8d45a042b41db58d5a5",
|
|
44
|
+
"wizard": "b2793f1654b9c518eb85386cc51f9218030c6dc83772bea3c128cb156c972300",
|
|
45
|
+
"writing-for-agents": "46d0c6f716d2c4cbb27ea157fd3e18675389fecf3d722343f05c82b7c1e61bf8",
|
|
46
|
+
"setup-matt-pocock-skills": "7fd2c1e02b10bdd59f2c15a7cbc364e247286884c1c5cdd21704f7cbc769b42a",
|
|
47
|
+
"improve-codebase-architecture": "4502270f003e0702f19da6c2436daffe0f9d4dafcea3de2759347b99c5a5c404",
|
|
48
|
+
"wayfinder": "a774efe838aede8db313dbf3cd16660075803b3ed3657d3297ec913ea67fad49",
|
|
49
|
+
"handoff": "5aff146205749c5daab83c1f0299b910a1caaa403bcd37f59f35513a6c13dc12",
|
|
50
|
+
"to-questionnaire": "51d0425a65248e2d5ca1b4d06e4f854cb131e49a43326f54a81690ce28e27535",
|
|
51
|
+
"retro": "e7b2f28bf8e88e539791db6f9ec566252b56afc179d5b881486340a477ec59bd",
|
|
52
|
+
"ask-matt": "b1cf1467569d4199e6cec74a3fa9036d42bb208e76084e5d5030e23cd7f1f1dc",
|
|
53
|
+
"grill-with-docs": "bbf60554b6f102ed734211b26c5d3cc237be19e0dd5d93c1a8dea1367d6ebc23",
|
|
54
|
+
"triage": "f44745c02d710fee1bd12e036f8a4d53a4615018c255dd90dba7ec09a23ebb6d",
|
|
55
|
+
"to-spec": "23e7133ad3781b22ddc23335c88a975b71ebc809a7b5f734b158bb05abaaa5e8",
|
|
56
|
+
"to-tickets": "b7296c8466d53eb832047afad28932db82b1f31da4b647ec0c63a5af824a8bbc",
|
|
57
|
+
"grill-me": "b37db6d78417792b8dd9a478bc8fcdf7a008dcb94cb172247b01fda6205ba6e3",
|
|
58
|
+
"teach": "78966fd2b3ab60f3c08c25660d7a237325c1a243a9ba1103e7dc77edf9713825",
|
|
59
|
+
"wait-what": "ea4bde2069b457b52a0b2ba39bfc686a54fff73b79c91ef974224d0215298a9f",
|
|
60
|
+
"pr": "4f2bdb1aaf75c6cd0f4696889ff1022cff86ab81c3c1e3a1ba4ce00964d98146",
|
|
59
61
|
"implement": "3180dbe245245f99dceb669e597cf633935cc87be0ca3c39a86dde54e62a4db9",
|
|
60
|
-
"
|
|
62
|
+
"implement-spec": "9f2d9a27a67a0edee8bcc1c12c5dae69ea77ffaf2a4898a939c6afd0c7db7f47"
|
|
61
63
|
});
|
|
62
64
|
export const MATT_CATALOG_DIGEST = crypto.createHash("sha256").update(JSON.stringify({
|
|
63
65
|
compatibility: MATT_COMPATIBILITY,
|
package/src/matt.js
CHANGED
|
@@ -1,127 +1,122 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { PLATFORMS, hashDirectory } from "./catalog.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
discardCandidate(candidate) {
|
|
124
|
-
if (candidate?.root) remove(candidate.root);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { PLATFORMS, hashDirectory } from "./catalog.js";
|
|
6
|
+
import { buildNpmProcessInvocation } from "./npm-invocation.js";
|
|
7
|
+
import { MATT_CATALOG_DIGEST, MATT_COMPATIBILITY, MATT_CONTENT_HASHES, MATT_INSTALLABLE_SKILLS } from "./matt-catalog.mjs";
|
|
8
|
+
|
|
9
|
+
export const mattReceiptPath = (projectRoot) => path.join(path.resolve(projectRoot), ".matrix", "matt-installation.json");
|
|
10
|
+
|
|
11
|
+
function readJson(file) {
|
|
12
|
+
try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return null; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function releaseOrder(left, right) {
|
|
16
|
+
const parse = (value) => String(value ?? "").replace(/^v/, "").split(".").map((part) => Number(part));
|
|
17
|
+
const a = parse(left); const b = parse(right);
|
|
18
|
+
if (a.some(Number.isNaN) || b.some(Number.isNaN)) return null;
|
|
19
|
+
for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
|
|
20
|
+
if ((a[index] ?? 0) !== (b[index] ?? 0)) return (a[index] ?? 0) > (b[index] ?? 0) ? 1 : -1;
|
|
21
|
+
}
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function inspectMattInstallation({ projectRoot, platforms, home = os.homedir(), contentHashes = MATT_CONTENT_HASHES, action = "matrix init . --with-mattpocock" }) {
|
|
26
|
+
const receipt = readJson(mattReceiptPath(projectRoot));
|
|
27
|
+
const selected = [...new Set(platforms ?? Object.keys(receipt?.platforms ?? {}))];
|
|
28
|
+
const localPresence = selected.reduce((count, platform) => {
|
|
29
|
+
const root = PLATFORMS[platform]?.skillRoot(projectRoot);
|
|
30
|
+
return count + MATT_INSTALLABLE_SKILLS.filter((skill) => root && fs.existsSync(path.join(root, skill, "SKILL.md"))).length;
|
|
31
|
+
}, 0);
|
|
32
|
+
const base = { supported: MATT_COMPATIBILITY, installed: receipt?.compatibility?.release ?? "unknown", action };
|
|
33
|
+
if (!receipt) return { ...base, status: localPresence ? "unverified" : "incomplete", platforms: [] };
|
|
34
|
+
const order = releaseOrder(receipt.compatibility?.release, MATT_COMPATIBILITY.release);
|
|
35
|
+
if (order !== 0 || receipt.compatibility?.commit !== MATT_COMPATIBILITY.commit || receipt.catalogDigest !== MATT_CATALOG_DIGEST) {
|
|
36
|
+
return { ...base, status: order != null && order > 0 ? "unsupported-newer" : "update-required", platforms: [] };
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const findings = selected.map((platform) => {
|
|
40
|
+
const root = PLATFORMS[platform].skillRoot(projectRoot);
|
|
41
|
+
const records = receipt.platforms?.[platform]?.skills ?? {};
|
|
42
|
+
const missing = MATT_INSTALLABLE_SKILLS.filter((skill) => !fs.existsSync(path.join(root, skill, "SKILL.md")) || !records[skill]?.hash);
|
|
43
|
+
const modified = MATT_INSTALLABLE_SKILLS.filter((skill) => !missing.includes(skill) && (() => {
|
|
44
|
+
const actual = hashDirectory(path.join(root, skill));
|
|
45
|
+
return actual !== records[skill].hash || actual !== contentHashes[skill];
|
|
46
|
+
})());
|
|
47
|
+
const globalRoot = PLATFORMS[platform].skillRoot(home);
|
|
48
|
+
const ignoredGlobal = MATT_INSTALLABLE_SKILLS.filter((skill) => !fs.existsSync(path.join(root, skill, "SKILL.md")) && fs.existsSync(path.join(globalRoot, skill, "SKILL.md"))).length;
|
|
49
|
+
return { platform, root, missing, modified, ignoredGlobal };
|
|
50
|
+
});
|
|
51
|
+
const status = findings.some((item) => item.missing.length) ? "incomplete"
|
|
52
|
+
: findings.some((item) => item.modified.length) ? "user-modified" : "compatible";
|
|
53
|
+
return { ...base, status, action: status === "compatible" ? null : base.action, platforms: findings };
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return { ...base, status: "unknown", message: error.message, platforms: [] };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function buildProcessInvocation({ command, args, platform = process.platform, nodeExecutable = process.execPath, npmCliPath }) {
|
|
60
|
+
return buildNpmProcessInvocation({ command, args, platform, nodeExecutable, npmCliPath });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function defaultProcessRunner({ command, args, cwd, timeout, stdio = "inherit" }) {
|
|
64
|
+
const invocation = buildProcessInvocation({ command, args });
|
|
65
|
+
return execFileSync(invocation.executable, invocation.args, { cwd, stdio, timeout, shell: invocation.shell });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function createMattAdapter({
|
|
69
|
+
run = defaultProcessRunner,
|
|
70
|
+
stdio = "inherit",
|
|
71
|
+
makeTemporary = () => fs.mkdtempSync(path.join(os.tmpdir(), "matrix-matt-")),
|
|
72
|
+
remove = (target) => fs.rmSync(target, { recursive: true, force: true }),
|
|
73
|
+
verifyCandidate = ({ root, platforms, skills }) => {
|
|
74
|
+
for (const platform of platforms) for (const skill of skills) {
|
|
75
|
+
const installed = path.join(PLATFORMS[platform].skillRoot(root), skill);
|
|
76
|
+
if (hashDirectory(installed) !== MATT_CONTENT_HASHES[skill]) throw new Error(`Matt candidate content did not match the reviewed release: ${platform}/${skill}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} = {}) {
|
|
80
|
+
return {
|
|
81
|
+
installMissing() {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
code: "MATT_DIRECT_INSTALL_UNSUPPORTED",
|
|
85
|
+
message: "Direct Matt installation was retired; use matrix init --with-mattpocock so Distribution owns staging, backup, and recovery.",
|
|
86
|
+
recovery: "Run matrix init --with-mattpocock."
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
prepareCandidate({ platforms, skills = MATT_INSTALLABLE_SKILLS, timeout = 300_000 }) {
|
|
90
|
+
const root = makeTemporary();
|
|
91
|
+
const attempted = [];
|
|
92
|
+
try {
|
|
93
|
+
for (const platform of platforms) {
|
|
94
|
+
const args = ["--yes", MATT_COMPATIBILITY.skillsCli, "add", MATT_COMPATIBILITY.archive, "--yes", "--copy", "--agent", PLATFORMS[platform].skillsCliAgent];
|
|
95
|
+
for (const skill of skills) args.push("--skill", skill);
|
|
96
|
+
run({ command: "npx", args, cwd: root, timeout, stdio });
|
|
97
|
+
attempted.push(platform);
|
|
98
|
+
}
|
|
99
|
+
verifyCandidate({ root, platforms, skills });
|
|
100
|
+
return {
|
|
101
|
+
ok: true,
|
|
102
|
+
code: "OK",
|
|
103
|
+
root,
|
|
104
|
+
attempted,
|
|
105
|
+
platforms: Object.fromEntries(platforms.map((platform) => [platform, PLATFORMS[platform].skillRoot(root)]))
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
remove(root);
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
code: "MATT_INSTALL_FAILED",
|
|
112
|
+
attempted,
|
|
113
|
+
message: error.message,
|
|
114
|
+
recovery: "Run matrix init --with-mattpocock after resolving the skills CLI error."
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
discardCandidate(candidate) {
|
|
119
|
+
if (candidate?.root) remove(candidate.root);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
package/src/messages.js
CHANGED
|
@@ -1,37 +1,46 @@
|
|
|
1
|
-
export const messages = {
|
|
2
|
-
en: {
|
|
3
|
-
title: "Evidence-driven workflow with Prim and Arch orchestration",
|
|
4
|
-
recommended: "Recommended setup", apply: "Apply", customize: "Customize", cancel: "Cancel",
|
|
5
|
-
project: "Project (current directory)", global: "Global Matrix Skills",
|
|
6
|
-
copy: "Copy (recommended)", symlink: "Symlink (advanced)",
|
|
7
|
-
matrix: "Matrix", matt: "Matt Pocock skills", installed: "installed", ready: "Matrix is ready.",
|
|
8
|
-
noPlatform: "No verified platform was detected. Select Claude Code, Codex, or
|
|
9
|
-
preview: "Planned changes", confirm: "Apply these changes?", doctor: "Installation diagnosis",
|
|
10
|
-
languageQuestion: "Language", scopeQuestion: "Installation scope", platformsQuestion: "Platforms", orchestrationQuestion: "Default orchestration",
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
manifestMissing: "
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
export const messages = {
|
|
2
|
+
en: {
|
|
3
|
+
title: "Evidence-driven workflow with Prim and Arch orchestration",
|
|
4
|
+
recommended: "Recommended setup", apply: "Apply", customize: "Customize", cancel: "Cancel",
|
|
5
|
+
project: "Project (current directory)", global: "Global Matrix Skills",
|
|
6
|
+
copy: "Copy (recommended)", symlink: "Symlink (advanced)",
|
|
7
|
+
matrix: "Matrix", matt: "Matt Pocock skills", installed: "installed", ready: "Matrix is ready.",
|
|
8
|
+
noPlatform: "No verified platform was detected. Select Claude Code, Codex, or ZCode.",
|
|
9
|
+
preview: "Planned changes", confirm: "Apply these changes?", doctor: "Installation diagnosis",
|
|
10
|
+
languageQuestion: "Language", scopeQuestion: "Installation scope", platformsQuestion: "Platforms", orchestrationQuestion: "Default orchestration",
|
|
11
|
+
orchestrationArchDetail: "Orchestrates the installed Matt Skills cohort (requires Matt Skills).", orchestrationPrimDetail: "Uses Matrix's own capabilities only (no Matt dependency).",
|
|
12
|
+
readyHint: "Type $matrix followed by your request in {platform} to start the evidence-driven workflow.",
|
|
13
|
+
mattQuestion: "Install or reconcile the supported Matt Pocock release in this project?", replaceQuestion: "Existing Matrix files are not proven managed. Back up and replace?",
|
|
14
|
+
mattReplaceQuestion: "Matt Skills contain local or unreadable content. Back them up and replace them with the supported release?",
|
|
15
|
+
mattRepairQuestion: "Matt Skills are {state}. Re-pull the supported release ({release}) now?",
|
|
16
|
+
updateScopeQuestion: "Update scope", updateScopeCurrent: "Current project only", updateScopeAll: "All indexed projects",
|
|
17
|
+
yes: "Yes", no: "No", stateMissing: "missing", stateMatching: "up to date", stateComplete: "complete", stateUserModified: "user-modified", statePartial: "partial", stateOutdated: "outdated", stateSafeUpdate: "safe update", stateAdoptable: "adoptable", stateUnreadable: "unreadable", stateCompatible: "compatible", stateUpdateRequired: "update required", stateUnsupportedNewer: "unsupported newer", stateUnverified: "unverified", stateUnknown: "unknown",
|
|
18
|
+
actionInstall: "install", actionKeep: "keep", actionBackupReplace: "back up and replace", actionRepair: "repair", actionBlocked: "requires approval",
|
|
19
|
+
dryRunComplete: "Dry run complete.", defaultOrchestration: "Default orchestration", mattCompatibilityStatus: "Matt {release}: {status}",
|
|
20
|
+
manifestMissing: "No Matrix installation manifest was found for this scope.", transactionPending: "An interrupted Matrix transaction is awaiting recovery. Run matrix init again before applying a new plan.", runtimeMissing: "Bundled Matrix runtime is missing.", brokenLink: "Broken Matrix link detected.", mattGlobalIgnored: "global Matt Skills are present but ignored by the project compatibility contract.", mattSetupHint: "Matt {release} is installed for this project. Optionally run $setup-matt-pocock-skills once to configure its user-owned integrations.",
|
|
21
|
+
matrixModifiedDiagnostic: "{platform}: existing Matrix assets are not proven managed.", mattModifiedDiagnostic: "{platform}: Matt Skills contain local or unreadable content that requires separate replacement approval.", archIncompleteDiagnostic: "Arch requires the exact reviewed cohort and trusted project receipt. Retry with --with-mattpocock.", matrixStateDiagnostic: "{platform}: Matrix is {state}.", mattStateDiagnostic: "{platform}: Matt Pocock skills are {state}.", codexLegacyDiagnostic: "Codex legacy .codex/skills was detected; Matrix will not write there.", unmanagedExtraDiagnostic: "{platform}: unmanaged extra Skills are preserved and will not be invoked: {skills}."
|
|
22
|
+
},
|
|
23
|
+
"zh-CN": {
|
|
24
|
+
manifestMissing: "当前安装范围没有 Matrix 安装清单。", transactionPending: "发现中断的 Matrix 安装事务。请再次运行 matrix init 后再应用新计划。", runtimeMissing: "缺少随附的 Matrix runtime。", brokenLink: "检测到断开的 Matrix 链接。", mattGlobalIgnored: "检测到全局 Matt Skills,但项目兼容性契约不会采用它们。", mattSetupHint: "已为当前项目安装 Matt {release}。如需配置由用户拥有的集成,可显式运行一次 $setup-matt-pocock-skills。",
|
|
25
|
+
languageQuestion: "语言", scopeQuestion: "安装范围", platformsQuestion: "要配置的平台", orchestrationQuestion: "默认编排模式",
|
|
26
|
+
orchestrationArchDetail: "编排项目内已安装的 Matt Skills 集合(需先安装 Matt)。",
|
|
27
|
+
orchestrationPrimDetail: "仅使用 Matrix 自带能力,不依赖 Matt Skills。",
|
|
28
|
+
readyHint: "在 {platform} 中输入 `$matrix` 加你的请求,即可启动证据驱动工作流。",
|
|
29
|
+
mattQuestion: "是否在当前项目安装或核对 Matrix 支持的 Matt Pocock Release?", replaceQuestion: "现有 Matrix 文件无法确认由 Matrix 管理。是否备份并替换?", mattReplaceQuestion: "Matt Skills 存在本地修改或不可读内容。是否先备份,再替换为受支持的 Release?",
|
|
30
|
+
mattRepairQuestion: "Matt Skills {state}。是否立即重新拉取受支持的 release({release})?",
|
|
31
|
+
updateScopeQuestion: "更新范围", updateScopeCurrent: "仅当前项目", updateScopeAll: "全部已索引项目",
|
|
32
|
+
yes: "是", no: "否", stateMissing: "未安装", stateMatching: "已是最新", stateComplete: "完整", stateUserModified: "已被用户修改", statePartial: "不完整", stateOutdated: "可更新", stateSafeUpdate: "可安全更新", stateAdoptable: "可接管", stateUnreadable: "不可读", stateCompatible: "兼容", stateUpdateRequired: "需要更新", stateUnsupportedNewer: "版本过新且不受支持", stateUnverified: "未验证", stateUnknown: "未知",
|
|
33
|
+
actionInstall: "安装", actionKeep: "保留", actionBackupReplace: "备份并替换", actionRepair: "修复", actionBlocked: "需要确认",
|
|
34
|
+
dryRunComplete: "预览完成。", defaultOrchestration: "默认编排", mattCompatibilityStatus: "Matt {release}:{status}",
|
|
35
|
+
title: "提供 Prim 与 Arch 编排的证据驱动工作流",
|
|
36
|
+
recommended: "推荐配置", apply: "开始安装", customize: "自定义", cancel: "取消",
|
|
37
|
+
project: "项目(当前目录)", global: "全局 Matrix Skills",
|
|
38
|
+
copy: "复制(推荐)", symlink: "符号链接(高级)",
|
|
39
|
+
matrix: "Matrix", matt: "Matt Pocock skills", installed: "已安装", ready: "Matrix 已就绪。",
|
|
40
|
+
noPlatform: "未检测到已验证的平台。请选择 Claude Code、Codex 或 ZCode。",
|
|
41
|
+
preview: "计划变更", confirm: "确认应用这些变更?", doctor: "安装诊断",
|
|
42
|
+
matrixModifiedDiagnostic: "{platform}:现有 Matrix 资产无法确认由 Matrix 管理。", mattModifiedDiagnostic: "{platform}:Matt Skills 存在本地修改或不可读内容,需要单独授权替换。", archIncompleteDiagnostic: "Arch 需要精确匹配已审查集合和可信项目 receipt。请使用 --with-mattpocock 重试。", matrixStateDiagnostic: "{platform}:Matrix 状态为 {state}。", mattStateDiagnostic: "{platform}:Matt Pocock Skills 状态为 {state}。", codexLegacyDiagnostic: "检测到 Codex 旧版 .codex/skills;Matrix 不会写入该目录。", unmanagedExtraDiagnostic: "{platform}:将保留但不会调用这些非托管附加 Skills:{skills}。"
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function text(language, key) { return messages[language]?.[key] ?? messages.en[key] ?? key; }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
// Windows CreateProcess cannot launch npm.cmd, so npm/npx must run as
|
|
5
|
+
// `node <npm-cli.js> ...`. Resolution order: explicit path, npm_execpath,
|
|
6
|
+
// the npm bundled beside the running Node. Non-Windows returns the command
|
|
7
|
+
// unchanged so every caller keeps its POSIX behavior.
|
|
8
|
+
export function resolveNpmCli({ platform = process.platform, nodeExecutable = process.execPath, npmCliPath } = {}) {
|
|
9
|
+
if (platform !== "win32") return null;
|
|
10
|
+
const candidates = [npmCliPath, process.env.npm_execpath, path.join(path.dirname(nodeExecutable), "node_modules", "npm", "bin", "npm-cli.js")].filter(Boolean);
|
|
11
|
+
const cli = candidates.find((candidate) => npmCliPath || fs.existsSync(candidate));
|
|
12
|
+
if (!cli) throw new Error("npm CLI was not found beside the Node runtime. Install the package manually with `npm i -g <package>` or reinstall Node.js so its bundled npm is present.");
|
|
13
|
+
return cli;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function buildNpmProcessInvocation({ command, args, platform = process.platform, nodeExecutable = process.execPath, npmCliPath }) {
|
|
17
|
+
if (platform !== "win32" || (command !== "npm" && command !== "npx")) return { executable: command, args, shell: false };
|
|
18
|
+
const cli = resolveNpmCli({ platform, nodeExecutable, npmCliPath });
|
|
19
|
+
if (command === "npm") return { executable: nodeExecutable, args: [cli, ...args], shell: false };
|
|
20
|
+
const [yes, packageSpec, ...commandArgs] = args;
|
|
21
|
+
if (yes !== "--yes" || !packageSpec) throw new Error("Windows npx invocation must use fixed npm exec arguments.");
|
|
22
|
+
return { executable: nodeExecutable, args: [cli, "exec", yes, packageSpec, "--", ...commandArgs], shell: false };
|
|
23
|
+
}
|