guardlink 1.3.0 → 1.4.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/CHANGELOG.md +44 -0
- package/README.md +43 -1
- package/dist/agents/launcher.d.ts +1 -1
- package/dist/agents/launcher.js +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +300 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +38 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/suggest.d.ts +1 -0
- package/dist/mcp/suggest.d.ts.map +1 -1
- package/dist/mcp/suggest.js +1 -0
- package/dist/mcp/suggest.js.map +1 -1
- package/dist/parser/parse-project.d.ts.map +1 -1
- package/dist/parser/parse-project.js +103 -0
- package/dist/parser/parse-project.js.map +1 -1
- package/dist/tui/commands.d.ts +3 -0
- package/dist/tui/commands.d.ts.map +1 -1
- package/dist/tui/commands.js +297 -39
- package/dist/tui/commands.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +17 -1
- package/dist/tui/index.js.map +1 -1
- package/dist/types/index.d.ts +39 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/workspace/index.d.ts +12 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +9 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/link.d.ts +91 -0
- package/dist/workspace/link.d.ts.map +1 -0
- package/dist/workspace/link.js +581 -0
- package/dist/workspace/link.js.map +1 -0
- package/dist/workspace/merge.d.ts +104 -0
- package/dist/workspace/merge.d.ts.map +1 -0
- package/dist/workspace/merge.js +752 -0
- package/dist/workspace/merge.js.map +1 -0
- package/dist/workspace/metadata.d.ts +34 -0
- package/dist/workspace/metadata.d.ts.map +1 -0
- package/dist/workspace/metadata.js +181 -0
- package/dist/workspace/metadata.js.map +1 -0
- package/dist/workspace/types.d.ts +134 -0
- package/dist/workspace/types.d.ts.map +1 -0
- package/dist/workspace/types.js +12 -0
- package/dist/workspace/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Workspace — link-project command logic.
|
|
3
|
+
*
|
|
4
|
+
* Scaffolds workspace.yaml in each repo and updates agent instruction
|
|
5
|
+
* files with workspace context so agents write cross-repo-aware annotations.
|
|
6
|
+
*
|
|
7
|
+
* @asset Workspace.Link (#workspace-link) -- "Multi-repo workspace linking setup"
|
|
8
|
+
* @flows UserArgs -> #workspace-link via linkProject -- "CLI args to workspace scaffolding"
|
|
9
|
+
* @flows #workspace-link -> AgentFiles via updateAgentWorkspaceContext -- "Inject workspace context"
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs';
|
|
12
|
+
import { writeFileSync } from 'node:fs';
|
|
13
|
+
import { resolve, basename, dirname, join } from 'node:path';
|
|
14
|
+
import { serializeWorkspaceYaml, loadWorkspaceConfig } from './metadata.js';
|
|
15
|
+
// ─── Fresh Link (all repos specified) ────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Link multiple repos into a workspace (fresh setup).
|
|
18
|
+
*
|
|
19
|
+
* For each repo path:
|
|
20
|
+
* 1. Auto-init if not yet guardlink-initialized
|
|
21
|
+
* 2. Detect repo name from git remote, package.json, or directory name
|
|
22
|
+
* 3. Generate .guardlink/workspace.yaml
|
|
23
|
+
* 4. Update agent instruction files with workspace context
|
|
24
|
+
*/
|
|
25
|
+
export function linkProject(options) {
|
|
26
|
+
const result = {
|
|
27
|
+
linked: [], skipped: [], agentFilesUpdated: [], initialized: [], updated: [],
|
|
28
|
+
};
|
|
29
|
+
// Resolve all repo paths and detect names
|
|
30
|
+
const repos = [];
|
|
31
|
+
for (const rp of options.repoPaths) {
|
|
32
|
+
const absPath = resolve(rp);
|
|
33
|
+
if (!existsSync(absPath)) {
|
|
34
|
+
result.skipped.push({ name: rp, reason: 'Directory not found' });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Auto-init if needed
|
|
38
|
+
const initResult = ensureInitialized(absPath);
|
|
39
|
+
if (initResult)
|
|
40
|
+
result.initialized.push(initResult);
|
|
41
|
+
const name = detectRepoName(absPath);
|
|
42
|
+
const registry = options.registry
|
|
43
|
+
? `${options.registry.replace(/\/$/, '')}/${name}`
|
|
44
|
+
: undefined;
|
|
45
|
+
repos.push({ name, path: absPath, registry });
|
|
46
|
+
}
|
|
47
|
+
if (repos.length === 0)
|
|
48
|
+
return result;
|
|
49
|
+
// Build the shared repo list
|
|
50
|
+
const workspaceRepos = repos.map(r => ({
|
|
51
|
+
name: r.name,
|
|
52
|
+
...(r.registry && { registry: r.registry }),
|
|
53
|
+
}));
|
|
54
|
+
// Write workspace.yaml + update agents in each repo
|
|
55
|
+
writeWorkspaceToRepos(repos, workspaceRepos, options.workspace, result);
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
// ─── Add to Existing Workspace ───────────────────────────────────────
|
|
59
|
+
/**
|
|
60
|
+
* Add a new repo to an existing workspace.
|
|
61
|
+
*
|
|
62
|
+
* 1. Read workspace.yaml from the existing repo
|
|
63
|
+
* 2. Get the full repo list + workspace name
|
|
64
|
+
* 3. Auto-init the new repo if needed
|
|
65
|
+
* 4. Discover existing workspace repos on disk (sibling directory scan)
|
|
66
|
+
* 5. Add the new repo to the list
|
|
67
|
+
* 6. Write updated workspace.yaml + agent files to ALL repos found on disk
|
|
68
|
+
*/
|
|
69
|
+
export function addToWorkspace(options) {
|
|
70
|
+
const result = {
|
|
71
|
+
linked: [], skipped: [], agentFilesUpdated: [], initialized: [], updated: [],
|
|
72
|
+
};
|
|
73
|
+
const existingPath = resolve(options.existingRepoPath);
|
|
74
|
+
const newPath = resolve(options.newRepoPath);
|
|
75
|
+
// 1. Read existing workspace config
|
|
76
|
+
const existingConfig = loadWorkspaceConfig(existingPath);
|
|
77
|
+
if (!existingConfig) {
|
|
78
|
+
result.skipped.push({
|
|
79
|
+
name: options.existingRepoPath,
|
|
80
|
+
reason: 'No .guardlink/workspace.yaml found — not a workspace repo',
|
|
81
|
+
});
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
// 2. Auto-init the new repo if needed
|
|
85
|
+
const initResult = ensureInitialized(newPath);
|
|
86
|
+
if (initResult)
|
|
87
|
+
result.initialized.push(initResult);
|
|
88
|
+
// 3. Detect new repo name and build its WorkspaceRepo entry
|
|
89
|
+
const newRepoName = detectRepoName(newPath);
|
|
90
|
+
// Check if already in workspace
|
|
91
|
+
if (existingConfig.repos.some(r => r.name === newRepoName)) {
|
|
92
|
+
result.skipped.push({
|
|
93
|
+
name: newRepoName,
|
|
94
|
+
reason: `Already in workspace "${existingConfig.workspace}"`,
|
|
95
|
+
});
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
// Infer registry from existing repos if not provided
|
|
99
|
+
const existingRegistry = existingConfig.repos.find(r => r.registry)?.registry;
|
|
100
|
+
const registryBase = options.registry || extractRegistryBase(existingRegistry);
|
|
101
|
+
const newRepoEntry = {
|
|
102
|
+
name: newRepoName,
|
|
103
|
+
...(registryBase && { registry: `${registryBase}/${newRepoName}` }),
|
|
104
|
+
};
|
|
105
|
+
// 4. Build updated repo list
|
|
106
|
+
const updatedRepos = [...existingConfig.repos, newRepoEntry];
|
|
107
|
+
// 5. Discover all workspace repos on disk
|
|
108
|
+
const discoveredPaths = discoverWorkspaceRepos(existingPath, existingConfig, newPath, newRepoName);
|
|
109
|
+
// 6. Write to all discovered repos
|
|
110
|
+
const reposWithPaths = discoveredPaths.map(d => ({
|
|
111
|
+
name: d.name,
|
|
112
|
+
path: d.path,
|
|
113
|
+
registry: updatedRepos.find(r => r.name === d.name)?.registry,
|
|
114
|
+
}));
|
|
115
|
+
writeWorkspaceToRepos(reposWithPaths, updatedRepos, existingConfig.workspace, result);
|
|
116
|
+
// Track which existing repos got updated vs the new one that got linked
|
|
117
|
+
for (const d of discoveredPaths) {
|
|
118
|
+
if (d.name !== newRepoName && result.linked.includes(d.name)) {
|
|
119
|
+
// Move from "linked" to "updated" for existing repos
|
|
120
|
+
result.linked = result.linked.filter(n => n !== d.name);
|
|
121
|
+
result.updated.push(d.name);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Remove a repo from an existing workspace.
|
|
128
|
+
*
|
|
129
|
+
* 1. Read workspace.yaml from the existing repo
|
|
130
|
+
* 2. Verify the named repo is actually in the workspace
|
|
131
|
+
* 3. Remove it from the repo list
|
|
132
|
+
* 4. Discover all remaining workspace repos on disk
|
|
133
|
+
* 5. Update workspace.yaml + agent files in all remaining repos
|
|
134
|
+
* 6. If the removed repo is found on disk, clean up its workspace.yaml
|
|
135
|
+
* and strip workspace context from its agent files
|
|
136
|
+
*/
|
|
137
|
+
export function removeFromWorkspace(options) {
|
|
138
|
+
const result = {
|
|
139
|
+
linked: [], skipped: [], agentFilesUpdated: [], initialized: [], updated: [],
|
|
140
|
+
};
|
|
141
|
+
const existingPath = resolve(options.existingRepoPath);
|
|
142
|
+
// 1. Read existing workspace config
|
|
143
|
+
const existingConfig = loadWorkspaceConfig(existingPath);
|
|
144
|
+
if (!existingConfig) {
|
|
145
|
+
result.skipped.push({
|
|
146
|
+
name: options.existingRepoPath,
|
|
147
|
+
reason: 'No .guardlink/workspace.yaml found — not a workspace repo',
|
|
148
|
+
});
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
// 2. Verify repo is in workspace
|
|
152
|
+
const targetRepo = existingConfig.repos.find(r => r.name === options.repoName);
|
|
153
|
+
if (!targetRepo) {
|
|
154
|
+
result.skipped.push({
|
|
155
|
+
name: options.repoName,
|
|
156
|
+
reason: `Not found in workspace "${existingConfig.workspace}" (repos: ${existingConfig.repos.map(r => r.name).join(', ')})`,
|
|
157
|
+
});
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
// 3. Can't remove if it would leave < 2 repos
|
|
161
|
+
if (existingConfig.repos.length <= 2) {
|
|
162
|
+
result.skipped.push({
|
|
163
|
+
name: options.repoName,
|
|
164
|
+
reason: 'Cannot remove — workspace must have at least 2 repos. Use fresh link-project to recreate.',
|
|
165
|
+
});
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
// 4. Build updated repo list (without the removed repo)
|
|
169
|
+
const updatedRepos = existingConfig.repos.filter(r => r.name !== options.repoName);
|
|
170
|
+
// 5. Discover remaining repos on disk
|
|
171
|
+
// We pass a dummy new path that won't match anything — we just need discovery
|
|
172
|
+
const discoveredPaths = discoverWorkspaceReposForRemoval(existingPath, existingConfig, options.repoName);
|
|
173
|
+
// 6. Update remaining repos
|
|
174
|
+
const remainingRepos = discoveredPaths
|
|
175
|
+
.filter(d => d.name !== options.repoName)
|
|
176
|
+
.map(d => ({
|
|
177
|
+
name: d.name,
|
|
178
|
+
path: d.path,
|
|
179
|
+
registry: updatedRepos.find(r => r.name === d.name)?.registry,
|
|
180
|
+
}));
|
|
181
|
+
writeWorkspaceToRepos(remainingRepos, updatedRepos, existingConfig.workspace, result);
|
|
182
|
+
// Move all from "linked" to "updated" since these are existing repos being updated
|
|
183
|
+
result.updated = [...result.linked];
|
|
184
|
+
result.linked = [];
|
|
185
|
+
// 7. Clean up the removed repo if found on disk
|
|
186
|
+
const removedOnDisk = discoveredPaths.find(d => d.name === options.repoName);
|
|
187
|
+
if (removedOnDisk) {
|
|
188
|
+
cleanupRemovedRepo(removedOnDisk.path, options.repoName, result);
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Clean up a removed repo: delete workspace.yaml, strip workspace context from agent files.
|
|
194
|
+
*/
|
|
195
|
+
function cleanupRemovedRepo(repoPath, repoName, result) {
|
|
196
|
+
// Delete workspace.yaml
|
|
197
|
+
const yamlPath = resolve(repoPath, '.guardlink', 'workspace.yaml');
|
|
198
|
+
if (existsSync(yamlPath)) {
|
|
199
|
+
unlinkSync(yamlPath);
|
|
200
|
+
}
|
|
201
|
+
// Strip workspace context block from agent files
|
|
202
|
+
for (const agent of AGENT_FILES) {
|
|
203
|
+
const filePath = resolve(repoPath, agent.path);
|
|
204
|
+
if (!existsSync(filePath))
|
|
205
|
+
continue;
|
|
206
|
+
let content = readFileSync(filePath, 'utf-8');
|
|
207
|
+
const markerIdx = content.indexOf(agent.marker);
|
|
208
|
+
if (markerIdx === -1)
|
|
209
|
+
continue;
|
|
210
|
+
// Remove from marker to next ## or end of file
|
|
211
|
+
const afterMarker = content.slice(markerIdx);
|
|
212
|
+
const nextSectionMatch = afterMarker.match(/\n## (?!Workspace Context)/);
|
|
213
|
+
const endIdx = nextSectionMatch
|
|
214
|
+
? markerIdx + (nextSectionMatch.index ?? afterMarker.length)
|
|
215
|
+
: content.length;
|
|
216
|
+
content = content.slice(0, markerIdx).trimEnd() + '\n';
|
|
217
|
+
writeFileSync(filePath, content);
|
|
218
|
+
result.agentFilesUpdated.push(`${repoName}/${agent.path} (cleaned)`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Discover workspace repos for removal — scans sibling dirs from the existing repo.
|
|
223
|
+
* Also tries to find the repo being removed so we can clean it up.
|
|
224
|
+
*/
|
|
225
|
+
function discoverWorkspaceReposForRemoval(existingRepoPath, config, removingRepoName) {
|
|
226
|
+
const discovered = [];
|
|
227
|
+
const found = new Set();
|
|
228
|
+
// Always include the existing repo
|
|
229
|
+
discovered.push({ name: config.this_repo, path: existingRepoPath });
|
|
230
|
+
found.add(config.this_repo);
|
|
231
|
+
// Find all other workspace repos (including the one being removed, for cleanup)
|
|
232
|
+
const remaining = config.repos
|
|
233
|
+
.map(r => r.name)
|
|
234
|
+
.filter(n => !found.has(n));
|
|
235
|
+
const scanDirs = new Set();
|
|
236
|
+
scanDirs.add(dirname(existingRepoPath));
|
|
237
|
+
scanDirs.add(dirname(dirname(existingRepoPath)));
|
|
238
|
+
for (const scanDir of scanDirs) {
|
|
239
|
+
if (!existsSync(scanDir))
|
|
240
|
+
continue;
|
|
241
|
+
let entries;
|
|
242
|
+
try {
|
|
243
|
+
entries = readdirSync(scanDir);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
for (const entry of entries) {
|
|
249
|
+
const entryPath = join(scanDir, entry);
|
|
250
|
+
try {
|
|
251
|
+
if (!statSync(entryPath).isDirectory())
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
for (const repoName of remaining) {
|
|
258
|
+
if (found.has(repoName))
|
|
259
|
+
continue;
|
|
260
|
+
if (matchesRepoName(entryPath, entry, repoName)) {
|
|
261
|
+
discovered.push({ name: repoName, path: entryPath });
|
|
262
|
+
found.add(repoName);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return discovered;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Find workspace repos on the local filesystem.
|
|
271
|
+
*
|
|
272
|
+
* Strategy:
|
|
273
|
+
* 1. Start with the known existing repo path and the new repo path
|
|
274
|
+
* 2. For remaining repos in workspace.yaml, scan common parent directories
|
|
275
|
+
* 3. Check: parent of existing repo, parent of new repo, grandparent
|
|
276
|
+
* 4. Match by directory name or git remote name
|
|
277
|
+
*/
|
|
278
|
+
function discoverWorkspaceRepos(existingRepoPath, config, newRepoPath, newRepoName) {
|
|
279
|
+
const discovered = [];
|
|
280
|
+
const found = new Set();
|
|
281
|
+
// Always include the existing repo and new repo
|
|
282
|
+
discovered.push({ name: config.this_repo, path: existingRepoPath });
|
|
283
|
+
found.add(config.this_repo);
|
|
284
|
+
discovered.push({ name: newRepoName, path: newRepoPath });
|
|
285
|
+
found.add(newRepoName);
|
|
286
|
+
// Find remaining workspace repos
|
|
287
|
+
const remaining = config.repos
|
|
288
|
+
.map(r => r.name)
|
|
289
|
+
.filter(n => !found.has(n));
|
|
290
|
+
if (remaining.length === 0)
|
|
291
|
+
return discovered;
|
|
292
|
+
// Directories to scan for sibling repos
|
|
293
|
+
const scanDirs = new Set();
|
|
294
|
+
scanDirs.add(dirname(existingRepoPath));
|
|
295
|
+
scanDirs.add(dirname(newRepoPath));
|
|
296
|
+
// Also try grandparent (for monorepo-style layouts like ~/projects/org/repos/)
|
|
297
|
+
scanDirs.add(dirname(dirname(existingRepoPath)));
|
|
298
|
+
for (const scanDir of scanDirs) {
|
|
299
|
+
if (!existsSync(scanDir))
|
|
300
|
+
continue;
|
|
301
|
+
let entries;
|
|
302
|
+
try {
|
|
303
|
+
entries = readdirSync(scanDir);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
for (const entry of entries) {
|
|
309
|
+
if (found.has(entry))
|
|
310
|
+
continue; // already discovered by name match
|
|
311
|
+
const entryPath = join(scanDir, entry);
|
|
312
|
+
try {
|
|
313
|
+
if (!statSync(entryPath).isDirectory())
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
// Check if this directory matches a remaining repo
|
|
320
|
+
for (const repoName of remaining) {
|
|
321
|
+
if (found.has(repoName))
|
|
322
|
+
continue;
|
|
323
|
+
if (matchesRepoName(entryPath, entry, repoName)) {
|
|
324
|
+
discovered.push({ name: repoName, path: entryPath });
|
|
325
|
+
found.add(repoName);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Warn about repos we couldn't find (they'll be in the updated workspace.yaml
|
|
331
|
+
// but won't get their files updated — user needs to update them manually)
|
|
332
|
+
// Caller handles this via checking which names are in result.linked vs config.repos
|
|
333
|
+
return discovered;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if a directory matches a workspace repo name.
|
|
337
|
+
* Matches by: exact directory name, or git remote repo name.
|
|
338
|
+
*/
|
|
339
|
+
function matchesRepoName(dirPath, dirName, repoName) {
|
|
340
|
+
// Direct name match
|
|
341
|
+
if (dirName === repoName)
|
|
342
|
+
return true;
|
|
343
|
+
// Check git remote
|
|
344
|
+
try {
|
|
345
|
+
const gitConfigPath = join(dirPath, '.git', 'config');
|
|
346
|
+
if (existsSync(gitConfigPath)) {
|
|
347
|
+
const gitConfig = readFileSync(gitConfigPath, 'utf-8');
|
|
348
|
+
const m = gitConfig.match(/url\s*=\s*.*[/:]([^/\s]+?)(?:\.git)?\s*$/m);
|
|
349
|
+
if (m && m[1] === repoName)
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch { /* ignore */ }
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Extract the org base URL from a full registry URL.
|
|
358
|
+
* "github.com/unstructured/payment-svc" → "github.com/unstructured"
|
|
359
|
+
*/
|
|
360
|
+
function extractRegistryBase(registry) {
|
|
361
|
+
if (!registry)
|
|
362
|
+
return undefined;
|
|
363
|
+
const lastSlash = registry.lastIndexOf('/');
|
|
364
|
+
return lastSlash > 0 ? registry.slice(0, lastSlash) : undefined;
|
|
365
|
+
}
|
|
366
|
+
// ─── Shared: Write Workspace Config to Repos ─────────────────────────
|
|
367
|
+
function writeWorkspaceToRepos(repos, workspaceRepos, workspace, result) {
|
|
368
|
+
for (const repo of repos) {
|
|
369
|
+
try {
|
|
370
|
+
const config = {
|
|
371
|
+
workspace,
|
|
372
|
+
this_repo: repo.name,
|
|
373
|
+
repos: workspaceRepos,
|
|
374
|
+
};
|
|
375
|
+
// Ensure .guardlink/ exists
|
|
376
|
+
const guardlinkDir = resolve(repo.path, '.guardlink');
|
|
377
|
+
if (!existsSync(guardlinkDir)) {
|
|
378
|
+
mkdirSync(guardlinkDir, { recursive: true });
|
|
379
|
+
}
|
|
380
|
+
// Write workspace.yaml
|
|
381
|
+
const yamlPath = resolve(guardlinkDir, 'workspace.yaml');
|
|
382
|
+
writeFileSync(yamlPath, serializeWorkspaceYaml(config));
|
|
383
|
+
// Update agent instruction files
|
|
384
|
+
const updated = updateAgentWorkspaceContext(repo.path, config, workspaceRepos);
|
|
385
|
+
result.agentFilesUpdated.push(...updated);
|
|
386
|
+
result.linked.push(repo.name);
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
result.skipped.push({
|
|
390
|
+
name: repo.name,
|
|
391
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// ─── Auto-Init ───────────────────────────────────────────────────────
|
|
397
|
+
/**
|
|
398
|
+
* Check if a repo has been guardlink-initialized.
|
|
399
|
+
* If not, create minimal structure: .guardlink/ dir and base agent files.
|
|
400
|
+
* Returns the repo name if initialized, null if already set up.
|
|
401
|
+
*/
|
|
402
|
+
function ensureInitialized(repoPath) {
|
|
403
|
+
const guardlinkDir = resolve(repoPath, '.guardlink');
|
|
404
|
+
const hasGuardlink = existsSync(guardlinkDir);
|
|
405
|
+
// Check for at least one agent instruction file
|
|
406
|
+
const hasAnyAgentFile = AGENT_FILES.some(a => existsSync(resolve(repoPath, a.path)));
|
|
407
|
+
if (hasGuardlink && hasAnyAgentFile)
|
|
408
|
+
return null; // already initialized
|
|
409
|
+
const repoName = detectRepoName(repoPath);
|
|
410
|
+
// Create .guardlink/ if missing
|
|
411
|
+
if (!hasGuardlink) {
|
|
412
|
+
mkdirSync(guardlinkDir, { recursive: true });
|
|
413
|
+
}
|
|
414
|
+
// Create minimal agent instruction files if none exist
|
|
415
|
+
if (!hasAnyAgentFile) {
|
|
416
|
+
createMinimalAgentFiles(repoPath, repoName);
|
|
417
|
+
}
|
|
418
|
+
return repoName;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Create minimal agent instruction files for a repo that hasn't been
|
|
422
|
+
* guardlink-initialized. We create a subset — just the most common ones
|
|
423
|
+
* (.claude/guardlink.md, AGENTS.md) rather than the full init flow,
|
|
424
|
+
* since the user may not have all agents installed.
|
|
425
|
+
*/
|
|
426
|
+
function createMinimalAgentFiles(repoPath, repoName) {
|
|
427
|
+
const baseContent = [
|
|
428
|
+
`# GuardLink — ${repoName}`,
|
|
429
|
+
'',
|
|
430
|
+
'This project uses [GuardLink](https://guardlink.bugb.io) for security annotations.',
|
|
431
|
+
'',
|
|
432
|
+
'## Annotation Rules',
|
|
433
|
+
'',
|
|
434
|
+
'- Add `@asset`, `@threat`, `@control` annotations to define security elements',
|
|
435
|
+
'- Use `@mitigates`, `@exposes`, `@accepts` to document relationships',
|
|
436
|
+
'- Use `@flows` to document data movement between components',
|
|
437
|
+
'- Never write `@accepts` — risk acceptance is human-only via `guardlink review`',
|
|
438
|
+
'- Run `guardlink validate .` after changes to check for errors',
|
|
439
|
+
'',
|
|
440
|
+
].join('\n');
|
|
441
|
+
// Create .claude/guardlink.md (most common agent)
|
|
442
|
+
const claudeDir = resolve(repoPath, '.claude');
|
|
443
|
+
if (!existsSync(claudeDir))
|
|
444
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
445
|
+
const claudePath = resolve(claudeDir, 'guardlink.md');
|
|
446
|
+
if (!existsSync(claudePath))
|
|
447
|
+
writeFileSync(claudePath, baseContent);
|
|
448
|
+
// Create AGENTS.md (universal)
|
|
449
|
+
const agentsPath = resolve(repoPath, 'AGENTS.md');
|
|
450
|
+
if (!existsSync(agentsPath))
|
|
451
|
+
writeFileSync(agentsPath, baseContent);
|
|
452
|
+
}
|
|
453
|
+
// ─── Repo Name Detection ─────────────────────────────────────────────
|
|
454
|
+
/**
|
|
455
|
+
* Detect repo name from (in order): git remote origin, package.json name,
|
|
456
|
+
* Cargo.toml name, or directory basename.
|
|
457
|
+
*/
|
|
458
|
+
export function detectRepoName(repoPath) {
|
|
459
|
+
// 1. Git remote
|
|
460
|
+
try {
|
|
461
|
+
const gitConfigPath = resolve(repoPath, '.git', 'config');
|
|
462
|
+
if (existsSync(gitConfigPath)) {
|
|
463
|
+
const gitConfig = readFileSync(gitConfigPath, 'utf-8');
|
|
464
|
+
const m = gitConfig.match(/url\s*=\s*.*[/:]([^/\s]+?)(?:\.git)?\s*$/m);
|
|
465
|
+
if (m)
|
|
466
|
+
return m[1];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
catch { /* ignore */ }
|
|
470
|
+
// 2. package.json
|
|
471
|
+
try {
|
|
472
|
+
const pkgPath = resolve(repoPath, 'package.json');
|
|
473
|
+
if (existsSync(pkgPath)) {
|
|
474
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
475
|
+
if (pkg.name && !isGenericName(pkg.name))
|
|
476
|
+
return pkg.name;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
catch { /* ignore */ }
|
|
480
|
+
// 3. Cargo.toml
|
|
481
|
+
try {
|
|
482
|
+
const cargoPath = resolve(repoPath, 'Cargo.toml');
|
|
483
|
+
if (existsSync(cargoPath)) {
|
|
484
|
+
const cargo = readFileSync(cargoPath, 'utf-8');
|
|
485
|
+
const m = cargo.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
486
|
+
if (m)
|
|
487
|
+
return m[1];
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch { /* ignore */ }
|
|
491
|
+
// 4. Directory name
|
|
492
|
+
return basename(repoPath);
|
|
493
|
+
}
|
|
494
|
+
const GENERIC_NAMES = new Set([
|
|
495
|
+
'my-app', 'my-project', 'app', 'project', 'unknown', 'starter',
|
|
496
|
+
'my-v0-project', 'vite-project', 'react-app', 'create-react-app',
|
|
497
|
+
]);
|
|
498
|
+
function isGenericName(name) {
|
|
499
|
+
return GENERIC_NAMES.has(name.toLowerCase());
|
|
500
|
+
}
|
|
501
|
+
// ─── Agent File Updates ──────────────────────────────────────────────
|
|
502
|
+
/** Known agent instruction file paths (relative to repo root) */
|
|
503
|
+
const AGENT_FILES = [
|
|
504
|
+
{ path: '.claude/guardlink.md', marker: '## Workspace Context' },
|
|
505
|
+
{ path: 'CLAUDE.md', marker: '## Workspace Context' },
|
|
506
|
+
{ path: '.cursor/rules/guardlink.mdc', marker: '## Workspace Context' },
|
|
507
|
+
{ path: '.windsurfrules', marker: '## Workspace Context' },
|
|
508
|
+
{ path: '.github/copilot-instructions.md', marker: '## Workspace Context' },
|
|
509
|
+
{ path: '.gemini/guardlink.md', marker: '## Workspace Context' },
|
|
510
|
+
{ path: 'AGENTS.md', marker: '## Workspace Context' },
|
|
511
|
+
];
|
|
512
|
+
/**
|
|
513
|
+
* Generate the workspace context block that gets injected into agent files.
|
|
514
|
+
*/
|
|
515
|
+
export function buildWorkspaceContextBlock(config, allRepos) {
|
|
516
|
+
const siblings = allRepos.filter(r => r.name !== config.this_repo);
|
|
517
|
+
const siblingNames = siblings.map(r => r.name).join(', ');
|
|
518
|
+
const lines = [];
|
|
519
|
+
lines.push('## Workspace Context');
|
|
520
|
+
lines.push('');
|
|
521
|
+
lines.push(`This repository (\`${config.this_repo}\`) is part of the **${config.workspace}** workspace`);
|
|
522
|
+
lines.push(`containing ${allRepos.length} linked services: ${allRepos.map(r => r.name).join(', ')}.`);
|
|
523
|
+
lines.push('');
|
|
524
|
+
lines.push('### Cross-Repo Annotation Rules');
|
|
525
|
+
lines.push('');
|
|
526
|
+
lines.push('When writing GuardLink annotations in this repo:');
|
|
527
|
+
lines.push('');
|
|
528
|
+
lines.push(`- **Tag prefix convention:** Use \`#${config.this_repo}.<component>\` for assets defined here.`);
|
|
529
|
+
lines.push(`- **Reference sibling repos:** You may reference assets/threats/controls from: ${siblingNames}.`);
|
|
530
|
+
lines.push(` Use their tag prefix, e.g. \`#${siblings[0]?.name || 'other-service'}.<component>\`.`);
|
|
531
|
+
lines.push('- **Cross-service data flows:** If this code calls or is called by another service, document it:');
|
|
532
|
+
lines.push(` \`@flows #request from #${config.this_repo}.handler to #${siblings[0]?.name || 'other-service'}.endpoint\``);
|
|
533
|
+
lines.push('- **Do not redefine** assets that belong to another repo. Reference them by tag.');
|
|
534
|
+
lines.push('- **External refs are OK:** Tags referencing sibling repos will show as "external refs"');
|
|
535
|
+
lines.push(' during local validation but resolve during workspace merge.');
|
|
536
|
+
lines.push('');
|
|
537
|
+
lines.push(`### Sibling Services`);
|
|
538
|
+
lines.push('');
|
|
539
|
+
for (const s of siblings) {
|
|
540
|
+
const reg = s.registry ? ` (${s.registry})` : '';
|
|
541
|
+
lines.push(`- **${s.name}**${reg}`);
|
|
542
|
+
}
|
|
543
|
+
lines.push('');
|
|
544
|
+
return lines.join('\n');
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Update agent instruction files in a repo with workspace context.
|
|
548
|
+
* If the file exists and already has a workspace context block, replace it.
|
|
549
|
+
* If the file exists without the block, append it.
|
|
550
|
+
* If the file doesn't exist, skip it.
|
|
551
|
+
*
|
|
552
|
+
* Returns list of files updated.
|
|
553
|
+
*/
|
|
554
|
+
function updateAgentWorkspaceContext(repoPath, config, allRepos) {
|
|
555
|
+
const contextBlock = buildWorkspaceContextBlock(config, allRepos);
|
|
556
|
+
const updated = [];
|
|
557
|
+
for (const agent of AGENT_FILES) {
|
|
558
|
+
const filePath = resolve(repoPath, agent.path);
|
|
559
|
+
if (!existsSync(filePath))
|
|
560
|
+
continue;
|
|
561
|
+
let content = readFileSync(filePath, 'utf-8');
|
|
562
|
+
const markerIdx = content.indexOf(agent.marker);
|
|
563
|
+
if (markerIdx !== -1) {
|
|
564
|
+
// Replace existing workspace context block (from marker to next ## or end)
|
|
565
|
+
const afterMarker = content.slice(markerIdx);
|
|
566
|
+
const nextSectionMatch = afterMarker.match(/\n## (?!Workspace Context)/);
|
|
567
|
+
const endIdx = nextSectionMatch
|
|
568
|
+
? markerIdx + (nextSectionMatch.index ?? afterMarker.length)
|
|
569
|
+
: content.length;
|
|
570
|
+
content = content.slice(0, markerIdx) + contextBlock + content.slice(endIdx);
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
// Append workspace context block
|
|
574
|
+
content = content.trimEnd() + '\n\n' + contextBlock;
|
|
575
|
+
}
|
|
576
|
+
writeFileSync(filePath, content);
|
|
577
|
+
updated.push(`${config.this_repo}/${agent.path}`);
|
|
578
|
+
}
|
|
579
|
+
return updated;
|
|
580
|
+
}
|
|
581
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/workspace/link.ts"],"names":[],"mappings":"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"}
|