@uniqbit/mate-core 0.15.5 → 0.16.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/.claude-plugin/plugin.json +2 -2
- package/claude-plugin/hooks/hooks.json +3 -6
- package/claude-plugin/hooks/session-guidance.mjs +8 -0
- package/claude-plugin/hooks/ts-loader.mjs +19 -0
- package/package.json +6 -4
- package/src/cli/commands/artifact/artifact.ts +19 -3
- package/src/cli/commands/artifact/finish/command.ts +183 -57
- package/src/cli/commands/artifact/finish/engine.ts +80 -91
- package/src/cli/commands/artifact/finish/finisher.ts +26 -33
- package/src/cli/commands/artifact/finish/git.ts +34 -23
- package/src/cli/commands/artifact/finish/index.ts +9 -3
- package/src/cli/commands/artifact/finish/openspec.ts +225 -97
- package/src/cli/commands/artifact/pending/command.ts +175 -0
- package/src/cli/commands/artifact/pending/discovery.ts +249 -0
- package/src/cli/commands/artifact/pending/index.ts +17 -0
- package/src/cli/commands/cap/index-cmd.ts +9 -1
- package/src/cli/commands/cap/index.ts +2 -6
- package/src/cli/commands/companion/companion.ts +5 -1
- package/src/cli/commands/companion/link.ts +2 -2
- package/src/cli/commands/companion/sync.ts +92 -0
- package/src/cli/commands/doctor.ts +0 -3
- package/src/cli/commands/launch/shared.ts +23 -5
- package/src/cli/commands/report/collector.ts +72 -78
- package/src/cli/commands/report/contract.ts +40 -1
- package/src/cli/commands/report/highlight.ts +27 -0
- package/src/cli/commands/report/index.ts +11 -18
- package/src/cli/commands/report/renderer.ts +199 -2
- package/src/cli/commands/report/types.ts +26 -1
- package/src/cli/commands/shared/companion-selection.ts +107 -10
- package/src/cli/commands/studio/areas.ts +68 -0
- package/src/cli/commands/studio/index.ts +69 -0
- package/src/cli/commands/studio/inventory.ts +55 -0
- package/src/cli/commands/studio/mate-inventory.ts +43 -0
- package/src/cli/commands/studio/openspec-cli.ts +198 -0
- package/src/cli/commands/studio/payload.ts +184 -0
- package/src/cli/commands/studio/routes.ts +2 -0
- package/src/cli/commands/studio/selection.ts +61 -0
- package/src/cli/commands/studio/server.ts +201 -0
- package/src/cli/commands/studio/snapshot.ts +63 -0
- package/src/cli/commands/studio/topology.ts +199 -0
- package/src/cli/commands/studio/views/client.ts +197 -0
- package/src/cli/commands/studio/views/companion-picker.tsx +91 -0
- package/src/cli/commands/studio/views/companion-selector.tsx +90 -0
- package/src/cli/commands/studio/views/dashboard/changes.tsx +107 -0
- package/src/cli/commands/studio/views/dashboard/index.tsx +19 -0
- package/src/cli/commands/studio/views/document.tsx +256 -0
- package/src/cli/commands/studio/views/error.tsx +20 -0
- package/src/cli/commands/studio/views/model.ts +34 -0
- package/src/cli/commands/studio/views/pairings.tsx +38 -0
- package/src/cli/commands/studio/views/skills/index.tsx +87 -0
- package/src/cli/commands/studio/views/specs/index.tsx +101 -0
- package/src/cli/commands/studio/views/styles.ts +389 -0
- package/src/cli/commands/studio/views/warnings.tsx +21 -0
- package/src/cli/commands/studio/views/workflow/index.tsx +21 -0
- package/src/cli/commands/studio/views/workflow/steps.ts +329 -0
- package/src/cli/commands/studio/views/workflow/transcript.tsx +190 -0
- package/src/cli/commands/unwrap.ts +70 -0
- package/src/cli/commands/wrap.ts +164 -0
- package/src/cli/main.ts +68 -19
- package/src/cli/parse-flags.ts +36 -11
- package/src/cli/usage.ts +12 -3
- package/src/framework.ts +1 -7
- package/src/hooks/session-banner.ts +64 -11
- package/src/hooks/session-guidance.ts +40 -0
- package/src/hooks/validate-artifact-path.ts +108 -35
- package/src/lib/fs-utils.ts +9 -0
- package/src/lib/install.ts +33 -0
- package/src/lib/orchestrator/adapters/base.ts +14 -125
- package/src/lib/orchestrator/adapters/claude.ts +0 -11
- package/src/lib/orchestrator/adapters/opencode.ts +2 -32
- package/src/lib/orchestrator/companion-git-sync.ts +94 -84
- package/src/lib/orchestrator/config-store.ts +2 -21
- package/src/lib/orchestrator/editor.ts +12 -22
- package/src/lib/orchestrator/framework-context.ts +17 -6
- package/src/lib/orchestrator/global-config-store.ts +1 -1
- package/src/lib/orchestrator/launcher.ts +97 -7
- package/src/lib/orchestrator/opencode-guidance.ts +4 -56
- package/src/lib/orchestrator/projection-claude-entry.ts +198 -0
- package/src/lib/orchestrator/projection-claude-skills.ts +120 -0
- package/src/lib/orchestrator/projection-companion-link.ts +62 -0
- package/src/lib/orchestrator/projection-entries.ts +377 -0
- package/src/lib/orchestrator/projection-record.ts +56 -0
- package/src/lib/orchestrator/projection-runtime-documents.ts +424 -0
- package/src/lib/orchestrator/projection-types.ts +169 -0
- package/src/lib/orchestrator/repo-local-registry.ts +37 -133
- package/src/lib/orchestrator/repo-local-store.ts +96 -0
- package/src/lib/orchestrator/setup-compatibilities.ts +1 -9
- package/src/lib/orchestrator/types.ts +1 -0
- package/src/lib/orchestrator/working-repo-projection.ts +366 -0
- package/src/lib/orchestrator/workspace-inventory.ts +1 -1
- package/src/lib/package-paths.ts +11 -1
- package/src/opencode/companion-hooks.ts +89 -245
- package/src/opencode/companion-policy.ts +35 -10
- package/src/opencode/index.ts +1 -0
- package/src/opencode/projected-guidance.ts +56 -0
- package/src/opencode/tui.tsx +13 -4
- package/src/playbooks/companion-guidance.ts +32 -116
- package/src/plugins.ts +0 -1
- package/src/runtime/companion-git-state.ts +156 -0
- package/src/runtime/companion-git.ts +203 -0
- package/src/runtime/companion-guidance.ts +222 -0
- package/src/runtime/companion-sync.ts +298 -0
- package/src/runtime/env-names.ts +30 -0
- package/src/runtime/env.ts +67 -35
- package/src/runtime/framework.ts +10 -0
- package/src/runtime/freshness.ts +58 -0
- package/src/runtime/index.ts +104 -0
- package/src/runtime/install.ts +30 -0
- package/src/runtime/policy.ts +66 -0
- package/src/runtime/projected-guidance.ts +45 -0
- package/src/runtime/projection.ts +224 -0
- package/src/runtime/repo-local.ts +64 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +56 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/templates/spec.md +48 -0
- package/src/templates/capabilities/openspec-cap/mate-minimal/templates/tasks.md +22 -0
- package/src/templates/capabilities/openspec-cap/mate-v1/schema.yaml +31 -90
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/design.md +3 -0
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/explore-brief.md +6 -6
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/spec.md +3 -5
- package/src/templates/capabilities/openspec-cap/mate-v1/templates/tasks.md +3 -0
- package/src/templates/capabilities/openspec-cap/openspec-conventions.yaml +30 -0
- package/src/templates/capabilities/react-doctor/claude/hooks/react-doctor.sh +2 -2
- package/src/templates/mate-skills/agents/mate-artifact-publish/SKILL.md +185 -0
- package/src/templates/mate-skills/agents/mate-artifact-publish/references/openspec.md +227 -0
- package/src/templates/mate-skills/agents/mate-domain-modeling/SKILL.md +68 -0
- package/src/templates/mate-skills/agents/mate-domain-modeling/references/ADR-FORMAT.md +9 -0
- package/src/templates/mate-skills/agents/mate-domain-modeling/references/CONTEXT-FORMAT.md +18 -0
- package/src/templates/mate-skills/agents/mate-grill-me/SKILL.md +14 -0
- package/src/templates/mate-skills/agents/mate-grill-with-docs/SKILL.md +29 -0
- package/src/templates/mate-skills/agents/mate-grilling/SKILL.md +49 -0
- package/src/templates/mate-skills/agents/mate-interview-me/SKILL.md +147 -0
- package/src/templates/{capabilities/openspec-cap/mate-skills → mate-skills}/agents/mate-openspec-backfill/SKILL.md +4 -2
- package/src/templates/mate-skills/agents/mate-show-me/SKILL.md +139 -0
- package/src/templates/mate-skills/agents/mate-simplify-code/SKILL.md +503 -0
- package/src/templates/mate-skills/claude/mate-artifact-publish/SKILL.md +185 -0
- package/src/templates/mate-skills/claude/mate-artifact-publish/references/openspec.md +227 -0
- package/src/templates/mate-skills/claude/mate-domain-modeling/SKILL.md +68 -0
- package/src/templates/mate-skills/claude/mate-domain-modeling/references/ADR-FORMAT.md +9 -0
- package/src/templates/mate-skills/claude/mate-domain-modeling/references/CONTEXT-FORMAT.md +18 -0
- package/src/templates/mate-skills/claude/mate-grill-me/SKILL.md +14 -0
- package/src/templates/mate-skills/claude/mate-grill-with-docs/SKILL.md +29 -0
- package/src/templates/mate-skills/claude/mate-grilling/SKILL.md +49 -0
- package/src/templates/mate-skills/claude/mate-interview-me/SKILL.md +147 -0
- package/src/templates/mate-skills/claude/mate-openspec-backfill/SKILL.md +67 -0
- package/src/templates/mate-skills/claude/mate-show-me/SKILL.md +139 -0
- package/src/templates/mate-skills/claude/mate-simplify-code/SKILL.md +503 -0
- package/src/templates/report-assets/README.md +32 -0
- package/src/templates/report-assets/mermaid.LICENSE +21 -0
- package/src/templates/report-assets/mermaid.min.js +4376 -0
- package/src/templates/root/TEMPLATE_CLAUDE.md +1 -9
- package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +1476 -197
- package/src/tools/setup/capabilities/graphify.ts +16 -7
- package/src/tools/setup/capabilities/openspec.ts +63 -56
- package/src/tools/setup/capabilities/tokensave.ts +47 -0
- package/src/tools/setup/engine.ts +34 -6
- package/src/tools/setup/mate.ts +42 -13
- package/src/tools/setup/plugin.ts +9 -0
- package/src/tools/setup/plugins/guidance.ts +11 -1
- package/src/tools/setup/providers/claude-format.ts +49 -4
- package/src/tools/setup/providers/claude-plugin-hooks.ts +117 -0
- package/src/tools/setup/providers/claude.ts +55 -220
- package/src/tools/setup/providers/opencode.ts +41 -14
- package/src/tools/setup/runtime-documents.ts +174 -0
- package/src/tools/setup/surface-target.ts +50 -0
- package/src/tools/setup/working-repo-cleanup.ts +33 -26
- package/src/tools/setup/working-repo-local-state.ts +21 -1
- package/src/tools/setup.ts +25 -3
- package/wrappers/bin/graphify +57 -8
- package/wrappers/bin/openspec +50 -3
- package/claude-plugin/hooks/artifact-finish-nudge.mjs +0 -8
- package/src/cli/commands/cap/headroom.ts +0 -52
- package/src/cli/commands/workspace/list.ts +0 -25
- package/src/cli/commands/workspace/materialize.ts +0 -46
- package/src/cli/commands/workspace/workspace.ts +0 -22
- package/src/hooks/artifact-finish-nudge.ts +0 -244
- package/src/lib/orchestrator/headroom/proxy.ts +0 -116
- package/src/lib/orchestrator/workspace-materialize.ts +0 -80
- package/src/templates/capabilities/openspec-cap/mate-skills/agents/mate-artifact-finish/SKILL.md +0 -51
- package/src/templates/capabilities/openspec-cap/mate-skills/agents/mate-artifact-finish/references/openspec.md +0 -134
- package/src/templates/capabilities/openspec-cap/mate-skills/claude/mate-artifact-finish/SKILL.md +0 -58
- package/src/templates/capabilities/openspec-cap/mate-skills/claude/mate-artifact-finish/references/openspec.md +0 -139
- package/src/tools/setup/capabilities/headroom.ts +0 -57
- /package/src/cli/commands/{workspace → companion}/open.ts +0 -0
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
import { parse
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ancestorDirectories,
|
|
8
|
+
repoLocalDirName,
|
|
9
|
+
repoLocalRegistryPath,
|
|
10
|
+
type RepoLocalRegistryFile,
|
|
11
|
+
} from "../../runtime/repo-local";
|
|
12
|
+
import { firstFailure } from "./projection-types";
|
|
13
|
+
import { normalizeLinkedRepository } from "./repo-local-store";
|
|
14
|
+
import { project } from "./working-repo-projection";
|
|
15
|
+
import type { RepoLocalRegistry } from "./repo-local-store";
|
|
9
16
|
import type { CompanionSource, LinkedRepository } from "./types";
|
|
10
17
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export {
|
|
19
|
+
repoLocalDirPath,
|
|
20
|
+
repoLocalFrameworkPath,
|
|
21
|
+
repoLocalRegistryPath,
|
|
22
|
+
} from "../../runtime/repo-local";
|
|
23
|
+
export { pathIsDirectory } from "../fs-utils";
|
|
24
|
+
export {
|
|
25
|
+
RepoLocalRegistryStore,
|
|
26
|
+
upsertRepoLocalCompanionPointer,
|
|
27
|
+
upsertRepoLocalLinkedRepository,
|
|
28
|
+
writeRepoLocalFrameworkConfig,
|
|
29
|
+
type RepoLocalCompanionPointer,
|
|
30
|
+
type RepoLocalRegistry,
|
|
31
|
+
} from "./repo-local-store";
|
|
21
32
|
|
|
22
|
-
const repoLocalDirName = () => `.${FRAMEWORK_NAME}`;
|
|
23
33
|
const repoLocalScanSkipDirNames = () =>
|
|
24
34
|
new Set([
|
|
25
35
|
".git",
|
|
@@ -35,100 +45,11 @@ const repoLocalScanSkipDirNames = () =>
|
|
|
35
45
|
".cache",
|
|
36
46
|
]);
|
|
37
47
|
|
|
38
|
-
export function repoLocalDirPath(repoPath: string): string {
|
|
39
|
-
return path.join(path.resolve(repoPath), repoLocalDirName());
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function repoLocalRegistryPath(repoPath: string): string {
|
|
43
|
-
return path.join(repoLocalDirPath(repoPath), "config", "registry.yaml");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function repoLocalFrameworkPath(repoPath: string): string {
|
|
47
|
-
return path.join(repoLocalDirPath(repoPath), "config", "framework.yaml");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export class RepoLocalRegistryStore extends YamlFileStore<RepoLocalRegistry> {
|
|
51
|
-
protected async onMissing(): Promise<RepoLocalRegistry> {
|
|
52
|
-
return { companions: [] };
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
48
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await ensureWorkingRepoLocalExcludes(repoPath);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Writes `.mate/config/framework.yaml` with `type: "working"` if it does not already exist. */
|
|
65
|
-
export async function writeRepoLocalFrameworkConfig(repoPath: string): Promise<void> {
|
|
66
|
-
const frameworkPath = repoLocalFrameworkPath(repoPath);
|
|
67
|
-
try {
|
|
68
|
-
await fs.access(frameworkPath);
|
|
69
|
-
return;
|
|
70
|
-
} catch {
|
|
71
|
-
// fall through to create it
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await fs.mkdir(path.dirname(frameworkPath), { recursive: true });
|
|
75
|
-
await fs.writeFile(frameworkPath, stringify({ type: "working" }), "utf8");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function loadRepoLocalRegistry(repoPath: string): Promise<RepoLocalRegistry> {
|
|
79
|
-
const store = new RepoLocalRegistryStore(repoLocalRegistryPath(repoPath));
|
|
80
|
-
return store.load();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function saveRepoLocalRegistry(repoPath: string, registry: RepoLocalRegistry): Promise<void> {
|
|
84
|
-
const store = new RepoLocalRegistryStore(repoLocalRegistryPath(repoPath));
|
|
85
|
-
await store.save(registry);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Field-explicit on purpose: also strips legacy per-repo policy fields
|
|
89
|
-
// (profile/overrides) from entries read from or written to disk.
|
|
90
|
-
function normalizeLinkedRepository(repository: LinkedRepository): LinkedRepository {
|
|
91
|
-
return {
|
|
92
|
-
id: repository.id,
|
|
93
|
-
path: path.resolve(repository.path),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function upsertRepoLocalLinkedRepository(
|
|
98
|
-
repoPath: string,
|
|
99
|
-
repository: LinkedRepository,
|
|
100
|
-
): Promise<void> {
|
|
101
|
-
const registry = await loadRepoLocalRegistry(repoPath);
|
|
102
|
-
registry.repository = normalizeLinkedRepository(repository);
|
|
103
|
-
await saveRepoLocalRegistry(repoPath, registry);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Upserts a companion pointer (by path) into the working repo's local registry. */
|
|
107
|
-
export async function upsertRepoLocalCompanionPointer(
|
|
108
|
-
repoPath: string,
|
|
109
|
-
companionPath: string,
|
|
110
|
-
repositoryId: string,
|
|
111
|
-
source: CompanionSource,
|
|
112
|
-
): Promise<void> {
|
|
113
|
-
const resolvedCompanionPath = path.resolve(companionPath);
|
|
114
|
-
const registry = await loadRepoLocalRegistry(repoPath);
|
|
115
|
-
const existingIndex = registry.companions.findIndex(
|
|
116
|
-
(pointer) => path.resolve(pointer.path) === resolvedCompanionPath,
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
if (existingIndex >= 0) {
|
|
120
|
-
registry.companions[existingIndex] = { path: resolvedCompanionPath, repositoryId, source };
|
|
121
|
-
} else {
|
|
122
|
-
registry.companions.push({ path: resolvedCompanionPath, repositoryId, source });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
await saveRepoLocalRegistry(repoPath, registry);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Single entry point for the dual-write at link time: ensures the `.mate`
|
|
130
|
-
* directory exists, is git-excluded, has a working-repo `framework.yaml`,
|
|
131
|
-
* and records the companion pointer in the repo-local registry.
|
|
49
|
+
* Records a Repository Link. Deliberately writes no projection file: wrapping is
|
|
50
|
+
* an explicit act, which is why the scope and not the inputs picks the entries.
|
|
51
|
+
* Throws on the first failed entry — this caller's own callers warn on it, so
|
|
52
|
+
* the owner's per-entry best-effort report must not silently become success.
|
|
132
53
|
*/
|
|
133
54
|
export async function writeRepoLocalRegistryEntry(
|
|
134
55
|
repoPath: string,
|
|
@@ -136,10 +57,9 @@ export async function writeRepoLocalRegistryEntry(
|
|
|
136
57
|
repository: LinkedRepository,
|
|
137
58
|
source: CompanionSource,
|
|
138
59
|
): Promise<void> {
|
|
139
|
-
await
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
await upsertRepoLocalCompanionPointer(repoPath, companionPath, repository.id, source);
|
|
60
|
+
const { outcomes } = await project("link", { repoPath, companionPath, repository, source });
|
|
61
|
+
const failure = firstFailure(outcomes);
|
|
62
|
+
if (failure) throw failure.error ?? new Error(`failed to project ${failure.path}`);
|
|
143
63
|
}
|
|
144
64
|
|
|
145
65
|
export async function findRepoLocalLinkedRepository(cwd: string): Promise<LinkedRepository | null> {
|
|
@@ -180,23 +100,16 @@ export async function listOtherRepoLocalCompanionPaths(
|
|
|
180
100
|
/** Walks up from `cwd` looking for the nearest ancestor holding a repo-local registry file. */
|
|
181
101
|
export async function findRepoLocalRegistryFile(
|
|
182
102
|
cwd: string,
|
|
183
|
-
): Promise<
|
|
184
|
-
|
|
185
|
-
for (;;) {
|
|
103
|
+
): Promise<RepoLocalRegistryFile | null> {
|
|
104
|
+
for (const dir of ancestorDirectories(cwd)) {
|
|
186
105
|
const candidate = repoLocalRegistryPath(dir);
|
|
187
106
|
try {
|
|
188
|
-
|
|
189
|
-
if (stats.isFile()) {
|
|
190
|
-
return { repoRoot: dir, registryPath: candidate };
|
|
191
|
-
}
|
|
107
|
+
if ((await fs.stat(candidate)).isFile()) return { repoRoot: dir, registryPath: candidate };
|
|
192
108
|
} catch {
|
|
193
109
|
// keep walking up
|
|
194
110
|
}
|
|
195
|
-
|
|
196
|
-
const parent = path.dirname(dir);
|
|
197
|
-
if (parent === dir) return null;
|
|
198
|
-
dir = parent;
|
|
199
111
|
}
|
|
112
|
+
return null;
|
|
200
113
|
}
|
|
201
114
|
|
|
202
115
|
/** Finds repo-local registries strictly beneath `rootPath`, skipping noisy directories. */
|
|
@@ -250,12 +163,3 @@ export async function findDescendantRepoLocalRegistries(rootPath: string): Promi
|
|
|
250
163
|
);
|
|
251
164
|
return shadowedPaths.filter((candidate): candidate is string => candidate !== null).sort();
|
|
252
165
|
}
|
|
253
|
-
|
|
254
|
-
export async function pathIsDirectory(candidatePath: string): Promise<boolean> {
|
|
255
|
-
try {
|
|
256
|
-
const stats = await fs.stat(candidatePath);
|
|
257
|
-
return stats.isDirectory();
|
|
258
|
-
} catch {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { stringify } from "yaml";
|
|
5
|
+
|
|
6
|
+
import { repoLocalFrameworkPath, repoLocalRegistryPath } from "../../runtime/repo-local";
|
|
7
|
+
import { YamlFileStore } from "./yaml-file-store";
|
|
8
|
+
import type { CompanionSource, LinkedRepository } from "./types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The repo-local registry's shape and its writers. Split from
|
|
12
|
+
* `repo-local-registry.ts` so the Managed Projection's catalogue can declare
|
|
13
|
+
* these writes without importing the module that calls the projection owner.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export interface RepoLocalCompanionPointer {
|
|
17
|
+
path: string;
|
|
18
|
+
repositoryId: string;
|
|
19
|
+
source?: CompanionSource;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RepoLocalRegistry {
|
|
23
|
+
repository?: LinkedRepository;
|
|
24
|
+
companions: RepoLocalCompanionPointer[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class RepoLocalRegistryStore extends YamlFileStore<RepoLocalRegistry> {
|
|
28
|
+
protected async onMissing(): Promise<RepoLocalRegistry> {
|
|
29
|
+
return { companions: [] };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Writes `.mate/config/framework.yaml` with `type: "working"` if it does not already exist. */
|
|
34
|
+
export async function writeRepoLocalFrameworkConfig(repoPath: string): Promise<boolean> {
|
|
35
|
+
const frameworkPath = repoLocalFrameworkPath(repoPath);
|
|
36
|
+
try {
|
|
37
|
+
await fs.access(frameworkPath);
|
|
38
|
+
return false;
|
|
39
|
+
} catch {
|
|
40
|
+
// fall through to create it
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await fs.mkdir(path.dirname(frameworkPath), { recursive: true });
|
|
44
|
+
await fs.writeFile(frameworkPath, stringify({ type: "working" }), "utf8");
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function loadRepoLocalRegistry(repoPath: string): Promise<RepoLocalRegistry> {
|
|
49
|
+
const store = new RepoLocalRegistryStore(repoLocalRegistryPath(repoPath));
|
|
50
|
+
return store.load();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function saveRepoLocalRegistry(repoPath: string, registry: RepoLocalRegistry): Promise<void> {
|
|
54
|
+
const store = new RepoLocalRegistryStore(repoLocalRegistryPath(repoPath));
|
|
55
|
+
await store.save(registry);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Field-explicit on purpose: also strips legacy per-repo policy fields
|
|
59
|
+
// (profile/overrides) from entries read from or written to disk.
|
|
60
|
+
export function normalizeLinkedRepository(repository: LinkedRepository): LinkedRepository {
|
|
61
|
+
return {
|
|
62
|
+
id: repository.id,
|
|
63
|
+
path: path.resolve(repository.path),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function upsertRepoLocalLinkedRepository(
|
|
68
|
+
repoPath: string,
|
|
69
|
+
repository: LinkedRepository,
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
const registry = await loadRepoLocalRegistry(repoPath);
|
|
72
|
+
registry.repository = normalizeLinkedRepository(repository);
|
|
73
|
+
await saveRepoLocalRegistry(repoPath, registry);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Upserts a companion pointer (by path) into the working repo's local registry. */
|
|
77
|
+
export async function upsertRepoLocalCompanionPointer(
|
|
78
|
+
repoPath: string,
|
|
79
|
+
companionPath: string,
|
|
80
|
+
repositoryId: string,
|
|
81
|
+
source: CompanionSource,
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
const resolvedCompanionPath = path.resolve(companionPath);
|
|
84
|
+
const registry = await loadRepoLocalRegistry(repoPath);
|
|
85
|
+
const existingIndex = registry.companions.findIndex(
|
|
86
|
+
(pointer) => path.resolve(pointer.path) === resolvedCompanionPath,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (existingIndex >= 0) {
|
|
90
|
+
registry.companions[existingIndex] = { path: resolvedCompanionPath, repositoryId, source };
|
|
91
|
+
} else {
|
|
92
|
+
registry.companions.push({ path: resolvedCompanionPath, repositoryId, source });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await saveRepoLocalRegistry(repoPath, registry);
|
|
96
|
+
}
|
|
@@ -185,20 +185,12 @@ export const BUILTIN_SETUP_COMPATIBILITIES: SetupCompatibility[] = [
|
|
|
185
185
|
description: "Enable TokenSave MCP access while keeping native repo-local .tokensave storage.",
|
|
186
186
|
defaultSelected: false,
|
|
187
187
|
},
|
|
188
|
-
{
|
|
189
|
-
id: "headroom",
|
|
190
|
-
kind: "capability",
|
|
191
|
-
capability: { name: "headroom" },
|
|
192
|
-
label: "Headroom",
|
|
193
|
-
description: "Wrap supported agent launches through Headroom when the binary is installed.",
|
|
194
|
-
defaultSelected: false,
|
|
195
|
-
},
|
|
196
188
|
{
|
|
197
189
|
id: "rtk",
|
|
198
190
|
kind: "capability",
|
|
199
191
|
capability: { name: "rtk" },
|
|
200
192
|
label: "RTK",
|
|
201
|
-
description: "Patch supported agent providers with RTK
|
|
193
|
+
description: "Patch supported agent providers with the RTK token-optimizing CLI proxy.",
|
|
202
194
|
defaultSelected: false,
|
|
203
195
|
},
|
|
204
196
|
{
|