@uniqbit/mate-core 0.15.0-canary.7 → 0.15.0-canary.9

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/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@uniqbit/mate-core",
3
- "version": "0.15.0-canary.7",
3
+ "version": "0.15.0-canary.9",
4
+ "description": "Core framework and plugin APIs for Mate.",
4
5
  "license": "MIT",
5
6
  "files": [
6
7
  "src/",
@@ -50,11 +50,14 @@ export async function runSetupCommand(argv: string[]): Promise<void> {
50
50
  * @description Drives the `mate companion setup` flow. Detects what kind of directory the
51
51
  * command is run in (unrecognized, existing companion, or linked working repo) via
52
52
  * {@link inspectSetupPreflight}, prompting to confirm initialization for an
53
- * unrecognized directory. Resolves agent/package-manager/capability selections
54
- * either from CLI flags (non-interactive) or from the interactive
55
- * `selectSetupCompatibilities` picker, seeded from the existing config when one
56
- * exists. Writes the resulting config via `setup.execute` and prints a summary
57
- * table of profiles, package managers, and capabilities.
53
+ * unrecognized directory. A linked working repo delegates to its companion —
54
+ * prompting with the companion selector first when multiple companions link the
55
+ * repo — and then runs the exact same flow as running inside that companion.
56
+ * Resolves agent/package-manager/capability selections either from CLI flags
57
+ * (non-interactive) or from the interactive `selectSetupCompatibilities` picker,
58
+ * seeded from the existing config when one exists. Writes the resulting config
59
+ * via `setup.execute` and prints a summary table of profiles, package managers,
60
+ * and capabilities.
58
61
  * @flags
59
62
  * - `--agents <list>` — parsed via `parseAllowedAgents`.
60
63
  * - `--package-managers <list>` — parsed via `parsePackageManagers`.
@@ -105,6 +108,36 @@ async function runSetupFlow(
105
108
  }
106
109
  }
107
110
 
111
+ // A linked working repo delegates setup to its companion and then follows
112
+ // the exact same flow as running inside that companion directory.
113
+ let targetCwd = cwd;
114
+ if (preflight.kind === "linked-working-repo") {
115
+ let companion = preflight.match;
116
+ const ambiguousMatches = preflight.ambiguousMatches ?? [];
117
+ if (ambiguousMatches.length > 1) {
118
+ // `main` pins the user's choice into MATE_ARTIFACT_PATH via
119
+ // ensureUnambiguousCompanion before commands run; honor that pin so the
120
+ // user is not prompted a second time.
121
+ const pinnedPath = process.env.MATE_ARTIFACT_PATH;
122
+ const pinned = pinnedPath
123
+ ? ambiguousMatches.find(
124
+ (match) => path.resolve(match.companionPath) === path.resolve(pinnedPath),
125
+ )
126
+ : undefined;
127
+ if (pinned) {
128
+ companion = pinned;
129
+ } else {
130
+ const selected = await chooseCompanion(ambiguousMatches);
131
+ if (!selected) {
132
+ process.stderr.write("Aborted.\n");
133
+ process.exit(1);
134
+ }
135
+ companion = selected;
136
+ }
137
+ }
138
+ targetCwd = path.resolve(companion.companionPath);
139
+ }
140
+
108
141
  const flags = parseFlags(argv);
109
142
  const flagAllowedAgents = parseAllowedAgents(flags);
110
143
  const flagPackageManagers = parsePackageManagers(flags);
@@ -118,56 +151,14 @@ async function runSetupFlow(
118
151
  flagOpenSpecSchema !== undefined ||
119
152
  flagGitMode !== undefined;
120
153
 
121
- if (preflight.kind === "linked-working-repo") {
122
- let companion = preflight.match;
123
- const ambiguousMatches = preflight.ambiguousMatches ?? [];
124
- if (ambiguousMatches.length > 1) {
125
- const selected = await chooseCompanion(ambiguousMatches);
126
- if (!selected) {
127
- process.stderr.write("Aborted.\n");
128
- process.exit(1);
129
- }
130
- companion = selected;
131
- }
132
-
133
- const linkedCapabilities =
134
- flagCapabilities ??
135
- (flagOpenSpecSchema === undefined
136
- ? undefined
137
- : getSetupSelectionsFromConfig(
138
- await new ConfigStore(
139
- path.join(
140
- companion.companionPath,
141
- `.${frameworkConfig.name}`,
142
- "config",
143
- "framework.yaml",
144
- ),
145
- ).load(),
146
- ).capabilities);
147
-
148
- await runExecuteSetup(
149
- {
150
- allowedAgents: flagAllowedAgents,
151
- packageManagers: flagPackageManagers,
152
- capabilities:
153
- linkedCapabilities === undefined
154
- ? undefined
155
- : applyOpenSpecSchemaSelection(linkedCapabilities, flagOpenSpecSchema),
156
- git: flagGitMode,
157
- },
158
- { cwd: companion.companionPath },
159
- );
160
- return;
161
- }
162
-
163
154
  const currentSelections =
164
- preflight.kind === "existing-companion"
165
- ? getSetupSelectionsFromConfig(
155
+ preflight.kind === "unrecognized"
156
+ ? getSetupSelectionsFromConfig(defaultConfig())
157
+ : getSetupSelectionsFromConfig(
166
158
  await new ConfigStore(
167
- path.join(cwd, `.${frameworkConfig.name}`, "config", "framework.yaml"),
159
+ path.join(targetCwd, `.${frameworkConfig.name}`, "config", "framework.yaml"),
168
160
  ).load(),
169
- )
170
- : getSetupSelectionsFromConfig(defaultConfig());
161
+ );
171
162
 
172
163
  const selections = hasExplicitSelections
173
164
  ? {
@@ -195,7 +186,7 @@ async function runSetupFlow(
195
186
  capabilities: selections.capabilities,
196
187
  git: selections.selectedGitMode,
197
188
  },
198
- { cwd },
189
+ { cwd: targetCwd },
199
190
  );
200
191
 
201
192
  const { config } = result;
@@ -9,6 +9,8 @@ import { PluginRegistry } from "./tools/setup/registry";
9
9
  export interface CreateMateOptions {
10
10
  config: DistributionConfig;
11
11
  plugins: PluginRegistration[];
12
+ /** Optional entry-point override for embedders that need to control CLI execution. */
13
+ main?: typeof main;
12
14
  }
13
15
 
14
16
  export interface MateCli {
@@ -24,7 +26,7 @@ export interface MateCli {
24
26
  * after `config.name` (built last since it reads the full plugin set).
25
27
  * Returns the runnable CLI.
26
28
  */
27
- export function createMate({ config, plugins }: CreateMateOptions): MateCli {
29
+ export function createMate({ config, plugins, main: runMain = main }: CreateMateOptions): MateCli {
28
30
  const registry = new PluginRegistry([
29
31
  ...plugins,
30
32
  { plugin: createBunPlugin(), policy: "required" },
@@ -36,7 +38,7 @@ export function createMate({ config, plugins }: CreateMateOptions): MateCli {
36
38
  config,
37
39
  registry,
38
40
  run: (argv = process.argv) =>
39
- main(argv).catch((error) => {
41
+ runMain(argv).catch((error) => {
40
42
  console.error(error instanceof Error ? error.message : String(error));
41
43
  process.exitCode = 1;
42
44
  }),
@@ -93,6 +93,8 @@ export abstract class LaunchAdapter {
93
93
 
94
94
  if (reactDoctorEnabled) {
95
95
  env.MATE_REACT_DOCTOR_BIN_PATH = getReactDoctorBinPath();
96
+ } else {
97
+ delete env.MATE_REACT_DOCTOR_BIN_PATH;
96
98
  }
97
99
 
98
100
  // Route launch-session graphify output to the companion store. graphifyy resolves its
@@ -97,8 +97,8 @@ export async function fetchLatestVersion(): Promise<string> {
97
97
  return fetchPublicPackageVersion(packageName, registry);
98
98
  }
99
99
 
100
- export function scheduleBackgroundCheck(store: UpdateStateStore): void {
101
- void (async () => {
100
+ export function scheduleBackgroundCheck(store: UpdateStateStore): Promise<void> {
101
+ return (async () => {
102
102
  try {
103
103
  const state = await store.load();
104
104
  const lastChecked = state.lastChecked ? new Date(state.lastChecked).getTime() : 0;
@@ -552,7 +552,7 @@ async function configureClaude(src: string, companionPath: string): Promise<void
552
552
  }
553
553
  }
554
554
 
555
- async function teardownClaude(companionPath: string, _allowedAgents: string[]): Promise<void> {
555
+ async function teardownClaude(companionPath: string, allowedAgents: string[]): Promise<void> {
556
556
  try {
557
557
  await fs.unlink(path.join(companionPath, ".claude", "hooks", "validate-artifact-path"));
558
558
  } catch {
@@ -603,10 +603,14 @@ async function teardownClaude(companionPath: string, _allowedAgents: string[]):
603
603
  }
604
604
  await pruneEmptyAncestors(path.join(companionPath, ".claude"), companionPath);
605
605
 
606
- try {
607
- await fs.unlink(path.join(companionPath, "AGENTS.md"));
608
- } catch {
609
- /* not present */
606
+ // AGENTS.md is shared with OpenCode. Claude must not remove it while the
607
+ // required OpenCode provider is still active.
608
+ if (!allowedAgents.includes("opencode")) {
609
+ try {
610
+ await fs.unlink(path.join(companionPath, "AGENTS.md"));
611
+ } catch {
612
+ /* not present */
613
+ }
610
614
  }
611
615
  }
612
616