@uniqbit/mate-core 0.18.4 → 1.0.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude-plugin/hooks/companion-instructions.mjs +9 -0
- package/claude-plugin/hooks/hooks.json +12 -2
- package/opencode-plugin/src/add-dir.ts +76 -10
- package/opencode-plugin/src/companion.ts +1 -8
- package/opencode-plugin/src/server.ts +2 -15
- package/package.json +10 -2
- package/src/brand/art.generated.ts +69 -0
- package/src/brand/index.ts +12 -0
- package/src/brand/palette.ts +19 -0
- package/src/brand/svg.generated.ts +8 -0
- package/src/brand/terminal.ts +83 -0
- package/src/brand/types.ts +33 -0
- package/src/cli/commands/artifact/artifact.ts +8 -0
- package/src/cli/commands/artifact/delivery/archive.ts +117 -0
- package/src/cli/commands/artifact/delivery/branch-flags.ts +55 -0
- package/src/cli/commands/artifact/delivery/environment.ts +104 -0
- package/src/cli/commands/artifact/delivery/link.ts +154 -0
- package/src/cli/commands/artifact/delivery/output.ts +58 -0
- package/src/cli/commands/artifact/finish/command.ts +33 -3
- package/src/cli/commands/artifact/finish/engine.ts +47 -3
- package/src/cli/commands/artifact/finish/finisher.ts +10 -0
- package/src/cli/commands/artifact/finish/openspec.ts +200 -129
- package/src/cli/commands/artifact/finish/secret-scan.ts +43 -0
- package/src/cli/commands/artifact/pending/command.ts +31 -3
- package/src/cli/commands/artifact/pending/discovery.ts +21 -57
- package/src/cli/commands/cap/graphify.ts +52 -3
- package/src/cli/commands/cap/index-cmd.ts +8 -1
- package/src/cli/commands/cap/openspec.ts +13 -25
- package/src/cli/commands/companion/open.ts +56 -39
- package/src/cli/commands/companion/update.ts +75 -42
- package/src/cli/commands/doctor.ts +257 -78
- package/src/cli/commands/install.ts +0 -8
- package/src/cli/commands/plugin/install.ts +9 -4
- package/src/cli/commands/plugin/plugin.ts +3 -2
- package/src/cli/commands/report/adapter.ts +11 -2
- package/src/cli/commands/report/contract.ts +21 -0
- package/src/cli/commands/report/highlight.ts +34 -4
- package/src/cli/commands/report/markdown.ts +110 -0
- package/src/cli/commands/report/palette.ts +118 -0
- package/src/cli/commands/report/renderer.ts +456 -153
- package/src/cli/commands/report/types.ts +16 -0
- package/src/cli/commands/setup.ts +7 -15
- package/src/cli/commands/studio/client-asset.ts +16 -0
- package/src/cli/commands/studio/openspec-cli.ts +10 -58
- package/src/cli/commands/studio/routes.ts +2 -0
- package/src/cli/commands/studio/selection.ts +19 -1
- package/src/cli/commands/studio/server.ts +42 -1
- package/src/cli/commands/studio/terminal-launch.ts +7 -16
- package/src/cli/commands/studio/views/client.ts +6 -616
- package/src/cli/commands/studio/views/dashboard/changes.tsx +5 -10
- package/src/cli/commands/studio/views/document.tsx +137 -69
- package/src/cli/commands/studio/views/markdown.tsx +250 -0
- package/src/cli/commands/studio/views/palette.ts +134 -0
- package/src/cli/commands/studio/views/reports/index.tsx +2 -7
- package/src/cli/commands/studio/views/skills/index.tsx +43 -62
- package/src/cli/commands/studio/views/specs/index.tsx +7 -15
- package/src/cli/commands/studio/views/studio-client/actions.ts +51 -0
- package/src/cli/commands/studio/views/studio-client/companion.ts +13 -0
- package/src/cli/commands/studio/views/studio-client/index.ts +32 -0
- package/src/cli/commands/studio/views/studio-client/keys.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/main.ts +3 -0
- package/src/cli/commands/studio/views/studio-client/page.ts +146 -0
- package/src/cli/commands/studio/views/studio-client/panels.ts +57 -0
- package/src/cli/commands/studio/views/studio-client/reports.ts +122 -0
- package/src/cli/commands/studio/views/studio-client/theme.ts +63 -0
- package/src/cli/commands/studio/views/studio-client/vault-editor.ts +166 -0
- package/src/cli/commands/studio/views/studio-client/vault-pane.ts +202 -0
- package/src/cli/commands/studio/views/studio-client/vault-tree.ts +258 -0
- package/src/cli/commands/studio/views/studio-client.generated.ts +2 -0
- package/src/cli/commands/studio/views/styles.ts +217 -206
- package/src/cli/commands/studio/views/vault/state.ts +3 -5
- package/src/cli/commands/studio/views/workflow/delivery-path.tsx +370 -0
- package/src/cli/commands/studio/views/workflow/graph.ts +220 -0
- package/src/cli/commands/studio/views/workflow/index.tsx +2 -3
- package/src/cli/commands/studio/views/workflow/steps.ts +228 -287
- package/src/cli/commands/wrap.ts +9 -42
- package/src/cli/main.ts +4 -1
- package/src/cli/parse-flags.ts +25 -7
- package/src/cli/setup-selector.tsx +38 -162
- package/src/cli/usage.ts +5 -2
- package/src/hooks/companion-instructions.ts +190 -0
- package/src/hooks/hook-io.ts +63 -0
- package/src/hooks/session-banner.ts +21 -29
- package/src/hooks/session-guidance.ts +10 -36
- package/src/hooks/session-prepare.ts +115 -28
- package/src/hooks/validate-artifact-path.ts +82 -24
- package/src/index.ts +4 -0
- package/src/lib/change-layout.ts +154 -0
- package/src/lib/components/wizard-header.tsx +3 -1
- package/src/lib/context-mode-package.ts +24 -11
- package/src/lib/delivery/archive-change.ts +154 -0
- package/src/lib/delivery/branches.ts +108 -0
- package/src/lib/delivery/environment.ts +29 -0
- package/src/lib/delivery/forge.ts +279 -0
- package/src/lib/delivery/overlap.ts +202 -0
- package/src/lib/delivery/record-delivery.ts +196 -0
- package/src/lib/delivery/record.ts +343 -0
- package/src/lib/delivery/refresh.ts +174 -0
- package/src/lib/delivery/repository-access.ts +97 -0
- package/src/lib/delivery/stages.ts +111 -0
- package/src/lib/delivery/token.ts +58 -0
- package/src/lib/frontmatter.ts +18 -0
- package/src/lib/opencode-plugin-package.ts +5 -5
- package/src/lib/openspec-cli.ts +116 -0
- package/src/lib/openspec-scopes.ts +86 -0
- package/src/lib/orchestrator/adapters/claude-args.ts +50 -0
- package/src/lib/orchestrator/adapters/claude.ts +60 -162
- package/src/lib/orchestrator/adapters/opencode.ts +9 -24
- package/src/lib/orchestrator/config-store.ts +2 -70
- package/src/lib/orchestrator/editor.ts +9 -9
- package/src/lib/orchestrator/openspec-store.ts +14 -54
- package/src/lib/orchestrator/projection-claude-commands.ts +36 -0
- package/src/lib/orchestrator/projection-claude-links.ts +159 -0
- package/src/lib/orchestrator/projection-claude-skills.ts +19 -190
- package/src/lib/orchestrator/projection-entries.ts +45 -15
- package/src/lib/orchestrator/projection-runtime-documents.ts +15 -6
- package/src/lib/orchestrator/projection-types.ts +3 -2
- package/src/lib/orchestrator/refresh-working-claude-links.ts +87 -0
- package/src/lib/orchestrator/session-prepare.ts +49 -87
- package/src/lib/orchestrator/setup-compatibilities.ts +18 -75
- package/src/lib/orchestrator/types.ts +2 -2
- package/src/lib/orchestrator/wrap-pass.ts +22 -88
- package/src/lib/package-paths.ts +8 -0
- package/src/opencode/companion-hooks.ts +64 -5
- package/src/opencode/companion-policy.ts +37 -18
- package/src/opencode/projected-guidance.ts +4 -1
- package/src/opencode/session-prepare.ts +2 -1
- package/src/opencode/tui.tsx +4 -2
- package/src/runtime/artifact-refusal.ts +63 -0
- package/src/runtime/claude-delivery-plan.ts +89 -7
- package/src/runtime/commit-attribution-guard.ts +181 -0
- package/src/runtime/companion-guidance.ts +15 -3
- package/src/runtime/companion-instructions.ts +340 -0
- package/src/runtime/error-message.ts +4 -0
- package/src/runtime/guidance.ts +0 -17
- package/src/runtime/index.ts +5 -0
- package/src/runtime/managed-block.ts +117 -0
- package/src/runtime/markdown-scan.ts +266 -0
- package/src/runtime/policy.ts +16 -15
- package/src/runtime/projected-flag.ts +7 -0
- package/src/runtime/projected-guidance.ts +1 -0
- package/src/runtime/runtime-document-manifest.ts +62 -28
- package/src/runtime/secret-guard.ts +148 -0
- package/src/runtime/secret-patterns.ts +164 -0
- package/src/runtime/secret-scan.ts +90 -0
- package/src/runtime/session-kind.ts +13 -0
- package/src/runtime/shell-heredoc.ts +81 -0
- package/src/runtime/wrap-state.ts +36 -6
- package/src/runtime/write-atomic.ts +64 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +8 -6
- package/src/templates/capabilities/openspec-cap/mate-minimal/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/mate-v1/schema.yaml +7 -9
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/openspec-conventions.yaml +10 -12
- package/src/templates/mate-skills/THIRD-PARTY-NOTICES.md +40 -0
- package/src/templates/mate-skills/agents/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/agents/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/agents/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{claude/mate-openspec-backfill → agents/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/agents/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/agents/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/agents/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/agents/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/agents/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/agents/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/agents/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/agents/{mate-artifact-publish → mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/agents/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/agents/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/agents/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/claude/mate-apply-change/SKILL.md +76 -0
- package/src/templates/mate-skills/claude/mate-apply-change/references/openspec-apply-change.md +198 -0
- package/src/templates/mate-skills/claude/mate-archive-change/SKILL.md +59 -0
- package/src/templates/mate-skills/{agents/mate-openspec-backfill → claude/mate-backfill-spec}/SKILL.md +4 -4
- package/src/templates/mate-skills/claude/mate-clarify-intent/SKILL.md +95 -0
- package/src/templates/mate-skills/claude/mate-explore-change/SKILL.md +50 -0
- package/src/templates/mate-skills/claude/mate-explore-change/references/openspec-explore.md +348 -0
- package/src/templates/mate-skills/claude/mate-grill-me/SKILL.md +3 -3
- package/src/templates/mate-skills/claude/mate-interview-me/SKILL.md +5 -5
- package/src/templates/mate-skills/claude/mate-propose-change/SKILL.md +103 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-propose.md +167 -0
- package/src/templates/mate-skills/claude/mate-propose-change/references/openspec-update-change.md +101 -0
- package/src/templates/mate-skills/claude/{mate-artifact-publish → mate-publish-artifact}/SKILL.md +91 -23
- package/src/templates/mate-skills/claude/{mate-artifact-publish → mate-publish-artifact}/references/openspec.md +4 -3
- package/src/templates/mate-skills/claude/mate-show-me/SKILL.md +74 -16
- package/src/templates/mate-skills/claude/mate-simplify-code/SKILL.md +74 -68
- package/src/templates/mate-skills/openspec-references.ts +140 -0
- package/src/templates/root/TEMPLATE_AGENTS.md +2 -2
- package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +3727 -320
- package/src/tools/setup/capabilities/context-mode.ts +25 -5
- package/src/tools/setup/capabilities/graphify-gate.ts +31 -0
- package/src/tools/setup/capabilities/graphify-secrets.ts +255 -0
- package/src/tools/setup/capabilities/graphify.ts +12 -0
- package/src/tools/setup/capabilities/openspec.ts +273 -270
- package/src/tools/setup/capabilities/tokensave.ts +36 -3
- package/src/tools/setup/context-services.ts +9 -17
- package/src/tools/setup/dynamic-plugins/audiences.ts +7 -39
- package/src/tools/setup/dynamic-plugins/declarations.ts +1 -1
- package/src/tools/setup/dynamic-plugins/hydrate.ts +4 -7
- package/src/tools/setup/dynamic-plugins/install.ts +24 -28
- package/src/tools/setup/engine.ts +93 -148
- package/src/tools/setup/managed-output.ts +51 -0
- package/src/tools/setup/mate.ts +86 -11
- package/src/tools/setup/plugin.ts +37 -17
- package/src/tools/setup/plugins/gitignore.ts +1 -7
- package/src/tools/setup/plugins/guidance.ts +7 -4
- package/src/tools/setup/providers/agent-file-sections.ts +4 -2
- package/src/tools/setup/providers/claude-attribution.ts +65 -0
- package/src/tools/setup/providers/claude-plugin-folders.ts +625 -0
- package/src/tools/setup/providers/claude-plugin-hooks.ts +39 -19
- package/src/tools/setup/providers/claude.ts +285 -34
- package/src/tools/setup/providers/opencode.ts +180 -11
- package/src/tools/setup/registry.ts +2 -24
- package/src/tools/setup/surface-target.ts +4 -13
- package/src/tools/setup/utils.ts +14 -4
- package/src/tools/setup.ts +131 -18
- package/wrappers/bin/graphify +52 -4
- package/wrappers/bin/openspec +33 -9
- package/wrappers/lib/graphify-gate.mjs +8 -0
- package/opencode-plugin/src/audience-layer.ts +0 -91
- package/src/cli/commands/studio/views/workflow/transcript.tsx +0 -190
- package/src/runtime/audience-layer.ts +0 -84
- package/src/runtime/opencode-audience-layer.ts +0 -176
- package/src/tools/setup/audience-isolation.fixture.ts +0 -325
- package/src/tools/setup/audience-layer.ts +0 -207
- package/src/tools/setup/audience-registrations.ts +0 -52
- package/src/tools/setup/contribution-ledger.ts +0 -207
- package/src/tools/setup/isolation-diagnostics.ts +0 -139
- package/src/tools/setup/runtime-documents.ts +0 -291
- package/src/tools/setup/upgrade-sweep.ts +0 -153
|
@@ -21,7 +21,7 @@ Explain the current topic visually in a browser-rendered Mate report. Skip the p
|
|
|
21
21
|
|
|
22
22
|
## Subject
|
|
23
23
|
|
|
24
|
-
- With no argument, explain the current topic
|
|
24
|
+
- With no argument, review the applied change when the user asks what a change did, or when the conversation is about work in the Working Repository and `git diff` there is not empty; otherwise explain the current topic. When both readings fit, review the change.
|
|
25
25
|
- With an argument naming a spec capability (`$ARGUMENTS`, for example `acme-capability`), explain that capability instead: read its canonical spec under `openspec/specs/` in the Companion Repository and report its purpose, its requirements, and the flow or structure they establish. Name the capability in the report `metadata`, include a `diagram` section, and omit the `diff` section.
|
|
26
26
|
- When the named capability has no canonical spec, say so, suggest close capability names from `openspec/specs/`, and write nothing: no report, no file.
|
|
27
27
|
|
|
@@ -89,6 +89,18 @@ src/
|
|
|
89
89
|
|
|
90
90
|
- Show a whole block in the report when most of it is new, when omitted context would hide ownership or order, or when the user needs a copyable target shape.
|
|
91
91
|
|
|
92
|
+
## Reviewing An Applied Change
|
|
93
|
+
|
|
94
|
+
- Read the change scope before drawing it, and draw the state after the change, not the one it replaced.
|
|
95
|
+
- Decide the diagram by what the change did. When it alters control flow or behaviour - new or changed branches, calls, ordering, return paths, or error handling - the first diagram is a `flowchart TD` of the resulting flow, limited to the part the change touches. A rename, a move, or an extraction that keeps behaviour identical gets one structure diagram and no flowchart.
|
|
96
|
+
- Mark new steps `added` and modified steps `changed`. Removed steps normally do not appear, since the diff shows what was there before; when removing a step is the point of the change, keep it as a `removed` node.
|
|
97
|
+
- When most of the drawn flow is new, marking every step carries no signal: mark at most the entry step `added`, and say in the caption that the flow is new.
|
|
98
|
+
- Keep a flowchart to about twelve nodes. Collapse a run of steps the change did not touch into one node instead of splitting the flow across several diagrams.
|
|
99
|
+
- When the change also alters structure - types, modules, or ownership - follow the flowchart with a structure diagram such as a `classDiagram`. A report carries at most two `diagram` sections, flowchart first, each with its own `caption`.
|
|
100
|
+
- Take the diff from `git diff` in the Working Repository. Keep only repository-relative paths in the patch, default to the working tree, and ask the user when their intent is a committed range instead.
|
|
101
|
+
- Run `git diff --numstat` over the same scope before choosing between the full diff and a curated report. Every excerpt is whole hunks copied unchanged from that diff.
|
|
102
|
+
- When the inspected scope has no changes, say so and omit the `diff` section. Never invent a patch.
|
|
103
|
+
|
|
92
104
|
## Browser Delivery
|
|
93
105
|
|
|
94
106
|
The report is mandatory. Prefer `mate report --input <temporary-json-file>` without `--json` so the CLI reads the complete document reliably and renders self-contained HTML. The CLI chooses the surface: inside a Studio terminal it hosts the report in Studio, elsewhere it opens it in the default browser. The CLI also supports `mate report --input -` when JSON is piped to stdin; if stdin delivery reports empty or truncated JSON, switch to a temporary JSON file rather than retrying the same transport. If validation fails, fix the report document and retry; do not fall back to an inline explanation or JSON-only delivery.
|
|
@@ -105,19 +117,33 @@ Build a JSON document that conforms to the `mate-create-report` contract, then h
|
|
|
105
117
|
A report assembled by this skill carries:
|
|
106
118
|
|
|
107
119
|
- `metadata` naming the subject and a neutral repository label, never a local path
|
|
108
|
-
-
|
|
120
|
+
- `diagram` sections, even when the visual is small: one for a topic or capability report, one or two for a change review as Reviewing An Applied Change describes
|
|
109
121
|
- use a `mermaid` payload for runtime control flow, call trees, data flow, or component relationships; use `text` only when a sketch or pseudocode is clearer
|
|
110
|
-
- one `diff` section
|
|
111
|
-
- a short `
|
|
122
|
+
- what changed, when there is something to diff: the complete unified diff in one `diff` section for a small change or when the user asks for it, otherwise a curated overview and excerpts as described in Curating A Large Diff
|
|
123
|
+
- a short Markdown `caption` on each `diagram` and `diff` section, saying what the reader should notice; do not repeat it in a separate `text` section
|
|
124
|
+
- a `text` section only for explanation that belongs to no single visual, with `"format": "markdown"` when it uses Markdown
|
|
125
|
+
|
|
126
|
+
A `diagram` section carries exactly one payload: `mermaid` for diagram source the report draws as a picture, or `text` for a monospace ASCII sketch or pseudocode block. A `diff` section carries a unified `patch` string. Both take an optional `caption`, rendered beneath the visual with the Markdown subset described in `mate-create-report`.
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"id": "flow",
|
|
131
|
+
"title": "Saving a document",
|
|
132
|
+
"type": "diagram",
|
|
133
|
+
"mermaid": "flowchart TD\n save[save] --> check{unchanged?}\n check -->|yes| cached[return cached]\n check -->|no| write[write content]\n class check,cached added\n class write changed",
|
|
134
|
+
"caption": "Unchanged content now **returns early** instead of being rewritten."
|
|
135
|
+
}
|
|
136
|
+
```
|
|
112
137
|
|
|
113
|
-
|
|
138
|
+
When a change also alters structure, the second `diagram` section is a structure diagram:
|
|
114
139
|
|
|
115
140
|
```json
|
|
116
141
|
{
|
|
117
142
|
"id": "structure",
|
|
118
143
|
"title": "Report rendering",
|
|
119
144
|
"type": "diagram",
|
|
120
|
-
"mermaid": "classDiagram\n Renderer --> Highlight : uses"
|
|
145
|
+
"mermaid": "classDiagram\n Renderer --> Highlight : uses",
|
|
146
|
+
"caption": "`Renderer` is the only caller of `Highlight`."
|
|
121
147
|
}
|
|
122
148
|
```
|
|
123
149
|
|
|
@@ -126,23 +152,55 @@ A `diagram` section carries exactly one payload: `mermaid` for diagram source th
|
|
|
126
152
|
"id": "changes",
|
|
127
153
|
"title": "What changed",
|
|
128
154
|
"type": "diff",
|
|
129
|
-
"patch": "diff --git a/src/acme.ts b/src/acme.ts\n..."
|
|
155
|
+
"patch": "diff --git a/src/acme.ts b/src/acme.ts\n...",
|
|
156
|
+
"caption": "Validation moves **before** rendering."
|
|
130
157
|
}
|
|
131
158
|
```
|
|
132
159
|
|
|
133
160
|
If the document fails contract validation, report the diagnostic and correct the document. Do not fall back to hand-written HTML.
|
|
134
161
|
|
|
162
|
+
## Curating A Large Diff
|
|
163
|
+
|
|
164
|
+
The reader already has the full diff in git; the report earns its place by choosing what is worth looking at.
|
|
165
|
+
|
|
166
|
+
- Measure first. Run `git diff --numstat` over the inspected scope and add the added and removed lines of every file; binary files count as zero.
|
|
167
|
+
- At or under 150 changed lines, or whenever the user asks for the full diff, include the complete unified diff in one `diff` section, whatever its size.
|
|
168
|
+
- Above 150 changed lines, curate:
|
|
169
|
+
- one `table` section with id `changed-files` and the columns File | Added | Removed | Role, listing every changed file in the scope, including tests, snapshots, and generated files. Added and Removed are numbers; Role is a short phrase such as "contract: optional fields" or "snapshot hashes".
|
|
170
|
+
- one to four focused `diff` sections with ids such as `diff-<topic>`, each making one point and carrying a `caption` that says why its hunks matter. Keep each section under about 60 lines.
|
|
171
|
+
- a `summary` metric labelled "Changed lines shown" with the value `<shown> of <total>`, where shown counts the `+` and `-` lines in the excerpts and total is the `--numstat` sum.
|
|
172
|
+
- Excerpts stay verbatim. A focused patch is the file's `diff --git`, `---`, and `+++` header followed by one or more whole hunks copied unchanged from `git diff`. Never alter, merge, or invent hunk lines, and never elide lines with `...`. Two hunks of the same file may share a section when they make the same point.
|
|
173
|
+
- Leave supporting files out of the excerpts: tests (`*.test.*`, `*.spec.*`, `__tests__/`), snapshots (`__snapshots__/`, `*.snap`), lockfiles (`bun.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`), generated files (`*.generated.*`), and formatting-only hunks. They still appear in the `changed-files` table. Excerpt them when the change is about them or the user asks for them.
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"id": "changed-files",
|
|
178
|
+
"title": "Changed files",
|
|
179
|
+
"type": "table",
|
|
180
|
+
"columns": ["File", "Added", "Removed", "Role"],
|
|
181
|
+
"rows": [
|
|
182
|
+
["src/report/contract.ts", 48, 6, "contract: optional fields"],
|
|
183
|
+
["src/report/renderer.test.ts", 210, 95, "tests"]
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"id": "diff-contract",
|
|
191
|
+
"title": "Contract gains optional fields",
|
|
192
|
+
"type": "diff",
|
|
193
|
+
"patch": "diff --git a/src/report/contract.ts b/src/report/contract.ts\n--- a/src/report/contract.ts\n+++ b/src/report/contract.ts\n@@ -40,6 +40,8 @@\n...",
|
|
194
|
+
"caption": "New fields are **optional**, so existing documents still validate."
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
135
198
|
## Mermaid Authoring Rules
|
|
136
199
|
|
|
137
200
|
- Use Mermaid whenever the user asks for a diagram or the subject has meaningful control flow, sequencing, lifecycle, or relationships. A `text` payload is a deliberate fallback, not the default for runtime flows.
|
|
138
|
-
- Pick the diagram type that matches the question: `classDiagram` for structure, `sequenceDiagram` for interaction between components, `stateDiagram-v2` for lifecycles, `flowchart TD` for control flow and call trees.
|
|
139
|
-
- Keep labels short enough to read at report width. A label that needs a sentence belongs in the
|
|
201
|
+
- Pick the diagram type that matches the question: `classDiagram` for structure, `sequenceDiagram` for interaction between components, `stateDiagram-v2` for lifecycles, `flowchart TD` for control flow and call trees. For a change review, Reviewing An Applied Change decides the diagram instead.
|
|
202
|
+
- Keep labels short enough to read at report width. A label that needs a sentence belongs in the section's `caption`.
|
|
140
203
|
- Do not use ELK-only layouts or math labels. The report loads the single-file mermaid build from a CDN, which does not carry those chunks.
|
|
141
|
-
-
|
|
204
|
+
- To mark nodes, apply the report's theme classes `added`, `changed`, or `removed` with `class a,b added` or `a:::added`. They follow the reader's colour scheme. Never fix a colour with `classDef`, `style`, or `linkStyle`: a fill picked for a white page hides the labels in dark mode, so the dark copy drops those lines.
|
|
205
|
+
- Give each Mermaid visual a short `caption` that calls out the ownership boundary or invariant the reader should notice.
|
|
142
206
|
- Prefer the `text` payload for pseudocode, shallow file trees, or cases where a picture would genuinely obscure the point.
|
|
143
|
-
|
|
144
|
-
## Reviewing An Applied Change
|
|
145
|
-
|
|
146
|
-
- Read the change scope before drawing it, then diagram the structure or flow the change establishes - not the structure it replaced.
|
|
147
|
-
- Take the diff from `git diff` in the Working Repository. Keep only repository-relative paths in the patch, default to the working tree, and ask the user when their intent is a committed range instead.
|
|
148
|
-
- When the inspected scope has no changes, say so and omit the `diff` section. Never invent a patch.
|
|
@@ -19,21 +19,12 @@ Simplify code by reducing complexity while preserving exact behavior. The goal i
|
|
|
19
19
|
|
|
20
20
|
- Inspect the requested scope and its callers, callees, and tests before editing. Use the available code-graph tools before broad source scans.
|
|
21
21
|
- Keep the refactor limited to the requested scope; do not make unrelated cleanup changes.
|
|
22
|
-
-
|
|
22
|
+
- Do not modify tests merely to make a refactor pass.
|
|
23
23
|
- Format touched files with the project's own formatter — detect it first (see Principle 2); never run a formatter the project has not adopted.
|
|
24
24
|
- Run `mate cap index --tokensave` after code changes.
|
|
25
25
|
- Never commit, push, or create a pull request unless the user explicitly asks.
|
|
26
26
|
|
|
27
|
-
## When to Use
|
|
28
|
-
|
|
29
|
-
- After a feature is working and tests pass, but the implementation feels heavier than it needs to be
|
|
30
|
-
- During code review when readability or complexity issues are flagged
|
|
31
|
-
- When you encounter deeply nested logic, long functions, or unclear names
|
|
32
|
-
- When refactoring code written under time pressure
|
|
33
|
-
- When consolidating related logic scattered across files
|
|
34
|
-
- After merging changes that introduced duplication or inconsistency
|
|
35
|
-
|
|
36
|
-
**When NOT to use:**
|
|
27
|
+
## When NOT to Use
|
|
37
28
|
|
|
38
29
|
- Code is already clean and readable — don't simplify for the sake of it
|
|
39
30
|
- You don't understand what the code does yet — comprehend before you simplify
|
|
@@ -75,25 +66,29 @@ Simplification that breaks project consistency is not simplification — it's ch
|
|
|
75
66
|
|
|
76
67
|
Detect the formatter before formatting anything — first match wins:
|
|
77
68
|
|
|
78
|
-
| Signal in the repo | Formatter to run
|
|
79
|
-
| --------------------------------------------------------------------------------- |
|
|
80
|
-
| `format` / `fmt` script in `package.json`, `Makefile`, `justfile`, `Taskfile.yml` |
|
|
81
|
-
| `biome.json` / `biome.jsonc` | `biome format --write`
|
|
82
|
-
| `.oxfmtrc.json`, or `oxfmt` in devDependencies | `oxfmt`
|
|
83
|
-
| `dprint.json` / `.dprint.jsonc` | `dprint fmt`
|
|
84
|
-
| `.prettierrc*`, `prettier.config.*`, or a `prettier` key in `package.json` | `prettier --write`
|
|
85
|
-
| `rustfmt.toml`, or any Cargo crate | `cargo fmt`
|
|
86
|
-
| `[tool.ruff]` in `pyproject.toml` | `ruff format`
|
|
87
|
-
| `[tool.black]` in `pyproject.toml` | `black`
|
|
88
|
-
| Go module | `gofmt -w` (or `goimports -w` if already used)
|
|
89
|
-
| Only `.editorconfig`, or no signal at all | Do not format — match the surrounding style by hand
|
|
69
|
+
| Signal in the repo | Formatter to run |
|
|
70
|
+
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
71
|
+
| `format` / `fmt` script in `package.json`, `Makefile`, `justfile`, `Taskfile.yml` | That script decides — narrow it to your files (see the rules below) |
|
|
72
|
+
| `biome.json` / `biome.jsonc` | `biome format --write` |
|
|
73
|
+
| `.oxfmtrc.json`, or `oxfmt` in devDependencies | `oxfmt` |
|
|
74
|
+
| `dprint.json` / `.dprint.jsonc` | `dprint fmt` |
|
|
75
|
+
| `.prettierrc*`, `prettier.config.*`, or a `prettier` key in `package.json` | `prettier --write` |
|
|
76
|
+
| `rustfmt.toml`, or any Cargo crate | `cargo fmt` |
|
|
77
|
+
| `[tool.ruff]` in `pyproject.toml` | `ruff format` |
|
|
78
|
+
| `[tool.black]` in `pyproject.toml` | `black` |
|
|
79
|
+
| Go module | `gofmt -w` (or `goimports -w` if already used) |
|
|
80
|
+
| Only `.editorconfig`, or no signal at all | Do not format — match the surrounding style by hand |
|
|
90
81
|
|
|
91
82
|
Rules:
|
|
92
83
|
|
|
93
84
|
- Invoke the project's pinned local binary through its package manager or runner, inferred from the lockfile (`bun`, `pnpm`, `yarn`, `npm`) — never a global install and never an `npx`-downloaded version, which may differ from the one that formatted the committed code.
|
|
85
|
+
- **A script decides the tool, not the paths.** Read the script to learn the tool, its config, and its flags, then run that tool on your files only. Scripts usually hard-code their own paths, so passing a file to them adds it to the run instead of narrowing it. If the script chains several steps, run only its formatting steps, each narrowed to your files — a lint `--fix` step is not formatting.
|
|
86
|
+
- In a monorepo, use the script from the nearest package manifest above the files that defines one — often only the repository root does.
|
|
87
|
+
- If a `format` script cannot be narrowed, do not run it: it rewrites files outside the scope, and reverting those with `git checkout` would also discard any uncommitted work in them. Match the surrounding style by hand and report it.
|
|
94
88
|
- If several formatters are configured, the `format` script decides. If there is no script and the signals conflict, ask which is canonical instead of picking one.
|
|
95
89
|
- Format only the files you changed. A repo-wide format pass is a separate change with its own diff.
|
|
96
|
-
-
|
|
90
|
+
- Before running any formatter, save a copy of each file you are about to format to a temporary directory (`$TMPDIR`) — never inside the repository, where a backup can be committed. Git cannot tell a formatter's hunks apart from uncommitted work already in the file; the copy can.
|
|
91
|
+
- If the formatter rewrites far more than the lines you touched, its config disagrees with the committed code. Stop, restore the copies you saved — never `git checkout` the file, which would also discard uncommitted work — match the surrounding style by hand, and report it. Do not fold that drift into a simplification change.
|
|
97
92
|
|
|
98
93
|
### 3. Prefer Clarity Over Cleverness
|
|
99
94
|
|
|
@@ -137,6 +132,7 @@ Simplification has a failure mode: over-simplification. Watch for these traps:
|
|
|
137
132
|
- **Combining unrelated logic** — two simple functions merged into one complex function is not simpler
|
|
138
133
|
- **Removing "unnecessary" abstraction** — some abstractions exist for extensibility or testability, not complexity
|
|
139
134
|
- **Optimizing for line count** — fewer lines is not the goal; easier comprehension is
|
|
135
|
+
- **Stripping return type annotations** — leave them; exported ones are contracts, and inference can silently widen the type
|
|
140
136
|
|
|
141
137
|
### 5. Scope to What Changed
|
|
142
138
|
|
|
@@ -160,6 +156,16 @@ BEFORE SIMPLIFYING, ANSWER:
|
|
|
160
156
|
|
|
161
157
|
If you can't answer these, you're not ready to simplify. Read more context first.
|
|
162
158
|
|
|
159
|
+
**When no test exercises the scope**, the safety net that Step 3 relies on is missing. Pick one, and report the missing coverage either way:
|
|
160
|
+
|
|
161
|
+
- Write characterization tests first. They pin the current behavior, including its quirks, and are never edited later to fit the refactor.
|
|
162
|
+
- In a type-checked project, restrict the pass to changes the type checker verifies on its own, and leave every other candidate in the report:
|
|
163
|
+
- Rename locals, or remove unused locals whose initializer has no side effects. A call, `await`, `new`, or getter in the initializer can have one, and removing it changes behavior the checker cannot see.
|
|
164
|
+
- Skip a rename when the local also supplies an object key (`{ user }`), a JSX prop, or a string lookup — renaming it changes data, and the checker cannot see that.
|
|
165
|
+
- Unexport a symbol only after it clears every box of the pre-removal checklist. The checker catches a broken importer, but not a framework or config that resolves the symbol by name.
|
|
166
|
+
|
|
167
|
+
Without a type checker, only characterization tests remain.
|
|
168
|
+
|
|
163
169
|
### Step 2: Identify Simplification Opportunities
|
|
164
170
|
|
|
165
171
|
#### Step 2a: Mechanical pre-scan (required)
|
|
@@ -181,7 +187,8 @@ PRE-SCAN THE REQUESTED SCOPE:
|
|
|
181
187
|
|
|
182
188
|
Do not skip the pre-scan because the file "looks clean". Judgment applies to the
|
|
183
189
|
candidates it produces, not to whether to produce them. Report candidates you
|
|
184
|
-
deliberately leave alone, with the reason.
|
|
190
|
+
deliberately leave alone, with the reason. Every "report it" in this skill means an entry
|
|
191
|
+
in the final [Report](#report), under its bucket.
|
|
185
192
|
|
|
186
193
|
**A pre-scan hit is a question, not a verdict.** These tools find symbols nothing
|
|
187
194
|
_imports_; they cannot see symbols resolved by name — framework exports, reflective
|
|
@@ -292,11 +299,6 @@ design decision rather than a behavior-preserving edit. Both collide with Princi
|
|
|
292
299
|
Describe the change and the affected files, then stop and let the user decide — the
|
|
293
300
|
same treatment the prop-drilling case gets under React guidance.
|
|
294
301
|
|
|
295
|
-
**When the pre-scan flags a symbol you cannot prove is unreferenced, leave it and say
|
|
296
|
-
so.** An export you were unsure about and kept costs a line of explanation. An export
|
|
297
|
-
you removed on a guess costs a production incident. Unverifiable candidates are
|
|
298
|
-
reported, not acted on.
|
|
299
|
-
|
|
300
302
|
```
|
|
301
303
|
BEFORE REMOVING ANY export, ALL MUST HOLD:
|
|
302
304
|
[ ] Not framework-resolved (checked against the list above)
|
|
@@ -310,7 +312,7 @@ Any box unchecked → report the candidate, do not touch it.
|
|
|
310
312
|
|
|
311
313
|
### Step 3: Apply Changes Incrementally
|
|
312
314
|
|
|
313
|
-
Make one simplification at a time
|
|
315
|
+
Make one simplification at a time and run tests after each change, so a failure points to the change that caused it. **Submit refactoring changes separately from feature or bug fix changes.** A PR that refactors and adds a feature is two PRs — split them.
|
|
314
316
|
|
|
315
317
|
```
|
|
316
318
|
FOR EACH SIMPLIFICATION:
|
|
@@ -322,9 +324,7 @@ FOR EACH SIMPLIFICATION:
|
|
|
322
324
|
4. If either fails → revert and reconsider
|
|
323
325
|
```
|
|
324
326
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
**The Rule of 500:** If a refactoring would touch more than 500 lines, invest in automation (codemods or AST transforms) rather than making the changes by hand. Manual edits at that scale are error-prone and exhausting to review.
|
|
327
|
+
**The Rule of 500:** If a refactoring would touch more than 500 lines, stop and propose it — the scope, the approach (codemod or AST transform included), and the affected files — instead of applying it, unless the user explicitly asked for that scope. A change that size is no longer scoped to what changed (Principle 5), and manual edits at that scale are error-prone and exhausting to review.
|
|
328
328
|
|
|
329
329
|
### Step 4: Verify the Result
|
|
330
330
|
|
|
@@ -334,29 +334,40 @@ Then step back and evaluate the whole:
|
|
|
334
334
|
|
|
335
335
|
```
|
|
336
336
|
COMPARE BEFORE AND AFTER:
|
|
337
|
-
- Is the simplified version genuinely easier to understand?
|
|
338
|
-
- Did you introduce any
|
|
339
|
-
- Is the diff clean and reviewable?
|
|
340
|
-
- Would a teammate approve this change?
|
|
337
|
+
- Is the simplified version genuinely easier to understand and review?
|
|
338
|
+
- Did you introduce any pattern inconsistent with the surrounding code?
|
|
341
339
|
```
|
|
342
340
|
|
|
343
|
-
If
|
|
341
|
+
If either answer is wrong, revert. Not every simplification attempt succeeds.
|
|
342
|
+
|
|
343
|
+
## Report
|
|
344
|
+
|
|
345
|
+
End every pass with one report. Every pre-scan candidate lands in exactly one bucket,
|
|
346
|
+
and each entry names the file, the candidate, and the reason. A candidate you could not
|
|
347
|
+
verify goes under **Unsure**, never into the code: an export kept on doubt costs a line
|
|
348
|
+
of explanation, one removed on a guess costs an incident.
|
|
349
|
+
|
|
350
|
+
**Group the noise, itemize the decisions.** Candidates under **Left alone on purpose**
|
|
351
|
+
that share a tool and a reason collapse into one line with a count and the threshold or
|
|
352
|
+
rule that dismissed them (for example, "14 complexity hits below nesting depth 3"). Every
|
|
353
|
+
candidate in the other buckets gets its own entry.
|
|
354
|
+
|
|
355
|
+
- **Applied** — what changed, and the check that proved it (type checker, tests)
|
|
356
|
+
- **Not applied — changes behavior** — what the fix would alter: ordering, concurrency,
|
|
357
|
+
mutation, error surface, or name resolution
|
|
358
|
+
- **Unsure** — what you could not verify, and which evidence is missing
|
|
359
|
+
- **Propose-only** — API reshapes and refactors past the Rule of 500: the proposed change
|
|
360
|
+
and the files it would touch
|
|
361
|
+
- **Left alone on purpose** — candidates not worth changing, with the reason
|
|
362
|
+
|
|
363
|
+
Close with anything that limited the pass: missing test coverage, or formatter drift you
|
|
364
|
+
reverted.
|
|
344
365
|
|
|
345
366
|
## Language-Specific Guidance
|
|
346
367
|
|
|
347
368
|
### TypeScript / JavaScript
|
|
348
369
|
|
|
349
370
|
```typescript
|
|
350
|
-
// SIMPLIFY: Unnecessary async wrapper
|
|
351
|
-
// Before
|
|
352
|
-
async function getUser(id: string): Promise<User> {
|
|
353
|
-
return await userService.findById(id);
|
|
354
|
-
}
|
|
355
|
-
// After
|
|
356
|
-
function getUser(id: string): Promise<User> {
|
|
357
|
-
return userService.findById(id);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
371
|
// SIMPLIFY: Verbose conditional assignment
|
|
361
372
|
// Before
|
|
362
373
|
let displayName: string;
|
|
@@ -454,15 +465,12 @@ function UserBadge({ user }: Props) {
|
|
|
454
465
|
|
|
455
466
|
## Common Rationalizations
|
|
456
467
|
|
|
457
|
-
| Rationalization
|
|
458
|
-
|
|
|
459
|
-
| "
|
|
460
|
-
| "
|
|
461
|
-
| "
|
|
462
|
-
| "
|
|
463
|
-
| "This abstraction might be useful later" | Don't preserve speculative abstractions. If it's not used now, it's complexity without value. Remove it and re-add when needed. |
|
|
464
|
-
| "The original author must have had a reason" | Maybe. Check git blame — apply Chesterton's Fence. But accumulated complexity often has no reason; it's just the residue of iteration under pressure. |
|
|
465
|
-
| "I'll refactor while adding this feature" | Separate refactoring from feature work. Mixed changes are harder to review, revert, and understand in history. |
|
|
468
|
+
| Rationalization | Reality |
|
|
469
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
470
|
+
| "Fewer lines is always simpler" | A 1-line nested ternary is not simpler than a 5-line if/else. Simplicity is about comprehension speed, not line count. |
|
|
471
|
+
| "This abstraction might be useful later" | Speculative abstractions are complexity without value. If nothing uses it now, remove it under the dead-code and export rules above. |
|
|
472
|
+
| "The original author must have had a reason" | Maybe. Check git blame — apply Chesterton's Fence. But accumulated complexity often has no reason; it's the residue of iteration. |
|
|
473
|
+
| "I'll refactor while adding this feature" | Separate refactoring from feature work. Mixed changes are harder to review, revert, and understand in history. |
|
|
466
474
|
|
|
467
475
|
## Red Flags
|
|
468
476
|
|
|
@@ -471,36 +479,34 @@ function UserBadge({ user }: Props) {
|
|
|
471
479
|
- Renaming things to match your preferences rather than project conventions
|
|
472
480
|
- Removing error handling because "it makes the code cleaner"
|
|
473
481
|
- Simplifying code you don't fully understand
|
|
474
|
-
-
|
|
475
|
-
- Refactoring code outside the scope of the current task without being asked
|
|
482
|
+
- Touching code outside the requested scope without being asked
|
|
476
483
|
- Deleting an export because a tool reported it unused, without checking whether the
|
|
477
484
|
framework resolves it by name (`page.tsx`, `route.ts`, stories, config-referenced files)
|
|
478
485
|
- Acting on a pre-scan candidate you could not verify — report it instead
|
|
486
|
+
- Applying a propose-only row (module collapse, barrel deletion) without user sign-off
|
|
479
487
|
- Treating a green test run as proof a visibility change was safe without a type check
|
|
480
488
|
- Unexporting a symbol whose only importer is a test, then editing the test to match
|
|
481
|
-
- Applying a propose-only row (module collapse, barrel deletion) without user sign-off
|
|
482
489
|
- Trusting "the compiler would catch it" in a project the type checker does not cover
|
|
490
|
+
- Dropping `async` or `return await` as a "simplification" — it changes how errors and stack traces surface
|
|
483
491
|
|
|
484
492
|
## Verification
|
|
485
493
|
|
|
486
494
|
After completing a simplification pass:
|
|
487
495
|
|
|
488
496
|
- [ ] All existing tests pass without modification
|
|
497
|
+
- [ ] Type checker passes, if the project has one
|
|
489
498
|
- [ ] Build succeeds with no new warnings
|
|
490
|
-
- [ ] The project's own formatter
|
|
491
|
-
- [ ] Formatting touched only the changed files (no repo-wide reformat mixed in)
|
|
499
|
+
- [ ] The project's own formatter ran on the touched files only
|
|
492
500
|
- [ ] Linter passes (no style regressions)
|
|
493
501
|
- [ ] Each simplification is a reviewable, incremental change
|
|
494
|
-
- [ ] The diff
|
|
502
|
+
- [ ] The diff holds nothing outside the requested scope
|
|
495
503
|
- [ ] Simplified code follows project conventions (checked against CLAUDE.md or equivalent)
|
|
496
504
|
- [ ] No error handling was removed or weakened
|
|
497
505
|
- [ ] No dead code was left behind (unused imports, unreachable branches)
|
|
498
|
-
- [ ]
|
|
499
|
-
- [ ] Export surface matches actual consumers — nothing exported without a caller outside its file
|
|
500
|
-
- [ ] Type checker passes — no unexport broke an importer
|
|
506
|
+
- [ ] Every removed `export` cleared the pre-removal checklist
|
|
501
507
|
- [ ] No framework-resolved export was unexported, renamed, or deleted
|
|
502
|
-
- [ ] Every removed `export` cleared all boxes of the pre-removal checklist
|
|
503
508
|
- [ ] No test was edited to accommodate a visibility change
|
|
504
509
|
- [ ] Propose-only findings were reported, not applied
|
|
510
|
+
- [ ] Every pre-scan candidate appears in the Report, itemized or counted in a grouped line
|
|
505
511
|
- [ ] Behavior is bit-for-bit identical: same inputs, outputs, side effects, error paths
|
|
506
512
|
- [ ] A teammate or review agent would approve the change as a net improvement
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { runOpenSpec } from "../../lib/openspec-cli";
|
|
6
|
+
|
|
7
|
+
/** OpenSpec workflow → the Mate skill that carries it as `references/<workflow>.md`. */
|
|
8
|
+
export const VENDORED_WORKFLOWS = [
|
|
9
|
+
{ workflow: "openspec-explore", skill: "mate-explore-change" },
|
|
10
|
+
{ workflow: "openspec-propose", skill: "mate-propose-change" },
|
|
11
|
+
{ workflow: "openspec-apply-change", skill: "mate-apply-change" },
|
|
12
|
+
{ workflow: "openspec-update-change", skill: "mate-propose-change" },
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
/** OpenSpec tools whose generated text is vendored, each into the Mate skill bucket of the same name. */
|
|
16
|
+
const TOOLS = ["claude", "agents"] as const;
|
|
17
|
+
|
|
18
|
+
/** `/opsx:<command>` and `/openspec-<workflow>` → the Mate skill that replaces both. */
|
|
19
|
+
const COMMAND_REWRITES: Record<string, string> = {
|
|
20
|
+
"/opsx:explore": "/mate-explore-change",
|
|
21
|
+
"/openspec-explore": "/mate-explore-change",
|
|
22
|
+
"/opsx:propose": "/mate-propose-change",
|
|
23
|
+
"/openspec-propose": "/mate-propose-change",
|
|
24
|
+
"/opsx:apply": "/mate-apply-change",
|
|
25
|
+
"/openspec-apply-change": "/mate-apply-change",
|
|
26
|
+
"/opsx:archive": "/mate-archive-change",
|
|
27
|
+
"/openspec-archive-change": "/mate-archive-change",
|
|
28
|
+
"/opsx:update": "/mate-propose-change",
|
|
29
|
+
"/openspec-update-change": "/mate-propose-change",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** A slash command, not a path segment such as `references/openspec-explore.md`. */
|
|
33
|
+
const COMMAND_REFERENCE = /(?<![\w.-])\/(?:opsx:|openspec-)[a-z][a-z-]*[a-z]/g;
|
|
34
|
+
const FRONTMATTER = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n)+/;
|
|
35
|
+
|
|
36
|
+
export const NOTICES_FILE = "THIRD-PARTY-NOTICES.md";
|
|
37
|
+
|
|
38
|
+
/** Every `/opsx:` or `/openspec-` command reference in `text`, in order. */
|
|
39
|
+
export function findCommandReferences(text: string): string[] {
|
|
40
|
+
return text.match(COMMAND_REFERENCE) ?? [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Rewrites mapped command references; bare `openspec <command>` CLI calls stay. */
|
|
44
|
+
export function rewriteCommandReferences(text: string): string {
|
|
45
|
+
return text.replace(COMMAND_REFERENCE, (reference) => COMMAND_REWRITES[reference] ?? reference);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Path below `mate-skills/` of a vendored reference file. */
|
|
49
|
+
function referencePath(
|
|
50
|
+
tool: (typeof TOOLS)[number],
|
|
51
|
+
{ workflow, skill }: (typeof VENDORED_WORKFLOWS)[number],
|
|
52
|
+
): string {
|
|
53
|
+
return `${tool}/${skill}/references/${workflow}.md`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function readPackageFile(cliPath: string, file: string): Promise<string> {
|
|
57
|
+
return fs.readFile(path.resolve(path.dirname(cliPath), "..", file), "utf8");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function readVersion(cliPath: string): Promise<string> {
|
|
61
|
+
return (JSON.parse(await readPackageFile(cliPath, "package.json")) as { version: string })
|
|
62
|
+
.version;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function header(workflow: string, tool: string, version: string): string {
|
|
66
|
+
return [
|
|
67
|
+
`<!-- Vendored from OpenSpec ${version}: the \`${workflow}\` workflow its \`${tool}\` tool generates.`,
|
|
68
|
+
" Copyright (c) OpenSpec Contributors, MIT License (see THIRD-PARTY-NOTICES.md in Mate).",
|
|
69
|
+
" Regenerated by `bun run vendor:openspec`; do not edit. -->",
|
|
70
|
+
"",
|
|
71
|
+
"",
|
|
72
|
+
].join("\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Each vendored reference file, keyed by its path below `mate-skills/`, rendered from
|
|
77
|
+
* the OpenSpec CLI at `cliPath`. Throws on a missing skill, missing frontmatter, or a
|
|
78
|
+
* command reference no rewrite rule maps, so no partial output is ever written.
|
|
79
|
+
*/
|
|
80
|
+
export async function renderOpenSpecReferences(cliPath: string): Promise<Map<string, string>> {
|
|
81
|
+
const version = await readVersion(cliPath);
|
|
82
|
+
const workdir = await fs.mkdtemp(path.join(os.tmpdir(), "mate-vendor-openspec-"));
|
|
83
|
+
try {
|
|
84
|
+
const init = await runOpenSpec(["init", "--tools", TOOLS.join(","), workdir], {
|
|
85
|
+
cwd: workdir,
|
|
86
|
+
bin: cliPath,
|
|
87
|
+
});
|
|
88
|
+
if (init.code !== 0) {
|
|
89
|
+
throw new Error(`openspec init exited with code ${init.code}: ${init.stderr.trim()}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const files = new Map<string, string>();
|
|
93
|
+
for (const tool of TOOLS) {
|
|
94
|
+
for (const vendored of VENDORED_WORKFLOWS) {
|
|
95
|
+
const { workflow } = vendored;
|
|
96
|
+
const generated = path.join(workdir, `.${tool}`, "skills", workflow, "SKILL.md");
|
|
97
|
+
const source = await fs.readFile(generated, "utf8");
|
|
98
|
+
if (!FRONTMATTER.test(source)) {
|
|
99
|
+
throw new Error(`OpenSpec ${workflow} (${tool}) has no skill frontmatter to strip.`);
|
|
100
|
+
}
|
|
101
|
+
const body = rewriteCommandReferences(source.replace(FRONTMATTER, ""));
|
|
102
|
+
const unmapped = findCommandReferences(body);
|
|
103
|
+
if (unmapped.length > 0) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`OpenSpec ${workflow} (${tool}) references commands with no Mate rewrite: ${[...new Set(unmapped)].join(", ")}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
files.set(referencePath(tool, vendored), header(workflow, tool, version) + body);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return files;
|
|
112
|
+
} finally {
|
|
113
|
+
await fs.rm(workdir, { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The notices file for the vendored text, carrying the bundled package's `LICENSE` verbatim. */
|
|
118
|
+
export async function renderOpenSpecNotices(cliPath: string): Promise<string> {
|
|
119
|
+
const version = await readVersion(cliPath);
|
|
120
|
+
const license = await readPackageFile(cliPath, "LICENSE");
|
|
121
|
+
const vendored = TOOLS.flatMap((tool) =>
|
|
122
|
+
VENDORED_WORKFLOWS.map((workflow) => `- \`${referencePath(tool, workflow)}\``),
|
|
123
|
+
);
|
|
124
|
+
return [
|
|
125
|
+
"# Third-Party Notices",
|
|
126
|
+
"",
|
|
127
|
+
`The following files contain workflow text from OpenSpec ${version}`,
|
|
128
|
+
"(https://github.com/Fission-AI/OpenSpec), with command references rewritten to",
|
|
129
|
+
"the matching Mate skills:",
|
|
130
|
+
"",
|
|
131
|
+
...vendored,
|
|
132
|
+
"",
|
|
133
|
+
"OpenSpec is distributed under this license:",
|
|
134
|
+
"",
|
|
135
|
+
"```text",
|
|
136
|
+
license.trimEnd(),
|
|
137
|
+
"```",
|
|
138
|
+
"",
|
|
139
|
+
].join("\n");
|
|
140
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- MATE:COMPANION:START -->
|
|
2
2
|
|
|
3
|
-
- When reporting information to me, be extremely concise and sacrifice grammar for the sake of concision. Apply this same preference to JSDoc.
|
|
4
|
-
- Code comments: JSDoc
|
|
3
|
+
- When reporting information to me, be extremely concise and sacrifice grammar for the sake of concision. Apply this same preference to comments and JSDoc, not implementation code; retain necessary contract details.
|
|
4
|
+
- Code comments: sparse and concise — explain non-obvious intent, constraints, or workarounds; avoid filler, restating code, or artifact rationale. Use JSDoc for JS/TS API documentation; line or ordinary block comments for local implementation notes, including JSX-supported expression comments. Preserve required documentation, tool directives, legal notices, generated files, and language-appropriate syntax. Do not rewrite unchanged comments or unrelated code for this preference.
|
|
5
5
|
- Never add a `Co-Authored-By: <model>` trailer or model-attribution footer to commit messages.
|
|
6
6
|
- Never commit, push, or open a pull request in the working repo (`$MATE_REPO_PATH`) unless the user explicitly asks for it.
|
|
7
7
|
- Never connect to a database (local or remote), touch live/external systems (deploys, infra), or take destructive/irreversible actions without asking the user first.
|