@uniqbit/mate-core 0.16.0 → 0.17.0-canary.10

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.
Files changed (49) hide show
  1. package/package.json +2 -2
  2. package/src/cli/commands/companion/companion.ts +8 -0
  3. package/src/cli/commands/companion/prepare.ts +76 -0
  4. package/src/cli/commands/companion/register.ts +47 -0
  5. package/src/cli/commands/launch/claude.ts +4 -3
  6. package/src/cli/commands/launch/opencode.ts +4 -3
  7. package/src/cli/commands/launch/shared.ts +41 -28
  8. package/src/cli/commands/shared/companion-selection.ts +3 -1
  9. package/src/cli/commands/studio/index.ts +85 -6
  10. package/src/cli/commands/studio/routes.ts +1 -1
  11. package/src/cli/commands/studio/selection.ts +11 -2
  12. package/src/cli/commands/studio/server.ts +212 -17
  13. package/src/cli/commands/studio/vault.ts +607 -0
  14. package/src/cli/commands/studio/views/client.ts +141 -1
  15. package/src/cli/commands/studio/views/companion-selector.tsx +1 -1
  16. package/src/cli/commands/studio/views/document.tsx +137 -3
  17. package/src/cli/commands/studio/views/model.ts +13 -0
  18. package/src/cli/commands/studio/views/styles.ts +17 -0
  19. package/src/cli/commands/studio/views/workflow/steps.ts +10 -3
  20. package/src/cli/commands/update.ts +6 -6
  21. package/src/cli/main.ts +56 -4
  22. package/src/cli/usage.ts +6 -3
  23. package/src/index.ts +1 -0
  24. package/src/lib/context-mode-package.ts +7 -4
  25. package/src/lib/node-engine-version.ts +15 -0
  26. package/src/lib/opencode-plugin-package.ts +10 -4
  27. package/src/lib/orchestrator/adapters/base.ts +65 -10
  28. package/src/lib/orchestrator/adapters/opencode.ts +27 -2
  29. package/src/lib/orchestrator/companion-registration.ts +73 -0
  30. package/src/lib/orchestrator/framework-context.ts +29 -3
  31. package/src/lib/orchestrator/launcher.ts +46 -22
  32. package/src/lib/orchestrator/projection-record.ts +24 -0
  33. package/src/lib/orchestrator/types.ts +11 -0
  34. package/src/lib/package-root.ts +43 -0
  35. package/src/lib/prebuilt-workspace-prepare.ts +152 -0
  36. package/src/lib/prebuilt-workspace.ts +246 -0
  37. package/src/lib/preinstalled-plugins.ts +106 -0
  38. package/src/lib/update-checker.ts +39 -0
  39. package/src/opencode/companion-hooks.ts +45 -20
  40. package/src/playbooks/companion-guidance.ts +1 -0
  41. package/src/runtime/companion-guidance.ts +61 -15
  42. package/src/runtime/env.ts +3 -3
  43. package/src/runtime/index.ts +1 -0
  44. package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +2 -1
  45. package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +127 -77
  46. package/src/tools/setup/capabilities/context-mode.ts +34 -2
  47. package/src/tools/setup/capabilities/openspec.ts +12 -2
  48. package/src/tools/setup/plugin.ts +7 -1
  49. package/src/tools/setup/providers/opencode.ts +24 -5
@@ -25,7 +25,7 @@ export interface GuidanceCapability {
25
25
 
26
26
  export interface GuidanceContext {
27
27
  companionPath: string;
28
- repository: { id: string; path: string };
28
+ repository?: { id: string; path: string };
29
29
  capabilities?: GuidanceCapability[];
30
30
  }
31
31
 
@@ -43,14 +43,21 @@ export function hasTokensaveCapability(capabilities: GuidanceCapability[] = []):
43
43
 
44
44
  export const GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT =
45
45
  "$MATE_ARTIFACT_PATH/.graphify/$MATE_REPO_ID/graphify-out/";
46
+ export const GRAPHIFY_COMPANION_PATH_CONTRACT =
47
+ "$MATE_ARTIFACT_PATH/.graphify/__companion__/graphify-out/";
46
48
 
47
49
  export function buildCodebaseExplorationGuidanceSection(
48
50
  options: {
49
51
  useGraphify?: boolean;
50
52
  useTokensave?: boolean;
53
+ graphifyOutContract?: string;
51
54
  } = {},
52
55
  ): string {
53
- const { useGraphify = false, useTokensave = false } = options;
56
+ const {
57
+ useGraphify = false,
58
+ useTokensave = false,
59
+ graphifyOutContract = GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT,
60
+ } = options;
54
61
 
55
62
  if (!useGraphify && !useTokensave) {
56
63
  return "";
@@ -58,7 +65,7 @@ export function buildCodebaseExplorationGuidanceSection(
58
65
 
59
66
  if (useGraphify && useTokensave) {
60
67
  return `<codebase-exploration-rules priority="mandatory">
61
- <path role="graphify-out">${GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT}</path>
68
+ <path role="graphify-out">${graphifyOutContract}</path>
62
69
  <trigger>Codebase-understanding: architecture, tracing, integrations, impact, "how does X work?"</trigger>
63
70
  <order>tokensave -> graphify -> grep/glob/read. MUST NOT skip steps.
64
71
  1. tokensave_context first.
@@ -71,7 +78,7 @@ export function buildCodebaseExplorationGuidanceSection(
71
78
 
72
79
  if (useGraphify) {
73
80
  return `<codebase-exploration-rules priority="mandatory">
74
- <path role="graphify-out">${GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT}</path>
81
+ <path role="graphify-out">${graphifyOutContract}</path>
75
82
  <trigger>Codebase-understanding: architecture, tracing, integrations, impact, "how does X work?"</trigger>
76
83
  <order>graphify -> grep/glob/read. MUST try graphify before raw source.
77
84
  1. graphify query "<question>" first.
@@ -111,7 +118,6 @@ export function buildCompanionPolicyXml(
111
118
  ` <overview>You are operating inside the ${FRAMEWORK_NAME} companion repository.</overview>`,
112
119
  " <context>",
113
120
  " <paths>",
114
- ` <path role="working-repository" env="MATE_REPO_PATH">${context.repository.path}</path>`,
115
121
  ` <path role="companion-repository" env="MATE_ARTIFACT_PATH">${context.companionPath}</path>`,
116
122
  ` <path role="package-wrapper-bin" env="MATE_WRAPPER_BIN_PATH">${wrapperBinPath}</path>`,
117
123
  " </paths>",
@@ -120,19 +126,47 @@ export function buildCompanionPolicyXml(
120
126
  ` <cli name="graphify" type="wrapper" invokeAs="${path.join(wrapperBinPath, "graphify")}" />`,
121
127
  ` <cli name="${FRAMEWORK_NAME}" type="global" invokeAs="${FRAMEWORK_NAME}" />`,
122
128
  " </cli-tools>",
123
- ` <linked-repository id="${context.repository.id}" />`,
124
129
  " </context>",
125
130
  " <mandatory-rules>",
126
- ` <rule id="artifact-location" severity="critical">Agent artifacts MUST go to ${context.companionPath}, NEVER ${context.repository.path}. Artifacts include plans, specs, ADRs, todos, notes, handoffs, reasoning docs, and scratch files.</rule>`,
127
- ` <rule id="pre-write-classification" severity="critical">Before ANY write, classify the target as product-code or agent-artifact. If unsure, treat it as agent-artifact.</rule>`,
128
- ` <rule id="product-code-location" severity="critical">Product code (README, docs, source, tests) belongs in ${context.repository.path}. Agent-artifacts belong in ${context.companionPath}.</rule>`,
129
- ` <rule id="local-artifact-exception" severity="critical">Only write artifacts in ${context.repository.path} when the exact path is gitignored AND intentionally local-only; otherwise use ${context.companionPath}.</rule>`,
130
- ` <rule id="guardrail" severity="critical">Bad artifact writes to ${context.repository.path} are rejected. Classify correctly first.</rule>`,
131
- ` <rule id="companion-multi-repository" severity="critical">This Companion Repository may serve multiple Working Repositories. The working-repository path above identifies this session's single primary Working Repository, not the companion's full repository set. The Companion Repository is the shared artifact and context plane; the primary Working Repository is the product-code plane.</rule>`,
132
- ` <rule id="repository-area-scope" severity="critical">For domain modeling, identify the canonical Working Repository and its repository-relative Area first. A checkout basename or Area alone is not a repository identity. Shared context applies only when the Companion Repository's CONTEXT-MAP explicitly maps it to the current repository and Area.</rule>`,
133
131
  ` <rule id="wrapper-only-cli-execution" severity="critical">For every CLI declared in cli-tools, invoke the exact path in its invokeAs attribute. Correct: ${path.join(wrapperBinPath, "openspec")} status ... . Incorrect: openspec status ... . Do not run bare openspec or graphify commands and do not rely on PATH, aliases, or shell functions. If the exact wrapper path is unavailable, stop and report it.</rule>`,
134
132
  ];
135
133
 
134
+ if (context.repository) {
135
+ lines.splice(
136
+ 8,
137
+ 0,
138
+ ` <path role="working-repository" env="MATE_REPO_PATH">${context.repository.path}</path>`,
139
+ );
140
+ lines.splice(
141
+ lines.indexOf(" </context>"),
142
+ 0,
143
+ ` <linked-repository id="${context.repository.id}" />`,
144
+ );
145
+ lines.splice(
146
+ lines.indexOf(" </mandatory-rules>"),
147
+ 0,
148
+ ` <rule id="artifact-location" severity="critical">Agent artifacts MUST go to ${context.companionPath}, NEVER ${context.repository.path}. Artifacts include plans, specs, ADRs, todos, notes, handoffs, reasoning docs, and scratch files.</rule>`,
149
+ ` <rule id="pre-write-classification" severity="critical">Before ANY write, classify the target as product-code or agent-artifact. If unsure, treat it as agent-artifact.</rule>`,
150
+ ` <rule id="product-code-location" severity="critical">Product code (README, docs, source, tests) belongs in ${context.repository.path}. Agent-artifacts belong in ${context.companionPath}.</rule>`,
151
+ ` <rule id="local-artifact-exception" severity="critical">Only write artifacts in ${context.repository.path} when the exact path is gitignored AND intentionally local-only; otherwise use ${context.companionPath}.</rule>`,
152
+ ` <rule id="guardrail" severity="critical">Bad artifact writes to ${context.repository.path} are rejected. Classify correctly first.</rule>`,
153
+ ` <rule id="companion-multi-repository" severity="critical">This Companion Repository may serve multiple Working Repositories. The working-repository path above identifies this session's single primary Working Repository, not the companion's full repository set. The Companion Repository is the shared artifact and context plane; the primary Working Repository is the product-code plane.</rule>`,
154
+ ` <rule id="repository-area-scope" severity="critical">For domain modeling, identify the canonical Working Repository and its repository-relative Area first. A checkout basename or Area alone is not a repository identity. Shared context applies only when the Companion Repository's CONTEXT-MAP explicitly maps it to the current repository and Area.</rule>`,
155
+ );
156
+ } else {
157
+ lines.splice(
158
+ lines.indexOf(" </mandatory-rules>"),
159
+ 0,
160
+ " <session>Companion-scoped launch with no Working Repository.</session>",
161
+ );
162
+ lines.splice(
163
+ lines.indexOf(" </mandatory-rules>"),
164
+ 0,
165
+ ` <rule id="artifact-location" severity="critical">Agent artifacts MUST go to ${context.companionPath}. The Companion Repository is the artifact and context plane for this session.</rule>`,
166
+ ` <rule id="pre-write-classification" severity="critical">Before ANY write, classify the target as product-code or agent-artifact. If unsure, treat it as agent-artifact.</rule>`,
167
+ );
168
+ }
169
+
136
170
  if (hasOpenspecCapability(context.capabilities)) {
137
171
  lines.push(
138
172
  ` <rule id="openspec-scope" severity="critical">In OpenSpec, the frontmatter repository identifies the Working Repository. areas are repository-relative paths within that repository. Canonical specs use repository plus flat areas; change artifacts use paired scopes entries. In a monorepo, an Area normally stops at the package root. A cross-repository change may declare multiple scopes, but each resulting spec remains owned by one repository, and each requirement must bind its Area explicitly.</rule>`,
@@ -168,6 +202,9 @@ export function buildCompanionGuidance(
168
202
  buildCodebaseExplorationGuidanceSection({
169
203
  useGraphify: graphifyEnabled,
170
204
  useTokensave: tokensaveEnabled,
205
+ graphifyOutContract: context.repository
206
+ ? GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT
207
+ : GRAPHIFY_COMPANION_PATH_CONTRACT,
171
208
  }),
172
209
  );
173
210
  }
@@ -186,11 +223,17 @@ export function buildCompanionGuidance(
186
223
  * so capability-gated companion-policy rules — e.g. openspec-publish — render
187
224
  * exactly as they do for the Claude provider.
188
225
  */
189
- export function buildOpenCodeGuidance(capabilities: GuidanceCapability[]): MateGuidanceFile {
226
+ export function buildOpenCodeGuidance(
227
+ capabilities: GuidanceCapability[],
228
+ options: { companionScoped?: boolean } = {},
229
+ ): MateGuidanceFile {
230
+ const repository = options.companionScoped
231
+ ? undefined
232
+ : { id: "$MATE_REPO_ID", path: "$MATE_REPO_PATH" };
190
233
  const companionGuidance = buildCompanionPolicyXml(
191
234
  {
192
235
  companionPath: "$MATE_ARTIFACT_PATH",
193
- repository: { id: "$MATE_REPO_ID", path: "$MATE_REPO_PATH" },
236
+ repository,
194
237
  capabilities,
195
238
  },
196
239
  { wrapperBinPath: "$MATE_WRAPPER_BIN_PATH" },
@@ -200,6 +243,9 @@ export function buildOpenCodeGuidance(capabilities: GuidanceCapability[]): MateG
200
243
  const codebaseExplorationGuidance = buildCodebaseExplorationGuidanceSection({
201
244
  useGraphify: graphifyEnabled,
202
245
  useTokensave: tokensaveEnabled,
246
+ graphifyOutContract: options.companionScoped
247
+ ? GRAPHIFY_COMPANION_PATH_CONTRACT
248
+ : GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT,
203
249
  });
204
250
  const errors: string[] = [];
205
251
 
@@ -90,9 +90,9 @@ export function readCompanionRuntimeContext(
90
90
  }
91
91
 
92
92
  /**
93
- * A session is Mate-managed only when both the companion path and the working
94
- * repository path resolved. Plugins must stay inert otherwise.
93
+ * A session is Mate-managed when a companion path resolved. A companion-scoped
94
+ * launch intentionally has no working repository.
95
95
  */
96
96
  export function isManagedCompanionContext(context: CompanionRuntimeContext): boolean {
97
- return Boolean(context.companionPath && context.repositoryPath);
97
+ return Boolean(context.companionPath);
98
98
  }
@@ -1,5 +1,6 @@
1
1
  export {
2
2
  GRAPHIFY_SHARED_COMPANION_PATH_CONTRACT,
3
+ GRAPHIFY_COMPANION_PATH_CONTRACT,
3
4
  buildCodebaseExplorationGuidanceSection,
4
5
  buildCompanionGuidance,
5
6
  buildCompanionPolicyXml,
@@ -39,7 +39,8 @@ artifacts:
39
39
  template: tasks.md
40
40
  instruction: |
41
41
  Create a flat implementation checklist that satisfies the delta specs. Keep it short: this
42
- workflow intentionally has no explore, proposal, or design artifact.
42
+ profile uses the shared `/openspec-explore` and `/openspec-propose` planning steps but
43
+ intentionally writes no explore, proposal, or design artifact.
43
44
 
44
45
  Number tasks `N.M` and group them under `## N. <group>` headers so apply tracking can address them individually.
45
46
  Read `openspec/mate-conventions.yaml` before writing the artifact and preserve its scope rules.