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.
Files changed (53) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +43 -1
  3. package/dist/agents/launcher.d.ts +1 -1
  4. package/dist/agents/launcher.js +1 -1
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.d.ts.map +1 -1
  7. package/dist/cli/index.js +300 -54
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/server.d.ts +1 -0
  14. package/dist/mcp/server.d.ts.map +1 -1
  15. package/dist/mcp/server.js +38 -1
  16. package/dist/mcp/server.js.map +1 -1
  17. package/dist/mcp/suggest.d.ts +1 -0
  18. package/dist/mcp/suggest.d.ts.map +1 -1
  19. package/dist/mcp/suggest.js +1 -0
  20. package/dist/mcp/suggest.js.map +1 -1
  21. package/dist/parser/parse-project.d.ts.map +1 -1
  22. package/dist/parser/parse-project.js +103 -0
  23. package/dist/parser/parse-project.js.map +1 -1
  24. package/dist/tui/commands.d.ts +3 -0
  25. package/dist/tui/commands.d.ts.map +1 -1
  26. package/dist/tui/commands.js +297 -39
  27. package/dist/tui/commands.js.map +1 -1
  28. package/dist/tui/index.d.ts.map +1 -1
  29. package/dist/tui/index.js +17 -1
  30. package/dist/tui/index.js.map +1 -1
  31. package/dist/types/index.d.ts +39 -0
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/workspace/index.d.ts +12 -0
  34. package/dist/workspace/index.d.ts.map +1 -0
  35. package/dist/workspace/index.js +9 -0
  36. package/dist/workspace/index.js.map +1 -0
  37. package/dist/workspace/link.d.ts +91 -0
  38. package/dist/workspace/link.d.ts.map +1 -0
  39. package/dist/workspace/link.js +581 -0
  40. package/dist/workspace/link.js.map +1 -0
  41. package/dist/workspace/merge.d.ts +104 -0
  42. package/dist/workspace/merge.d.ts.map +1 -0
  43. package/dist/workspace/merge.js +752 -0
  44. package/dist/workspace/merge.js.map +1 -0
  45. package/dist/workspace/metadata.d.ts +34 -0
  46. package/dist/workspace/metadata.d.ts.map +1 -0
  47. package/dist/workspace/metadata.js +181 -0
  48. package/dist/workspace/metadata.js.map +1 -0
  49. package/dist/workspace/types.d.ts +134 -0
  50. package/dist/workspace/types.d.ts.map +1 -0
  51. package/dist/workspace/types.js +12 -0
  52. package/dist/workspace/types.js.map +1 -0
  53. 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":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAmC5E,wEAAwE;AAExE;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,MAAM,GAAe;QACzB,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;KAC7E,CAAC;IAEF,0CAA0C;IAC1C,MAAM,KAAK,GAA6D,EAAE,CAAC;IAC3E,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACjE,SAAS;QACX,CAAC;QAED,sBAAsB;QACtB,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,UAAU;YAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;YAC/B,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE;YAClD,CAAC,CAAC,SAAS,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAEtC,6BAA6B;IAC7B,MAAM,cAAc,GAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;KAC5C,CAAC,CAAC,CAAC;IAEJ,oDAAoD;IACpD,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAExE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AAExE;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,MAAM,GAAe;QACzB,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;KAC7E,CAAC;IAEF,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7C,oCAAoC;IACpC,MAAM,cAAc,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,OAAO,CAAC,gBAAgB;YAC9B,MAAM,EAAE,2DAA2D;SACpE,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sCAAsC;IACtC,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,UAAU;QAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEpD,4DAA4D;IAC5D,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAE5C,gCAAgC;IAChC,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QAC3D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,yBAAyB,cAAc,CAAC,SAAS,GAAG;SAC7D,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,qDAAqD;IACrD,MAAM,gBAAgB,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,IAAI,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAkB;QAClC,IAAI,EAAE,WAAW;QACjB,GAAG,CAAC,YAAY,IAAI,EAAE,QAAQ,EAAE,GAAG,YAAY,IAAI,WAAW,EAAE,EAAE,CAAC;KACpE,CAAC;IAEF,6BAA6B;IAC7B,MAAM,YAAY,GAAoB,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAE9E,0CAA0C;IAC1C,MAAM,eAAe,GAAG,sBAAsB,CAC5C,YAAY,EACZ,cAAc,EACd,OAAO,EACP,WAAW,CACZ,CAAC;IAEF,mCAAmC;IACnC,MAAM,cAAc,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ;KAC9D,CAAC,CAAC,CAAC;IAEJ,qBAAqB,CAAC,cAAc,EAAE,YAAY,EAAE,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEtF,wEAAwE;IACxE,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7D,qDAAqD;YACrD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAWD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAmC;IACrE,MAAM,MAAM,GAAe;QACzB,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;KAC7E,CAAC;IAEF,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEvD,oCAAoC;IACpC,MAAM,cAAc,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,OAAO,CAAC,gBAAgB;YAC9B,MAAM,EAAE,2DAA2D;SACpE,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,OAAO,CAAC,QAAQ;YACtB,MAAM,EAAE,2BAA2B,cAAc,CAAC,SAAS,aAAa,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SAC5H,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,8CAA8C;IAC9C,IAAI,cAAc,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,OAAO,CAAC,QAAQ;YACtB,MAAM,EAAE,2FAA2F;SACpG,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,wDAAwD;IACxD,MAAM,YAAY,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEnF,sCAAsC;IACtC,iFAAiF;IACjF,MAAM,eAAe,GAAG,gCAAgC,CACtD,YAAY,EACZ,cAAc,EACd,OAAO,CAAC,QAAQ,CACjB,CAAC;IAEF,4BAA4B;IAC5B,MAAM,cAAc,GAAG,eAAe;SACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC;SACxC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACT,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ;KAC9D,CAAC,CAAC,CAAC;IAEN,qBAAqB,CAAC,cAAc,EAAE,YAAY,EAAE,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEtF,mFAAmF;IACnF,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;IAEnB,gDAAgD;IAChD,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,aAAa,EAAE,CAAC;QAClB,kBAAkB,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,QAAgB,EAAE,MAAkB;IAChF,wBAAwB;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC;IACnE,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,iDAAiD;IACjD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEpC,IAAI,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,SAAS,KAAK,CAAC,CAAC;YAAE,SAAS;QAE/B,+CAA+C;QAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,gBAAgB;YAC7B,CAAC,CAAC,SAAS,GAAG,CAAC,gBAAgB,CAAC,KAAK,IAAI,WAAW,CAAC,MAAM,CAAC;YAC5D,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QAEnB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;QACvD,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gCAAgC,CACvC,gBAAwB,EACxB,MAAuB,EACvB,gBAAwB;IAExB,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,mCAAmC;IACnC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAE5B,gFAAgF;IAChF,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QACnC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QAE3D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACvC,IAAI,CAAC;gBAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;oBAAE,SAAS;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAS;YAAC,CAAC;YAE7E,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAClC,IAAI,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;oBAChD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBACrD,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AASD;;;;;;;;GAQG;AACH,SAAS,sBAAsB,CAC7B,gBAAwB,EACxB,MAAuB,EACvB,WAAmB,EACnB,WAAmB;IAEnB,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,gDAAgD;IAChD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAE5B,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC1D,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAEvB,iCAAiC;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAE9C,wCAAwC;IACxC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QAEnC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS,CAAC,mCAAmC;YAEnE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACvC,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;oBAAE,SAAS;YACnD,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,mDAAmD;YACnD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAElC,IAAI,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;oBAChD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBACrD,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,0EAA0E;IAC1E,oFAAoF;IAEpF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,OAAe,EAAE,OAAe,EAAE,QAAgB;IACzE,oBAAoB;IACpB,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEtC,mBAAmB;IACnB,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;YACvE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;QAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,QAA4B;IACvD,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5C,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC;AAED,wEAAwE;AAExE,SAAS,qBAAqB,CAC5B,KAA+D,EAC/D,cAA+B,EAC/B,SAAiB,EACjB,MAAkB;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAoB;gBAC9B,SAAS;gBACT,SAAS,EAAE,IAAI,CAAC,IAAI;gBACpB,KAAK,EAAE,cAAc;aACtB,CAAC;YAEF,4BAA4B;YAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YACtD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC9B,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC;YAED,uBAAuB;YACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;YACzD,aAAa,CAAC,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;YAExD,iCAAiC;YACjC,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;YAC/E,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACzD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,wEAAwE;AAExE;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAE9C,gDAAgD;IAChD,MAAM,eAAe,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAErF,IAAI,YAAY,IAAI,eAAe;QAAE,OAAO,IAAI,CAAC,CAAC,sBAAsB;IAExE,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE1C,gCAAgC;IAChC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,uDAAuD;IACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAAC,QAAgB,EAAE,QAAgB;IACjE,MAAM,WAAW,GAAG;QAClB,iBAAiB,QAAQ,EAAE;QAC3B,EAAE;QACF,oFAAoF;QACpF,EAAE;QACF,qBAAqB;QACrB,EAAE;QACF,+EAA+E;QAC/E,sEAAsE;QACtE,6DAA6D;QAC7D,iFAAiF;QACjF,gEAAgE;QAChE,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,kDAAkD;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAEpE,+BAA+B;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACtE,CAAC;AAED,wEAAwE;AAExE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,gBAAgB;IAChB,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC1D,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;YACvE,IAAI,CAAC;gBAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExB,kBAAkB;IAClB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,GAAG,CAAC,IAAI,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExB,gBAAgB;IAChB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACnD,IAAI,CAAC;gBAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExB,oBAAoB;IACpB,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;IAC9D,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB;CACjE,CAAC,CAAC;AAEH,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,wEAAwE;AAExE,iEAAiE;AACjE,MAAM,WAAW,GAAG;IAClB,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,sBAAsB,EAAE;IAChE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,sBAAsB,EAAE;IACrD,EAAE,IAAI,EAAE,6BAA6B,EAAE,MAAM,EAAE,sBAAsB,EAAE;IACvE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,EAAE;IAC1D,EAAE,IAAI,EAAE,iCAAiC,EAAE,MAAM,EAAE,sBAAsB,EAAE;IAC3E,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,sBAAsB,EAAE;IAChE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,sBAAsB,EAAE;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAuB,EACvB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,SAAS,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,SAAS,wBAAwB,MAAM,CAAC,SAAS,cAAc,CAAC,CAAC;IACzG,KAAK,CAAC,IAAI,CAAC,cAAc,QAAQ,CAAC,MAAM,qBAAqB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,uCAAuC,MAAM,CAAC,SAAS,yCAAyC,CAAC,CAAC;IAC7G,KAAK,CAAC,IAAI,CAAC,kFAAkF,YAAY,GAAG,CAAC,CAAC;IAC9G,KAAK,CAAC,IAAI,CAAC,mCAAmC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,eAAe,iBAAiB,CAAC,CAAC;IACrG,KAAK,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAC;IAC/G,KAAK,CAAC,IAAI,CAAC,6BAA6B,MAAM,CAAC,SAAS,gBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,eAAe,aAAa,CAAC,CAAC;IAC3H,KAAK,CAAC,IAAI,CAAC,kFAAkF,CAAC,CAAC;IAC/F,KAAK,CAAC,IAAI,CAAC,yFAAyF,CAAC,CAAC;IACtG,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IAC5E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,2BAA2B,CAClC,QAAgB,EAChB,MAAuB,EACvB,QAAyB;IAEzB,MAAM,YAAY,GAAG,0BAA0B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEpC,IAAI,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEhD,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,2EAA2E;YAC3E,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACzE,MAAM,MAAM,GAAG,gBAAgB;gBAC7B,CAAC,CAAC,SAAS,GAAG,CAAC,gBAAgB,CAAC,KAAK,IAAI,WAAW,CAAC,MAAM,CAAC;gBAC5D,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YACnB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/E,CAAC;aAAM,CAAC;YACN,iCAAiC;YACjC,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,YAAY,CAAC;QACtD,CAAC;QAED,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}