@uniqbit/mate-core 0.17.0-canary.8 → 0.17.1
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 +11 -5
- package/src/cli/commands/artifact/finish/index.ts +0 -9
- package/src/cli/commands/artifact/finish/openspec.ts +2 -2
- package/src/cli/commands/artifact/finish/registry.ts +1 -1
- package/src/cli/commands/artifact/pending/discovery.ts +1 -1
- package/src/cli/commands/artifact/pending/index.ts +0 -16
- package/src/cli/commands/cap/graphify.ts +1 -1
- package/src/cli/commands/cap/index-cmd.ts +1 -1
- package/src/cli/commands/cap/tokensave.ts +4 -3
- package/src/cli/commands/companion/companion.ts +4 -0
- package/src/cli/commands/companion/hub.ts +2 -1
- package/src/cli/commands/companion/list.ts +2 -1
- package/src/cli/commands/companion/prepare.ts +2 -2
- package/src/cli/commands/companion/update.ts +334 -0
- package/src/cli/commands/doctor.ts +2 -1
- package/src/cli/commands/install.ts +59 -5
- package/src/cli/commands/launch/shared.ts +2 -1
- package/src/cli/commands/plugin/plugin.ts +4 -0
- package/src/cli/commands/plugin/verify.ts +25 -0
- package/src/cli/commands/report/highlight.ts +1 -4
- package/src/cli/commands/report/renderer.ts +0 -2
- package/src/cli/commands/studio/access.ts +201 -0
- package/src/cli/commands/studio/index.ts +207 -26
- package/src/cli/commands/studio/openspec-cli.ts +1 -1
- package/src/cli/commands/studio/selection.ts +127 -11
- package/src/cli/commands/studio/server.ts +355 -64
- package/src/cli/commands/studio/terminal-assets.ts +50 -0
- package/src/cli/commands/studio/terminal-launch.ts +71 -0
- package/src/cli/commands/studio/terminal.ts +593 -0
- package/src/cli/commands/studio/vault.ts +320 -75
- package/src/cli/commands/studio/views/client.ts +90 -9
- package/src/cli/commands/studio/views/companion-picker.tsx +9 -5
- package/src/cli/commands/studio/views/companion-selector.tsx +11 -7
- package/src/cli/commands/studio/views/document.tsx +411 -107
- package/src/cli/commands/studio/views/model.ts +14 -1
- package/src/cli/commands/studio/views/selection-fields.tsx +14 -0
- package/src/cli/commands/studio/views/styles.ts +106 -13
- package/src/cli/commands/studio/views/terminal.tsx +426 -0
- package/src/cli/commands/studio/views/vault/state.ts +42 -0
- package/src/cli/commands/studio/views/workflow/steps.ts +10 -3
- package/src/cli/commands/update.ts +11 -8
- package/src/cli/companion-link-wizard.tsx +1 -1
- package/src/cli/companion-selector.tsx +1 -1
- package/src/cli/launch-selector.tsx +1 -1
- package/src/cli/main.ts +2 -1
- package/src/cli/usage.ts +7 -3
- package/src/cli/write-json-stdout.ts +2 -2
- package/src/lib/components/spinner.tsx +2 -2
- package/src/lib/components/startup-progress.tsx +1 -1
- package/src/lib/context-mode-package.ts +1 -1
- package/src/lib/opencode-plugin-package.ts +3 -0
- package/src/lib/orchestrator/adapters/opencode.ts +53 -13
- package/src/lib/orchestrator/companion-hub.ts +3 -3
- package/src/lib/orchestrator/companion-registry-store.ts +1 -1
- package/src/lib/orchestrator/config-store.ts +2 -2
- package/src/lib/orchestrator/editor.ts +4 -12
- package/src/lib/orchestrator/engine-guard.ts +9 -1
- package/src/lib/orchestrator/projection-entries.ts +1 -1
- package/src/lib/orchestrator/projection-record.ts +1 -1
- package/src/lib/orchestrator/projection-types.ts +0 -4
- package/src/lib/orchestrator/repo-local-registry.ts +0 -1
- package/src/lib/orchestrator/root-context.ts +1 -1
- package/src/lib/orchestrator/setup-compatibilities.ts +1 -1
- package/src/lib/orchestrator/setup-preflight.ts +1 -1
- package/src/lib/orchestrator/types.ts +1 -1
- package/src/lib/orchestrator/working-repo-projection.ts +1 -1
- package/src/lib/orchestrator/workspace-inventory.ts +2 -2
- package/src/lib/package-paths.ts +1 -11
- package/src/lib/package-root.ts +43 -0
- package/src/lib/prebuilt-workspace.ts +1 -1
- package/src/lib/public-npm.ts +1 -1
- package/src/opencode/companion-hooks.ts +131 -153
- package/src/opencode/index.ts +12 -6
- package/src/opencode/tui.tsx +46 -49
- package/src/playbooks/companion-guidance.ts +1 -28
- package/src/runtime/companion-sync.ts +0 -3
- package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +2 -1
- package/src/templates/providers/opencode/opencode.json +6 -4
- package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +500 -408
- package/src/tools/setup/capabilities/context-mode.ts +45 -25
- package/src/tools/setup/capabilities/graphify-shared.ts +3 -3
- package/src/tools/setup/capabilities/graphify.ts +2 -2
- package/src/tools/setup/capabilities/openspec.ts +2 -7
- package/src/tools/setup/capabilities/react-doctor.ts +1 -1
- package/src/tools/setup/capabilities/rtk.ts +2 -2
- package/src/tools/setup/capabilities/tokensave.ts +98 -12
- package/src/tools/setup/context-services.ts +3 -6
- package/src/tools/setup/dynamic-plugins/declarations.ts +47 -0
- package/src/tools/setup/dynamic-plugins/frozen.ts +215 -0
- package/src/tools/setup/dynamic-plugins/hydrate.ts +1 -40
- package/src/tools/setup/dynamic-plugins/loader.ts +16 -0
- package/src/tools/setup/dynamic-plugins/policy.ts +55 -0
- package/src/tools/setup/dynamic-plugins/staging.ts +53 -0
- package/src/tools/setup/dynamic-plugins/verify.ts +70 -0
- package/src/tools/setup/mate.ts +1 -1
- package/src/tools/setup/providers/claude-format.ts +1 -1
- package/src/tools/setup/providers/claude.ts +1 -1
- package/src/tools/setup/providers/opencode-format.ts +220 -25
- package/src/tools/setup/providers/opencode.ts +63 -21
- package/src/tools/setup/runtime-documents.ts +9 -11
- package/src/tools/setup.ts +0 -4
- package/src/cli/commands/studio/views/pairings.tsx +0 -38
- package/src/templates/providers/opencode/tui.json +0 -3
|
@@ -25,6 +25,7 @@ import { mergeDir, pruneEmptyAncestors } from "../utils";
|
|
|
25
25
|
import {
|
|
26
26
|
getOpenCodePluginReferences,
|
|
27
27
|
isRecord,
|
|
28
|
+
normalizeOpenCodeConfig,
|
|
28
29
|
readOpenCodeConfig,
|
|
29
30
|
setOpenCodePluginReferences,
|
|
30
31
|
toOpenCodeMcpEntry,
|
|
@@ -34,6 +35,8 @@ import {
|
|
|
34
35
|
} from "./opencode-format";
|
|
35
36
|
import { getSetupProvidersRoot, getSetupRootTemplates } from "./utils";
|
|
36
37
|
|
|
38
|
+
const COMPANION_GITIGNORE_ENTRIES = [".opencode/service.json"];
|
|
39
|
+
|
|
37
40
|
// Copied Mate plugin source files from earlier releases. Plugin code is
|
|
38
41
|
// package-owned now; these exact filenames are removed during sync and
|
|
39
42
|
// teardown while every other companion-local plugin is preserved.
|
|
@@ -111,6 +114,11 @@ function isLegacyMatePluginConfigEntry(entry: unknown): boolean {
|
|
|
111
114
|
return typeof entry === "string" && LEGACY_PLUGIN_CONFIG_ENTRY_PATTERN.test(entry);
|
|
112
115
|
}
|
|
113
116
|
|
|
117
|
+
/** Current package references and legacy copied-file references alike. */
|
|
118
|
+
function isMatePluginEntry(entry: unknown): boolean {
|
|
119
|
+
return isMateOpenCodePluginReference(entry) || isLegacyMatePluginConfigEntry(entry);
|
|
120
|
+
}
|
|
121
|
+
|
|
114
122
|
/**
|
|
115
123
|
* Replace any Mate plugin entry (stale package pins and legacy copied-file
|
|
116
124
|
* references) with the current pinned package reference while preserving
|
|
@@ -118,16 +126,16 @@ function isLegacyMatePluginConfigEntry(entry: unknown): boolean {
|
|
|
118
126
|
*/
|
|
119
127
|
function ensureMatePluginReference(config: OpenCodeConfig, pluginReference: string): void {
|
|
120
128
|
const preserved = getOpenCodePluginReferences(config).filter(
|
|
121
|
-
(entry) => !
|
|
129
|
+
(entry) => !isMatePluginEntry(entry),
|
|
122
130
|
);
|
|
123
131
|
setOpenCodePluginReferences(config, [...preserved, pluginReference]);
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
function stripMatePluginReference(config: OpenCodeConfig): void {
|
|
127
|
-
if (!Array.isArray(config.plugin)) return;
|
|
135
|
+
if (!Array.isArray(config.plugin) && !Array.isArray(config.plugins)) return;
|
|
128
136
|
|
|
129
137
|
const preserved = getOpenCodePluginReferences(config).filter(
|
|
130
|
-
(entry) => !
|
|
138
|
+
(entry) => !isMatePluginEntry(entry),
|
|
131
139
|
);
|
|
132
140
|
setOpenCodePluginReferences(config, preserved);
|
|
133
141
|
}
|
|
@@ -137,11 +145,15 @@ async function syncOpenCodeConfigFile(
|
|
|
137
145
|
destPath: string,
|
|
138
146
|
pluginReference: string,
|
|
139
147
|
): Promise<void> {
|
|
140
|
-
const defaults =
|
|
148
|
+
const defaults = normalizeOpenCodeConfig(
|
|
149
|
+
JSON.parse(await fs.readFile(srcPath, "utf8")) as Record<string, unknown>,
|
|
150
|
+
);
|
|
141
151
|
|
|
142
152
|
let existing: Record<string, unknown> = {};
|
|
143
153
|
try {
|
|
144
|
-
existing =
|
|
154
|
+
existing = normalizeOpenCodeConfig(
|
|
155
|
+
JSON.parse(await fs.readFile(destPath, "utf8")) as Record<string, unknown>,
|
|
156
|
+
);
|
|
145
157
|
} catch (error) {
|
|
146
158
|
const code = (error as NodeJS.ErrnoException).code;
|
|
147
159
|
if (code !== "ENOENT") {
|
|
@@ -154,6 +166,38 @@ async function syncOpenCodeConfigFile(
|
|
|
154
166
|
await writeOpenCodeConfig(destPath, existing);
|
|
155
167
|
}
|
|
156
168
|
|
|
169
|
+
/**
|
|
170
|
+
* V2 loads TUI components exposed by server plugins declared in opencode.json;
|
|
171
|
+
* project-local tui.json is no longer a config destination. Strip only Mate's
|
|
172
|
+
* old duplicate reference and leave unrelated legacy contents for OpenCode's
|
|
173
|
+
* own TUI-config migration.
|
|
174
|
+
*/
|
|
175
|
+
async function removeMatePluginFromLegacyTuiConfig(configDir: string): Promise<void> {
|
|
176
|
+
const configPath = path.join(configDir, "tui.json");
|
|
177
|
+
let config: Record<string, unknown>;
|
|
178
|
+
try {
|
|
179
|
+
const parsed = JSON.parse(await fs.readFile(configPath, "utf8")) as unknown;
|
|
180
|
+
if (!isRecord(parsed)) return;
|
|
181
|
+
config = parsed;
|
|
182
|
+
} catch {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (const key of ["plugin", "plugins"]) {
|
|
187
|
+
if (!Array.isArray(config[key])) continue;
|
|
188
|
+
const kept = (config[key] as unknown[]).filter((entry) => !isMatePluginEntry(entry));
|
|
189
|
+
if (kept.length > 0) config[key] = kept;
|
|
190
|
+
else delete config[key];
|
|
191
|
+
}
|
|
192
|
+
if (config.$schema === "https://opencode.ai/tui.json") delete config.$schema;
|
|
193
|
+
|
|
194
|
+
if (Object.keys(config).length === 0) {
|
|
195
|
+
await fs.unlink(configPath).catch(() => {});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
await writeOpenCodeConfig(configPath, config);
|
|
199
|
+
}
|
|
200
|
+
|
|
157
201
|
function normalizeForComparison(value: unknown): unknown {
|
|
158
202
|
if (Array.isArray(value)) {
|
|
159
203
|
return value.map(normalizeForComparison);
|
|
@@ -284,11 +328,7 @@ async function syncOpenCodeRuntimeFiles(
|
|
|
284
328
|
path.join(dest, "opencode.json"),
|
|
285
329
|
pluginReference,
|
|
286
330
|
);
|
|
287
|
-
await
|
|
288
|
-
path.join(src, "tui.json"),
|
|
289
|
-
path.join(dest, "tui.json"),
|
|
290
|
-
pluginReference,
|
|
291
|
-
);
|
|
331
|
+
await removeMatePluginFromLegacyTuiConfig(dest);
|
|
292
332
|
await removeLegacyRuntimeFiles(dest);
|
|
293
333
|
await removeLegacyTuiDependencies(dest);
|
|
294
334
|
|
|
@@ -331,7 +371,7 @@ async function teardownOpenCode(companionPath: string, activeProviders: string[]
|
|
|
331
371
|
path.join(src, "opencode.json"),
|
|
332
372
|
path.join(dest, "opencode.json"),
|
|
333
373
|
);
|
|
334
|
-
await
|
|
374
|
+
await removeMatePluginFromLegacyTuiConfig(dest);
|
|
335
375
|
await removeLegacyRuntimeFiles(dest);
|
|
336
376
|
await removeLegacyTuiDependencies(dest);
|
|
337
377
|
await pruneEmptyAncestors(path.join(dest, "plugins"), companionPath);
|
|
@@ -405,10 +445,10 @@ export async function removeOpenCodeForeignPluginReferences(
|
|
|
405
445
|
}
|
|
406
446
|
try {
|
|
407
447
|
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
408
|
-
if (Array.isArray(parsed.plugin)) {
|
|
448
|
+
if (Array.isArray(parsed.plugin) || Array.isArray(parsed.plugins)) {
|
|
409
449
|
setOpenCodePluginReferences(
|
|
410
450
|
parsed,
|
|
411
|
-
parsed.
|
|
451
|
+
getOpenCodePluginReferences(parsed).filter((entry) => !isForeign(entry)),
|
|
412
452
|
);
|
|
413
453
|
}
|
|
414
454
|
if (Object.keys(parsed).length === 0) {
|
|
@@ -428,7 +468,7 @@ export async function removeOpenCodeForeignPluginReferences(
|
|
|
428
468
|
// skill trees.
|
|
429
469
|
// ---------------------------------------------------------------------------
|
|
430
470
|
|
|
431
|
-
const OPENCODE_CONTRIBUTION_CONFIG_FILES = ["opencode.json"
|
|
471
|
+
const OPENCODE_CONTRIBUTION_CONFIG_FILES = ["opencode.json"];
|
|
432
472
|
|
|
433
473
|
export async function reconcileOpenCodeContributions(
|
|
434
474
|
ctx: SetupContext,
|
|
@@ -517,7 +557,7 @@ async function reconcileOpenCodeMcpContributions(
|
|
|
517
557
|
}
|
|
518
558
|
}
|
|
519
559
|
|
|
520
|
-
/** The Mate-managed `mcp` map of one pass, as a value. */
|
|
560
|
+
/** The Mate-managed V2 `mcp.servers` map of one pass, as a value. */
|
|
521
561
|
export function renderManagedOpenCodeMcpServers(
|
|
522
562
|
contributions: CapabilityContributionInput[] = [],
|
|
523
563
|
): Record<string, unknown> {
|
|
@@ -532,14 +572,17 @@ export function renderManagedOpenCodeMcpServers(
|
|
|
532
572
|
}
|
|
533
573
|
|
|
534
574
|
/**
|
|
535
|
-
* The Mate-managed `
|
|
536
|
-
*
|
|
575
|
+
* The Mate-managed V2 `external_directory` rules. Rendered once for both
|
|
576
|
+
* destinations a session can reach them through — the projected
|
|
537
577
|
* document and the launch environment — so the two cannot drift.
|
|
538
578
|
*/
|
|
539
579
|
export function renderCompanionExternalDirectoryPermissions(
|
|
540
580
|
companionPath: string,
|
|
541
|
-
):
|
|
542
|
-
return
|
|
581
|
+
): Array<{ action: string; resource: string; effect: string }> {
|
|
582
|
+
return [
|
|
583
|
+
{ action: "external_directory", resource: companionPath, effect: "allow" },
|
|
584
|
+
{ action: "external_directory", resource: `${companionPath}/**`, effect: "allow" },
|
|
585
|
+
];
|
|
543
586
|
}
|
|
544
587
|
|
|
545
588
|
/**
|
|
@@ -575,6 +618,7 @@ export function createOpenCodePlugin(): ProviderPlugin {
|
|
|
575
618
|
description: "Install the OpenCode plugin workspace.",
|
|
576
619
|
defaultSelected: false,
|
|
577
620
|
isEnabled: (config) => (config.allowedAgents ?? []).includes("opencode"),
|
|
621
|
+
gitignoreEntries: () => COMPANION_GITIGNORE_ENTRIES,
|
|
578
622
|
hosting: {
|
|
579
623
|
mcp: {
|
|
580
624
|
async register(ctx: SetupContext, descriptor) {
|
|
@@ -610,5 +654,3 @@ export function createOpenCodePlugin(): ProviderPlugin {
|
|
|
610
654
|
},
|
|
611
655
|
};
|
|
612
656
|
}
|
|
613
|
-
|
|
614
|
-
export { OPENCODE_PLUGIN_PACKAGE_NAME };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CLAUDE_LOCAL_CONFIG_DOCUMENT,
|
|
3
|
-
CLAUDE_MCP_DOCUMENT,
|
|
4
3
|
CLAUDE_SETTINGS_DOCUMENT,
|
|
5
4
|
OPENCODE_CONFIG_DOCUMENT,
|
|
6
5
|
} from "../../lib/orchestrator/projection-runtime-documents";
|
|
@@ -32,12 +31,7 @@ import { projectionRepoRoot } from "./surface-target";
|
|
|
32
31
|
* differs from the companion target.
|
|
33
32
|
*/
|
|
34
33
|
|
|
35
|
-
export {
|
|
36
|
-
CLAUDE_LOCAL_CONFIG_DOCUMENT,
|
|
37
|
-
CLAUDE_MCP_DOCUMENT,
|
|
38
|
-
CLAUDE_SETTINGS_DOCUMENT,
|
|
39
|
-
OPENCODE_CONFIG_DOCUMENT,
|
|
40
|
-
};
|
|
34
|
+
export { CLAUDE_LOCAL_CONFIG_DOCUMENT };
|
|
41
35
|
|
|
42
36
|
function nonEmpty(region: ManagedRegion): boolean {
|
|
43
37
|
if (region.kind === "list") return region.values.length > 0;
|
|
@@ -157,15 +151,19 @@ export function renderDocumentsForTarget(
|
|
|
157
151
|
documents.push(
|
|
158
152
|
...document(OPENCODE_CONFIG_DOCUMENT, [
|
|
159
153
|
{
|
|
160
|
-
at: ["
|
|
154
|
+
at: ["plugins"],
|
|
161
155
|
kind: "list",
|
|
162
156
|
values: [getOpenCodePluginPackageReference()],
|
|
163
157
|
},
|
|
164
|
-
{ at: ["mcp"], kind: "map", entries: renderManagedOpenCodeMcpServers(inputs) },
|
|
165
158
|
{
|
|
166
|
-
at: ["
|
|
159
|
+
at: ["mcp", "servers"],
|
|
167
160
|
kind: "map",
|
|
168
|
-
entries:
|
|
161
|
+
entries: renderManagedOpenCodeMcpServers(inputs),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
at: ["permissions"],
|
|
165
|
+
kind: "list",
|
|
166
|
+
values: renderCompanionExternalDirectoryPermissions(ctx.companionPath),
|
|
169
167
|
},
|
|
170
168
|
]),
|
|
171
169
|
);
|
package/src/tools/setup.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { FRAMEWORK_NAME } from "../framework";
|
|
|
5
5
|
import { ConfigStore, mergeWithDefaults } from "../lib/orchestrator/config-store";
|
|
6
6
|
import { GlobalConfigStore } from "../lib/orchestrator/global-config-store";
|
|
7
7
|
import {
|
|
8
|
-
BUILTIN_SETUP_COMPATIBILITIES,
|
|
9
8
|
dedupeCapabilities,
|
|
10
9
|
getSetupSelectionsFromConfig,
|
|
11
10
|
} from "../lib/orchestrator/setup-compatibilities";
|
|
@@ -194,6 +193,3 @@ export function createUvPluginForTest(deps: PackageManagerSetupDeps) {
|
|
|
194
193
|
}
|
|
195
194
|
|
|
196
195
|
export default setup;
|
|
197
|
-
|
|
198
|
-
// Re-export BUILTIN_SETUP_COMPATIBILITIES passthrough for setup-selector UI compatibility.
|
|
199
|
-
export { BUILTIN_SETUP_COMPATIBILITIES };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource hono/jsx */
|
|
2
|
-
|
|
3
|
-
import type { StudioInventoryCompanion } from "../inventory";
|
|
4
|
-
|
|
5
|
-
interface PairingsProps {
|
|
6
|
-
companion: StudioInventoryCompanion | null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Context, never a selection: everything Studio serves is companion-scoped, so
|
|
11
|
-
* a Working Repository is listed and never chosen.
|
|
12
|
-
*/
|
|
13
|
-
export function Pairings({ companion }: PairingsProps) {
|
|
14
|
-
const pairings = companion?.pairings ?? [];
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<div className="sidebar-pairings">
|
|
18
|
-
<span className="sidebar-label">Working repositories</span>
|
|
19
|
-
{pairings.length === 0 ? (
|
|
20
|
-
<p className="empty">no linked working repository</p>
|
|
21
|
-
) : (
|
|
22
|
-
<ul className="plain pairings">
|
|
23
|
-
{pairings.map((pairing) => (
|
|
24
|
-
<li key={pairing.repositoryPath} data-repository={pairing.repositoryPath}>
|
|
25
|
-
<span className="mono">{pairing.repositoryId}</span>
|
|
26
|
-
{pairing.ambiguous ? <span className="chip">also paired elsewhere</span> : null}
|
|
27
|
-
{pairing.health === "ready" ? null : (
|
|
28
|
-
<span className="chip chip-invalid">{pairing.health}</span>
|
|
29
|
-
)}
|
|
30
|
-
<br />
|
|
31
|
-
<span className="muted">{pairing.repositoryPath}</span>
|
|
32
|
-
</li>
|
|
33
|
-
))}
|
|
34
|
-
</ul>
|
|
35
|
-
)}
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
}
|