@uniqbit/mate-core 0.15.5 → 0.16.0-canary.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.
Files changed (186) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +2 -2
  2. package/claude-plugin/hooks/hooks.json +3 -6
  3. package/claude-plugin/hooks/session-guidance.mjs +8 -0
  4. package/claude-plugin/hooks/ts-loader.mjs +19 -0
  5. package/package.json +7 -5
  6. package/src/cli/commands/artifact/artifact.ts +19 -3
  7. package/src/cli/commands/artifact/finish/command.ts +183 -57
  8. package/src/cli/commands/artifact/finish/engine.ts +80 -91
  9. package/src/cli/commands/artifact/finish/finisher.ts +26 -33
  10. package/src/cli/commands/artifact/finish/git.ts +34 -23
  11. package/src/cli/commands/artifact/finish/index.ts +9 -3
  12. package/src/cli/commands/artifact/finish/openspec.ts +225 -97
  13. package/src/cli/commands/artifact/pending/command.ts +175 -0
  14. package/src/cli/commands/artifact/pending/discovery.ts +249 -0
  15. package/src/cli/commands/artifact/pending/index.ts +17 -0
  16. package/src/cli/commands/cap/index-cmd.ts +9 -1
  17. package/src/cli/commands/cap/index.ts +2 -6
  18. package/src/cli/commands/cap/tokensave.ts +4 -4
  19. package/src/cli/commands/companion/companion.ts +5 -1
  20. package/src/cli/commands/companion/link.ts +2 -2
  21. package/src/cli/commands/companion/sync.ts +92 -0
  22. package/src/cli/commands/doctor.ts +0 -3
  23. package/src/cli/commands/launch/shared.ts +23 -5
  24. package/src/cli/commands/report/collector.ts +72 -78
  25. package/src/cli/commands/report/contract.ts +40 -1
  26. package/src/cli/commands/report/highlight.ts +27 -0
  27. package/src/cli/commands/report/index.ts +11 -18
  28. package/src/cli/commands/report/renderer.ts +199 -2
  29. package/src/cli/commands/report/types.ts +26 -1
  30. package/src/cli/commands/shared/companion-selection.ts +107 -10
  31. package/src/cli/commands/studio/areas.ts +68 -0
  32. package/src/cli/commands/studio/index.ts +69 -0
  33. package/src/cli/commands/studio/inventory.ts +55 -0
  34. package/src/cli/commands/studio/mate-inventory.ts +43 -0
  35. package/src/cli/commands/studio/openspec-cli.ts +198 -0
  36. package/src/cli/commands/studio/payload.ts +184 -0
  37. package/src/cli/commands/studio/routes.ts +2 -0
  38. package/src/cli/commands/studio/selection.ts +61 -0
  39. package/src/cli/commands/studio/server.ts +201 -0
  40. package/src/cli/commands/studio/snapshot.ts +63 -0
  41. package/src/cli/commands/studio/topology.ts +199 -0
  42. package/src/cli/commands/studio/views/client.ts +197 -0
  43. package/src/cli/commands/studio/views/companion-picker.tsx +91 -0
  44. package/src/cli/commands/studio/views/companion-selector.tsx +90 -0
  45. package/src/cli/commands/studio/views/dashboard/changes.tsx +107 -0
  46. package/src/cli/commands/studio/views/dashboard/index.tsx +19 -0
  47. package/src/cli/commands/studio/views/document.tsx +256 -0
  48. package/src/cli/commands/studio/views/error.tsx +20 -0
  49. package/src/cli/commands/studio/views/model.ts +34 -0
  50. package/src/cli/commands/studio/views/pairings.tsx +38 -0
  51. package/src/cli/commands/studio/views/skills/index.tsx +87 -0
  52. package/src/cli/commands/studio/views/specs/index.tsx +101 -0
  53. package/src/cli/commands/studio/views/styles.ts +389 -0
  54. package/src/cli/commands/studio/views/warnings.tsx +21 -0
  55. package/src/cli/commands/studio/views/workflow/index.tsx +21 -0
  56. package/src/cli/commands/studio/views/workflow/steps.ts +329 -0
  57. package/src/cli/commands/studio/views/workflow/transcript.tsx +190 -0
  58. package/src/cli/commands/unwrap.ts +70 -0
  59. package/src/cli/commands/wrap.ts +164 -0
  60. package/src/cli/main.ts +68 -19
  61. package/src/cli/parse-flags.ts +36 -11
  62. package/src/cli/usage.ts +12 -3
  63. package/src/framework.ts +1 -7
  64. package/src/hooks/session-banner.ts +64 -11
  65. package/src/hooks/session-guidance.ts +40 -0
  66. package/src/hooks/validate-artifact-path.ts +108 -35
  67. package/src/lib/fs-utils.ts +9 -0
  68. package/src/lib/install.ts +33 -0
  69. package/src/lib/orchestrator/adapters/base.ts +14 -125
  70. package/src/lib/orchestrator/adapters/claude.ts +0 -11
  71. package/src/lib/orchestrator/adapters/opencode.ts +2 -32
  72. package/src/lib/orchestrator/companion-git-sync.ts +94 -84
  73. package/src/lib/orchestrator/config-store.ts +2 -21
  74. package/src/lib/orchestrator/editor.ts +12 -22
  75. package/src/lib/orchestrator/framework-context.ts +17 -6
  76. package/src/lib/orchestrator/global-config-store.ts +1 -1
  77. package/src/lib/orchestrator/launcher.ts +97 -7
  78. package/src/lib/orchestrator/opencode-guidance.ts +4 -56
  79. package/src/lib/orchestrator/projection-claude-entry.ts +198 -0
  80. package/src/lib/orchestrator/projection-claude-skills.ts +120 -0
  81. package/src/lib/orchestrator/projection-companion-link.ts +62 -0
  82. package/src/lib/orchestrator/projection-entries.ts +377 -0
  83. package/src/lib/orchestrator/projection-record.ts +56 -0
  84. package/src/lib/orchestrator/projection-runtime-documents.ts +424 -0
  85. package/src/lib/orchestrator/projection-types.ts +169 -0
  86. package/src/lib/orchestrator/repo-local-registry.ts +37 -133
  87. package/src/lib/orchestrator/repo-local-store.ts +96 -0
  88. package/src/lib/orchestrator/setup-compatibilities.ts +1 -9
  89. package/src/lib/orchestrator/types.ts +1 -0
  90. package/src/lib/orchestrator/working-repo-projection.ts +366 -0
  91. package/src/lib/orchestrator/workspace-inventory.ts +1 -1
  92. package/src/lib/package-paths.ts +11 -1
  93. package/src/lib/public-npm.ts +2 -1
  94. package/src/lib/update-checker.ts +15 -9
  95. package/src/opencode/companion-hooks.ts +89 -245
  96. package/src/opencode/companion-policy.ts +35 -10
  97. package/src/opencode/index.ts +1 -0
  98. package/src/opencode/projected-guidance.ts +56 -0
  99. package/src/opencode/tui.tsx +13 -4
  100. package/src/playbooks/companion-guidance.ts +32 -116
  101. package/src/plugins.ts +0 -1
  102. package/src/runtime/companion-git-state.ts +156 -0
  103. package/src/runtime/companion-git.ts +203 -0
  104. package/src/runtime/companion-guidance.ts +222 -0
  105. package/src/runtime/companion-sync.ts +298 -0
  106. package/src/runtime/env-names.ts +30 -0
  107. package/src/runtime/env.ts +67 -35
  108. package/src/runtime/framework.ts +10 -0
  109. package/src/runtime/freshness.ts +58 -0
  110. package/src/runtime/index.ts +104 -0
  111. package/src/runtime/install.ts +30 -0
  112. package/src/runtime/policy.ts +66 -0
  113. package/src/runtime/projected-guidance.ts +45 -0
  114. package/src/runtime/projection.ts +224 -0
  115. package/src/runtime/repo-local.ts +64 -0
  116. package/src/templates/capabilities/openspec-cap/mate-minimal/schema.yaml +56 -0
  117. package/src/templates/capabilities/openspec-cap/mate-minimal/templates/spec.md +48 -0
  118. package/src/templates/capabilities/openspec-cap/mate-minimal/templates/tasks.md +22 -0
  119. package/src/templates/capabilities/openspec-cap/mate-v1/schema.yaml +31 -90
  120. package/src/templates/capabilities/openspec-cap/mate-v1/templates/design.md +3 -0
  121. package/src/templates/capabilities/openspec-cap/mate-v1/templates/explore-brief.md +6 -6
  122. package/src/templates/capabilities/openspec-cap/mate-v1/templates/spec.md +3 -5
  123. package/src/templates/capabilities/openspec-cap/mate-v1/templates/tasks.md +3 -0
  124. package/src/templates/capabilities/openspec-cap/openspec-conventions.yaml +30 -0
  125. package/src/templates/capabilities/react-doctor/claude/hooks/react-doctor.sh +2 -2
  126. package/src/templates/mate-skills/agents/mate-artifact-publish/SKILL.md +185 -0
  127. package/src/templates/mate-skills/agents/mate-artifact-publish/references/openspec.md +227 -0
  128. package/src/templates/mate-skills/agents/mate-domain-modeling/SKILL.md +68 -0
  129. package/src/templates/mate-skills/agents/mate-domain-modeling/references/ADR-FORMAT.md +9 -0
  130. package/src/templates/mate-skills/agents/mate-domain-modeling/references/CONTEXT-FORMAT.md +18 -0
  131. package/src/templates/mate-skills/agents/mate-grill-me/SKILL.md +14 -0
  132. package/src/templates/mate-skills/agents/mate-grill-with-docs/SKILL.md +29 -0
  133. package/src/templates/mate-skills/agents/mate-grilling/SKILL.md +49 -0
  134. package/src/templates/mate-skills/agents/mate-interview-me/SKILL.md +156 -0
  135. package/src/templates/{capabilities/openspec-cap/mate-skills → mate-skills}/agents/mate-openspec-backfill/SKILL.md +4 -2
  136. package/src/templates/mate-skills/agents/mate-show-me/SKILL.md +139 -0
  137. package/src/templates/mate-skills/agents/mate-simplify-code/SKILL.md +503 -0
  138. package/src/templates/mate-skills/claude/mate-artifact-publish/SKILL.md +185 -0
  139. package/src/templates/mate-skills/claude/mate-artifact-publish/references/openspec.md +227 -0
  140. package/src/templates/mate-skills/claude/mate-domain-modeling/SKILL.md +68 -0
  141. package/src/templates/mate-skills/claude/mate-domain-modeling/references/ADR-FORMAT.md +9 -0
  142. package/src/templates/mate-skills/claude/mate-domain-modeling/references/CONTEXT-FORMAT.md +18 -0
  143. package/src/templates/mate-skills/claude/mate-grill-me/SKILL.md +14 -0
  144. package/src/templates/mate-skills/claude/mate-grill-with-docs/SKILL.md +29 -0
  145. package/src/templates/mate-skills/claude/mate-grilling/SKILL.md +49 -0
  146. package/src/templates/mate-skills/claude/mate-interview-me/SKILL.md +156 -0
  147. package/src/templates/mate-skills/claude/mate-openspec-backfill/SKILL.md +67 -0
  148. package/src/templates/mate-skills/claude/mate-show-me/SKILL.md +139 -0
  149. package/src/templates/mate-skills/claude/mate-simplify-code/SKILL.md +503 -0
  150. package/src/templates/report-assets/README.md +32 -0
  151. package/src/templates/report-assets/mermaid.LICENSE +21 -0
  152. package/src/templates/report-assets/mermaid.min.js +4376 -0
  153. package/src/templates/root/TEMPLATE_CLAUDE.md +1 -9
  154. package/src/tools/setup/__snapshots__/runtime-surface-golden.test.ts.snap +1476 -197
  155. package/src/tools/setup/capabilities/graphify.ts +16 -7
  156. package/src/tools/setup/capabilities/openspec.ts +63 -56
  157. package/src/tools/setup/capabilities/tokensave.ts +116 -2
  158. package/src/tools/setup/engine.ts +34 -6
  159. package/src/tools/setup/mate.ts +42 -13
  160. package/src/tools/setup/plugin.ts +9 -0
  161. package/src/tools/setup/plugins/guidance.ts +11 -1
  162. package/src/tools/setup/providers/claude-format.ts +49 -4
  163. package/src/tools/setup/providers/claude-plugin-hooks.ts +117 -0
  164. package/src/tools/setup/providers/claude.ts +55 -220
  165. package/src/tools/setup/providers/opencode.ts +41 -14
  166. package/src/tools/setup/runtime-documents.ts +174 -0
  167. package/src/tools/setup/surface-target.ts +50 -0
  168. package/src/tools/setup/working-repo-cleanup.ts +33 -26
  169. package/src/tools/setup/working-repo-local-state.ts +21 -1
  170. package/src/tools/setup.ts +25 -3
  171. package/wrappers/bin/graphify +57 -8
  172. package/wrappers/bin/openspec +50 -3
  173. package/claude-plugin/hooks/artifact-finish-nudge.mjs +0 -8
  174. package/src/cli/commands/cap/headroom.ts +0 -52
  175. package/src/cli/commands/workspace/list.ts +0 -25
  176. package/src/cli/commands/workspace/materialize.ts +0 -46
  177. package/src/cli/commands/workspace/workspace.ts +0 -22
  178. package/src/hooks/artifact-finish-nudge.ts +0 -244
  179. package/src/lib/orchestrator/headroom/proxy.ts +0 -116
  180. package/src/lib/orchestrator/workspace-materialize.ts +0 -80
  181. package/src/templates/capabilities/openspec-cap/mate-skills/agents/mate-artifact-finish/SKILL.md +0 -51
  182. package/src/templates/capabilities/openspec-cap/mate-skills/agents/mate-artifact-finish/references/openspec.md +0 -134
  183. package/src/templates/capabilities/openspec-cap/mate-skills/claude/mate-artifact-finish/SKILL.md +0 -58
  184. package/src/templates/capabilities/openspec-cap/mate-skills/claude/mate-artifact-finish/references/openspec.md +0 -139
  185. package/src/tools/setup/capabilities/headroom.ts +0 -57
  186. /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, stringify } from "yaml";
5
-
6
- import { FRAMEWORK_NAME } from "../../framework";
7
- import { ensureWorkingRepoLocalExcludes } from "../../tools/setup/working-repo-local-state";
8
- import { YamlFileStore } from "./yaml-file-store";
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 interface RepoLocalCompanionPointer {
12
- path: string;
13
- repositoryId: string;
14
- source?: CompanionSource;
15
- }
16
-
17
- export interface RepoLocalRegistry {
18
- repository?: LinkedRepository;
19
- companions: RepoLocalCompanionPointer[];
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
- * Adds the working repo's `.mate` directory to `.git/info/exclude` so it
58
- * never needs a tracked `.gitignore` entry, mirroring `ensureTokensaveStoreExcluded`.
59
- */
60
- export async function ensureRepoLocalDirExcluded(repoPath: string): Promise<void> {
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 ensureRepoLocalDirExcluded(repoPath);
140
- await writeRepoLocalFrameworkConfig(repoPath);
141
- await upsertRepoLocalLinkedRepository(repoPath, repository);
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<{ repoRoot: string; registryPath: string } | null> {
184
- let dir = path.resolve(cwd);
185
- for (;;) {
103
+ ): Promise<RepoLocalRegistryFile | null> {
104
+ for (const dir of ancestorDirectories(cwd)) {
186
105
  const candidate = repoLocalRegistryPath(dir);
187
106
  try {
188
- const stats = await fs.stat(candidate);
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 independently from Headroom.",
193
+ description: "Patch supported agent providers with the RTK token-optimizing CLI proxy.",
202
194
  defaultSelected: false,
203
195
  },
204
196
  {
@@ -135,6 +135,7 @@ export interface LaunchRequest {
135
135
  tool: string;
136
136
  args: string[];
137
137
  skipGit?: boolean;
138
+ interactiveGit?: boolean;
138
139
  }
139
140
 
140
141
  export interface LaunchResult {