@rosenfan/matrix 0.1.6 → 0.1.8
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 +11 -9
- package/README.zh-CN.md +10 -8
- package/assets/skills/matrix/SKILL.md +3 -3
- 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 +4 -4
- package/assets/skills/matrix-handoff/agents/openai.yaml +3 -3
- package/assets/skills/matrix-open/SKILL.md +2 -2
- package/assets/skills/matrix-verify/SKILL.md +4 -4
- package/assets/skills-zh-CN/matrix/SKILL.md +3 -3
- 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 +4 -4
- package/assets/skills-zh-CN/matrix-open/SKILL.md +2 -2
- package/package.json +1 -1
- package/src/catalog.js +9 -1
- package/src/cli.js +5 -5
- package/src/distribution.js +2 -2
- package/src/installer.js +45 -45
- package/src/matt-catalog.mjs +35 -33
- package/src/messages.js +2 -2
- package/src/runtime-resolver.js +76 -76
- package/src/workflow.js +33 -8
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ Each phase:
|
|
|
69
69
|
|
|
70
70
|
## Prerequisites
|
|
71
71
|
|
|
72
|
-
- [Claude Code](https://docs.anthropic.com/claude-code)
|
|
72
|
+
- [Claude Code](https://docs.anthropic.com/claude-code), [Codex](https://openai.com/codex), or [ZCode](https://zcode.ai) installed as the Skill host (agents that read the Agent Skills open-standard `.agents/skills` directory — opencode, Kimi Code, and other compatible tools — share the Codex installation)
|
|
73
73
|
- Node.js 18+ and `npm` on `PATH` (for the Matrix CLI)
|
|
74
74
|
- Python is optional during the compatibility window; new installations use the bundled Node workflow runtime.
|
|
75
75
|
- Git is only needed when installing from GitHub or contributing to Matrix.
|
|
@@ -93,10 +93,10 @@ matrix init
|
|
|
93
93
|
|
|
94
94
|
The interactive setup lets you:
|
|
95
95
|
|
|
96
|
-
- Choose English or Chinese, project or global Matrix discovery scope, and Claude Code, Codex,
|
|
96
|
+
- Choose English or Chinese, project or global Matrix discovery scope, and any combination of Claude Code, Codex, and ZCode
|
|
97
97
|
- Copy skills (recommended) or symlink them for local development
|
|
98
98
|
- Safely reconfigure an existing installation with an automatic backup
|
|
99
|
-
- Review all
|
|
99
|
+
- Review all 27 official Matt Skills v1.3.1 roles and install the 25 compatible Skills into the target project
|
|
100
100
|
- Choose **Prim** or **Arch** as the project default without disabling the other available mode
|
|
101
101
|
|
|
102
102
|
For automation and CI:
|
|
@@ -133,7 +133,9 @@ matrix update --yes
|
|
|
133
133
|
|
|
134
134
|
`matrix update` preserves the installation's scope, platforms, language, mode, and orchestration. It first validates a newer npm package in isolation, then re-runs the new CLI to refresh Matrix assets. When the local Matt Skills are incomplete or outdated, an interactive `matrix update` asks once and repairs them to the supported release in the same run — CLI upgrade, asset refresh, and Matt repair complete in a single command (`--with-mattpocock` gives non-interactive/CI the same behavior; `--force-matt` additionally replaces locally modified Matt Skills and requires that flag; Matt Skills are never removed by `matrix update`). `--all` extends the run to every indexed project (`~/.matrix/projects.json`); each project updates in isolation and missing directories are pruned from the index. npm and project assets are separate transactions: if asset refresh fails after a CLI upgrade, run `matrix update --skip-self-update` to retry. On Windows the self-update chain runs npm through Node (no shell), so one-command upgrades work without manual steps.
|
|
135
135
|
|
|
136
|
-
Matrix 0.1.
|
|
136
|
+
Matrix 0.1.7 is bound to Matt Skills v1.3.1 at commit `24fe0ef7737efae15c87225755e9f6f5965e4888`. `matrix init --with-mattpocock` always uses that exact archive and its reviewed 25-Skill compatible manifest, even if upstream has a newer release. The two official but incompatible Skills, `implement` and `implement-spec`, are not Matrix-managed or installed. Matrix scope controls Matrix Skill discovery only: Matt Skills and `.matrix/matt-installation.json` are always project-local. Global Matt copies are preserved but never used to complete project readiness. Upstream v1.3.1 also renamed the domain-doc convention: Matt Skills now read `GLOSSARY.md`/`GLOSSARY-MAP.md` instead of `CONTEXT.md`/`CONTEXT-MAP.md`; rename existing files with `git mv` after updating.
|
|
137
|
+
|
|
138
|
+
Matrix ships dedicated platform entries only for agents with their own skill-directory convention: Claude Code (`.claude/skills`), Codex (`.agents/skills`), and ZCode (`.zcode/skills`). Installing the Codex platform also serves every agent that reads the Agent Skills open-standard `.agents/skills` directory by default — opencode, Kimi Code, and other compatible tools pick up Matrix and Matt Skills from there without a separate Matrix platform.
|
|
137
139
|
|
|
138
140
|
The language selected by `matrix init` controls the prose in new Matrix artifacts. Markdown headings required by Matrix guards remain stable English tokens; the artifact body is Chinese for `zh-CN` and English for `en`. A change freezes this language at creation time.
|
|
139
141
|
|
|
@@ -217,8 +219,8 @@ matrix workflow guard open
|
|
|
217
219
|
# Advance (only if guard passes)
|
|
218
220
|
matrix workflow transition design
|
|
219
221
|
|
|
220
|
-
# Lightweight: approve the compact proposal and enter Build
|
|
221
|
-
matrix workflow transition build --confirmed
|
|
222
|
+
# Lightweight: approve the compact proposal and enter Build (executor choice merged into the same pause)
|
|
223
|
+
matrix workflow transition build --confirmed --executor <current|model|handoff:<agent-id>>
|
|
222
224
|
|
|
223
225
|
# Return from verification failure; stale evidence is retained in history
|
|
224
226
|
matrix workflow return build --reason verification-failed
|
|
@@ -286,7 +288,7 @@ The sidecar does NOT change Matrix state. It's a pure export — like taking a s
|
|
|
286
288
|
|
|
287
289
|
## Integration with Matt Pocock's Skills
|
|
288
290
|
|
|
289
|
-
Prim uses Matrix's own capability. Matrix reviews all
|
|
291
|
+
Prim uses Matrix's own capability. Matrix reviews all 27 official Matt v1.3.1 roles, installs the 25 compatible Skills, and lets Arch automatically invoke only this reviewed ten-capability cohort:
|
|
290
292
|
|
|
291
293
|
| Phase | Capability | Trigger |
|
|
292
294
|
|---|---|---|
|
|
@@ -301,11 +303,11 @@ Prim uses Matrix's own capability. Matrix reviews all 25 official Matt v1.2.3 ro
|
|
|
301
303
|
| build | `/wizard` | The Contract requires generated human-run shell steps; Matrix never runs them end-to-end |
|
|
302
304
|
| verify | `/code-review` | Standards and Spec review evidence is required |
|
|
303
305
|
|
|
304
|
-
Matrix may recommend but never nest these user-invoked handoffs: `setup-matt-pocock-skills`, `improve-codebase-architecture`, `wayfinder`, `handoff`, and `to-questionnaire`. The user explicitly runs them outside the active phase; selected output may enter a governed Change.
|
|
306
|
+
Matrix may recommend but never nest these user-invoked handoffs: `setup-matt-pocock-skills`, `improve-codebase-architecture`, `wayfinder`, `handoff`, `retro`, and `to-questionnaire`. The user explicitly runs them outside the active phase; selected output may enter a governed Change.
|
|
305
307
|
|
|
306
308
|
Arch records a Runtime-managed review receipt after `code-review`, binding its fixed point and committed HEAD diff to the current Contract, review evidence, and workspace. A normal `code-review` receipt requires a clean candidate worktree outside Matrix-managed assets. When Git has no usable baseline, the committed diff is empty, staged/unstaged/untracked candidate files still exist, or the correctly installed capability fails, Matrix may perform one explicitly labelled same-capability fallback for that revision. The `uncommitted-worktree` fallback binds both the fixed point and a content hash of the complete worktree candidate. Installation-integrity failures never fall back. A heading or self-description without the matching receipt cannot advance Verify.
|
|
307
309
|
|
|
308
|
-
Installed standalone Skills are `ask-matt`, `grill-with-docs`, `triage`, `to-spec`, `to-tickets`, `grill-me`, `teach`,
|
|
310
|
+
Installed standalone Skills are `ask-matt`, `grill-with-docs`, `triage`, `to-spec`, `to-tickets`, `grill-me`, `teach`, `wait-what`, and `pr`. `implement` and `implement-spec` are incompatible because they can take over TDD/review/staging/commit effects owned by Matrix, so 0.1.7 neither installs nor manages them. Pre-existing copies (including any legacy `resolving-merge-conflicts`) are preserved and reported as unmanaged extras. Installation never grants automatic invocation, and no companion may transition, commit, archive, recover, or write Matrix state.
|
|
309
311
|
|
|
310
312
|
---
|
|
311
313
|
|
package/README.zh-CN.md
CHANGED
|
@@ -69,7 +69,7 @@ verify --acceptance-or-design-gap------> design
|
|
|
69
69
|
|
|
70
70
|
## 前置条件
|
|
71
71
|
|
|
72
|
-
- 已安装 [Claude Code](https://docs.anthropic.com/claude-code)
|
|
72
|
+
- 已安装 [Claude Code](https://docs.anthropic.com/claude-code)、[Codex](https://openai.com/codex) 或 [ZCode](https://zcode.ai) 之一,作为 Skill 宿主(默认读取 Agent Skills 开放标准 `.agents/skills` 目录的 agent(如 opencode、Kimi Code 等兼容工具)直接共享 Codex 平台的安装产物)
|
|
73
73
|
- Node.js 18+,且 `npm` 已加入 PATH(用于 Matrix CLI)
|
|
74
74
|
- Python 仅在兼容窗口内的旧适配器路径使用;新安装使用内置 Node workflow runtime
|
|
75
75
|
- Git 仅在从 GitHub 安装或参与 Matrix 开发时需要
|
|
@@ -96,7 +96,7 @@ matrix init
|
|
|
96
96
|
- 选择 Matrix Skill 发现入口安装到当前项目或全局
|
|
97
97
|
- 复制 skills(推荐)或为本地开发创建符号链接
|
|
98
98
|
- 安全地重新配置已有安装,并自动备份被替换的 Matrix 文件
|
|
99
|
-
- 审查 Matt Skills v1.
|
|
99
|
+
- 审查 Matt Skills v1.3.1 官方 27 项角色,并在目标项目安装其中 25 项兼容 Skill
|
|
100
100
|
- 选择 Prim 或 Arch 作为项目默认值,且不禁用另一种可用模式
|
|
101
101
|
|
|
102
102
|
自动化或 CI 环境可以使用:
|
|
@@ -130,7 +130,9 @@ matrix update --yes
|
|
|
130
130
|
|
|
131
131
|
`matrix update` 会保留既有安装的 scope、平台、语言、mode 与 orchestration。它先隔离验证 npm 新包,再由新 CLI 同步 Matrix 资产。当本地 Matt Skills 不完整或过期时,交互式 `matrix update` 会询问一次,并在同一轮把 Matt 修复到受支持 release——CLI 升级、资产刷新、Matt 修复一条命令完成(`--with-mattpocock` 为自动化/CI 提供等价的非交互行为;`--force-matt` 可额外替换被本地修改的 Matt Skills,且必须与 `--with-mattpocock` 同传;`matrix update` 绝不删除 Matt Skills)。`--all` 可将更新扩展到全部已索引项目(`~/.matrix/projects.json`),各项目隔离更新,失效目录自动从索引清理。npm 与项目资产是两个事务:若 CLI 已更新但资产同步失败,可运行 `matrix update --skip-self-update` 重试。Windows 上自升级链路经 Node 调用 npm(不经 shell),一条命令升级无需手动步骤。
|
|
132
132
|
|
|
133
|
-
Matrix 0.1.
|
|
133
|
+
Matrix 0.1.7 固定对应 Matt Skills v1.3.1,commit 为 `24fe0ef7737efae15c87225755e9f6f5965e4888`。即使上游已有新版,`matrix init --with-mattpocock` 仍使用该确切 archive 与经过审查的 25 项兼容 manifest。官方角色中的 `implement` 与 `implement-spec` 不兼容,因此 Matrix 不安装也不管理它们。Matrix scope 只控制 Matrix Skill 的发现位置;Matt Skills 与 `.matrix/matt-installation.json` 始终属于目标项目。全局 Matt 副本会保留,但绝不用于补齐项目 readiness。上游 v1.3.1 同时把域文档约定改名:Matt Skills 现在读取 `GLOSSARY.md`/`GLOSSARY-MAP.md`(原 `CONTEXT.md`/`CONTEXT-MAP.md`);升级后请用 `git mv` 跟随改名。
|
|
134
|
+
|
|
135
|
+
Matrix 只为拥有独立 skill 目录约定的 agent 内置平台条目:Claude Code(`.claude/skills`)、Codex(`.agents/skills`)与 ZCode(`.zcode/skills`)。安装 Codex 平台即同时覆盖所有默认读取 Agent Skills 开放标准 `.agents/skills` 目录的工具——opencode、Kimi Code 等兼容 agent 无需单独的 Matrix 平台条目即可使用 Matrix 与 Matt Skills。
|
|
134
136
|
|
|
135
137
|
`matrix init` 选择的语言决定新 Matrix 产物的正文语言:`zh-CN` 使用中文、`en` 使用英文。Runtime 守卫依赖的 Markdown 英文标题 token 保持不变;每个 change 在创建时冻结该语言。
|
|
136
138
|
|
|
@@ -214,8 +216,8 @@ matrix workflow guard open
|
|
|
214
216
|
# 推进(仅在守卫通过时)
|
|
215
217
|
matrix workflow transition design
|
|
216
218
|
|
|
217
|
-
# lightweight:确认紧凑 proposal 后进入 Build
|
|
218
|
-
matrix workflow transition build --confirmed
|
|
219
|
+
# lightweight:确认紧凑 proposal 后进入 Build(执行主体选择并入同一次暂停)
|
|
220
|
+
matrix workflow transition build --confirmed --executor <current|model|handoff:<agent-id>>
|
|
219
221
|
|
|
220
222
|
# 验证失败时返回 Build;旧证据保留在历史目录
|
|
221
223
|
matrix workflow return build --reason verification-failed
|
|
@@ -283,7 +285,7 @@ $matrix → open → design → build → verify → archive
|
|
|
283
285
|
|
|
284
286
|
## 与 Matt Pocock Skills 的集成
|
|
285
287
|
|
|
286
|
-
Prim 使用 Matrix 自身能力。Matrix 会审查 Matt v1.
|
|
288
|
+
Prim 使用 Matrix 自身能力。Matrix 会审查 Matt v1.3.1 官方 27 项角色,安装其中 25 项兼容 Skill,但 Arch 只自动调用以下十项经过审查的能力:
|
|
287
289
|
|
|
288
290
|
| 阶段 | 能力 | 触发条件 |
|
|
289
291
|
|---|---|---|
|
|
@@ -298,11 +300,11 @@ Prim 使用 Matrix 自身能力。Matrix 会审查 Matt v1.2.3 官方 25 项角
|
|
|
298
300
|
| build | `/wizard` | Contract 需要生成人工执行的 shell 步骤;Matrix 不端到端运行 |
|
|
299
301
|
| verify | `/code-review` | 需要 Standards 与 Spec 双轴证据 |
|
|
300
302
|
|
|
301
|
-
Matrix 可以推荐但绝不嵌套以下 user-invoked handoff:`setup-matt-pocock-skills`、`improve-codebase-architecture`、`wayfinder`、`handoff`、`to-questionnaire`。它们由用户在活动阶段外显式运行,选中的结果可以再进入受治理 Change。
|
|
303
|
+
Matrix 可以推荐但绝不嵌套以下 user-invoked handoff:`setup-matt-pocock-skills`、`improve-codebase-architecture`、`wayfinder`、`handoff`、`retro`、`to-questionnaire`。它们由用户在活动阶段外显式运行,选中的结果可以再进入受治理 Change。
|
|
302
304
|
|
|
303
305
|
Arch 在 `code-review` 后记录由 Runtime 管理的审查回执,把 fixed point 与已提交的 HEAD diff 绑定到当前 Contract、审查正文和工作区。正常的 `code-review` 回执要求 Matrix 管理资产之外的候选工作区是干净的。无可用 Git 基线、已提交 diff 为空、仍存在 staged/unstaged/untracked 候选,或正确安装的 capability 真实失败时,Matrix 可为该 revision 执行一次明确标记的同能力 fallback;其中 `uncommitted-worktree` 会同时绑定 fixed point 与完整工作区候选的内容 hash。安装完整性失败不得 fallback。只有标题或自述、但没有匹配回执时,Verify 不能推进。
|
|
304
306
|
|
|
305
|
-
安装但保持 standalone 的 Skill 是 `ask-matt`、`grill-with-docs`、`triage`、`to-spec`、`to-tickets`、`grill-me`、`teach`、`wait-what`。`implement` 与
|
|
307
|
+
安装但保持 standalone 的 Skill 是 `ask-matt`、`grill-with-docs`、`triage`、`to-spec`、`to-tickets`、`grill-me`、`teach`、`wait-what`、`pr`。`implement` 与 `implement-spec` 可能接管 Matrix 所有的 TDD、review、stage 或 commit 副作用,因此 0.1.7 不安装也不管理它们;已有副本(含遗留的 `resolving-merge-conflicts`)会被保留并报告为未管理额外项。安装不代表自动调用;任何 companion 都不得推进、提交、归档、恢复或写 Matrix 状态。
|
|
306
308
|
|
|
307
309
|
---
|
|
308
310
|
|
|
@@ -33,7 +33,7 @@ An explicit mode wins; otherwise Runtime uses the project `default_orchestration
|
|
|
33
33
|
## Orchestration
|
|
34
34
|
|
|
35
35
|
- **Prim** uses Matrix's own capability in every phase and never requires Matt Skills.
|
|
36
|
-
- **Arch** conditionally invokes the ten reviewed automatic capabilities frozen by the active Change. Matrix 0.1.
|
|
36
|
+
- **Arch** conditionally invokes the ten reviewed automatic capabilities frozen by the active Change. Matrix 0.1.7 reviews all 27 official Matt Skills v1.3.1 roles and installs only the 25 compatible Skills project-locally; `implement` and `implement-spec` are excluded.
|
|
37
37
|
|
|
38
38
|
Both orchestration modes use the same selected workflow profile. `full` uses `open → design → build → verify → archive`; `hotfix` and `tweak` share one internal `lightweight` profile, `open → build → verify → archive`, with different evidence policies. Companion Skills never write Matrix state, transition, commit, archive, or create competing workflow artifacts.
|
|
39
39
|
|
|
@@ -73,7 +73,7 @@ Use it only when the user explicitly chooses a different implementation agent; n
|
|
|
73
73
|
|
|
74
74
|
## Cross-Cutting Skills
|
|
75
75
|
|
|
76
|
-
Matrix never nests user-invoked Matt Skills. When relevant, explain the reason and ask the user to invoke one explicitly: `setup-matt-pocock-skills` for one-time setup, `improve-codebase-architecture` for an out-of-band scan, `wayfinder` for generating a separate large-effort candidate, `handoff` at a context boundary, or `to-questionnaire` when another person owns blocking facts. `ask-matt`, `grill-with-docs`, `triage`, `to-spec`, `to-tickets`, `grill-me`, `teach`,
|
|
76
|
+
Matrix never nests user-invoked Matt Skills. When relevant, explain the reason and ask the user to invoke one explicitly: `setup-matt-pocock-skills` for one-time setup, `improve-codebase-architecture` for an out-of-band scan, `wayfinder` for generating a separate large-effort candidate, `handoff` at a context boundary, `retro` for a post-session agent-environment retrospective, or `to-questionnaire` when another person owns blocking facts. `ask-matt`, `grill-with-docs`, `triage`, `to-spec`, `to-tickets`, `grill-me`, `teach`, `wait-what`, and `pr` remain standalone. Matrix does not install or manage `implement` or `implement-spec`; preserve pre-existing copies (including any legacy `resolving-merge-conflicts`) as unmanaged extras and never suggest them inside an active Change.
|
|
77
77
|
|
|
78
78
|
## Rules
|
|
79
79
|
|
|
@@ -84,5 +84,5 @@ Matrix never nests user-invoked Matt Skills. When relevant, explain the reason a
|
|
|
84
84
|
- `node <matrix-skill-directory>/scripts/matrix-runtime.mjs doctor` is read-only. Every transaction or stale-lock repair must explicitly bind the identity reported by doctor; do not edit or delete `.matrix/transactions/` or `.matrix/workflow.lock`.
|
|
85
85
|
- Do not replace required evidence with an assertion that work is complete.
|
|
86
86
|
- Pause for user confirmation at material architecture/scope decisions and before archive/commit.
|
|
87
|
-
- Before entering Build (full: after the design guard; lightweight: merged into the `transition build --confirmed` pause), present the implementation-actor choice — continue with the current agent/model, switch the model in the user's client, or switch the implementation agent via `$matrix-handoff` — and
|
|
87
|
+
- Before entering Build (full: after the design guard; lightweight: merged into the `transition build --confirmed` pause), present the implementation-actor choice — continue with the current agent/model, switch the model in the user's client, or switch the implementation agent via `$matrix-handoff` — and pass the recorded choice to the Runtime with `transition build --executor <current|model|handoff:<agent-id>>` (lightweight also carries `--confirmed`). The Runtime rejects Build entry without it and stores the choice as `implementation_actor`.
|
|
88
88
|
- On shortcut scope expansion, run `node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason design-gap`; Runtime upgrades the change to `full`. Never silently continue the old contract.
|
|
@@ -34,3 +34,5 @@ node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
After successful commit, the change is under `.matrix/archive/` and the workflow is complete.
|
|
37
|
+
|
|
38
|
+
Optionally, when the session produced findings worth keeping (repeated friction, missing guardrails, unclear pointers), recommend that the user run `retro` (a user-invoked Matt handoff) to turn them into agent-environment improvements. Recommend only; never invoke it inside the workflow.
|
|
@@ -20,7 +20,7 @@ Use Matrix's own implementation and test discipline.
|
|
|
20
20
|
- invoke `writing-for-agents` when the approved Contract changes agent-facing instructions;
|
|
21
21
|
- invoke `wizard` only to generate and statically verify human-run shell steps required by the Contract; never execute the wizard end-to-end or collect secrets.
|
|
22
22
|
|
|
23
|
-
Resolve an in-progress merge/rebase through Matrix-owned conflict handling
|
|
23
|
+
Resolve an in-progress merge/rebase through Matrix-owned conflict handling; never hand lifecycle control to a legacy `resolving-merge-conflicts` copy or any skill that stages, continues, or commits on its own. Never invoke `implement` or `implement-spec` inside an active Change.
|
|
24
24
|
|
|
25
25
|
Announce each triggered capability and reason. No companion may commit, review, transition, archive, or broaden scope. A correctly installed capability gets at most one Matrix-owned fallback for that same capability; record the Skill, failure, fallback, and evidence. Installation-integrity failure stops the phase.
|
|
26
26
|
|
|
@@ -44,25 +44,25 @@ node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard design
|
|
|
44
44
|
|
|
45
45
|
## Implementation Decision Point
|
|
46
46
|
|
|
47
|
-
After the design guard passes and before `transition build`, pause and present the implementation-actor choice to the user. Do not transition without an explicit choice:
|
|
47
|
+
After the design guard passes and before `transition build`, pause and present the implementation-actor choice to the user. Do not transition without an explicit choice. The Runtime enforces this gate: `transition build` fails with `EXECUTOR_CONFIRMATION_REQUIRED` unless it carries the recorded choice, which is stored as `implementation_actor` in the change state.
|
|
48
48
|
|
|
49
49
|
### Option A: Continue with the current agent / model (default)
|
|
50
50
|
|
|
51
51
|
Run transition and enter `$matrix-build`:
|
|
52
52
|
|
|
53
53
|
```powershell
|
|
54
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build
|
|
54
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --executor current
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
Then enter `$matrix-build` to implement directly in this session.
|
|
58
58
|
|
|
59
59
|
### Option B: Switch the model, keep this agent
|
|
60
60
|
|
|
61
|
-
The user switches the model in their own client (for example, a stronger model for design, an efficient one for implementation), returns to this session, and confirms. Then run transition
|
|
61
|
+
The user switches the model in their own client (for example, a stronger model for design, an efficient one for implementation), returns to this session, and confirms. Then run the transition with `--executor model`. Matrix cannot see the client-side model; it provides the mandatory pause point only.
|
|
62
62
|
|
|
63
63
|
### Option C: Switch the implementation agent
|
|
64
64
|
|
|
65
|
-
First approve the frozen contract by transitioning to Build, then run `$matrix-handoff` to export a bounded task package for
|
|
65
|
+
First approve the frozen contract by transitioning to Build with the chosen agent recorded (`--executor handoff:<agent-id>`), then run `$matrix-handoff` to export a bounded task package for that agent (for example Codex designs, Claude Code implements; or zcode designs, opencode implements). This:
|
|
66
66
|
- Does not change the Build phase or state beyond the preceding transition
|
|
67
67
|
- Creates `artifacts/handoff-task-<task-id>.md` with all implementation details
|
|
68
68
|
- Includes acceptance criteria, test seams, and required commands
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
|
-
display_name: "Matrix
|
|
3
|
-
short_description: "Export
|
|
4
|
-
default_prompt: "Use $matrix-
|
|
2
|
+
display_name: "Matrix Implementation Handoff"
|
|
3
|
+
short_description: "Export an approved Matrix Contract as a bounded task package"
|
|
4
|
+
default_prompt: "Use $matrix-handoff to export the approved Contract to an implementation agent."
|
|
@@ -48,6 +48,6 @@ Companion output is evidence for the Matrix proposal. It must not create another
|
|
|
48
48
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard open
|
|
49
49
|
# full
|
|
50
50
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition design
|
|
51
|
-
# hotfix/tweak, only after explicit confirmation
|
|
52
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --confirmed
|
|
51
|
+
# hotfix/tweak, only after explicit confirmation (actor choice merged into the same pause)
|
|
52
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --confirmed --executor <choice>
|
|
53
53
|
```
|
|
@@ -13,8 +13,8 @@ Write verification prose in `artifact_language` from inspect while preserving th
|
|
|
13
13
|
|
|
14
14
|
This phase can receive implementation from two sources:
|
|
15
15
|
|
|
16
|
-
1. **Direct
|
|
17
|
-
2. **
|
|
16
|
+
1. **Direct implementation** — from the `$matrix-build` phase in this session
|
|
17
|
+
2. **Handed-off implementation** — from a `$matrix-handoff` task package executed by another implementation agent
|
|
18
18
|
|
|
19
19
|
Regardless of source, the verification process is the same: check that implementation evidence meets the plan's requirements.
|
|
20
20
|
|
|
@@ -27,7 +27,7 @@ Before starting verification, ensure:
|
|
|
27
27
|
- [ ] All commands from the plan's `## Validation` section have been run
|
|
28
28
|
- [ ] Test results are recorded
|
|
29
29
|
|
|
30
|
-
If these are missing (
|
|
30
|
+
If these are missing (for example, a handed-off agent did not produce complete evidence), return to `$matrix-build` or ask the implementation agent to fill in the missing evidence.
|
|
31
31
|
|
|
32
32
|
## Orchestration
|
|
33
33
|
|
|
@@ -55,7 +55,7 @@ Never label fallback output as a successful `code-review` run. `empty-head-diff`
|
|
|
55
55
|
## Failure Handling
|
|
56
56
|
|
|
57
57
|
If verification or review fails:
|
|
58
|
-
- If the issue is in the implementation, run `node <matrix-skill-directory>/scripts/matrix-runtime.mjs return build --reason verification-failed`, then enter `$matrix-build` or ask
|
|
58
|
+
- If the issue is in the implementation, run `node <matrix-skill-directory>/scripts/matrix-runtime.mjs return build --reason verification-failed`, then enter `$matrix-build` or ask the implementation agent to fix it.
|
|
59
59
|
- If the issue is in the acceptance criteria or design, run `node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason acceptance-or-design-gap`, then enter `$matrix-design`.
|
|
60
60
|
|
|
61
61
|
Both Return paths rotate the current `verification.md` and any `review-receipt.json` into revisioned evidence history. Do not copy stale conclusions or receipts back into the new current evidence.
|
|
@@ -28,7 +28,7 @@ node <matrix-skill-directory>/scripts/matrix-runtime.mjs init <change-id> --work
|
|
|
28
28
|
## 编排模式
|
|
29
29
|
|
|
30
30
|
- **Prim**:各阶段使用 Matrix 自身能力,不依赖 Matt Skills。
|
|
31
|
-
- **Arch**:仅在任务事实满足触发条件时,调用活动 Change 冻结的十项自动能力。Matrix 0.1.
|
|
31
|
+
- **Arch**:仅在任务事实满足触发条件时,调用活动 Change 冻结的十项自动能力。Matrix 0.1.7 审查 Matt Skills v1.3.1 官方 27 项角色,只把其中 25 项兼容 Skill 安装在项目本地;排除 `implement` 与 `implement-spec`。
|
|
32
32
|
|
|
33
33
|
两种编排模式使用已选定的 workflow profile:`full` 走 `open → design → build → verify → archive`;`hotfix` 与 `tweak` 共用内部 `lightweight` profile,走 `open → build → verify → archive`,仅证据策略不同。Arch 能力不得写 Matrix 状态、推进阶段、提交、归档或创建竞争工作流。
|
|
34
34
|
|
|
@@ -71,7 +71,7 @@ full 的 `design -> build` 会批准 proposal/design/plan;lightweight 的 `ope
|
|
|
71
71
|
|
|
72
72
|
## 显式 Matt handoff
|
|
73
73
|
|
|
74
|
-
Matrix 不嵌套 user-invoked Skill。适用时只解释原因,并让用户显式调用:一次性配置使用 `setup-matt-pocock-skills`,工作流外架构扫描使用 `improve-codebase-architecture`,独立大型候选生成使用 `wayfinder`,上下文边界使用 `handoff`,他人掌握阻塞事实时使用 `to-questionnaire`。`ask-matt`、`grill-with-docs`、`triage`、`to-spec`、`to-tickets`、`grill-me`、`teach`、`wait-what` 保持 standalone。Matrix 不安装也不管理 `implement`
|
|
74
|
+
Matrix 不嵌套 user-invoked Skill。适用时只解释原因,并让用户显式调用:一次性配置使用 `setup-matt-pocock-skills`,工作流外架构扫描使用 `improve-codebase-architecture`,独立大型候选生成使用 `wayfinder`,上下文边界使用 `handoff`,会话复盘改进 agent 环境使用 `retro`,他人掌握阻塞事实时使用 `to-questionnaire`。`ask-matt`、`grill-with-docs`、`triage`、`to-spec`、`to-tickets`、`grill-me`、`teach`、`wait-what`、`pr` 保持 standalone。Matrix 不安装也不管理 `implement` 与 `implement-spec`;已有副本(含遗留的 `resolving-merge-conflicts`)保留为未管理额外项,活动 Change 内不得建议使用。
|
|
75
75
|
|
|
76
76
|
## 规则
|
|
77
77
|
|
|
@@ -80,5 +80,5 @@ Matrix 不嵌套 user-invoked Skill。适用时只解释原因,并让用户显
|
|
|
80
80
|
- 成功 Archive 必须使用两步乐观提交:先运行 `node <matrix-skill-directory>/scripts/matrix-runtime.mjs archive --dry-run`,再将其精确 hash 传给 `node <matrix-skill-directory>/scripts/matrix-runtime.mjs archive --expect-preflight <sha256>`;不得绕过预演。
|
|
81
81
|
- `node <matrix-skill-directory>/scripts/matrix-runtime.mjs doctor` 始终只读;transaction 与陈旧锁 repair 必须显式绑定 doctor 报告的 identity,不得手工编辑或删除 `.matrix/transactions/`、`.matrix/workflow.lock`。
|
|
82
82
|
- 重大架构/范围决定和 archive/commit 前应暂停等待用户确认。
|
|
83
|
-
- 进入 Build 前(full 在 design guard 之后;lightweight 并入 `transition build --confirmed` 的暂停)必须呈现执行主体选择——当前 agent/原模型继续、用户客户端切换模型、或经 `$matrix-handoff` 切换实现 agent
|
|
83
|
+
- 进入 Build 前(full 在 design guard 之后;lightweight 并入 `transition build --confirmed` 的暂停)必须呈现执行主体选择——当前 agent/原模型继续、用户客户端切换模型、或经 `$matrix-handoff` 切换实现 agent——并以 `transition build --executor <current|model|handoff:<agent-id>>` 把选择传给 Runtime(lightweight 同时携带 `--confirmed`)。缺省时 Runtime 拒绝进入 Build,并把选择存为 `implementation_actor`。
|
|
84
84
|
- shortcut 范围扩大时执行 `node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason design-gap`;Runtime 将其升级为 full。
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: matrix-build
|
|
3
|
-
description: 用测试优先的纵向切片实现冻结的 Matrix 计划。仅在活动 Matrix 阶段为 build 时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Matrix Build
|
|
7
|
-
|
|
8
|
-
读取 `node <matrix-skill-directory>/scripts/matrix-runtime.mjs inspect` 与已批准 Contract。full/legacy-full 读取 proposal/design/plan;lightweight 只读取紧凑 proposal,不补写 Design 产物。
|
|
9
|
-
|
|
10
|
-
Build 证据与面向用户的说明使用 `artifact_language`;Runtime 所需英文标题 token 保持不变。
|
|
11
|
-
|
|
12
|
-
## 编排
|
|
13
|
-
|
|
14
|
-
- **Prim**:使用 Matrix 自身实现与测试能力。
|
|
15
|
-
- **Arch**:可测试行为变化时调用 `tdd`;真实失败且根因未知时调用 `diagnosing-bugs`;批准 Contract 修改 agent-facing 指令时调用 `writing-for-agents`;只有 Contract 需要人工执行 shell 步骤时,才用 `wizard` 生成并静态验证脚本,绝不端到端执行或收集秘密。
|
|
16
|
-
|
|
17
|
-
进行中的 merge/rebase 冲突由 Matrix
|
|
18
|
-
|
|
19
|
-
调用前说明能力与原因。companion 不得 commit、review、transition、archive 或扩大范围。正确安装的能力失败时最多执行一次同能力 Matrix fallback,并记录调用、失败、fallback 与证据;安装完整性问题必须停止并修复。
|
|
20
|
-
|
|
21
|
-
## 范围纪律
|
|
22
|
-
|
|
23
|
-
若实现暴露范围或设计变化,停止并执行:
|
|
24
|
-
|
|
25
|
-
```powershell
|
|
26
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason design-gap
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
回到 Design 会清除既有 Contract 批准并轮换当前验证证据;重新进入 Build 必须生成新的批准与新证据。
|
|
30
|
-
|
|
31
|
-
## 流程
|
|
32
|
-
|
|
33
|
-
1. 对可测试的行为变化使用 `tdd` 纵向切片;纯文档或不可观察的机械变更使用相称的静态检查。
|
|
34
|
-
2. 在 `## Build evidence` 记录共同事实;hotfix 另写 `## Reproduction evidence`、`## Root cause`,tweak 另写 `## Scope evidence`。
|
|
35
|
-
3. 运行 Build guard;它同时确认批准的 Contract 仍精确匹配。
|
|
36
|
-
4. 通过后推进至 Verify,并进入 `$matrix-verify`。
|
|
37
|
-
|
|
38
|
-
```powershell
|
|
39
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard build
|
|
40
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition verify
|
|
41
|
-
```
|
|
1
|
+
---
|
|
2
|
+
name: matrix-build
|
|
3
|
+
description: 用测试优先的纵向切片实现冻结的 Matrix 计划。仅在活动 Matrix 阶段为 build 时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Matrix Build
|
|
7
|
+
|
|
8
|
+
读取 `node <matrix-skill-directory>/scripts/matrix-runtime.mjs inspect` 与已批准 Contract。full/legacy-full 读取 proposal/design/plan;lightweight 只读取紧凑 proposal,不补写 Design 产物。
|
|
9
|
+
|
|
10
|
+
Build 证据与面向用户的说明使用 `artifact_language`;Runtime 所需英文标题 token 保持不变。
|
|
11
|
+
|
|
12
|
+
## 编排
|
|
13
|
+
|
|
14
|
+
- **Prim**:使用 Matrix 自身实现与测试能力。
|
|
15
|
+
- **Arch**:可测试行为变化时调用 `tdd`;真实失败且根因未知时调用 `diagnosing-bugs`;批准 Contract 修改 agent-facing 指令时调用 `writing-for-agents`;只有 Contract 需要人工执行 shell 步骤时,才用 `wizard` 生成并静态验证脚本,绝不端到端执行或收集秘密。
|
|
16
|
+
|
|
17
|
+
进行中的 merge/rebase 冲突由 Matrix 自身治理,不得把生命周期控制交给遗留的 `resolving-merge-conflicts` 副本或任何会自行 stage、continue、commit 的 skill。活动 Change 内不得调用 `implement` 与 `implement-spec`。
|
|
18
|
+
|
|
19
|
+
调用前说明能力与原因。companion 不得 commit、review、transition、archive 或扩大范围。正确安装的能力失败时最多执行一次同能力 Matrix fallback,并记录调用、失败、fallback 与证据;安装完整性问题必须停止并修复。
|
|
20
|
+
|
|
21
|
+
## 范围纪律
|
|
22
|
+
|
|
23
|
+
若实现暴露范围或设计变化,停止并执行:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs return design --reason design-gap
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
回到 Design 会清除既有 Contract 批准并轮换当前验证证据;重新进入 Build 必须生成新的批准与新证据。
|
|
30
|
+
|
|
31
|
+
## 流程
|
|
32
|
+
|
|
33
|
+
1. 对可测试的行为变化使用 `tdd` 纵向切片;纯文档或不可观察的机械变更使用相称的静态检查。
|
|
34
|
+
2. 在 `## Build evidence` 记录共同事实;hotfix 另写 `## Reproduction evidence`、`## Root cause`,tweak 另写 `## Scope evidence`。
|
|
35
|
+
3. 运行 Build guard;它同时确认批准的 Contract 仍精确匹配。
|
|
36
|
+
4. 通过后推进至 Verify,并进入 `$matrix-verify`。
|
|
37
|
+
|
|
38
|
+
```powershell
|
|
39
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard build
|
|
40
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition verify
|
|
41
|
+
```
|
|
@@ -24,15 +24,15 @@ node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard design
|
|
|
24
24
|
|
|
25
25
|
## 执行主体确认点(Build 前)
|
|
26
26
|
|
|
27
|
-
`guard design` 通过后、`transition build`
|
|
27
|
+
`guard design` 通过后、`transition build` 之前,必须暂停并向用户确认执行主体,未确认不得推进。该闸门由 Runtime 强制执行:`transition build` 未携带所记录的选择时报 `EXECUTOR_CONFIRMATION_REQUIRED`,选择会以 `implementation_actor` 写入 change 状态:
|
|
28
28
|
|
|
29
29
|
- **选项 A:当前 agent / 原模型继续(默认)**——直接推进:
|
|
30
30
|
```powershell
|
|
31
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build
|
|
31
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --executor current
|
|
32
32
|
```
|
|
33
33
|
随后进入 `$matrix-build` 在本会话内实现。
|
|
34
|
-
- **选项 B:切换模型、保留本 agent
|
|
35
|
-
- **选项 C:切换执行 agent
|
|
34
|
+
- **选项 B:切换模型、保留本 agent**——用户在自己的客户端完成模型切换(例如设计用强模型、实现用高性价比模型),回到会话确认后以 `--executor model` 推进。Matrix 无法感知客户端模型,只提供强制暂停点。
|
|
35
|
+
- **选项 C:切换执行 agent**——先以 `--executor handoff:<agent-id>` 记录所选 agent 并推进 Build 批准冻结 Contract,再用 `$matrix-handoff` 为目标 agent 导出有界任务包(例如 Codex 设计、Claude Code 实现,或 zcode 设计、opencode 实现)。实现 agent 完成并补齐 `## Build evidence` 后:
|
|
36
36
|
```powershell
|
|
37
37
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard build
|
|
38
38
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition verify
|
|
@@ -35,6 +35,6 @@ companion 输出只能作为当前 proposal 的证据,不得创建第二套工
|
|
|
35
35
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs guard open
|
|
36
36
|
# full
|
|
37
37
|
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition design
|
|
38
|
-
# hotfix/tweak
|
|
39
|
-
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --confirmed
|
|
38
|
+
# hotfix/tweak,仅在用户明确确认后(执行主体选择并入同一次暂停)
|
|
39
|
+
node <matrix-skill-directory>/scripts/matrix-runtime.mjs transition build --confirmed --executor <choice>
|
|
40
40
|
```
|
package/package.json
CHANGED
package/src/catalog.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { MATT_INSTALLABLE_SKILLS, MATT_ROLES } from "./matt-catalog.mjs";
|
|
7
7
|
|
|
8
8
|
export const LANGUAGE_IDS = ["en", "zh-CN"];
|
|
9
|
-
export const PLATFORM_IDS = ["claude-code", "codex"];
|
|
9
|
+
export const PLATFORM_IDS = ["claude-code", "codex", "zcode"];
|
|
10
10
|
export const MATRIX_SKILLS = [
|
|
11
11
|
"matrix", "matrix-open", "matrix-design", "matrix-build", "matrix-verify",
|
|
12
12
|
"matrix-archive", "matrix-hotfix", "matrix-tweak", "matrix-status", "matrix-handoff"
|
|
@@ -28,6 +28,14 @@ export const PLATFORMS = {
|
|
|
28
28
|
id: "codex", name: "Codex", skillsCliAgent: "codex",
|
|
29
29
|
skillRoot(base) { return path.join(base, ".agents", "skills"); },
|
|
30
30
|
legacyRoots(base) { return [path.join(base, ".codex", "skills")]; }
|
|
31
|
+
},
|
|
32
|
+
// Agents that read the Agent Skills open-standard directory (.agents/skills)
|
|
33
|
+
// by default — opencode, Kimi Code, and other compatible tools — share the
|
|
34
|
+
// Codex installation and need no dedicated platform entry.
|
|
35
|
+
zcode: {
|
|
36
|
+
id: "zcode", name: "ZCode", skillsCliAgent: "zcode",
|
|
37
|
+
skillRoot(base) { return path.join(base, ".zcode", "skills"); },
|
|
38
|
+
legacyRoots() { return []; }
|
|
31
39
|
}
|
|
32
40
|
};
|
|
33
41
|
|
package/src/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { PLATFORMS } from "./catalog.js";
|
|
5
|
+
import { PLATFORMS, PLATFORM_IDS } from "./catalog.js";
|
|
6
6
|
import { createDistribution, installedIntent } from "./distribution.js";
|
|
7
7
|
import { createMattAdapter, inspectMattInstallation } from "./matt.js";
|
|
8
8
|
import { text } from "./messages.js";
|
|
@@ -15,7 +15,7 @@ import { MATT_COMPATIBILITY } from "./matt-catalog.mjs";
|
|
|
15
15
|
|
|
16
16
|
const packagePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
17
17
|
const version = JSON.parse(fs.readFileSync(packagePath, "utf8")).version;
|
|
18
|
-
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
|
|
18
|
+
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 <${PLATFORM_IDS.join("|")}> (repeatable)\n --mode <copy|symlink>\n --with-mattpocock | --without-mattpocock\n --force-matt (with --with-mattpocock; replace modified Matt Skills)\n --default-orchestration <prim|arch>\n update only: --all | --project-only (update scope across indexed projects)\n --skip-self-update --force --yes, -y --dry-run --json --no-color`;
|
|
19
19
|
|
|
20
20
|
function parse(argv) {
|
|
21
21
|
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, all: false, projectOnly: false };
|
|
@@ -69,7 +69,7 @@ async function intentFrom(options, ui) {
|
|
|
69
69
|
const language = options.language ?? (options.yes ? "en" : await ui.select("Language / 语言", [{ label: "English", value: "en" }, { label: "中文", value: "zh-CN" }]));
|
|
70
70
|
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" }]));
|
|
71
71
|
let platforms = options.platforms;
|
|
72
|
-
if (!platforms.length && interactive && !options.yes) platforms = await ui.selectMany(text(language, "platformsQuestion"),
|
|
72
|
+
if (!platforms.length && interactive && !options.yes) platforms = await ui.selectMany(text(language, "platformsQuestion"), PLATFORM_IDS.map((id) => ({ label: PLATFORMS[id].name, value: id })));
|
|
73
73
|
const matt = options.matt ?? (interactive && !options.yes ? (await ui.confirm(text(language, "mattQuestion"), true, labelsFor(language)) ? "missing" : "none") : "missing");
|
|
74
74
|
const defaultOrchestration = options.defaultOrchestration ?? (interactive && !options.yes && matt === "missing"
|
|
75
75
|
? await ui.select(text(language, "orchestrationQuestion"), [
|
|
@@ -115,12 +115,12 @@ async function refresh(intent, options, ui) {
|
|
|
115
115
|
}
|
|
116
116
|
if (options.json) {
|
|
117
117
|
if (!evaluation.ok || options.dryRun) {
|
|
118
|
-
const output = options.updateMode ? { ...evaluation, matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms }) } : evaluation;
|
|
118
|
+
const output = options.updateMode ? { ...evaluation, matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms, action: "matrix update --with-mattpocock" }) } : evaluation;
|
|
119
119
|
console.log(JSON.stringify(output)); return evaluation.ok ? 0 : 2;
|
|
120
120
|
}
|
|
121
121
|
const result = distribution.commit(evaluation.plan);
|
|
122
122
|
const output = { ...evaluation, ...result, intent: evaluation.intent, observations: evaluation.observations, actions: evaluation.actions,
|
|
123
|
-
...(options.updateMode ? { matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms }) } : {}) };
|
|
123
|
+
...(options.updateMode ? { matt: inspectMattInstallation({ projectRoot: intent.projectRoot, home: intent.home, platforms: intent.platforms, action: "matrix update --with-mattpocock" }) } : {}) };
|
|
124
124
|
console.log(JSON.stringify(output));
|
|
125
125
|
return !result.ok ? 2 : result.code === "PARTIAL" ? 1 : 0;
|
|
126
126
|
}
|
package/src/distribution.js
CHANGED
|
@@ -40,12 +40,12 @@ const configContent = (existing, defaultOrchestration, scope, language) => {
|
|
|
40
40
|
const values = {
|
|
41
41
|
...existing,
|
|
42
42
|
schema: "matrix/config/v1",
|
|
43
|
-
auto_transition: existing.auto_transition === "false" ? "false" : "true",
|
|
44
43
|
default_orchestration: defaultOrchestration,
|
|
45
44
|
installation_scope: scope,
|
|
46
45
|
language
|
|
47
46
|
};
|
|
48
|
-
|
|
47
|
+
delete values.auto_transition;
|
|
48
|
+
const preferred = ["schema", "default_orchestration", "installation_scope", "language"];
|
|
49
49
|
const keys = [...preferred, ...Object.keys(values).filter((key) => !preferred.includes(key)).sort()];
|
|
50
50
|
return `${keys.map((key) => `${key}: ${values[key]}`).join("\n")}\n`;
|
|
51
51
|
};
|
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.8",
|
|
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/messages.js
CHANGED
|
@@ -5,7 +5,7 @@ export const messages = {
|
|
|
5
5
|
project: "Project (current directory)", global: "Global Matrix Skills",
|
|
6
6
|
copy: "Copy (recommended)", symlink: "Symlink (advanced)",
|
|
7
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
|
|
8
|
+
noPlatform: "No verified platform was detected. Select Claude Code, Codex, or ZCode.",
|
|
9
9
|
preview: "Planned changes", confirm: "Apply these changes?", doctor: "Installation diagnosis",
|
|
10
10
|
languageQuestion: "Language", scopeQuestion: "Installation scope", platformsQuestion: "Platforms", orchestrationQuestion: "Default orchestration",
|
|
11
11
|
orchestrationArchDetail: "Orchestrates the installed Matt Skills cohort (requires Matt Skills).", orchestrationPrimDetail: "Uses Matrix's own capabilities only (no Matt dependency).",
|
|
@@ -37,7 +37,7 @@ export const messages = {
|
|
|
37
37
|
project: "项目(当前目录)", global: "全局 Matrix Skills",
|
|
38
38
|
copy: "复制(推荐)", symlink: "符号链接(高级)",
|
|
39
39
|
matrix: "Matrix", matt: "Matt Pocock skills", installed: "已安装", ready: "Matrix 已就绪。",
|
|
40
|
-
noPlatform: "未检测到已验证的平台。请选择 Claude Code、Codex
|
|
40
|
+
noPlatform: "未检测到已验证的平台。请选择 Claude Code、Codex 或 ZCode。",
|
|
41
41
|
preview: "计划变更", confirm: "确认应用这些变更?", doctor: "安装诊断",
|
|
42
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
43
|
}
|
package/src/runtime-resolver.js
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { MATRIX_VERSION, PLATFORMS, hashDirectory, releaseCatalog } from "./catalog.js";
|
|
4
|
-
|
|
5
|
-
function readJson(file) {
|
|
6
|
-
try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return null; }
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function installationScope(projectRoot) {
|
|
10
|
-
try {
|
|
11
|
-
const line = fs.readFileSync(path.join(projectRoot, ".matrix", "config.yaml"), "utf8").split(/\r?\n/).find((value) => value.startsWith("installation_scope:"));
|
|
12
|
-
return line?.split(":").slice(1).join(":").trim() === "global" ? "global" : "project";
|
|
13
|
-
} catch { return "project"; }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function runtimeCommand(runtime) {
|
|
17
|
-
const quoted = process.platform === "win32" ? `"${runtime}"` : `'${runtime.replaceAll("'", "'\\''")}'`;
|
|
18
|
-
return `node ${quoted}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function resolveProjectRuntime({ projectRoot = process.cwd() } = {}) {
|
|
22
|
-
const root = path.resolve(projectRoot);
|
|
23
|
-
const manifest = readJson(path.join(root, ".matrix", "installation.json"));
|
|
24
|
-
if (!manifest) return installationScope(root) === "global"
|
|
25
|
-
? { ok: true, code: "GLOBAL_INSTALLATION", runtime: null }
|
|
26
|
-
: { ok: true, code: "PROJECT_INSTALLATION_ABSENT", runtime: null };
|
|
27
|
-
const candidates = [];
|
|
28
|
-
let currentCatalog = null;
|
|
29
|
-
let catalogUnavailable = false;
|
|
30
|
-
try { currentCatalog = releaseCatalog(manifest.language ?? "en"); } catch { catalogUnavailable = true; }
|
|
31
|
-
for (const platform of
|
|
32
|
-
const expected = manifest.platforms?.[platform]?.skills?.matrix?.hash;
|
|
33
|
-
if (!expected) continue;
|
|
34
|
-
const matrixRoot = path.join(PLATFORMS[platform].skillRoot(root), "matrix");
|
|
35
|
-
const runtime = path.join(matrixRoot, "scripts", "matrix-runtime.mjs");
|
|
36
|
-
if (!fs.existsSync(runtime)) { candidates.push({ platform, matrixRoot, runtime, reason: "missing" }); continue; }
|
|
37
|
-
try {
|
|
38
|
-
const actual = hashDirectory(matrixRoot);
|
|
39
|
-
if (actual === expected) {
|
|
40
|
-
if (manifest.catalogVersion !== MATRIX_VERSION) {
|
|
41
|
-
const catalogVersion = manifest.catalogVersion ?? null;
|
|
42
|
-
return {
|
|
43
|
-
ok: false,
|
|
44
|
-
code: catalogVersion ? "PROJECT_RUNTIME_VERSION_MISMATCH" : "PROJECT_RUNTIME_VERSION_UNKNOWN",
|
|
45
|
-
message: catalogVersion
|
|
46
|
-
? `The project Matrix Runtime is ${catalogVersion}, while this launcher is ${MATRIX_VERSION}. The project remains authoritative, but a different-release Runtime requires explicit invocation.`
|
|
47
|
-
: `The project Matrix Runtime has no release identity. The project remains authoritative, but an unidentified Runtime requires explicit invocation.`,
|
|
48
|
-
platform,
|
|
49
|
-
runtime,
|
|
50
|
-
catalogVersion,
|
|
51
|
-
launcherVersion: MATRIX_VERSION,
|
|
52
|
-
recovery_command: runtimeCommand(runtime)
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
if (catalogUnavailable
|
|
56
|
-
|| manifest.catalogDigest !== currentCatalog.digest || expected !== currentCatalog.skills.matrix) {
|
|
57
|
-
return {
|
|
58
|
-
ok: false,
|
|
59
|
-
code: "PROJECT_RUNTIME_RELEASE_MISMATCH",
|
|
60
|
-
message: `The project Matrix Runtime claims ${MATRIX_VERSION} but does not match that release catalog. Run matrix update.`,
|
|
61
|
-
platform,
|
|
62
|
-
runtime,
|
|
63
|
-
catalogVersion: manifest.catalogVersion,
|
|
64
|
-
expected: currentCatalog?.skills.matrix ?? null,
|
|
65
|
-
actual
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
return { ok: true, code: "PROJECT_RUNTIME", platform, runtime, catalogVersion: manifest.catalogVersion };
|
|
69
|
-
}
|
|
70
|
-
candidates.push({ platform, matrixRoot, runtime, reason: "modified" });
|
|
71
|
-
} catch { candidates.push({ platform, matrixRoot, runtime, reason: "unreadable" }); }
|
|
72
|
-
}
|
|
73
|
-
return candidates.length
|
|
74
|
-
? { ok: false, code: "PROJECT_RUNTIME_UNTRUSTED", message: "The project Matrix Runtime does not match its installation manifest.", findings: candidates }
|
|
75
|
-
: { ok: true, code: "PROJECT_RUNTIME_ABSENT", runtime: null };
|
|
76
|
-
}
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { MATRIX_VERSION, PLATFORMS, PLATFORM_IDS, hashDirectory, releaseCatalog } from "./catalog.js";
|
|
4
|
+
|
|
5
|
+
function readJson(file) {
|
|
6
|
+
try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return null; }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function installationScope(projectRoot) {
|
|
10
|
+
try {
|
|
11
|
+
const line = fs.readFileSync(path.join(projectRoot, ".matrix", "config.yaml"), "utf8").split(/\r?\n/).find((value) => value.startsWith("installation_scope:"));
|
|
12
|
+
return line?.split(":").slice(1).join(":").trim() === "global" ? "global" : "project";
|
|
13
|
+
} catch { return "project"; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function runtimeCommand(runtime) {
|
|
17
|
+
const quoted = process.platform === "win32" ? `"${runtime}"` : `'${runtime.replaceAll("'", "'\\''")}'`;
|
|
18
|
+
return `node ${quoted}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolveProjectRuntime({ projectRoot = process.cwd() } = {}) {
|
|
22
|
+
const root = path.resolve(projectRoot);
|
|
23
|
+
const manifest = readJson(path.join(root, ".matrix", "installation.json"));
|
|
24
|
+
if (!manifest) return installationScope(root) === "global"
|
|
25
|
+
? { ok: true, code: "GLOBAL_INSTALLATION", runtime: null }
|
|
26
|
+
: { ok: true, code: "PROJECT_INSTALLATION_ABSENT", runtime: null };
|
|
27
|
+
const candidates = [];
|
|
28
|
+
let currentCatalog = null;
|
|
29
|
+
let catalogUnavailable = false;
|
|
30
|
+
try { currentCatalog = releaseCatalog(manifest.language ?? "en"); } catch { catalogUnavailable = true; }
|
|
31
|
+
for (const platform of PLATFORM_IDS) {
|
|
32
|
+
const expected = manifest.platforms?.[platform]?.skills?.matrix?.hash;
|
|
33
|
+
if (!expected) continue;
|
|
34
|
+
const matrixRoot = path.join(PLATFORMS[platform].skillRoot(root), "matrix");
|
|
35
|
+
const runtime = path.join(matrixRoot, "scripts", "matrix-runtime.mjs");
|
|
36
|
+
if (!fs.existsSync(runtime)) { candidates.push({ platform, matrixRoot, runtime, reason: "missing" }); continue; }
|
|
37
|
+
try {
|
|
38
|
+
const actual = hashDirectory(matrixRoot);
|
|
39
|
+
if (actual === expected) {
|
|
40
|
+
if (manifest.catalogVersion !== MATRIX_VERSION) {
|
|
41
|
+
const catalogVersion = manifest.catalogVersion ?? null;
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
code: catalogVersion ? "PROJECT_RUNTIME_VERSION_MISMATCH" : "PROJECT_RUNTIME_VERSION_UNKNOWN",
|
|
45
|
+
message: catalogVersion
|
|
46
|
+
? `The project Matrix Runtime is ${catalogVersion}, while this launcher is ${MATRIX_VERSION}. The project remains authoritative, but a different-release Runtime requires explicit invocation.`
|
|
47
|
+
: `The project Matrix Runtime has no release identity. The project remains authoritative, but an unidentified Runtime requires explicit invocation.`,
|
|
48
|
+
platform,
|
|
49
|
+
runtime,
|
|
50
|
+
catalogVersion,
|
|
51
|
+
launcherVersion: MATRIX_VERSION,
|
|
52
|
+
recovery_command: runtimeCommand(runtime)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (catalogUnavailable
|
|
56
|
+
|| manifest.catalogDigest !== currentCatalog.digest || expected !== currentCatalog.skills.matrix) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
code: "PROJECT_RUNTIME_RELEASE_MISMATCH",
|
|
60
|
+
message: `The project Matrix Runtime claims ${MATRIX_VERSION} but does not match that release catalog. Run matrix update.`,
|
|
61
|
+
platform,
|
|
62
|
+
runtime,
|
|
63
|
+
catalogVersion: manifest.catalogVersion,
|
|
64
|
+
expected: currentCatalog?.skills.matrix ?? null,
|
|
65
|
+
actual
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { ok: true, code: "PROJECT_RUNTIME", platform, runtime, catalogVersion: manifest.catalogVersion };
|
|
69
|
+
}
|
|
70
|
+
candidates.push({ platform, matrixRoot, runtime, reason: "modified" });
|
|
71
|
+
} catch { candidates.push({ platform, matrixRoot, runtime, reason: "unreadable" }); }
|
|
72
|
+
}
|
|
73
|
+
return candidates.length
|
|
74
|
+
? { ok: false, code: "PROJECT_RUNTIME_UNTRUSTED", message: "The project Matrix Runtime does not match its installation manifest.", findings: candidates }
|
|
75
|
+
: { ok: true, code: "PROJECT_RUNTIME_ABSENT", runtime: null };
|
|
76
|
+
}
|
package/src/workflow.js
CHANGED
|
@@ -49,6 +49,13 @@ const LEGACY_ARCH_SKILLS = [
|
|
|
49
49
|
"grilling", "domain-modeling", "research", "wayfinder", "prototype",
|
|
50
50
|
"codebase-design", "tdd", "diagnosing-bugs", "resolving-merge-conflicts", "code-review"
|
|
51
51
|
];
|
|
52
|
+
// The bundled runtime is injected without catalog.js, so this platform→skill-root
|
|
53
|
+
// mapping mirrors catalog.js PLATFORMS and is pinned by a parity test.
|
|
54
|
+
export const PLATFORM_SKILL_ROOTS = Object.freeze({
|
|
55
|
+
"claude-code": ".claude/skills",
|
|
56
|
+
codex: ".agents/skills",
|
|
57
|
+
zcode: ".zcode/skills"
|
|
58
|
+
});
|
|
52
59
|
const ARTIFACT_POLICY = {
|
|
53
60
|
proposal: ["## Goal", "## Scope", "## Non-goals", "## Acceptance", "## Risks"],
|
|
54
61
|
design: ["## Decisions", "## Boundaries", "## Test seams", "## Risks"],
|
|
@@ -249,9 +256,11 @@ function archIntegrity(cwd, flow = null, contentHashes = MATT_CONTENT_HASHES) {
|
|
|
249
256
|
}
|
|
250
257
|
const findings = [];
|
|
251
258
|
for (const [platform, record] of platforms) {
|
|
259
|
+
const relativeRoot = PLATFORM_SKILL_ROOTS[platform];
|
|
252
260
|
for (const skill of legacy ? LEGACY_ARCH_SKILLS : MATT_AUTOMATIC_SKILLS) {
|
|
261
|
+
if (!relativeRoot) { findings.push({ platform, skill, reason: "unsupported" }); continue; }
|
|
253
262
|
const installed = legacy ? record?.matt?.skills?.[skill] : mattReceipt?.platforms?.[platform]?.skills?.[skill];
|
|
254
|
-
const expectedRoot = path.join(cwd,
|
|
263
|
+
const expectedRoot = path.join(cwd, relativeRoot, skill);
|
|
255
264
|
const target = legacy ? installed?.root : expectedRoot;
|
|
256
265
|
if (!legacy && installed?.root && path.resolve(installed.root) !== path.resolve(expectedRoot)) {
|
|
257
266
|
findings.push({ platform, skill, reason: "non-project" });
|
|
@@ -328,8 +337,8 @@ function readFlow(p) {
|
|
|
328
337
|
return normalizeFlow(parsed);
|
|
329
338
|
}
|
|
330
339
|
function flowContent(flow) {
|
|
331
|
-
const order = ["schema", "id", "workflow", "workflow_profile", "orchestration", "artifact_language", "arch_catalog_digest", "matt_release", "status", "phase", "revision", "approved_contract_hash", "contract_approved_revision", "title", "created_at", "updated_at", "acceptance", "scope"];
|
|
332
|
-
return `${order.filter((key) => (!["workflow_profile", "artifact_language", "arch_catalog_digest", "matt_release"].includes(key) || flow[key])).map((key) => `${key}: ${flow[key] ?? ""}`).join("\n")}\n`;
|
|
340
|
+
const order = ["schema", "id", "workflow", "workflow_profile", "orchestration", "artifact_language", "arch_catalog_digest", "matt_release", "status", "phase", "revision", "approved_contract_hash", "contract_approved_revision", "implementation_actor", "title", "created_at", "updated_at", "acceptance", "scope"];
|
|
341
|
+
return `${order.filter((key) => (!["workflow_profile", "artifact_language", "arch_catalog_digest", "matt_release", "implementation_actor"].includes(key) || flow[key])).map((key) => `${key}: ${flow[key] ?? ""}`).join("\n")}\n`;
|
|
333
342
|
}
|
|
334
343
|
function active(cwd) { const activeFile = path.join(rootFor(cwd), "active.json"); if (!fs.existsSync(activeFile)) return null; return read(activeFile).change_id; }
|
|
335
344
|
function meaningful(file, headings) {
|
|
@@ -385,7 +394,7 @@ function managedReviewPrefixes(cwd) {
|
|
|
385
394
|
const { manifest, mattReceipt } = orchestrationConfig(cwd);
|
|
386
395
|
const prefixes = [];
|
|
387
396
|
for (const [platform, record] of Object.entries(manifest?.platforms ?? {})) {
|
|
388
|
-
const root = platform
|
|
397
|
+
const root = PLATFORM_SKILL_ROOTS[platform];
|
|
389
398
|
if (!root) continue;
|
|
390
399
|
for (const skill of Object.keys(record?.skills ?? {})) prefixes.push(`${root}/${skill}`);
|
|
391
400
|
for (const skill of Object.keys(mattReceipt?.platforms?.[platform]?.skills ?? {})) prefixes.push(`${root}/${skill}`);
|
|
@@ -696,7 +705,7 @@ export function invoke(argv, { cwd = process.cwd(), failAfterOperation = null, m
|
|
|
696
705
|
const operations = [
|
|
697
706
|
...(!fs.existsSync(path.join(p.root, "archive")) ? [workflowMkdirOperation(cwd, path.join(p.root, "archive"))] : []),
|
|
698
707
|
workflowMkdirOperation(cwd, p.artifacts),
|
|
699
|
-
...(!fs.existsSync(path.join(p.root, "config.yaml")) ? [workflowWriteOperation(cwd, path.join(p.root, "config.yaml"), `schema: matrix/config/v1\
|
|
708
|
+
...(!fs.existsSync(path.join(p.root, "config.yaml")) ? [workflowWriteOperation(cwd, path.join(p.root, "config.yaml"), `schema: matrix/config/v1\ndefault_orchestration: ${configured.defaultOrchestration}\ninstallation_scope: project\nlanguage: ${configured.artifactLanguage}\n`)] : []),
|
|
700
709
|
...(!fs.existsSync(path.join(p.root, ".gitignore")) ? [workflowWriteOperation(cwd, path.join(p.root, ".gitignore"), "active.json\ninstallation.json\nmatt-installation.json\nchanges/*/events.jsonl\nchanges/*/artifacts/handoff.md\n")] : []),
|
|
701
710
|
workflowWriteOperation(cwd, p.flow, flowContent(flow)),
|
|
702
711
|
...(workspaceBaseline ? [workflowWriteOperation(cwd, p.workspaceBaseline, `${JSON.stringify(workspaceBaseline, null, 2)}\n`)] : []),
|
|
@@ -858,7 +867,13 @@ export function invoke(argv, { cwd = process.cwd(), failAfterOperation = null, m
|
|
|
858
867
|
if (command === "transition") {
|
|
859
868
|
const to = args[0];
|
|
860
869
|
const confirmed = args.includes("--confirmed");
|
|
861
|
-
|
|
870
|
+
const executorFlag = args.indexOf("--executor");
|
|
871
|
+
const executor = executorFlag >= 0 ? args[executorFlag + 1] : null;
|
|
872
|
+
if (args.slice(1).some((arg, offset) => {
|
|
873
|
+
const index = offset + 1;
|
|
874
|
+
if (index === executorFlag || index === executorFlag + 1) return false;
|
|
875
|
+
return arg !== "--confirmed";
|
|
876
|
+
})) return fail("INVALID_INTENT", "Transition accepts only a target phase, optional --confirmed, and optional --executor <choice>.");
|
|
862
877
|
if (flow.status !== "active") return fail("CHANGE_NOT_ACTIVE", `Matrix change is ${flow.status}.`);
|
|
863
878
|
const profile = workflowProfile(p, flow);
|
|
864
879
|
if (profile.next[flow.phase] !== to) return fail("ILLEGAL_TRANSITION", `Illegal ${profile.id} transition ${flow.phase} -> ${to}.`);
|
|
@@ -868,14 +883,24 @@ export function invoke(argv, { cwd = process.cwd(), failAfterOperation = null, m
|
|
|
868
883
|
const order = workspaceOrderGuard(cwd, p);
|
|
869
884
|
if (!order.ok) return order;
|
|
870
885
|
}
|
|
886
|
+
// The implementation-actor gate is runtime-enforced, not prompt-level: Build
|
|
887
|
+
// may not be entered until the actor choice is recorded explicitly.
|
|
888
|
+
if (to === "build") {
|
|
889
|
+
if (executor != null && !/^(current|model|handoff:[a-z0-9]+(?:-[a-z0-9]+)*)$/.test(executor)) {
|
|
890
|
+
return fail("INVALID_INTENT", "Executor choice must be current, model, or handoff:<agent-id>.");
|
|
891
|
+
}
|
|
892
|
+
if (!executor) {
|
|
893
|
+
return fail("EXECUTOR_CONFIRMATION_REQUIRED", "Present the implementation-actor choice to the user before Build: continue with the current agent/model, switch the model in the user's client, or hand off to another agent. Then rerun with --executor <current|model|handoff:<agent-id>>.");
|
|
894
|
+
}
|
|
895
|
+
}
|
|
871
896
|
const before = flow.phase;
|
|
872
897
|
const approval = to === "build" ? contractState(p, flow) : null;
|
|
873
898
|
if (approval && approval.status !== "approved-and-matching" && approval.status !== "unapproved") return { ...contractFailure(flow, approval), change_id: id };
|
|
874
899
|
if (to === "build" && approval.snapshot.missing) return { ...fail("GUARD_FAILED", "Workflow contract artifacts are incomplete."), change_id: id };
|
|
875
|
-
const next = { ...flow, schema: "matrix/change/v2", phase: to, revision: flow.revision + 1, updated_at: stamp(), ...(to === "build" ? { approved_contract_hash: approval.snapshot.hash, contract_approved_revision: flow.revision + 1 } : {}) };
|
|
900
|
+
const next = { ...flow, schema: "matrix/change/v2", phase: to, revision: flow.revision + 1, updated_at: stamp(), ...(to === "build" ? { approved_contract_hash: approval.snapshot.hash, contract_approved_revision: flow.revision + 1, implementation_actor: executor } : {}) };
|
|
876
901
|
const nextProfile = workflowProfile(p, next);
|
|
877
902
|
const details = to === "build"
|
|
878
|
-
? { approved_contract_hash: next.approved_contract_hash, contract_approved_revision: next.contract_approved_revision, ...(shortcut(flow) ? { confirmed, profile: nextProfile.id } : {}) }
|
|
903
|
+
? { approved_contract_hash: next.approved_contract_hash, contract_approved_revision: next.contract_approved_revision, implementation_actor: next.implementation_actor, ...(shortcut(flow) ? { confirmed, profile: nextProfile.id } : {}) }
|
|
879
904
|
: shortcut(flow) ? { profile: nextProfile.id } : {};
|
|
880
905
|
const resultFields = { ok: true, code: "OK", change_id: id, workflow: next.workflow, profile: nextProfile.id, evidence_policy: evidencePolicy(next, nextProfile), orchestration: next.orchestration, artifact_language: next.artifact_language ?? artifactLanguage, status: next.status, phase: to, revision: next.revision, next_skill: skill(to), ...contractFields(next, contractState(p, next)) };
|
|
881
906
|
return runWorkflowTransaction({
|