link-agents 0.9.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.
Files changed (184) hide show
  1. package/AGENTS.md +127 -0
  2. package/README.md +93 -0
  3. package/cursor-rules-notes.md +23 -0
  4. package/dist/cli/interactive.d.ts +9 -0
  5. package/dist/cli/interactive.d.ts.map +1 -0
  6. package/dist/cli/interactive.js +1176 -0
  7. package/dist/cli/interactive.js.map +1 -0
  8. package/dist/cli/options.d.ts +3 -0
  9. package/dist/cli/options.d.ts.map +1 -0
  10. package/dist/cli/options.js +107 -0
  11. package/dist/cli/options.js.map +1 -0
  12. package/dist/cli/options.spec.d.ts +2 -0
  13. package/dist/cli/options.spec.d.ts.map +1 -0
  14. package/dist/cli/options.spec.js +74 -0
  15. package/dist/cli/options.spec.js.map +1 -0
  16. package/dist/clients/definitions.d.ts +5 -0
  17. package/dist/clients/definitions.d.ts.map +1 -0
  18. package/dist/clients/definitions.js +82 -0
  19. package/dist/clients/definitions.js.map +1 -0
  20. package/dist/clients/definitions.spec.d.ts +2 -0
  21. package/dist/clients/definitions.spec.d.ts.map +1 -0
  22. package/dist/clients/definitions.spec.js +135 -0
  23. package/dist/clients/definitions.spec.js.map +1 -0
  24. package/dist/commands/doctor.d.ts +3 -0
  25. package/dist/commands/doctor.d.ts.map +1 -0
  26. package/dist/commands/doctor.js +81 -0
  27. package/dist/commands/doctor.js.map +1 -0
  28. package/dist/commands/restore.d.ts +3 -0
  29. package/dist/commands/restore.d.ts.map +1 -0
  30. package/dist/commands/restore.js +36 -0
  31. package/dist/commands/restore.js.map +1 -0
  32. package/dist/commands/sync.d.ts +3 -0
  33. package/dist/commands/sync.d.ts.map +1 -0
  34. package/dist/commands/sync.js +193 -0
  35. package/dist/commands/sync.js.map +1 -0
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +30 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/types/index.d.ts +98 -0
  41. package/dist/types/index.d.ts.map +1 -0
  42. package/dist/types/index.js +2 -0
  43. package/dist/types/index.js.map +1 -0
  44. package/dist/utils/apply.d.ts +22 -0
  45. package/dist/utils/apply.d.ts.map +1 -0
  46. package/dist/utils/apply.js +215 -0
  47. package/dist/utils/apply.js.map +1 -0
  48. package/dist/utils/bootstrap.d.ts +18 -0
  49. package/dist/utils/bootstrap.d.ts.map +1 -0
  50. package/dist/utils/bootstrap.js +31 -0
  51. package/dist/utils/bootstrap.js.map +1 -0
  52. package/dist/utils/bootstrap.spec.d.ts +2 -0
  53. package/dist/utils/bootstrap.spec.d.ts.map +1 -0
  54. package/dist/utils/bootstrap.spec.js +92 -0
  55. package/dist/utils/bootstrap.spec.js.map +1 -0
  56. package/dist/utils/canonical.d.ts +17 -0
  57. package/dist/utils/canonical.d.ts.map +1 -0
  58. package/dist/utils/canonical.js +136 -0
  59. package/dist/utils/canonical.js.map +1 -0
  60. package/dist/utils/canonicalState.d.ts +19 -0
  61. package/dist/utils/canonicalState.d.ts.map +1 -0
  62. package/dist/utils/canonicalState.js +21 -0
  63. package/dist/utils/canonicalState.js.map +1 -0
  64. package/dist/utils/cursorHistory.d.ts +7 -0
  65. package/dist/utils/cursorHistory.d.ts.map +1 -0
  66. package/dist/utils/cursorHistory.js +54 -0
  67. package/dist/utils/cursorHistory.js.map +1 -0
  68. package/dist/utils/cursorPaths.d.ts +3 -0
  69. package/dist/utils/cursorPaths.d.ts.map +1 -0
  70. package/dist/utils/cursorPaths.js +17 -0
  71. package/dist/utils/cursorPaths.js.map +1 -0
  72. package/dist/utils/discovery.d.ts +8 -0
  73. package/dist/utils/discovery.d.ts.map +1 -0
  74. package/dist/utils/discovery.js +93 -0
  75. package/dist/utils/discovery.js.map +1 -0
  76. package/dist/utils/frontmatter.d.ts +32 -0
  77. package/dist/utils/frontmatter.d.ts.map +1 -0
  78. package/dist/utils/frontmatter.js +263 -0
  79. package/dist/utils/frontmatter.js.map +1 -0
  80. package/dist/utils/frontmatter.spec.d.ts +2 -0
  81. package/dist/utils/frontmatter.spec.d.ts.map +1 -0
  82. package/dist/utils/frontmatter.spec.js +264 -0
  83. package/dist/utils/frontmatter.spec.js.map +1 -0
  84. package/dist/utils/fs.d.ts +27 -0
  85. package/dist/utils/fs.d.ts.map +1 -0
  86. package/dist/utils/fs.js +137 -0
  87. package/dist/utils/fs.js.map +1 -0
  88. package/dist/utils/fs.spec.d.ts +2 -0
  89. package/dist/utils/fs.spec.d.ts.map +1 -0
  90. package/dist/utils/fs.spec.js +73 -0
  91. package/dist/utils/fs.spec.js.map +1 -0
  92. package/dist/utils/gitignore.d.ts +10 -0
  93. package/dist/utils/gitignore.d.ts.map +1 -0
  94. package/dist/utils/gitignore.js +63 -0
  95. package/dist/utils/gitignore.js.map +1 -0
  96. package/dist/utils/manifest.d.ts +28 -0
  97. package/dist/utils/manifest.d.ts.map +1 -0
  98. package/dist/utils/manifest.js +89 -0
  99. package/dist/utils/manifest.js.map +1 -0
  100. package/dist/utils/mcp.d.ts +73 -0
  101. package/dist/utils/mcp.d.ts.map +1 -0
  102. package/dist/utils/mcp.js +529 -0
  103. package/dist/utils/mcp.js.map +1 -0
  104. package/dist/utils/mcp.spec.d.ts +2 -0
  105. package/dist/utils/mcp.spec.d.ts.map +1 -0
  106. package/dist/utils/mcp.spec.js +488 -0
  107. package/dist/utils/mcp.spec.js.map +1 -0
  108. package/dist/utils/merge.d.ts +17 -0
  109. package/dist/utils/merge.d.ts.map +1 -0
  110. package/dist/utils/merge.js +45 -0
  111. package/dist/utils/merge.js.map +1 -0
  112. package/dist/utils/merge.spec.d.ts +2 -0
  113. package/dist/utils/merge.spec.d.ts.map +1 -0
  114. package/dist/utils/merge.spec.js +134 -0
  115. package/dist/utils/merge.spec.js.map +1 -0
  116. package/dist/utils/paths.d.ts +11 -0
  117. package/dist/utils/paths.d.ts.map +1 -0
  118. package/dist/utils/paths.js +164 -0
  119. package/dist/utils/paths.js.map +1 -0
  120. package/dist/utils/paths.spec.d.ts +2 -0
  121. package/dist/utils/paths.spec.d.ts.map +1 -0
  122. package/dist/utils/paths.spec.js +282 -0
  123. package/dist/utils/paths.spec.js.map +1 -0
  124. package/dist/utils/plan.d.ts +7 -0
  125. package/dist/utils/plan.d.ts.map +1 -0
  126. package/dist/utils/plan.js +118 -0
  127. package/dist/utils/plan.js.map +1 -0
  128. package/dist/utils/plan.spec.d.ts +2 -0
  129. package/dist/utils/plan.spec.d.ts.map +1 -0
  130. package/dist/utils/plan.spec.js +420 -0
  131. package/dist/utils/plan.spec.js.map +1 -0
  132. package/dist/utils/reporting.d.ts +21 -0
  133. package/dist/utils/reporting.d.ts.map +1 -0
  134. package/dist/utils/reporting.js +82 -0
  135. package/dist/utils/reporting.js.map +1 -0
  136. package/dist/utils/reporting.spec.d.ts +2 -0
  137. package/dist/utils/reporting.spec.d.ts.map +1 -0
  138. package/dist/utils/reporting.spec.js +78 -0
  139. package/dist/utils/reporting.spec.js.map +1 -0
  140. package/dist/utils/reset.d.ts +14 -0
  141. package/dist/utils/reset.d.ts.map +1 -0
  142. package/dist/utils/reset.js +81 -0
  143. package/dist/utils/reset.js.map +1 -0
  144. package/dist/utils/revert.d.ts +30 -0
  145. package/dist/utils/revert.d.ts.map +1 -0
  146. package/dist/utils/revert.js +89 -0
  147. package/dist/utils/revert.js.map +1 -0
  148. package/dist/utils/revert.spec.d.ts +2 -0
  149. package/dist/utils/revert.spec.d.ts.map +1 -0
  150. package/dist/utils/revert.spec.js +102 -0
  151. package/dist/utils/revert.spec.js.map +1 -0
  152. package/dist/utils/similarity.d.ts +14 -0
  153. package/dist/utils/similarity.d.ts.map +1 -0
  154. package/dist/utils/similarity.js +70 -0
  155. package/dist/utils/similarity.js.map +1 -0
  156. package/dist/utils/similarity.spec.d.ts +2 -0
  157. package/dist/utils/similarity.spec.d.ts.map +1 -0
  158. package/dist/utils/similarity.spec.js +62 -0
  159. package/dist/utils/similarity.spec.js.map +1 -0
  160. package/dist/utils/snapshots.d.ts +21 -0
  161. package/dist/utils/snapshots.d.ts.map +1 -0
  162. package/dist/utils/snapshots.js +81 -0
  163. package/dist/utils/snapshots.js.map +1 -0
  164. package/dist/utils/snapshots.spec.d.ts +2 -0
  165. package/dist/utils/snapshots.spec.d.ts.map +1 -0
  166. package/dist/utils/snapshots.spec.js +56 -0
  167. package/dist/utils/snapshots.spec.js.map +1 -0
  168. package/dist/utils/syncFilters.d.ts +3 -0
  169. package/dist/utils/syncFilters.d.ts.map +1 -0
  170. package/dist/utils/syncFilters.js +8 -0
  171. package/dist/utils/syncFilters.js.map +1 -0
  172. package/dist/utils/syncRuntime.d.ts +3 -0
  173. package/dist/utils/syncRuntime.d.ts.map +1 -0
  174. package/dist/utils/syncRuntime.js +31 -0
  175. package/dist/utils/syncRuntime.js.map +1 -0
  176. package/dist/utils/validation.d.ts +3 -0
  177. package/dist/utils/validation.d.ts.map +1 -0
  178. package/dist/utils/validation.js +19 -0
  179. package/dist/utils/validation.js.map +1 -0
  180. package/dist/utils/validation.spec.d.ts +2 -0
  181. package/dist/utils/validation.spec.d.ts.map +1 -0
  182. package/dist/utils/validation.spec.js +36 -0
  183. package/dist/utils/validation.spec.js.map +1 -0
  184. package/package.json +63 -0
@@ -0,0 +1,215 @@
1
+ import chalk from "chalk";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { writeFileSafe, createBackup, restoreBackup, verifyFileHash, readFileSafe, hashContent, fileExists, } from "./fs.js";
6
+ import { transformContentForClient } from "./frontmatter.js";
7
+ import { updateManifest, pruneStaleFiles } from "./manifest.js";
8
+ const BACKUP_DIR = path.join(os.homedir(), ".link-agents", "backups");
9
+ const MAX_BACKUPS = 10;
10
+ function getWriteModeLabel(useSymlink, action) {
11
+ return useSymlink ? "link" : action;
12
+ }
13
+ export async function applyPlan(plan, options) {
14
+ const result = {
15
+ applied: 0,
16
+ skipped: 0,
17
+ failed: 0,
18
+ backups: [],
19
+ errors: [],
20
+ rolledBack: false,
21
+ };
22
+ if (plan.length === 0) {
23
+ if (options.verbose) {
24
+ console.log(chalk.green("No changes required."));
25
+ }
26
+ return result;
27
+ }
28
+ const appliedChanges = [];
29
+ for (const entry of plan) {
30
+ const displayPath = entry.targetRelativePath ?? entry.asset.relativePath;
31
+ if (entry.action === "skip") {
32
+ if (options.verbose) {
33
+ console.log(chalk.gray(`skip ${entry.targetClient} :: ${displayPath}`));
34
+ }
35
+ result.skipped++;
36
+ continue;
37
+ }
38
+ // Transform content for target client (e.g., OpenCode frontmatter format)
39
+ const transformedContent = transformContentForClient(entry.asset.content, entry.targetClient, entry.asset.type);
40
+ const symlinkEligible = Boolean(options.link) &&
41
+ (await canWriteAsSymlink(entry, transformedContent));
42
+ const actionLabel = getWriteModeLabel(symlinkEligible, entry.action);
43
+ if (symlinkEligible) {
44
+ const alreadyLinked = await isSymlinkToTarget(entry.targetPath, entry.asset.path);
45
+ if (alreadyLinked) {
46
+ if (options.verbose) {
47
+ console.log(chalk.gray(`unchanged ${entry.targetClient} :: ${displayPath}`));
48
+ }
49
+ result.skipped++;
50
+ continue;
51
+ }
52
+ }
53
+ else {
54
+ // Check if file already has identical content (skip unchanged)
55
+ const existingContent = await readFileSafe(entry.targetPath);
56
+ if (existingContent !== null) {
57
+ const existingHash = hashContent(existingContent);
58
+ const newHash = hashContent(transformedContent);
59
+ if (existingHash === newHash) {
60
+ if (options.verbose) {
61
+ console.log(chalk.gray(`unchanged ${entry.targetClient} :: ${displayPath}`));
62
+ }
63
+ result.skipped++;
64
+ continue;
65
+ }
66
+ }
67
+ }
68
+ if (options.dryRun) {
69
+ console.log(chalk.yellow(`${actionLabel.padEnd(7)} ${entry.targetClient} :: ${displayPath}`));
70
+ result.applied++;
71
+ continue;
72
+ }
73
+ let backupPath = null;
74
+ try {
75
+ // Create backup before overwrite
76
+ backupPath = await createBackup(entry.targetPath);
77
+ if (backupPath) {
78
+ result.backups.push(backupPath);
79
+ if (options.verbose) {
80
+ console.log(chalk.dim(` backup: ${backupPath}`));
81
+ }
82
+ }
83
+ if (symlinkEligible) {
84
+ await writeSymlinkSafe(entry.asset.path, entry.targetPath);
85
+ }
86
+ else {
87
+ await writeFileSafe(entry.targetPath, transformedContent);
88
+ }
89
+ console.log(chalk.green(`${actionLabel.padEnd(7)} ${entry.targetClient} :: ${displayPath}`));
90
+ // Post-sync verification
91
+ const verified = symlinkEligible
92
+ ? await isSymlinkToTarget(entry.targetPath, entry.asset.path)
93
+ : await verifyFileHash(entry.targetPath, transformedContent);
94
+ if (!verified) {
95
+ const error = `Verification failed for ${entry.targetPath}`;
96
+ result.errors.push(error);
97
+ console.log(chalk.red(` ✗ ${error}`));
98
+ result.failed++;
99
+ await rollbackChanges(appliedChanges, result, options.verbose);
100
+ return result;
101
+ }
102
+ appliedChanges.push({ targetPath: entry.targetPath, backupPath });
103
+ result.applied++;
104
+ }
105
+ catch (err) {
106
+ const error = `Failed to write ${entry.targetPath}: ${err}`;
107
+ result.errors.push(error);
108
+ console.log(chalk.red(` ✗ ${error}`));
109
+ result.failed++;
110
+ await rollbackChanges(appliedChanges, result, options.verbose);
111
+ return result;
112
+ }
113
+ }
114
+ return result;
115
+ }
116
+ async function canWriteAsSymlink(entry, transformedContent) {
117
+ const sourceContent = await readFileSafe(entry.asset.path);
118
+ return sourceContent === transformedContent;
119
+ }
120
+ async function isSymlinkToTarget(linkPath, targetPath) {
121
+ try {
122
+ const stats = await fs.lstat(linkPath);
123
+ if (!stats.isSymbolicLink()) {
124
+ return false;
125
+ }
126
+ const linkTarget = await fs.readlink(linkPath);
127
+ const resolvedTarget = path.resolve(path.dirname(linkPath), linkTarget);
128
+ return resolvedTarget === path.resolve(targetPath);
129
+ }
130
+ catch {
131
+ return false;
132
+ }
133
+ }
134
+ async function writeSymlinkSafe(sourcePath, targetPath) {
135
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
136
+ await fs.rm(targetPath, { force: true, recursive: true });
137
+ const linkTarget = path.relative(path.dirname(targetPath), sourcePath);
138
+ await fs.symlink(linkTarget, targetPath);
139
+ }
140
+ async function rollbackChanges(changes, result, verbose) {
141
+ if (changes.length === 0)
142
+ return;
143
+ console.log();
144
+ console.log(chalk.yellow(`Rolling back ${changes.length} change(s)...`));
145
+ for (const change of changes.reverse()) {
146
+ if (change.backupPath) {
147
+ const restored = await restoreBackup(change.backupPath, change.targetPath);
148
+ if (restored) {
149
+ if (verbose) {
150
+ console.log(chalk.dim(` restored: ${change.targetPath}`));
151
+ }
152
+ }
153
+ else {
154
+ result.errors.push(`Failed to restore ${change.targetPath}`);
155
+ }
156
+ }
157
+ }
158
+ result.rolledBack = true;
159
+ console.log(chalk.yellow("Rollback complete."));
160
+ }
161
+ /**
162
+ * Cleanup old backups beyond MAX_BACKUPS limit.
163
+ */
164
+ export async function cleanupOldBackups() {
165
+ try {
166
+ if (!(await fileExists(BACKUP_DIR))) {
167
+ return 0;
168
+ }
169
+ const entries = await fs.readdir(BACKUP_DIR);
170
+ const backupDirs = entries
171
+ .filter((e) => e.match(/^\d{4}-\d{2}-\d{2}T/))
172
+ .sort()
173
+ .reverse();
174
+ if (backupDirs.length <= MAX_BACKUPS) {
175
+ return 0;
176
+ }
177
+ const toDelete = backupDirs.slice(MAX_BACKUPS);
178
+ let deleted = 0;
179
+ for (const dir of toDelete) {
180
+ try {
181
+ await fs.rm(path.join(BACKUP_DIR, dir), { recursive: true });
182
+ deleted++;
183
+ }
184
+ catch {
185
+ // Ignore deletion errors
186
+ }
187
+ }
188
+ return deleted;
189
+ }
190
+ catch {
191
+ return 0;
192
+ }
193
+ }
194
+ /**
195
+ * Update manifest with generated files and prune stale files.
196
+ */
197
+ export async function postApplyCleanup(appliedPaths, verbose) {
198
+ // Prune stale files from previous syncs
199
+ const pruned = await pruneStaleFiles(appliedPaths);
200
+ if (pruned.length > 0 && verbose) {
201
+ console.log(chalk.dim(`Cleaned up ${pruned.length} stale file(s)`));
202
+ for (const f of pruned) {
203
+ console.log(chalk.dim(` removed: ${f}`));
204
+ }
205
+ }
206
+ // Update manifest with current files
207
+ await updateManifest(appliedPaths);
208
+ // Cleanup old backups
209
+ const deletedBackups = await cleanupOldBackups();
210
+ if (deletedBackups > 0 && verbose) {
211
+ console.log(chalk.dim(`Cleaned up ${deletedBackups} old backup(s)`));
212
+ }
213
+ return { pruned, manifestUpdated: true };
214
+ }
215
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/utils/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { AgentClientName, AssetContent } from "../types/index.js";
2
+ interface BootstrapResolutionInput {
3
+ canonicalPath: string;
4
+ candidates: AssetContent[];
5
+ bootstrapSource?: AgentClientName;
6
+ }
7
+ type BootstrapResolution = {
8
+ status: "missing";
9
+ } | {
10
+ status: "selected";
11
+ asset: AssetContent;
12
+ } | {
13
+ status: "ambiguous";
14
+ candidates: AssetContent[];
15
+ };
16
+ export declare function getBootstrapResolution(input: BootstrapResolutionInput): BootstrapResolution;
17
+ export {};
18
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/utils/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEvE,UAAU,wBAAwB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,KAAK,mBAAmB,GACpB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAExD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,wBAAwB,GAC9B,mBAAmB,CAsCrB"}
@@ -0,0 +1,31 @@
1
+ export function getBootstrapResolution(input) {
2
+ const { candidates, bootstrapSource, canonicalPath } = input;
3
+ if (candidates.length === 0) {
4
+ return { status: "missing" };
5
+ }
6
+ if (bootstrapSource) {
7
+ const matches = candidates.filter((asset) => asset.client === bootstrapSource);
8
+ if (matches.length === 0) {
9
+ throw new Error(`bootstrap-source ${bootstrapSource} is not available for ${canonicalPath}`);
10
+ }
11
+ if (matches.length === 1) {
12
+ return { status: "selected", asset: matches[0] };
13
+ }
14
+ return { status: "ambiguous", candidates: matches };
15
+ }
16
+ if (candidates.length === 1) {
17
+ return { status: "selected", asset: candidates[0] };
18
+ }
19
+ // All candidates have the same content — pick the newest, no need to ask
20
+ const allIdentical = candidates.every((c) => c.hash === candidates[0].hash);
21
+ if (allIdentical) {
22
+ const newest = [...candidates].sort((a, b) => {
23
+ const ta = a.modifiedAt?.getTime() ?? 0;
24
+ const tb = b.modifiedAt?.getTime() ?? 0;
25
+ return tb - ta;
26
+ });
27
+ return { status: "selected", asset: newest[0] };
28
+ }
29
+ return { status: "ambiguous", candidates };
30
+ }
31
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/utils/bootstrap.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,sBAAsB,CACpC,KAA+B;IAE/B,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAE7D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAC/B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,eAAe,CAC5C,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,oBAAoB,eAAe,yBAAyB,aAAa,EAAE,CAC5E,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IACtD,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,CAAC;IAED,yEAAyE;IACzE,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACxC,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bootstrap.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.spec.d.ts","sourceRoot":"","sources":["../../src/utils/bootstrap.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { hashContent } from "./fs.js";
3
+ import { getBootstrapResolution } from "./bootstrap.js";
4
+ import { buildLegacyDefinitions } from "./canonical.js";
5
+ function makeAsset(client, type, relativePath, content = `${client}:${relativePath}`) {
6
+ return {
7
+ client,
8
+ type,
9
+ path: `/${client}/${relativePath}`,
10
+ relativePath,
11
+ canonicalPath: relativePath,
12
+ name: relativePath,
13
+ content,
14
+ hash: hashContent(content),
15
+ };
16
+ }
17
+ describe("getBootstrapResolution", () => {
18
+ it("returns missing when there are no candidates", () => {
19
+ expect(getBootstrapResolution({
20
+ canonicalPath: "AGENTS.md",
21
+ candidates: [],
22
+ })).toEqual({ status: "missing" });
23
+ });
24
+ it("auto-selects the only candidate", () => {
25
+ const candidate = makeAsset("claude", "agents", "AGENTS.md");
26
+ expect(getBootstrapResolution({
27
+ canonicalPath: "AGENTS.md",
28
+ candidates: [candidate],
29
+ })).toEqual({ status: "selected", asset: candidate });
30
+ });
31
+ it("uses the explicit bootstrap source when present", () => {
32
+ const claude = makeAsset("claude", "agents", "AGENTS.md");
33
+ const cursor = makeAsset("cursor", "agents", "AGENTS.md");
34
+ expect(getBootstrapResolution({
35
+ canonicalPath: "AGENTS.md",
36
+ candidates: [claude, cursor],
37
+ bootstrapSource: "cursor",
38
+ })).toEqual({ status: "selected", asset: cursor });
39
+ });
40
+ it("errors when the explicit bootstrap source is not available", () => {
41
+ const claude = makeAsset("claude", "agents", "AGENTS.md");
42
+ const cursor = makeAsset("cursor", "agents", "AGENTS.md");
43
+ expect(() => getBootstrapResolution({
44
+ canonicalPath: "AGENTS.md",
45
+ candidates: [claude, cursor],
46
+ bootstrapSource: "codex",
47
+ })).toThrow(/bootstrap-source codex is not available/i);
48
+ });
49
+ it("auto-selects newest when all candidates have identical content", () => {
50
+ const shared = "identical content";
51
+ const claude = makeAsset("claude", "agents", "AGENTS.md", shared);
52
+ claude.modifiedAt = new Date("2026-01-01");
53
+ const cursor = makeAsset("cursor", "agents", "AGENTS.md", shared);
54
+ cursor.modifiedAt = new Date("2026-03-01");
55
+ expect(getBootstrapResolution({
56
+ canonicalPath: "AGENTS.md",
57
+ candidates: [claude, cursor],
58
+ })).toEqual({ status: "selected", asset: cursor });
59
+ });
60
+ it("surfaces ambiguity when candidates have different content", () => {
61
+ const claude = makeAsset("claude", "agents", "AGENTS.md");
62
+ const cursor = makeAsset("cursor", "agents", "AGENTS.md");
63
+ expect(getBootstrapResolution({
64
+ canonicalPath: "AGENTS.md",
65
+ candidates: [claude, cursor],
66
+ })).toEqual({
67
+ status: "ambiguous",
68
+ candidates: [claude, cursor],
69
+ });
70
+ });
71
+ it("surfaces ambiguity when bootstrap-source still matches multiple files", () => {
72
+ const projectCursor = makeAsset("project", "mcp", "mcp.json", "cursor");
73
+ projectCursor.path = "/project/.cursor/mcp.json";
74
+ const projectRoot = makeAsset("project", "mcp", "mcp.json", "root");
75
+ projectRoot.path = "/project/.mcp.json";
76
+ expect(getBootstrapResolution({
77
+ canonicalPath: "mcp.json",
78
+ candidates: [projectCursor, projectRoot],
79
+ bootstrapSource: "project",
80
+ })).toEqual({
81
+ status: "ambiguous",
82
+ candidates: [projectCursor, projectRoot],
83
+ });
84
+ });
85
+ });
86
+ describe("buildLegacyDefinitions", () => {
87
+ it("excludes the project client from legacy bootstrap sources", () => {
88
+ const defs = buildLegacyDefinitions("/repo");
89
+ expect(defs.every((def) => ["codex", "claude", "cursor", "opencode"].includes(def.name))).toBe(true);
90
+ });
91
+ });
92
+ //# sourceMappingURL=bootstrap.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.spec.js","sourceRoot":"","sources":["../../src/utils/bootstrap.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { AssetContent, ClientDefinition, ManagedAssetType } from "../types/index.js";
2
+ import type { SyncCommandOptions, SyncPlanEntry } from "../types/index.js";
3
+ export declare function buildCanonicalDefinition(projectRoot: string): ClientDefinition;
4
+ export declare function buildLegacyDefinitions(projectRoot: string): ClientDefinition[];
5
+ export declare function discoverCanonicalAssets(projectRoot: string, types?: ManagedAssetType[]): Promise<AssetContent[]>;
6
+ export declare function discoverLegacyAssets(projectRoot: string, types?: ManagedAssetType[]): Promise<AssetContent[]>;
7
+ export declare function discoverIgnoredCursorRules(projectRoot: string): Promise<AssetContent[]>;
8
+ export declare function groupAssetsByCanonicalKey(assets: AssetContent[]): Map<string, AssetContent[]>;
9
+ export declare function synthesizeCanonicalAsset(projectRoot: string, asset: AssetContent): AssetContent;
10
+ export declare function buildBootstrapEntry(projectRoot: string, asset: AssetContent): SyncPlanEntry;
11
+ export declare function buildFanoutPlan(canonicalAssets: AssetContent[], defs: ClientDefinition[], options: SyncCommandOptions): SyncPlanEntry[];
12
+ export declare function getBootstrapChoices(candidates: AssetContent[]): {
13
+ value: string;
14
+ label: string;
15
+ hint: string;
16
+ }[];
17
+ //# sourceMappingURL=canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/utils/canonical.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAa3B,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAI3E,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAYlB;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAClB,gBAAgB,EAAE,CAEpB;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,gBAAgB,EAAE,GACzB,OAAO,CAAC,YAAY,EAAE,CAAC,CAIzB;AAED,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,gBAAgB,EAAE,GACzB,OAAO,CAAC,YAAY,EAAE,CAAC,CAGzB;AAED,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,EAAE,CAAC,CAezB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,YAAY,EAAE,GACrB,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAU7B;AAED,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,YAAY,GAClB,YAAY,CASd;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,YAAY,GAClB,aAAa,CAUf;AAED,wBAAgB,eAAe,CAC7B,eAAe,EAAE,YAAY,EAAE,EAC/B,IAAI,EAAE,gBAAgB,EAAE,EACxB,OAAO,EAAE,kBAAkB,GAC1B,aAAa,EAAE,CA0CjB;AA6BD,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,YAAY,EAAE,GACzB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAMlD"}
@@ -0,0 +1,136 @@
1
+ import path from "node:path";
2
+ import { buildClientDefinitions, clientSupportsAssetType, } from "../clients/definitions.js";
3
+ import { discoverAssets } from "./discovery.js";
4
+ import { hashContent } from "./fs.js";
5
+ import { buildTargetAbsolutePath, remapRelativePathForTarget, resolveTargetRelativePath, } from "./paths.js";
6
+ import { shouldSkipTargetAsset } from "./syncFilters.js";
7
+ const CODEX_COMMAND_METADATA = "policy:\n allow_implicit_invocation: false\n";
8
+ export function buildCanonicalDefinition(projectRoot) {
9
+ return {
10
+ name: "project",
11
+ displayName: "Canonical",
12
+ root: path.join(projectRoot, ".agents"),
13
+ assets: [
14
+ { type: "agents", patterns: ["AGENTS.md"] },
15
+ { type: "commands", patterns: ["commands/**/*.md"] },
16
+ { type: "skills", patterns: ["skills/**/SKILL.md"] },
17
+ { type: "mcp", patterns: [], files: ["mcp.json"] },
18
+ ],
19
+ };
20
+ }
21
+ export function buildLegacyDefinitions(projectRoot) {
22
+ return buildClientDefinitions(projectRoot);
23
+ }
24
+ export async function discoverCanonicalAssets(projectRoot, types) {
25
+ return discoverAssets([buildCanonicalDefinition(projectRoot)], {
26
+ types: types,
27
+ });
28
+ }
29
+ export async function discoverLegacyAssets(projectRoot, types) {
30
+ const defs = buildLegacyDefinitions(projectRoot);
31
+ return discoverAssets(defs, { types: types });
32
+ }
33
+ export async function discoverIgnoredCursorRules(projectRoot) {
34
+ const cursorDef = buildLegacyDefinitions(projectRoot).find((def) => def.name === "cursor");
35
+ if (!cursorDef) {
36
+ return [];
37
+ }
38
+ return discoverAssets([
39
+ {
40
+ ...cursorDef,
41
+ assets: [
42
+ { type: "rules", patterns: ["rules/**/*.md", "rules/**/*.mdc"] },
43
+ ],
44
+ },
45
+ ]);
46
+ }
47
+ export function groupAssetsByCanonicalKey(assets) {
48
+ const grouped = new Map();
49
+ for (const asset of assets) {
50
+ const canonicalPath = asset.canonicalPath ?? asset.relativePath;
51
+ const key = `${asset.type}::${canonicalPath}`;
52
+ const bucket = grouped.get(key) ?? [];
53
+ bucket.push(asset);
54
+ grouped.set(key, bucket);
55
+ }
56
+ return grouped;
57
+ }
58
+ export function synthesizeCanonicalAsset(projectRoot, asset) {
59
+ const canonicalPath = asset.canonicalPath ?? asset.relativePath;
60
+ return {
61
+ ...asset,
62
+ client: "project",
63
+ path: path.join(projectRoot, ".agents", canonicalPath),
64
+ relativePath: canonicalPath,
65
+ canonicalPath,
66
+ };
67
+ }
68
+ export function buildBootstrapEntry(projectRoot, asset) {
69
+ const canonicalAsset = synthesizeCanonicalAsset(projectRoot, asset);
70
+ return {
71
+ asset,
72
+ targetClient: "project",
73
+ targetPath: canonicalAsset.path,
74
+ targetRelativePath: canonicalAsset.relativePath,
75
+ action: "create",
76
+ reason: "bootstrap",
77
+ };
78
+ }
79
+ export function buildFanoutPlan(canonicalAssets, defs, options) {
80
+ const plan = [];
81
+ for (const asset of canonicalAssets) {
82
+ for (const def of defs) {
83
+ if (shouldSkipTargetAsset(options, def.name, asset)) {
84
+ continue;
85
+ }
86
+ if (!clientSupportsAssetType(def, asset.type)) {
87
+ continue;
88
+ }
89
+ const baseRelative = resolveTargetRelativePath(def.name, asset);
90
+ const targetRelative = remapRelativePathForTarget(asset, def.name, baseRelative, defs);
91
+ const targetPath = buildTargetAbsolutePath(def.root, targetRelative);
92
+ if (targetPath !== asset.path) {
93
+ plan.push({
94
+ asset,
95
+ targetClient: def.name,
96
+ targetPath,
97
+ targetRelativePath: targetRelative,
98
+ action: "create",
99
+ reason: "fanout",
100
+ });
101
+ }
102
+ if (def.name === "codex" && asset.type === "commands") {
103
+ plan.push(buildCodexCommandMetadataEntry(asset, def.root, targetRelative));
104
+ }
105
+ }
106
+ }
107
+ return plan;
108
+ }
109
+ function buildCodexCommandMetadataEntry(asset, root, commandTargetRelative) {
110
+ const metadataRelative = normalizeCodexMetadataPath(commandTargetRelative);
111
+ const syntheticAsset = {
112
+ ...asset,
113
+ content: CODEX_COMMAND_METADATA,
114
+ hash: hashContent(CODEX_COMMAND_METADATA),
115
+ name: `${asset.name}-openai-yaml`,
116
+ };
117
+ return {
118
+ asset: syntheticAsset,
119
+ targetClient: "codex",
120
+ targetPath: buildTargetAbsolutePath(root, metadataRelative),
121
+ targetRelativePath: metadataRelative,
122
+ action: "create",
123
+ reason: "fanout",
124
+ };
125
+ }
126
+ function normalizeCodexMetadataPath(commandTargetRelative) {
127
+ return commandTargetRelative.replace(/\/SKILL\.md$/i, "/agents/openai.yaml");
128
+ }
129
+ export function getBootstrapChoices(candidates) {
130
+ return candidates.map((asset, i) => ({
131
+ value: asset.path,
132
+ label: `${asset.client}: ${asset.relativePath}`,
133
+ hint: `${asset.path}${i === 0 ? " (newest)" : ""}`,
134
+ }));
135
+ }
136
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/utils/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { AgentClientName, ManagedAssetType } from "../types/index.js";
2
+ export interface GeneratedStateEntry {
3
+ path: string;
4
+ sourcePath: string;
5
+ canonicalPath: string;
6
+ targetClient: AgentClientName;
7
+ type: ManagedAssetType;
8
+ mode: "copy" | "symlink";
9
+ expectedContent?: string;
10
+ }
11
+ interface CanonicalState {
12
+ version: 1;
13
+ updatedAt: string;
14
+ generated: GeneratedStateEntry[];
15
+ }
16
+ export declare function readCanonicalState(): Promise<CanonicalState>;
17
+ export declare function writeCanonicalState(entries: GeneratedStateEntry[]): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=canonicalState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalState.d.ts","sourceRoot":"","sources":["../../src/utils/canonicalState.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI3E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC,CAMlE;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,EAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAef"}
@@ -0,0 +1,21 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ const STATE_PATH = path.join(os.homedir(), ".link-agents", "canonical-state.json");
5
+ export async function readCanonicalState() {
6
+ try {
7
+ return JSON.parse(await fs.readFile(STATE_PATH, "utf8"));
8
+ }
9
+ catch {
10
+ return { version: 1, updatedAt: new Date(0).toISOString(), generated: [] };
11
+ }
12
+ }
13
+ export async function writeCanonicalState(entries) {
14
+ await fs.mkdir(path.dirname(STATE_PATH), { recursive: true });
15
+ await fs.writeFile(STATE_PATH, JSON.stringify({
16
+ version: 1,
17
+ updatedAt: new Date().toISOString(),
18
+ generated: entries,
19
+ }, null, 2), "utf8");
20
+ }
21
+ //# sourceMappingURL=canonicalState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalState.js","sourceRoot":"","sources":["../../src/utils/canonicalState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC;AAkBnF,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAmB,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC7E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA8B;IAE9B,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,EAAE,CAAC,SAAS,CAChB,UAAU,EACV,IAAI,CAAC,SAAS,CACZ;QACE,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,OAAO;KACM,EAC1B,IAAI,EACJ,CAAC,CACF,EACD,MAAM,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface ExportOptions {
2
+ destination?: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare function exportCursorHistory(options?: ExportOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=cursorHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursorHistory.d.ts","sourceRoot":"","sources":["../../src/utils/cursorHistory.ts"],"names":[],"mappings":"AAOA,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CpF"}