@cmkk/agentlink 0.1.0-beta.1 → 0.1.0-beta.3

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 CHANGED
@@ -4,7 +4,50 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
- ## [0.1.0] - 2026-05-11
7
+ ## [0.1.0-beta.3] - 2026-06-09
8
+
9
+ ### 变更
10
+
11
+ - **移除 `AGENTLINK_SOURCE` 环境变量**:持久化 source 请用 `agentlink.config.json` 的 `source` 字段;临时覆盖仍可用 `--source`。解析链简化为 `--source` → `config.source` → `./.agents` → `~/.agents`
12
+ - **移除 `AGENTLINK_CONFIG` 环境变量**:指定 config 请用 `--config`;否则走就近发现或 `~/agentlink.config.json`
13
+
14
+ ### 修复
15
+
16
+ - **config.source 优先于 `./.agents`**:config 里显式写了 `source` 时,不再被仓库里零散的 `.agents/commands/` 等局部目录挡住;未写 `source` 时仍走 `./.agents` → `~/.agents` 自动发现
17
+ - **CLI `--version` 与 npm 包版本不一致**:改为从 `package.json` 读取 `name` / `version`,不再硬编码
18
+
19
+ ### 改进
20
+
21
+ - `init` 非默认 source 提示去掉已废弃的环境变量,改为 config / `--source` / symlink 三种方式
22
+
23
+ ### 文档
24
+
25
+ - README 更新 source / config 解析链,移除对已删环境变量的说明
26
+
27
+ ## [0.1.0-beta.2] - 2026-06-09
28
+
29
+ ### 新增
30
+
31
+ - **config 持久化路径**:`agentlink.config.json` 支持可选的 `source`、`target`、`user` 字段,避免每次 `sync` 都带 flag;CLI flag / 环境变量仍优先于 config
32
+ - **source / destination 解析链扩展**:`config.source` 位于 flag/env 之后、`cwd/.agents` 之前;`config.target` / `config.user` 位于 CLI flag 与默认 `cwd` 之间
33
+ - **测试基础设施**:`tests/helpers/` 共享 sandbox / fs / io 工具;`load-context` 与 config 驱动 `sync` 集成测
34
+
35
+ ### 改进
36
+
37
+ - `loadContext` 先解析 config 再解析路径,避免重复读配置文件
38
+ - `init` 自定义 source 时写入 config 的 `source` 优先使用相对路径或 `~/…` 形式,便于跨机器移植
39
+ - `SourceNotFoundError` 诊断区分「config 未加载」「config 里未设置 source」等状态
40
+ - 发布脚本:`preversion` / `publish:beta` / `publish:latest`;发布手册移至根目录 `RELEASE.md`
41
+
42
+ ### 文档
43
+
44
+ - README 补充 destination 解析链、config 字段说明及「整文件生效、不按字段合并」语义
45
+
46
+ ### 工程
47
+
48
+ - vitest 用例增至 121 个(11 个测试文件)
49
+
50
+ ## [0.1.0-beta.1] - 2026-05-11
8
51
 
9
52
  首次公开发布。
10
53
 
@@ -29,5 +72,7 @@
29
72
  - ESM-only,tsup 打包,dts 同步生成
30
73
  - Node ≥ 18
31
74
 
32
- [Unreleased]: https://github.com/rankangkang/dot-agents/compare/agentlink-v0.1.0...HEAD
33
- [0.1.0]: https://github.com/rankangkang/dot-agents/releases/tag/agentlink-v0.1.0
75
+ [Unreleased]: https://github.com/rankangkang/agentlink/compare/v0.1.0-beta.3...HEAD
76
+ [0.1.0-beta.3]: https://github.com/rankangkang/agentlink/compare/v0.1.0-beta.2...v0.1.0-beta.3
77
+ [0.1.0-beta.2]: https://github.com/rankangkang/agentlink/compare/v0.1.0-beta.1...v0.1.0-beta.2
78
+ [0.1.0-beta.1]: https://github.com/rankangkang/agentlink/releases/tag/v0.1.0-beta.1
package/README.md CHANGED
@@ -62,8 +62,8 @@ agentlink init [--local | --source <path>] [--force] [--yes]
62
62
  (--local 写 cwd,否则写 ~),不在 source 内部。
63
63
 
64
64
  agentlink sync [--source <path>] [--target <dir> | --user] [-n] [-f] [--strict]
65
- 刷新所有 symlink。source 按以下优先级解析:
66
- --source flag $AGENTLINK_SOURCE ./.agents ~/.agents
65
+ 刷新所有 symlink。source / destination 见下方解析链;也可写在
66
+ agentlink.config.json source / target / user 字段里持久化。
67
67
  destination root 默认是 cwd;--user / -u 改为 $HOME(把 source
68
68
  投影到 ~/.cursor / ~/.claude / ...),--target <dir> 指定任意项目根。
69
69
  --dry-run / -n 预览将做什么,不动文件系统
@@ -85,27 +85,39 @@ agentlink doctor
85
85
 
86
86
  ## source 与 config 解析
87
87
 
88
- agentlink 把"**对什么数据操作**"(`.agents/` source)与"**怎么操作**"(`agentlink.config.json`)解耦:两者各有独立解析链,可以共享同一份 source 但每个项目用自己的 config 覆盖行为。
88
+ agentlink 把"**对什么数据操作**"(`.agents/` source)与"**怎么操作**"(`agentlink.config.json`)大体解耦:config 主要描述投影行为,也可选地持久化 `source` / `target` 默认值。两者各有独立解析链。
89
+
90
+ **配置文件是整文件生效**——从 cwd 向上找到最近的一份 `agentlink.config.json` 后,**整份**用于 adapters / include 等;不会把「项目 config 的 adapters」和「全局 config 的 source」按字段合并。若项目目录里已有 config 文件,就不会再去读 `~/agentlink.config.json`。
89
91
 
90
92
  ### source 解析
91
93
 
92
94
  | # | 来源 | 说明 |
93
95
  |---|---|---|
94
96
  | 1 | `--source <path>` | 显式 flag |
95
- | 2 | `AGENTLINK_SOURCE` 环境变量 | 适合写在 shell rc |
96
- | 3 | `./.agents` | **本地优先** 克隆的项目自带 `.agents/` 时压过个人全局 |
97
+ | 2 | `config.source` | 来自**已解析的那份** config;显式设置时**优先于** `./.agents`(避免仓库里只有几条运维 command 却挡住个人全局源) |
98
+ | 3 | `./.agents` | 项目内完整 source(config 未写 `source` 时生效) |
97
99
  | 4 | `~/.agents` | 个人推荐默认 |
98
100
  | 5 | _(报错)_ | 提示用户跑 `agentlink init` |
99
101
 
100
- ### config 解析
102
+ ### destination 解析
103
+
104
+ | # | 来源 | 说明 |
105
+ |---|---|---|
106
+ | 1 | `--target <dir>` | 显式 flag |
107
+ | 2 | `--user` / `-u` | 投影根改为 `$HOME` |
108
+ | 3 | `config.target` / `config.user` | 来自已解析的那份 config;`target` 相对路径同样相对 config 文件目录 |
109
+ | 4 | `cwd` | 默认 |
110
+
111
+ `config.target` 与 `config.user` 互斥(schema 校验)。
112
+
113
+ ### config 文件位置
101
114
 
102
115
  | # | 来源 | 说明 |
103
116
  |---|---|---|
104
117
  | 1 | `--config <path>` | 显式 flag |
105
- | 2 | `AGENTLINK_CONFIG` 环境变量 | |
106
- | 3 | 从 cwd 向上找最近的 `agentlink.config.json` | cwd 在 home 内时停在 home;cwd 在 home 外时走到 fs 根 |
107
- | 4 | `~/agentlink.config.json` | 全局兜底 |
108
- | 5 | _(默认值)_ | 没找到 = 视为空配置 `{}` |
118
+ | 2 | 从 cwd 向上找最近的 `agentlink.config.json` | cwd 在 home 内时停在 home;cwd 在 home 外时走到 fs 根 |
119
+ | 3 | `~/agentlink.config.json` | 全局兜底 |
120
+ | 4 | _(默认值)_ | 没找到 = 视为空配置 `{}` |
109
121
 
110
122
  类似 git / eslint / tsconfig 的就近发现机制。
111
123
 
@@ -117,8 +129,13 @@ agentlink 把"**对什么数据操作**"(`.agents/` source)与"**怎么操
117
129
 
118
130
  ```jsonc
119
131
  {
132
+ // 可选。持久化 source / destination,省得每次带 flag。
133
+ // 相对路径相对于本文件所在目录解析。
134
+ // "source": "~/.dotfiles/agents",
135
+ // "target": ".",
136
+ // "user": true, // 与 target 二选一,等价于 --user
137
+
120
138
  // asset 类型白名单。默认:["skills", "rules", "commands"]
121
- // 想启用 prompts / templates / agents 在这里加上即可
122
139
  "include": ["skills", "rules", "commands"],
123
140
 
124
141
  // asset 类型黑名单(永远压过 include)
package/dist/cli.js CHANGED
@@ -1,3 +1,87 @@
1
+ // package.json
2
+ var package_default = {
3
+ name: "@cmkk/agentlink",
4
+ version: "0.1.0-beta.3",
5
+ description: "Symlink your .agents/ assets into .cursor / .claude / .codebuddy and other AI agent directories with a single npx.",
6
+ keywords: [
7
+ "ai",
8
+ "agent",
9
+ "agents",
10
+ "skills",
11
+ "cursor",
12
+ "claude",
13
+ "codebuddy",
14
+ "symlink",
15
+ "cli",
16
+ "dotfiles"
17
+ ],
18
+ license: "MIT",
19
+ author: "rankangkang <rankangkang@foxmail.com>",
20
+ homepage: "https://github.com/rankangkang/agentlink#readme",
21
+ repository: {
22
+ type: "git",
23
+ url: "git+https://github.com/rankangkang/agentlink.git"
24
+ },
25
+ bugs: {
26
+ url: "https://github.com/rankangkang/agentlink/issues"
27
+ },
28
+ type: "module",
29
+ engines: {
30
+ node: ">=18"
31
+ },
32
+ bin: {
33
+ agentlink: "bin/agentlink.js"
34
+ },
35
+ main: "./dist/index.js",
36
+ module: "./dist/index.js",
37
+ types: "./dist/index.d.ts",
38
+ exports: {
39
+ ".": {
40
+ types: "./dist/index.d.ts",
41
+ import: "./dist/index.js"
42
+ }
43
+ },
44
+ files: [
45
+ "bin",
46
+ "dist",
47
+ "templates",
48
+ "README.md",
49
+ "CHANGELOG.md",
50
+ "LICENSE"
51
+ ],
52
+ scripts: {
53
+ build: "tsup",
54
+ dev: "tsup --watch",
55
+ test: "vitest run",
56
+ "test:watch": "vitest",
57
+ typecheck: "tsc --noEmit",
58
+ preversion: "pnpm typecheck && pnpm test && pnpm build",
59
+ prepublishOnly: "pnpm build && pnpm test && pnpm typecheck",
60
+ "publish:beta": "pnpm publish --tag beta --access public",
61
+ "publish:latest": "pnpm publish --access public"
62
+ },
63
+ publishConfig: {
64
+ access: "public"
65
+ },
66
+ dependencies: {
67
+ cac: "^7.0.0",
68
+ picocolors: "^1.1.1",
69
+ picomatch: "^4.0.4",
70
+ prompts: "^2.4.2",
71
+ "strip-json-comments": "^5.0.3",
72
+ zod: "^4.4.3"
73
+ },
74
+ devDependencies: {
75
+ "@types/node": "^25.6.2",
76
+ "@types/picomatch": "^4.0.3",
77
+ "@types/prompts": "^2.4.9",
78
+ "@vitest/coverage-v8": "^4.1.5",
79
+ tsup: "^8.5.1",
80
+ typescript: "^6.0.3",
81
+ vitest: "^4.1.5"
82
+ }
83
+ };
84
+
1
85
  // src/cli.ts
2
86
  import { cac } from "cac";
3
87
  import pc7 from "picocolors";
@@ -204,7 +288,6 @@ var DEFAULT_INCLUDE = ["skills", "rules", "commands"];
204
288
 
205
289
  // src/core/config.ts
206
290
  var CONFIG_FILENAME = "agentlink.config.json";
207
- var ENV_CONFIG_KEY = "AGENTLINK_CONFIG";
208
291
  var ASSET_TYPE_VALUES = ["skills", "rules", "commands", "prompts", "templates", "agents"];
209
292
  var ASSET_TYPE_SET = new Set(ASSET_TYPE_VALUES);
210
293
  var assetTypeSchema = z.enum(ASSET_TYPE_VALUES);
@@ -231,11 +314,23 @@ var adapterOverrideSchema = z.union([
231
314
  var adapterNameSchema = z.enum(
232
315
  Object.keys(adapterRegistry)
233
316
  );
317
+ var rootPathSchema = z.string().min(1);
234
318
  var configSchema = z.object({
319
+ source: rootPathSchema.optional(),
320
+ target: rootPathSchema.optional(),
321
+ user: z.boolean().optional(),
235
322
  include: z.array(assetTypeSchema).optional(),
236
323
  exclude: z.array(assetTypeSchema).optional(),
237
324
  adapters: z.partialRecord(adapterNameSchema, adapterOverrideSchema).optional()
238
- }).strict();
325
+ }).strict().superRefine((val, ctx) => {
326
+ if (val.target !== void 0 && val.user === true) {
327
+ ctx.addIssue({
328
+ code: "custom",
329
+ message: "`target` and `user` are mutually exclusive",
330
+ path: ["target"]
331
+ });
332
+ }
333
+ });
239
334
  var ConfigParseError = class extends AgentlinkError {
240
335
  issues;
241
336
  constructor(filePath, issues) {
@@ -245,13 +340,17 @@ ${lines.join("\n")}`);
245
340
  this.issues = issues;
246
341
  }
247
342
  };
248
- async function loadConfig(opts) {
343
+ async function loadConfigBundle(opts = {}) {
249
344
  const location = await resolveConfigPath(opts);
250
- const userConfig = location.path ? await readUserConfig(location.path) : {};
345
+ const parsed = location.path ? await readUserConfig(location.path) : {};
346
+ const configBase = location.path ? path2.dirname(location.path) : null;
347
+ return { location, parsed, configBase };
348
+ }
349
+ function resolveConfigFromParsed(userConfig, location, source) {
251
350
  const adapters = mergeAdapters(userConfig.adapters);
252
351
  const assetTypes = resolveAssetTypes(userConfig.include, userConfig.exclude);
253
352
  return {
254
- source: opts.source,
353
+ source,
255
354
  adapters,
256
355
  assetTypes,
257
356
  configPath: location.path,
@@ -261,16 +360,10 @@ async function loadConfig(opts) {
261
360
  async function resolveConfigPath(opts = {}) {
262
361
  const cwd = opts.cwd ?? process.cwd();
263
362
  const home = opts.home ?? os.homedir();
264
- const env = opts.env ?? process.env;
265
363
  if (opts.config !== void 0 && opts.config !== "") {
266
364
  const abs = await assertConfigFile(expandTilde(opts.config, home), "--config", cwd);
267
365
  return { path: abs, origin: "flag" };
268
366
  }
269
- const envValue = env[ENV_CONFIG_KEY];
270
- if (envValue !== void 0 && envValue !== "") {
271
- const abs = await assertConfigFile(expandTilde(envValue, home), `$${ENV_CONFIG_KEY}`, cwd);
272
- return { path: abs, origin: "env" };
273
- }
274
367
  const ancestor = await searchAncestors(path2.resolve(cwd), home);
275
368
  if (ancestor) {
276
369
  return { path: ancestor, origin: "cwd-ancestor" };
@@ -425,7 +518,6 @@ function resolveAssetTypes(include, exclude) {
425
518
  import { promises as fs3 } from "fs";
426
519
  import os2 from "os";
427
520
  import path3 from "path";
428
- var ENV_SOURCE_KEY = "AGENTLINK_SOURCE";
429
521
  var AGENTS_DIRNAME = ".agents";
430
522
  async function resolvePaths(opts = {}) {
431
523
  const [src, dst] = await Promise.all([resolveSource(opts), resolveDestRoot(opts)]);
@@ -445,15 +537,19 @@ async function resolvePaths(opts = {}) {
445
537
  async function resolveSource(opts = {}) {
446
538
  const cwd = opts.cwd ?? process.cwd();
447
539
  const home = opts.home ?? os2.homedir();
448
- const env = opts.env ?? process.env;
449
540
  if (opts.source !== void 0 && opts.source !== "") {
450
541
  const abs = await assertDir(expandTilde2(opts.source, home), "--source", cwd);
451
542
  return { path: abs, origin: "flag" };
452
543
  }
453
- const envValue = env[ENV_SOURCE_KEY];
454
- if (envValue !== void 0 && envValue !== "") {
455
- const abs = await assertDir(expandTilde2(envValue, home), `$${ENV_SOURCE_KEY}`, cwd);
456
- return { path: abs, origin: "env" };
544
+ const configSource = opts.configSource;
545
+ if (configSource !== void 0 && configSource !== "") {
546
+ const base = opts.configBase ?? cwd;
547
+ const abs = await assertDir(
548
+ resolveConfigPathValue(configSource, base, home),
549
+ "config.source",
550
+ cwd
551
+ );
552
+ return { path: abs, origin: "config" };
457
553
  }
458
554
  const local = path3.join(cwd, AGENTS_DIRNAME);
459
555
  if (await isDir(local)) {
@@ -465,11 +561,23 @@ async function resolveSource(opts = {}) {
465
561
  }
466
562
  throw new SourceNotFoundError([
467
563
  { origin: "--source flag", status: "not provided" },
468
- { origin: `$${ENV_SOURCE_KEY}`, status: "not set" },
469
- { origin: local, status: "missing" },
564
+ { origin: "config.source", status: configSourceStatus(opts) },
565
+ { origin: local, status: localProbeStatus(local) },
470
566
  { origin: homeAgents, status: "missing" }
471
567
  ]);
472
568
  }
569
+ function localProbeStatus(_local) {
570
+ return "missing (used when config.source is not set)";
571
+ }
572
+ function configSourceStatus(opts) {
573
+ if (opts.configSource !== void 0 && opts.configSource !== "") {
574
+ return "not reached";
575
+ }
576
+ if (opts.resolvedConfigPath) {
577
+ return `not set in ${opts.resolvedConfigPath}`;
578
+ }
579
+ return "no config file loaded";
580
+ }
473
581
  async function resolveDestRoot(opts = {}) {
474
582
  const cwd = opts.cwd ?? process.cwd();
475
583
  const home = opts.home ?? os2.homedir();
@@ -483,8 +591,27 @@ async function resolveDestRoot(opts = {}) {
483
591
  if (opts.user) {
484
592
  return { path: home, origin: "user" };
485
593
  }
594
+ if (opts.configTarget !== void 0 && opts.configTarget !== "" && opts.configUser) {
595
+ throw new ConflictError("config `target` and `user` are mutually exclusive");
596
+ }
597
+ if (opts.configTarget !== void 0 && opts.configTarget !== "") {
598
+ const base = opts.configBase ?? cwd;
599
+ const abs = await assertDir(
600
+ resolveConfigPathValue(opts.configTarget, base, home),
601
+ "config.target",
602
+ cwd
603
+ );
604
+ return { path: abs, origin: "config" };
605
+ }
606
+ if (opts.configUser) {
607
+ return { path: home, origin: "config" };
608
+ }
486
609
  return { path: cwd, origin: "cwd" };
487
610
  }
611
+ function resolveConfigPathValue(input, configBase, home) {
612
+ const expanded = expandTilde2(input, home);
613
+ return path3.isAbsolute(expanded) ? expanded : path3.resolve(configBase, expanded);
614
+ }
488
615
  function expandTilde2(p, home) {
489
616
  if (p === "~") return home;
490
617
  if (p.startsWith("~/")) return path3.join(home, p.slice(2));
@@ -511,15 +638,20 @@ function isInside2(child, parent) {
511
638
 
512
639
  // src/commands/_shared.ts
513
640
  async function loadContext(flags) {
641
+ const bundle = await loadConfigBundle({
642
+ ...flags.config !== void 0 ? { config: flags.config } : {}
643
+ });
514
644
  const paths = await resolvePaths({
515
645
  ...flags.source !== void 0 ? { source: flags.source } : {},
516
646
  ...flags.target !== void 0 ? { target: flags.target } : {},
517
- ...flags.user !== void 0 ? { user: flags.user } : {}
518
- });
519
- const rawConfig = await loadConfig({
520
- source: paths.source,
521
- ...flags.config !== void 0 ? { config: flags.config } : {}
647
+ ...flags.user !== void 0 ? { user: flags.user } : {},
648
+ ...bundle.parsed.source !== void 0 ? { configSource: bundle.parsed.source } : {},
649
+ ...bundle.parsed.target !== void 0 ? { configTarget: bundle.parsed.target } : {},
650
+ ...bundle.parsed.user !== void 0 ? { configUser: bundle.parsed.user } : {},
651
+ ...bundle.configBase !== null ? { configBase: bundle.configBase } : {},
652
+ resolvedConfigPath: bundle.location.path
522
653
  });
654
+ const rawConfig = resolveConfigFromParsed(bundle.parsed, bundle.location, paths.source);
523
655
  const config = await gateAdapters(rawConfig, paths.destRoot);
524
656
  return { paths, config };
525
657
  }
@@ -1175,14 +1307,32 @@ async function writeConfigFile(answers, quiet, dryRun) {
1175
1307
  if (!quiet) console.log(`${pc5.green("[NEW]")} ${configPath}`);
1176
1308
  return 1;
1177
1309
  }
1310
+ function formatSourceForConfig(target, configPath) {
1311
+ const resolved = path8.resolve(target);
1312
+ const configDir = path8.resolve(path8.dirname(configPath));
1313
+ const home = path8.resolve(os3.homedir());
1314
+ const rel = path8.relative(configDir, resolved);
1315
+ if (rel !== "" && !rel.startsWith("..") && !path8.isAbsolute(rel)) {
1316
+ return rel;
1317
+ }
1318
+ if (resolved === home || resolved.startsWith(home + path8.sep)) {
1319
+ const tail = path8.relative(home, resolved);
1320
+ return tail === "" ? "~" : `~/${tail}`;
1321
+ }
1322
+ return resolved;
1323
+ }
1178
1324
  function renderConfig(answers) {
1179
1325
  const includeJson = JSON.stringify(answers.include);
1180
1326
  const adapterLines = ALL_ADAPTER_NAMES.map((name) => {
1181
1327
  const value = answers.adapters.includes(name) ? "true" : "false";
1182
1328
  return ` "${name}": ${value}`;
1183
1329
  }).join(",\n");
1330
+ const sourceBlock = answers.targetCategory === "custom" ? ` // Persistent default for \`agentlink sync\` (relative paths resolve from this file).
1331
+ "source": ${JSON.stringify(formatSourceForConfig(answers.target, answers.configPath))},
1332
+
1333
+ ` : "";
1184
1334
  return `{
1185
- // Asset type allowlist. Default: ["skills", "rules", "commands"].
1335
+ ${sourceBlock} // Asset type allowlist. Default: ["skills", "rules", "commands"].
1186
1336
  // Add "prompts", "templates" or "agents" here to opt them in.
1187
1337
  "include": ${includeJson},
1188
1338
 
@@ -1207,9 +1357,9 @@ function printNonDefaultLocationHint(target) {
1207
1357
  console.log(pc5.bold("Tip \u2014 your source is at a non-default location:"));
1208
1358
  console.log(` ${target}`);
1209
1359
  console.log("");
1210
- console.log("Future invocations of `agentlink sync` need to know about it. Either:");
1211
- console.log(` - pass ${pc5.cyan(`--source ${target}`)} each time, or`);
1212
- console.log(` - export ${pc5.cyan(`AGENTLINK_SOURCE=${target}`)} in your shell rc, or`);
1360
+ console.log("Future invocations of `agentlink sync` will read `source` from your");
1361
+ console.log("`agentlink.config.json` (written during init). You can also:");
1362
+ console.log(` - pass ${pc5.cyan(`--source ${target}`)} to override, or`);
1213
1363
  console.log(` - symlink it: ${pc5.cyan(`ln -s ${target} ~/.agents`)}`);
1214
1364
  }
1215
1365
 
@@ -1256,8 +1406,8 @@ async function runUnlink(flags = {}) {
1256
1406
  }
1257
1407
 
1258
1408
  // src/cli.ts
1259
- var PKG_NAME = "@cmkk/agentlink";
1260
- var PKG_VERSION = "0.1.0";
1409
+ var PKG_NAME = package_default.name;
1410
+ var PKG_VERSION = package_default.version;
1261
1411
  function applyGlobalOptions(cli) {
1262
1412
  cli.option("--source <path>", "Override the source .agents/ location").option("-t, --target <dir>", "Run against a specific destination root").option("-u, --user", "Link into $HOME (user-level install target)").option("--config <path>", "Load a specific agentlink.config.json").option("-n, --dry-run", "Preview changes without touching the filesystem").option("-f, --force", "Replace symlinks that point somewhere unexpected").option("-q, --quiet", "Only print changes and errors").option("-v, --verbose", "Print debug-level output").option("--strict", "Treat collisions as errors instead of warnings");
1263
1413
  }
@@ -1292,6 +1442,7 @@ function renderError(err) {
1292
1442
  console.error("Hints:");
1293
1443
  console.error(" - run `agentlink init` to scaffold ~/.agents/");
1294
1444
  console.error(" - run `agentlink init --local` to scaffold ./.agents/");
1445
+ console.error(' - set `"source"` in `agentlink.config.json`');
1295
1446
  console.error(" - or pass `--source <path>` explicitly");
1296
1447
  return;
1297
1448
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/clean.ts","../src/core/linker.ts","../src/commands/_shared.ts","../src/adapters/claude.ts","../src/adapters/codebuddy.ts","../src/adapters/cursor.ts","../src/adapters/index.ts","../src/core/config.ts","../src/core/errors.ts","../src/core/types.ts","../src/core/resolve.ts","../src/commands/doctor.ts","../src/core/layout.ts","../src/commands/init.ts","../src/commands/sync.ts","../src/commands/unlink.ts"],"sourcesContent":["import { cac } from 'cac';\nimport pc from 'picocolors';\n\nimport { runClean } from './commands/clean.js';\nimport { runDoctor } from './commands/doctor.js';\nimport { runInit } from './commands/init.js';\nimport { runSync } from './commands/sync.js';\nimport { runUnlink } from './commands/unlink.js';\nimport type { CommandFlags } from './commands/_shared.js';\nimport {\n AgentlinkError,\n ConflictError,\n InvalidPathError,\n SourceNotFoundError,\n} from './core/errors.js';\nimport { ConfigParseError } from './core/config.js';\nimport { StrictModeViolation } from './commands/sync.js';\n\nconst PKG_NAME = '@cmkk/agentlink';\nconst PKG_VERSION = '0.1.0';\n\nfunction applyGlobalOptions(cli: ReturnType<typeof cac>): void {\n cli\n .option('--source <path>', 'Override the source .agents/ location')\n .option('-t, --target <dir>', 'Run against a specific destination root')\n .option('-u, --user', 'Link into $HOME (user-level install target)')\n .option('--config <path>', 'Load a specific agentlink.config.json')\n .option('-n, --dry-run', 'Preview changes without touching the filesystem')\n .option('-f, --force', 'Replace symlinks that point somewhere unexpected')\n .option('-q, --quiet', 'Only print changes and errors')\n .option('-v, --verbose', 'Print debug-level output')\n .option('--strict', 'Treat collisions as errors instead of warnings');\n}\n\nasync function main(): Promise<void> {\n const cli = cac('agentlink');\n\n cli\n .command('init', 'Create an empty .agents/ scaffold and run sync once')\n .option('--local', 'Scaffold into ./.agents instead of ~/.agents')\n .option('-y, --yes', 'Skip interactive prompts and use defaults (CI-friendly)')\n .action((flags: CommandFlags & { local?: boolean; yes?: boolean }) => runInit(flags));\n\n cli\n .command('sync', 'Refresh all symlinks (default command)')\n .action((flags: CommandFlags) => runSync(flags));\n\n cli\n .command('clean', 'Remove dangling agentlink-managed symlinks')\n .action((flags: CommandFlags) => runClean(flags));\n\n cli\n .command('unlink', 'Remove every symlink agentlink ever created')\n .action((flags: CommandFlags) => runUnlink(flags));\n\n cli\n .command('doctor', 'Diagnose configuration, adapters, and link health')\n .action((flags: CommandFlags) => runDoctor(flags));\n\n cli\n .command('', 'Default command (alias for `sync`)')\n .action((flags: CommandFlags) => runSync(flags));\n\n applyGlobalOptions(cli);\n cli.help();\n cli.version(PKG_VERSION);\n\n try {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n } catch (err) {\n renderError(err);\n process.exit(1);\n }\n}\n\nfunction renderError(err: unknown): void {\n if (err instanceof SourceNotFoundError) {\n console.error(pc.red(`[${PKG_NAME}] no source .agents/ directory found.\\n`));\n console.error('Searched:');\n for (const { origin, status } of err.searched) {\n console.error(` ${origin.padEnd(40)} ${pc.dim(status)}`);\n }\n console.error('');\n console.error('Hints:');\n console.error(' - run `agentlink init` to scaffold ~/.agents/');\n console.error(' - run `agentlink init --local` to scaffold ./.agents/');\n console.error(' - or pass `--source <path>` explicitly');\n return;\n }\n\n if (err instanceof StrictModeViolation) {\n console.error(pc.red(`[${PKG_NAME}] aborted: ${err.message}`));\n console.error(pc.dim(' rerun without --strict to accept the warnings, or fix the source.'));\n return;\n }\n\n if (err instanceof ConfigParseError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n if (err instanceof InvalidPathError || err instanceof ConflictError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n if (err instanceof AgentlinkError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n const msg = err instanceof Error ? err.message : String(err);\n console.error(pc.red(`[${PKG_NAME}] ${msg}`));\n if (process.env['AGENTLINK_DEBUG']) {\n console.error(err);\n }\n}\n\nawait main();\n","import pc from 'picocolors';\n\nimport { findStaleLinks, removeLinks } from '../core/linker.js';\nimport {\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runClean(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'clean', flags);\n\n const targets = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targets.map(findStaleLinks))).flat();\n\n if (stale.length === 0) {\n console.log(pc.dim(' no dangling symlinks found'));\n return;\n }\n\n const outcomes = await removeLinks(stale, flags.dryRun ? { dryRun: true } : {});\n\n let cleaned = 0;\n let dry = 0;\n let errored = 0;\n for (const o of outcomes) {\n if (o.status === 'removed') {\n cleaned++;\n if (!flags.quiet) console.log(`${pc.yellow('[CLEAN]')} ${o.path}`);\n } else if (o.status === 'dry-remove') {\n dry++;\n if (!flags.quiet) console.log(`${pc.dim('[DRY]')} would clean ${o.path}`);\n } else if (o.status === 'errored') {\n errored++;\n console.error(`${pc.red('[ERR]')} ${o.path} ${pc.dim(`(${o.message ?? ''})`)}`);\n }\n }\n\n console.log('');\n const parts: string[] = [];\n if (cleaned) parts.push(pc.yellow(`${cleaned} cleaned`));\n if (dry) parts.push(pc.dim(`${dry} dry-run`));\n if (errored) parts.push(pc.red(`${errored} errored`));\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n\n if (errored > 0) process.exitCode = 1;\n}\n","/**\n * Filesystem layer for agentlink. All symlink reads/writes funnel through this\n * module so command implementations stay declarative and the test suite can\n * exercise edge cases against a real tmpdir.\n *\n * Conventions:\n * - Symlinks are written **relatively** (`path.relative(targetDir, source)`)\n * so they survive moving the project root, mirroring the legacy\n * `init.sh` behaviour.\n * - Existing real files / directories are never overwritten — they always\n * produce a `warned` outcome so the user can decide.\n * - `dry-run` is a hard mode switch: no writes, but every check still runs\n * so the user sees exactly what `sync` _would_ do.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport type { LinkPlan } from './layout.js';\n\nexport type LinkStatus =\n | 'created' // new symlink written\n | 'skipped' // already pointed at the right place\n | 'fixed' // existed but pointed elsewhere; replaced (force)\n | 'warned' // exists with conflicting kind; left untouched\n | 'errored' // unexpected fs failure\n | 'dry-create' // dry-run: would create\n | 'dry-fix'; // dry-run: would replace\n\nexport interface LinkOutcome {\n plan: LinkPlan;\n status: LinkStatus;\n message?: string;\n}\n\nexport interface ApplyOptions {\n dryRun?: boolean;\n /** Replace symlinks that point somewhere unexpected. */\n force?: boolean;\n}\n\n/**\n * Apply each plan exactly once, returning per-plan outcomes in input order.\n * Never throws on per-plan errors; surfaces them as `errored` outcomes so a\n * single bad file does not halt a large sync.\n */\nexport async function applyPlans(\n plans: readonly LinkPlan[],\n options: ApplyOptions = {},\n): Promise<LinkOutcome[]> {\n const outcomes: LinkOutcome[] = [];\n for (const plan of plans) {\n outcomes.push(await applyOne(plan, options));\n }\n return outcomes;\n}\n\nasync function applyOne(plan: LinkPlan, options: ApplyOptions): Promise<LinkOutcome> {\n const { dryRun = false, force = false } = options;\n const targetDir = path.dirname(plan.target);\n const expected = path.relative(targetDir, plan.source);\n\n try {\n const lstat = await fs.lstat(plan.target).catch(() => null);\n\n if (lstat?.isSymbolicLink()) {\n const current = await fs.readlink(plan.target);\n if (current === expected) return { plan, status: 'skipped' };\n if (force) {\n if (dryRun) {\n return { plan, status: 'dry-fix', message: `${current} -> ${expected}` };\n }\n await fs.unlink(plan.target);\n await fs.symlink(expected, plan.target);\n return { plan, status: 'fixed', message: `${current} -> ${expected}` };\n }\n return {\n plan,\n status: 'warned',\n message: `points to ${current} (use --force to repair)`,\n };\n }\n\n if (lstat) {\n const kind = lstat.isDirectory() ? 'directory' : 'file';\n return { plan, status: 'warned', message: `${kind} already exists at target` };\n }\n\n if (dryRun) {\n return { plan, status: 'dry-create' };\n }\n\n await fs.mkdir(targetDir, { recursive: true });\n await fs.symlink(expected, plan.target);\n return { plan, status: 'created' };\n } catch (err) {\n return { plan, status: 'errored', message: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/* ────────────────────────── Stale link detection ─────────────────────── */\n\n/**\n * Inspect a directory and return the absolute paths of every entry that is a\n * symlink whose target no longer resolves (`fs.stat` fails — dangling).\n *\n * Non-recursive: only the top level of `targetDir` is scanned, matching the\n * legacy `init.sh` behaviour. Symlinks pointing to nested-but-existing files\n * are left alone.\n */\nexport async function findStaleLinks(targetDir: string): Promise<string[]> {\n const entries = await fs.readdir(targetDir, { withFileTypes: true }).catch(() => null);\n if (!entries) return [];\n\n const stale: string[] = [];\n for (const entry of entries) {\n if (!entry.isSymbolicLink()) continue;\n const full = path.join(targetDir, entry.name);\n const exists = await fs.stat(full).catch(() => null);\n if (!exists) stale.push(full);\n }\n return stale;\n}\n\n/* ────────────────────────── Managed-link detection (unlink) ──────────── */\n\n/**\n * Inspect a directory and return symlinks whose resolved target lives under\n * `sourceRoot`. Used by `agentlink unlink` to find every symlink we ever\n * created without requiring a \"manifest\" file.\n *\n * Resolves the symlink target lexically (no `realpath`) so the user can swap\n * the source directory at any time without bricking the unlink path.\n *\n * Defaults to a non-recursive single-directory scan (mirroring what sync\n * publishes one level deep). Pass `{ recursive: true }` to descend into every\n * subdirectory — used by `unlink` and `doctor` to catch links that live in\n * asset subdirs the current config has dropped.\n */\nexport async function findManagedLinks(\n targetDir: string,\n sourceRoot: string,\n options: { recursive?: boolean } = {},\n): Promise<string[]> {\n const sourceAbs = path.resolve(sourceRoot);\n const out: string[] = [];\n\n await (async function descend(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => null);\n if (!entries) return;\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) {\n const raw = await fs.readlink(full).catch(() => null);\n if (!raw) continue;\n const resolved = path.isAbsolute(raw) ? path.normalize(raw) : path.resolve(dir, raw);\n if (resolved === sourceAbs || resolved.startsWith(sourceAbs + path.sep)) {\n out.push(full);\n }\n } else if (options.recursive && entry.isDirectory()) {\n await descend(full);\n }\n }\n })(targetDir);\n\n return out;\n}\n\n/* ────────────────────────── Removal helpers ─────────────────────────── */\n\nexport type RemovalStatus = 'removed' | 'dry-remove' | 'errored';\n\nexport interface RemovalOutcome {\n path: string;\n status: RemovalStatus;\n message?: string;\n}\n\nexport interface RemoveOptions {\n dryRun?: boolean;\n}\n\n/**\n * Delete the supplied symlinks. Errors are returned per-path rather than\n * thrown, mirroring `applyPlans`.\n */\nexport async function removeLinks(\n paths: readonly string[],\n options: RemoveOptions = {},\n): Promise<RemovalOutcome[]> {\n const { dryRun = false } = options;\n const out: RemovalOutcome[] = [];\n for (const p of paths) {\n if (dryRun) {\n out.push({ path: p, status: 'dry-remove' });\n continue;\n }\n try {\n await fs.unlink(p);\n out.push({ path: p, status: 'removed' });\n } catch (err) {\n out.push({\n path: p,\n status: 'errored',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return out;\n}\n\n/**\n * Best-effort `rmdir` of empty managed directories left behind by `unlink`.\n * Failure to remove (e.g. user-owned siblings inside) is silent — the goal is\n * tidiness, not enforcement.\n */\nexport async function pruneEmptyDirs(dirs: readonly string[]): Promise<void> {\n for (const dir of dirs) {\n await fs.rmdir(dir).catch(() => undefined);\n }\n}\n","/**\n * Shared scaffolding for command implementations:\n * - flag plumbing (every command takes the same global flags)\n * - context loading (resolve paths + load config)\n * - common header printing\n * - target-directory enumeration used by clean / unlink\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nimport { adapterRegistry } from '../adapters/index.js';\nimport { loadConfig } from '../core/config.js';\nimport { resolvePaths, type ResolvedPaths } from '../core/resolve.js';\nimport type { Adapter, AssetType, ResolvedConfig } from '../core/types.js';\n\nexport interface CommandFlags {\n source?: string;\n target?: string;\n user?: boolean;\n config?: string;\n dryRun?: boolean;\n force?: boolean;\n quiet?: boolean;\n verbose?: boolean;\n strict?: boolean;\n}\n\nexport interface CommandContext {\n paths: ResolvedPaths;\n config: ResolvedConfig;\n}\n\nexport async function loadContext(flags: CommandFlags): Promise<CommandContext> {\n const paths = await resolvePaths({\n ...(flags.source !== undefined ? { source: flags.source } : {}),\n ...(flags.target !== undefined ? { target: flags.target } : {}),\n ...(flags.user !== undefined ? { user: flags.user } : {}),\n });\n const rawConfig = await loadConfig({\n source: paths.source,\n ...(flags.config !== undefined ? { config: flags.config } : {}),\n });\n const config = await gateAdapters(rawConfig, paths.destRoot);\n return { paths, config };\n}\n\n/**\n * Drop adapters whose `rootDir` does not exist under the destination root.\n *\n * This mirrors the legacy `init.sh` \"auto-detect\" behaviour: a missing\n * `.cursor` directory is treated as \"this user does not use cursor on this\n * machine\" rather than \"create one for them\". Users opt-in by `mkdir\n * .cursor` (or running their AI tool which does so).\n */\nasync function gateAdapters(config: ResolvedConfig, destRoot: string): Promise<ResolvedConfig> {\n const live: Adapter[] = [];\n for (const adapter of config.adapters) {\n const root = path.join(destRoot, adapter.rootDir);\n const stat = await fs.stat(root).catch(() => null);\n if (stat?.isDirectory()) live.push(adapter);\n }\n if (live.length === config.adapters.length) return config;\n return { ...config, adapters: live };\n}\n\nexport function printHeader(ctx: CommandContext, mode: string, flags: CommandFlags): void {\n if (flags.quiet) return;\n console.log('');\n console.log(pc.bold(`[agentlink] ${mode}`));\n console.log(` source: ${ctx.paths.source} ${pc.dim(`(${ctx.paths.sourceOrigin})`)}`);\n console.log(` target: ${ctx.paths.destRoot} ${pc.dim(`(${ctx.paths.destOrigin})`)}`);\n const configLine = ctx.config.configPath\n ? `${ctx.config.configPath} ${pc.dim(`(${ctx.config.configOrigin})`)}`\n : pc.dim('(defaults)');\n console.log(` config: ${configLine}`);\n console.log(` adapters: ${ctx.config.adapters.map((a) => a.name).join(', ') || pc.dim('(none)')}`);\n if (flags.dryRun) console.log(pc.yellow(' mode: dry-run'));\n console.log('');\n}\n\n/**\n * Walk the (adapter × assetType) combinations relevant for the run, returning\n * each adapter's set of `targetAssetDir`s. Used by clean / unlink to know\n * which directories to inspect without re-deriving the layout themselves.\n */\nexport function enumerateTargetDirs(ctx: CommandContext): {\n adapter: Adapter;\n assetType: AssetType;\n targetDir: string;\n rootDir: string;\n}[] {\n const out: { adapter: Adapter; assetType: AssetType; targetDir: string; rootDir: string }[] = [];\n const root = ctx.paths.destRoot;\n for (const adapter of ctx.config.adapters) {\n for (const assetType of ctx.config.assetTypes as ReadonlySet<AssetType>) {\n const slot = adapter.layout[assetType];\n if (slot === undefined || slot === false) continue;\n out.push({\n adapter,\n assetType,\n targetDir: path.join(root, adapter.rootDir, slot.targetSubdir),\n rootDir: path.join(root, adapter.rootDir),\n });\n }\n }\n return out;\n}\n\n/**\n * Return every built-in adapter rootDir that exists under `destRoot`,\n * regardless of whether the user has currently enabled it in config.\n *\n * Used by `unlink` and `doctor`'s orphan sweep: those operations must not\n * skip directories that the user just disabled — otherwise the legacy links\n * created when the adapter *was* enabled would be unreachable.\n *\n * `enumerateTargetDirs` (above) keeps gate semantics for sync / clean,\n * which legitimately operate only on what the current config selects.\n */\nexport async function enumerateAllAdapterRoots(\n destRoot: string,\n): Promise<{ name: string; rootDir: string }[]> {\n const out: { name: string; rootDir: string }[] = [];\n for (const [name, preset] of Object.entries(adapterRegistry)) {\n const rootDir = path.join(destRoot, preset.rootDir);\n const stat = await fs.stat(rootDir).catch(() => null);\n if (stat?.isDirectory()) out.push({ name, rootDir });\n }\n return out;\n}\n","import type { Adapter } from '../core/types.js';\n\n/**\n * Claude Code's conventions: nested directories are fine across all asset\n * types, no special suffix requirements.\n */\nexport const claude: Adapter = {\n name: 'claude',\n rootDir: '.claude',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules' },\n commands: { targetSubdir: 'commands' },\n },\n};\n","import type { Adapter } from '../core/types.js';\n\n/**\n * CodeBuddy supports nested commands and the same `<root>/<asset>/` shape as\n * claude. Kept symmetric with the claude adapter for now; will diverge if the\n * agent gets stricter conventions.\n */\nexport const codebuddy: Adapter = {\n name: 'codebuddy',\n rootDir: '.codebuddy',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules' },\n commands: { targetSubdir: 'commands' },\n },\n};\n","import type { Adapter } from '../core/types.js';\n\n/**\n * Cursor's filesystem conventions:\n * - `.cursor/skills/<name>/SKILL.md` recursive (nested OK)\n * - `.cursor/rules/<file>.mdc` flat, must use `.mdc` suffix\n * - `.cursor/commands/<file>.md` flat (no nested subdirs)\n * - prompts: not consumed; explicitly skipped\n */\nexport const cursor: Adapter = {\n name: 'cursor',\n rootDir: '.cursor',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules', flatten: true, ext: '.mdc' },\n commands: { targetSubdir: 'commands', flatten: true },\n prompts: false,\n },\n};\n","import type { Adapter } from '../core/types.js';\nimport { claude } from './claude.js';\nimport { codebuddy } from './codebuddy.js';\nimport { cursor } from './cursor.js';\n\n/**\n * v1 ships with three built-in adapters. The keys here are also the only valid\n * names accepted in `agentlink.config.json`'s `adapters` field — supporting a\n * new agent requires publishing a new package version.\n */\nexport const adapterRegistry = {\n cursor,\n claude,\n codebuddy,\n} as const satisfies Record<string, Adapter>;\n\nexport type AdapterName = keyof typeof adapterRegistry;\n\nexport { claude, codebuddy, cursor };\n","/**\n * Locate, validate, and merge `agentlink.config.json` with built-in adapter\n * presets to produce a {@link ResolvedConfig}.\n *\n * Config and source are **decoupled** — config tells agentlink _what to do_,\n * source tells it _what data to operate on_. Each has its own resolution chain.\n *\n * Config resolution chain (highest first):\n * 1. `--config <path>` flag\n * 2. `AGENTLINK_CONFIG` env var\n * 3. nearest `agentlink.config.json` from cwd up to (but not past) the\n * home directory or filesystem root\n * 4. `~/agentlink.config.json`\n * 5. (none) — fall back to all defaults\n *\n * Validation philosophy:\n * - **Closed asset-type universe**: keys must be one of the literal\n * {@link AssetType} values. Unknown names yield a friendly zod error.\n * - **Closed adapter universe** (v1): `adapters` keys must match a built-in\n * name (cursor / claude / codebuddy).\n * - **Tolerant defaults**: every field is optional; missing config equals\n * an empty `{}`.\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport stripJsonComments from 'strip-json-comments';\nimport { z } from 'zod';\n\nimport { adapterRegistry, type AdapterName } from '../adapters/index.js';\nimport { AgentlinkError, InvalidPathError } from './errors.js';\nimport {\n DEFAULT_INCLUDE,\n type Adapter,\n type AssetLayout,\n type AssetType,\n type ResolvedConfig,\n} from './types.js';\n\nexport const CONFIG_FILENAME = 'agentlink.config.json';\nconst ENV_CONFIG_KEY = 'AGENTLINK_CONFIG';\n\nconst ASSET_TYPE_VALUES = ['skills', 'rules', 'commands', 'prompts', 'templates', 'agents'] as const;\nconst ASSET_TYPE_SET: ReadonlySet<AssetType> = new Set(ASSET_TYPE_VALUES);\n\nconst assetTypeSchema = z.enum(ASSET_TYPE_VALUES);\n\n/**\n * `targetSubdir` is `path.join`'d under each adapter's rootDir. Letting users\n * write `..`, absolute paths, or path separators here would let them escape\n * the rootDir sandbox (and silently smear symlinks across the destination).\n *\n * We reject the obviously bad shapes at the schema layer so zod produces a\n * focused, path-aware error message instead of a generic ConfigPatchError\n * later in mergeLayout.\n */\nconst targetSubdirSchema = z\n .string()\n .min(1)\n .refine((s) => !path.isAbsolute(s), {\n message: 'targetSubdir must be relative (no leading `/` or drive letter)',\n })\n .refine((s) => !s.split(/[\\\\/]/).some((seg) => seg === '..'), {\n message: 'targetSubdir cannot traverse upward (`..` segment forbidden)',\n });\n\nconst assetLayoutSchema = z.object({\n targetSubdir: targetSubdirSchema.optional(),\n flatten: z.boolean().optional(),\n include: z.array(z.string().min(1)).optional(),\n exclude: z.array(z.string().min(1)).optional(),\n ext: z.string().min(1).optional(),\n});\n\nconst adapterOverrideSchema = z.union([\n z.boolean(),\n z\n .object({\n // partialRecord: zod v4 z.record(enum,…) is exhaustive by default;\n // partialRecord lets each key be optional, which is what users expect.\n layout: z.partialRecord(assetTypeSchema, assetLayoutSchema).optional(),\n })\n .strict(),\n]);\n\nconst adapterNameSchema = z.enum(\n Object.keys(adapterRegistry) as [AdapterName, ...AdapterName[]],\n);\n\n/**\n * Strict closed-world schema. Unknown root keys, unknown adapter names, and\n * unknown asset types all surface as friendly zod errors.\n */\nconst configSchema = z\n .object({\n include: z.array(assetTypeSchema).optional(),\n exclude: z.array(assetTypeSchema).optional(),\n adapters: z.partialRecord(adapterNameSchema, adapterOverrideSchema).optional(),\n })\n .strict();\n\ntype ParsedConfig = z.infer<typeof configSchema>;\n\nexport class ConfigParseError extends AgentlinkError {\n readonly issues: ReadonlyArray<{ path: string; message: string }>;\n\n constructor(filePath: string, issues: ReadonlyArray<{ path: string; message: string }>) {\n const lines = issues.map(({ path: p, message }) => ` at ${p || '<root>'}: ${message}`);\n super(`invalid agentlink config at ${filePath}\\n${lines.join('\\n')}`);\n this.issues = issues;\n }\n}\n\nexport type ConfigOrigin = 'flag' | 'env' | 'cwd-ancestor' | 'home-global' | 'defaults';\n\nexport interface ResolveConfigOptions {\n /** `--config` flag value. */\n config?: string;\n /** Override `process.cwd()`. */\n cwd?: string;\n /** Override `os.homedir()`. */\n home?: string;\n /** Override `process.env`. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface ConfigLocation {\n /** Absolute path that was loaded — `null` if no config file exists. */\n path: string | null;\n origin: ConfigOrigin;\n}\n\nexport interface LoadConfigOptions extends ResolveConfigOptions {\n /** Absolute path to the source `.agents/` — only used to populate ResolvedConfig. */\n source: string;\n}\n\n/**\n * Read + validate + merge the config. Returns a fully resolved view that is\n * safe to feed into command implementations.\n */\nexport async function loadConfig(opts: LoadConfigOptions): Promise<ResolvedConfig> {\n const location = await resolveConfigPath(opts);\n const userConfig = location.path ? await readUserConfig(location.path) : ({} as ParsedConfig);\n\n const adapters = mergeAdapters(userConfig.adapters);\n const assetTypes = resolveAssetTypes(userConfig.include, userConfig.exclude);\n\n return {\n source: opts.source,\n adapters,\n assetTypes,\n configPath: location.path,\n configOrigin: location.origin,\n };\n}\n\n/**\n * Resolve the location of the config file (independent of source). Pure with\n * respect to everything except `fs.stat` — easy to unit-test.\n */\nexport async function resolveConfigPath(opts: ResolveConfigOptions = {}): Promise<ConfigLocation> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n const env = opts.env ?? process.env;\n\n if (opts.config !== undefined && opts.config !== '') {\n const abs = await assertConfigFile(expandTilde(opts.config, home), '--config', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n const envValue = env[ENV_CONFIG_KEY];\n if (envValue !== undefined && envValue !== '') {\n const abs = await assertConfigFile(expandTilde(envValue, home), `$${ENV_CONFIG_KEY}`, cwd);\n return { path: abs, origin: 'env' };\n }\n\n const ancestor = await searchAncestors(path.resolve(cwd), home);\n if (ancestor) {\n return { path: ancestor, origin: 'cwd-ancestor' };\n }\n\n const homeConfig = path.join(home, CONFIG_FILENAME);\n if (await isFile(homeConfig)) {\n return { path: homeConfig, origin: 'home-global' };\n }\n\n return { path: null, origin: 'defaults' };\n}\n\n/**\n * Walk up the directory tree from `start`, looking for `agentlink.config.json`.\n * Stops as soon as we leave the home directory (or hit the filesystem root) so\n * configs from unrelated trees never leak in.\n */\nasync function searchAncestors(start: string, home: string): Promise<string | null> {\n const homeAbs = path.resolve(home);\n let current = start;\n while (true) {\n if (current === homeAbs) {\n // Don't probe `~/agentlink.config.json` here — it has its own dedicated\n // tier so the diagnostic origin reads as \"home-global\", not \"ancestor\".\n return null;\n }\n\n const candidate = path.join(current, CONFIG_FILENAME);\n if (await isFile(candidate)) return candidate;\n\n const parent = path.dirname(current);\n if (parent === current) return null; // hit filesystem root\n\n // Stop ascending if we are about to leave the home tree (only when start\n // was inside home). If start was outside home all along, keep walking up.\n if (isInside(current, homeAbs) && !isInside(parent, homeAbs) && parent !== homeAbs) {\n return null;\n }\n current = parent;\n }\n}\n\nasync function assertConfigFile(input: string, flag: string, cwd: string): Promise<string> {\n const abs = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) throw new InvalidPathError(flag, abs, 'missing');\n if (!stat.isFile()) throw new InvalidPathError(flag, abs, 'not-a-file');\n return abs;\n}\n\nasync function isFile(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isFile() ?? false;\n}\n\nfunction expandTilde(p: string, home: string): string {\n if (p === '~') return home;\n if (p.startsWith('~/')) return path.join(home, p.slice(2));\n return p;\n}\n\nfunction isInside(child: string, parent: string): boolean {\n const c = path.resolve(child);\n const p = path.resolve(parent);\n if (c === p) return true;\n const rel = path.relative(p, c);\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n\n/**\n * Read the *raw* user config and report which adapter names the user\n * explicitly opted into (i.e. anything not literally `false`). Best-effort —\n * returns an empty set on any IO/parse error so callers (e.g. doctor) can\n * fall back gracefully without hiding the real validation error from the\n * primary {@link loadConfig} pipeline.\n *\n * Centralised here so the JSONC tolerance stays consistent with `loadConfig`\n * (same comment + trailing-comma stripping) — earlier drafts had doctor.ts\n * hand-roll its own regex, which was both wrong on URLs and inconsistent\n * with the loader.\n */\nexport async function readExplicitAdapters(\n configPath: string | null,\n): Promise<ReadonlySet<string>> {\n if (!configPath) return new Set();\n const raw = await fs.readFile(configPath, 'utf8').catch(() => null);\n if (raw === null) return new Set();\n try {\n const parsed = JSON.parse(stripJsonComments(raw, { trailingCommas: true })) as {\n adapters?: Record<string, unknown>;\n };\n if (!parsed.adapters) return new Set();\n return new Set(Object.keys(parsed.adapters).filter((k) => parsed.adapters?.[k] !== false));\n } catch {\n return new Set();\n }\n}\n\nasync function readUserConfig(filePath: string): Promise<ParsedConfig> {\n const raw = await fs.readFile(filePath, 'utf8').catch((err: NodeJS.ErrnoException) => {\n if (err.code === 'ENOENT') return null;\n throw err;\n });\n if (raw === null) return {};\n\n let parsed: unknown;\n try {\n // JSONC: tolerate `//` and `/* */` comments plus trailing commas. The\n // template ships annotated so users can discover schema by reading.\n parsed = JSON.parse(stripJsonComments(raw, { trailingCommas: true }));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigParseError(filePath, [{ path: '', message: `not valid JSON: ${message}` }]);\n }\n\n const result = configSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues.map((issue) => ({\n path: issue.path.map((seg) => String(seg)).join('.'),\n message: issue.message,\n }));\n throw new ConfigParseError(filePath, issues);\n }\n return result.data;\n}\n\n/**\n * Apply user overrides to built-in adapter presets, returning only the adapters\n * that are enabled. Disabled adapters (`false` override) drop out entirely;\n * adapters not mentioned in user config keep their preset.\n */\nfunction mergeAdapters(\n overrides: ParsedConfig['adapters'] | undefined,\n): readonly Adapter[] {\n const result: Adapter[] = [];\n\n for (const [name, preset] of Object.entries(adapterRegistry) as Array<[AdapterName, Adapter]>) {\n const override = overrides?.[name];\n\n if (override === false) continue;\n\n if (override === undefined || override === true) {\n result.push(preset);\n continue;\n }\n\n result.push({\n name: preset.name,\n rootDir: preset.rootDir,\n layout: mergeLayout(preset.layout, override.layout),\n });\n }\n\n return result;\n}\n\n/**\n * Shape of a single `layout[<assetType>]` entry as it comes out of zod parse.\n * Differs from `Partial<AssetLayout>` because `exactOptionalPropertyTypes`\n * distinguishes \"may be omitted\" from \"may be `undefined`\".\n */\ninterface LayoutPatchValue {\n targetSubdir?: string | undefined;\n flatten?: boolean | undefined;\n include?: string[] | undefined;\n exclude?: string[] | undefined;\n ext?: string | undefined;\n}\n\ntype LayoutPatch = Partial<Record<AssetType, LayoutPatchValue>>;\n\nfunction mergeLayout(\n base: Adapter['layout'],\n patch: LayoutPatch | undefined,\n): Adapter['layout'] {\n if (!patch) return base;\n\n const merged: Adapter['layout'] = { ...base };\n for (const key of Object.keys(patch) as AssetType[]) {\n const value = patch[key];\n if (value === undefined) continue;\n\n const baseLayout = base[key];\n if (baseLayout === undefined || baseLayout === false) {\n const targetSubdir = value.targetSubdir;\n if (targetSubdir === undefined) {\n throw new ConfigPatchError(\n `adapter override for \"${key}\" needs a targetSubdir because the built-in adapter does not define one`,\n );\n }\n merged[key] = compactLayout(targetSubdir, value);\n continue;\n }\n merged[key] = mergeIntoBase(baseLayout, value);\n }\n return merged;\n}\n\n/** Strip `undefined` so the result respects exactOptionalPropertyTypes. */\nfunction compactLayout(targetSubdir: string, v: LayoutPatchValue): AssetLayout {\n const out: { -readonly [K in keyof AssetLayout]: AssetLayout[K] } = { targetSubdir };\n if (v.flatten !== undefined) out.flatten = v.flatten;\n if (v.include !== undefined) out.include = v.include;\n if (v.exclude !== undefined) out.exclude = v.exclude;\n if (v.ext !== undefined) out.ext = v.ext;\n return out;\n}\n\nfunction mergeIntoBase(base: AssetLayout, patch: LayoutPatchValue): AssetLayout {\n const out: { -readonly [K in keyof AssetLayout]: AssetLayout[K] } = { ...base };\n if (patch.targetSubdir !== undefined) out.targetSubdir = patch.targetSubdir;\n if (patch.flatten !== undefined) out.flatten = patch.flatten;\n if (patch.include !== undefined) out.include = patch.include;\n if (patch.exclude !== undefined) out.exclude = patch.exclude;\n if (patch.ext !== undefined) out.ext = patch.ext;\n return out;\n}\n\nclass ConfigPatchError extends AgentlinkError {}\n\n/**\n * Compute the set of asset types that should participate in this run.\n * `include` defaults to {@link DEFAULT_INCLUDE}; `exclude` is always a hard\n * subtraction applied last.\n */\nfunction resolveAssetTypes(\n include: readonly AssetType[] | undefined,\n exclude: readonly AssetType[] | undefined,\n): ReadonlySet<string> {\n const candidates = new Set<string>(include ?? DEFAULT_INCLUDE);\n for (const denied of exclude ?? []) {\n candidates.delete(denied);\n }\n return candidates;\n}\n\nexport const __test__ = {\n ASSET_TYPE_SET,\n CONFIG_FILENAME,\n};\n","/**\n * Domain-specific error types thrown by agentlink core modules.\n *\n * Using a small class hierarchy (rather than plain `Error` with codes) so the\n * CLI layer can `instanceof`-match and render targeted help text without\n * coupling to error message strings.\n */\n\nexport class AgentlinkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/**\n * No `.agents/` directory could be located via any resolution channel.\n * `searched` records every probe and its outcome so the CLI can render a\n * \"Searched: …\" diagnostic block.\n */\nexport class SourceNotFoundError extends AgentlinkError {\n readonly searched: ReadonlyArray<{ origin: string; status: string }>;\n\n constructor(searched: ReadonlyArray<{ origin: string; status: string }>) {\n super('no source .agents/ directory found');\n this.searched = searched;\n }\n}\n\n/**\n * A user-supplied path (via flag or env) is missing or has the wrong shape.\n * `flag` is the originating channel name as the user would recognize it\n * (e.g. `--source`, `AGENTLINK_SOURCE`).\n */\nexport class InvalidPathError extends AgentlinkError {\n readonly flag: string;\n readonly path: string;\n readonly reason: 'missing' | 'not-a-directory' | 'not-a-file';\n\n constructor(flag: string, p: string, reason: 'missing' | 'not-a-directory' | 'not-a-file') {\n super(InvalidPathError.message(flag, p, reason));\n this.flag = flag;\n this.path = p;\n this.reason = reason;\n }\n\n private static message(\n flag: string,\n p: string,\n reason: 'missing' | 'not-a-directory' | 'not-a-file',\n ): string {\n if (reason === 'missing') return `${flag} does not exist: ${p}`;\n if (reason === 'not-a-directory') return `${flag} is not a directory: ${p}`;\n return `${flag} is not a file: ${p}`;\n }\n}\n\n/** Two mutually exclusive options were supplied together (e.g. --target and --user). */\nexport class ConflictError extends AgentlinkError {}\n","/**\n * Asset categories agentlink knows how to symlink.\n * Extend cautiously — adding a value here is a breaking change for adapters.\n */\nexport type AssetType = 'skills' | 'rules' | 'commands' | 'prompts' | 'templates' | 'agents';\n\n/**\n * Per-asset-type projection rule. Sentinel `false` (\"skip this asset entirely\")\n * is represented at the {@link Adapter.layout} value level rather than inside\n * AssetLayout, so that `keyof AssetLayout` stays meaningful for code that maps\n * over its fields.\n */\nexport interface AssetLayout {\n /** Subdirectory under the adapter's `rootDir`, e.g. 'skills' / 'commands'. */\n targetSubdir: string;\n /**\n * If true, source files in nested subdirectories are flattened into the target\n * directory using `__` as the path separator (e.g. `git/commit.md` → `git__commit.md`).\n * Use this for agents that don't support nested command/rule directories (e.g. cursor).\n */\n flatten?: boolean;\n /** Glob patterns (relative to source asset dir) to include. Defaults to all files. */\n include?: readonly string[];\n /** Glob patterns to exclude. Applied after `include`. */\n exclude?: readonly string[];\n /** Force a specific file extension on the link target (e.g. `.mdc` for cursor rules). */\n ext?: string;\n /**\n * Custom rename hook. Receives the relative source path; returns the target file name\n * (without `targetSubdir`). v1: only used by built-in adapters; not exposed via JSON config.\n */\n rename?: (relPath: string) => string;\n}\n\n/** A layout slot is either a real layout or `false` to mean \"skip this asset type\". */\nexport type LayoutSlot = AssetLayout | false;\n\n/**\n * Built-in or user-supplied adapter describing how to project `.agents/` into one AI agent's\n * directory layout.\n */\nexport interface Adapter {\n /** Stable identifier, e.g. 'cursor' / 'claude' / 'codebuddy'. */\n name: string;\n /** Directory under target root, e.g. '.cursor'. */\n rootDir: string;\n /** Per-asset-type projection rules. */\n layout: Partial<Record<AssetType, LayoutSlot>>;\n}\n\n/**\n * Per-adapter overrides as written by the user in JSON config.\n * Value semantics:\n * - `true` : enable built-in adapter with default layout\n * - `false` : disable adapter even if its rootDir exists\n * - `{ layout }` : enable + deep-merge layout overrides onto built-in defaults\n */\nexport type AdapterOverride =\n | boolean\n | { layout?: Partial<Record<AssetType, AssetLayout>> };\n\n/**\n * User-facing JSON configuration loaded from `<source>/agentlink.config.json`.\n * Every field is optional; sensible defaults apply.\n */\nexport interface AgentlinkConfig {\n /**\n * Asset type allowlist. When omitted, falls back to the built-in default\n * (`['skills', 'rules', 'commands']`). Use this to opt into less-common\n * asset types like `prompts` / `templates` / `agents`.\n */\n include?: readonly string[];\n /**\n * Asset type denylist applied AFTER `include`. Always wins over `include`,\n * useful for temporarily silencing one type without rewriting the allowlist.\n */\n exclude?: readonly string[];\n /** Per-adapter overrides; see {@link AdapterOverride}. */\n adapters?: Record<string, AdapterOverride>;\n}\n\n/**\n * Result of {@link loadConfig}: raw JSON has been validated, defaults filled,\n * and built-in adapter presets merged with user overrides. This is what every\n * runtime command (sync/clean/unlink/doctor) consumes.\n */\nexport interface ResolvedConfig {\n /** Absolute path to the source `.agents/` directory. */\n source: string;\n /** Adapters that are enabled, with overrides already applied to layouts. */\n adapters: readonly Adapter[];\n /** Asset type names that should participate in this run. */\n assetTypes: ReadonlySet<string>;\n /** Absolute path of the config file actually loaded; null when no file existed. */\n configPath: string | null;\n /** Where the config came from. `'defaults'` means no file was found. */\n configOrigin: 'flag' | 'env' | 'cwd-ancestor' | 'home-global' | 'defaults';\n}\n\n/** Built-in default for {@link AgentlinkConfig.include}. */\nexport const DEFAULT_INCLUDE = ['skills', 'rules', 'commands'] as const;\n","/**\n * Locate the source `.agents/` directory and the destination root for a sync run.\n *\n * Two independent resolution chains share the same {@link ResolveOptions} and\n * produce a {@link ResolvedPaths} record. Both chains are pure with respect to\n * everything except `fs.stat` probes, so they are easy to unit-test with a\n * tmpdir + injected `cwd / home / env`.\n *\n * Source chain (highest first):\n * 1. `--source <path>` flag\n * 2. `AGENTLINK_SOURCE` environment variable\n * 3. `<cwd>/.agents/` — local-first so team repos override personal globals\n * 4. `<home>/.agents/` — recommended default for the npx workflow\n * 5. (none) → SourceNotFoundError\n *\n * Destination chain (highest first):\n * 1. `--target <path>` flag\n * 2. `--user` → home (user-level install target)\n * 3. (default) cwd\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { ConflictError, InvalidPathError, SourceNotFoundError } from './errors.js';\n\nexport type SourceOrigin = 'flag' | 'env' | 'cwd-local' | 'home-global';\nexport type DestOrigin = 'flag' | 'user' | 'cwd';\n\nexport interface ResolveOptions {\n /** `--source` flag value. */\n source?: string;\n /** `--target` flag value. */\n target?: string;\n /** `--user` flag value — link into $HOME. */\n user?: boolean;\n /** Override `process.cwd()`. */\n cwd?: string;\n /** Override `os.homedir()`. */\n home?: string;\n /** Override `process.env`. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface ResolvedPaths {\n source: string;\n sourceOrigin: SourceOrigin;\n destRoot: string;\n destOrigin: DestOrigin;\n}\n\nconst ENV_SOURCE_KEY = 'AGENTLINK_SOURCE';\nconst AGENTS_DIRNAME = '.agents';\n\n/**\n * Top-level entry. Resolves source and destination concurrently and emits a\n * Node warning if `destRoot` lives inside `source` (likely a self-link mistake).\n */\nexport async function resolvePaths(opts: ResolveOptions = {}): Promise<ResolvedPaths> {\n const [src, dst] = await Promise.all([resolveSource(opts), resolveDestRoot(opts)]);\n\n if (isInside(dst.path, src.path)) {\n process.emitWarning(\n `destination root \"${dst.path}\" lives inside source \"${src.path}\" — this may create self-references.`,\n { code: 'AGENTLINK_NESTED_DEST' },\n );\n }\n\n return {\n source: src.path,\n sourceOrigin: src.origin,\n destRoot: dst.path,\n destOrigin: dst.origin,\n };\n}\n\nexport async function resolveSource(\n opts: ResolveOptions = {},\n): Promise<{ path: string; origin: SourceOrigin }> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n const env = opts.env ?? process.env;\n\n if (opts.source !== undefined && opts.source !== '') {\n const abs = await assertDir(expandTilde(opts.source, home), '--source', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n const envValue = env[ENV_SOURCE_KEY];\n if (envValue !== undefined && envValue !== '') {\n const abs = await assertDir(expandTilde(envValue, home), `$${ENV_SOURCE_KEY}`, cwd);\n return { path: abs, origin: 'env' };\n }\n\n const local = path.join(cwd, AGENTS_DIRNAME);\n if (await isDir(local)) {\n return { path: local, origin: 'cwd-local' };\n }\n\n // Note: `homeAgents` is the source path under home; unrelated to the\n // destination `--user` flag (which maps the *target* root to home).\n const homeAgents = path.join(home, AGENTS_DIRNAME);\n if (await isDir(homeAgents)) {\n return { path: homeAgents, origin: 'home-global' };\n }\n\n throw new SourceNotFoundError([\n { origin: '--source flag', status: 'not provided' },\n { origin: `$${ENV_SOURCE_KEY}`, status: 'not set' },\n { origin: local, status: 'missing' },\n { origin: homeAgents, status: 'missing' },\n ]);\n}\n\nexport async function resolveDestRoot(\n opts: ResolveOptions = {},\n): Promise<{ path: string; origin: DestOrigin }> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n\n if (opts.target !== undefined && opts.target !== '' && opts.user) {\n throw new ConflictError('--target and --user are mutually exclusive');\n }\n\n if (opts.target !== undefined && opts.target !== '') {\n const abs = await assertDir(expandTilde(opts.target, home), '--target', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n if (opts.user) {\n return { path: home, origin: 'user' };\n }\n\n return { path: cwd, origin: 'cwd' };\n}\n\n/**\n * Expand a leading `~` or `~/` to the supplied home directory.\n * Intentionally narrower than shell tilde expansion (no `~user` lookup).\n */\nexport function expandTilde(p: string, home: string): string {\n if (p === '~') return home;\n if (p.startsWith('~/')) return path.join(home, p.slice(2));\n return p;\n}\n\nasync function assertDir(input: string, flag: string, cwd: string): Promise<string> {\n const abs = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) throw new InvalidPathError(flag, abs, 'missing');\n if (!stat.isDirectory()) throw new InvalidPathError(flag, abs, 'not-a-directory');\n return abs;\n}\n\nasync function isDir(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isDirectory() ?? false;\n}\n\n/**\n * `true` iff `child` is inside `parent` (or equal).\n *\n * Compares lexically — neither path is realpath-resolved, matching the rest of\n * the resolver's \"preserve symlinks\" stance.\n */\nexport function isInside(child: string, parent: string): boolean {\n const c = path.resolve(child);\n const p = path.resolve(parent);\n if (c === p) return true;\n const rel = path.relative(p, c);\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n","/**\n * `agentlink doctor` — read-only health check for the current source/destination\n * pair. Designed to answer \"would `agentlink sync` do something useful here,\n * and would it run cleanly?\" without writing anything to disk.\n *\n * Reports four sections:\n * 1. Adapter availability (rootDir present / config-disabled / missing)\n * 2. Link plan (count + any target-path collisions)\n * 3. Existing links (dangling, orphan)\n * 4. Aggregate verdict — sets `process.exitCode = 1` only on errors;\n * warnings are non-blocking so doctor can be wired into pre-commit\n * hooks without false positives.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nimport { adapterRegistry } from '../adapters/index.js';\nimport { readExplicitAdapters } from '../core/config.js';\nimport { buildLinkPlans } from '../core/layout.js';\nimport { findManagedLinks, findStaleLinks } from '../core/linker.js';\nimport {\n enumerateAllAdapterRoots,\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runDoctor(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'doctor', flags);\n\n let warnings = 0;\n let errors = 0;\n\n // Read the *raw* user config so we can distinguish \"user explicitly opted\n // into this adapter\" (warn when its rootDir is missing) from \"default\n // pickup\" (dim when missing — most users don't have all three agents).\n const explicitlyEnabled = await readExplicitAdapters(ctx.config.configPath);\n\n // ── 1. Adapter availability ──────────────────────────────────────────────\n console.log(pc.bold('Adapters'));\n for (const [name, preset] of Object.entries(adapterRegistry)) {\n const root = path.join(ctx.paths.destRoot, preset.rootDir);\n const stat = await fs.stat(root).catch(() => null);\n if (stat?.isDirectory()) {\n console.log(\n ` ${pc.green('✓')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.dim('(active)')}`,\n );\n } else if (explicitlyEnabled.has(name)) {\n warnings++;\n console.log(\n ` ${pc.yellow('⚠')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.yellow('rootDir not found — sync will skip')}`,\n );\n } else {\n console.log(\n ` ${pc.dim('—')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.dim('not in use on this machine')}`,\n );\n }\n }\n console.log('');\n\n // ── 2. Link plan ────────────────────────────────────────────────────────\n const { plans, collisions } = await buildLinkPlans({\n source: ctx.paths.source,\n destRoot: ctx.paths.destRoot,\n config: ctx.config,\n });\n\n console.log(pc.bold('Link plan'));\n console.log(` ${plans.length} plan${plans.length === 1 ? '' : 's'}`);\n if (collisions.length === 0) {\n console.log(` ${pc.green('✓')} no collisions`);\n } else {\n warnings += collisions.length;\n console.log(` ${pc.yellow('⚠')} ${collisions.length} collision(s):`);\n for (const c of collisions) {\n console.log(` ${pc.dim(c.adapterName + '/' + c.assetType)} ${c.target}`);\n for (const s of c.sources) console.log(` ${pc.dim('←')} ${s}`);\n }\n }\n console.log('');\n\n // ── 3. Existing links ───────────────────────────────────────────────────\n const targetDirs = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targetDirs.map(findStaleLinks))).flat();\n\n // Recursive sweep — orphans can live in asset subdirs that the current\n // config no longer mentions, AND in adapter rootDirs the user has just\n // disabled. Walk every built-in adapter rootDir that exists, ignoring the\n // current `ctx.config.adapters` gate so doctor stays comprehensive.\n const allRoots = await enumerateAllAdapterRoots(ctx.paths.destRoot);\n const managed = (\n await Promise.all(\n allRoots.map((r) => findManagedLinks(r.rootDir, ctx.paths.source, { recursive: true })),\n )\n ).flat();\n const staleSet = new Set(stale);\n const planTargets = new Set(plans.map((p) => p.target));\n const orphans = managed.filter((p) => !planTargets.has(p) && !staleSet.has(p));\n\n console.log(pc.bold('Existing links'));\n if (stale.length === 0 && orphans.length === 0) {\n console.log(` ${pc.green('✓')} all clear`);\n } else {\n if (stale.length > 0) {\n warnings += stale.length;\n console.log(\n ` ${pc.yellow('⚠')} ${stale.length} dangling ${pc.dim('(run `agentlink clean` to drop):')}`,\n );\n for (const p of stale) console.log(` ${p}`);\n }\n if (orphans.length > 0) {\n warnings += orphans.length;\n console.log(\n ` ${pc.yellow('⚠')} ${orphans.length} orphan ${pc.dim('(linked into source but not in current plan; `unlink` then `sync` will rebuild):')}`,\n );\n for (const p of orphans) console.log(` ${p}`);\n }\n }\n console.log('');\n\n // ── 4. Verdict ──────────────────────────────────────────────────────────\n if (warnings + errors === 0) {\n console.log(pc.green('Healthy'));\n return;\n }\n const parts: string[] = [];\n if (warnings > 0) parts.push(pc.yellow(`${warnings} warning${warnings === 1 ? '' : 's'}`));\n if (errors > 0) parts.push(pc.red(`${errors} error${errors === 1 ? '' : 's'}`));\n console.log(`Issues: ${parts.join(', ')}`);\n if (errors > 0) process.exitCode = 1;\n}\n\n","/**\n * Translate a {@link ResolvedConfig} into a flat list of {@link LinkPlan}s\n * that the linker module can execute one symlink at a time.\n *\n * For each `(adapter, assetType)` pair this module:\n * - resolves the source asset directory under `<source>/<assetType>`\n * - resolves the target directory under `<destRoot>/<rootDir>/<targetSubdir>`\n * - applies `flatten` / `ext` / `rename` / `include` / `exclude`\n * - detects target-path collisions and surfaces them as {@link Conflict}s\n *\n * Conflict policy is intentionally _diagnostic only_ here — the caller decides\n * whether to warn (default) or fail (`--strict`).\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\n\nimport type {\n Adapter,\n AssetLayout,\n AssetType,\n ResolvedConfig,\n} from './types.js';\n\nexport interface LinkPlan {\n /** Absolute source path (file when flattened, file-or-directory otherwise). */\n source: string;\n /** Absolute target path the symlink will live at. */\n target: string;\n /** Asset type bucket this plan came from. */\n assetType: AssetType;\n /** Name of the adapter that produced this plan. */\n adapterName: string;\n /** True when source enumeration recursed into nested files. */\n flattened: boolean;\n}\n\nexport interface Conflict {\n /** Target path that two or more plans claim. */\n target: string;\n /** Source paths competing for the same target. */\n sources: readonly string[];\n /** Asset type / adapter the collision happened in (for diagnostics). */\n adapterName: string;\n assetType: AssetType;\n}\n\nexport interface BuildResult {\n /** Plans whose targets are unique. Safe to apply. */\n plans: readonly LinkPlan[];\n /** Plans dropped because their target collided with another (default policy). */\n collisions: readonly Conflict[];\n}\n\nexport interface BuildOptions {\n /** Absolute path to the source `.agents/` directory. */\n source: string;\n /** Absolute path to the destination root. */\n destRoot: string;\n /** Resolved config (loaded via {@link loadConfig}). */\n config: ResolvedConfig;\n}\n\n/**\n * Build the flat plan list. Pure function — only reads the filesystem; never\n * writes. Safe to call from `--dry-run`.\n */\nexport async function buildLinkPlans(opts: BuildOptions): Promise<BuildResult> {\n const { source, destRoot, config } = opts;\n const draft: LinkPlan[] = [];\n\n for (const adapter of config.adapters) {\n for (const assetType of config.assetTypes as ReadonlySet<AssetType>) {\n const slot = adapter.layout[assetType];\n if (slot === undefined || slot === false) continue;\n\n const sourceAssetDir = path.join(source, assetType);\n if (!(await isDir(sourceAssetDir))) continue;\n\n const targetAssetDir = path.join(destRoot, adapter.rootDir, slot.targetSubdir);\n const planned = slot.flatten\n ? await planFlattened(sourceAssetDir, targetAssetDir, slot, adapter, assetType)\n : await planShallow(sourceAssetDir, targetAssetDir, slot, adapter, assetType);\n\n draft.push(...planned);\n }\n }\n\n return splitByCollision(draft);\n}\n\n/* ────────────────────────── flatten = true ───────────────────────────── */\n\nasync function planFlattened(\n sourceAssetDir: string,\n targetAssetDir: string,\n layout: AssetLayout,\n adapter: Adapter,\n assetType: AssetType,\n): Promise<LinkPlan[]> {\n const files = await walkFiles(sourceAssetDir);\n const includeMatch = makeIncludeMatcher(layout.include);\n const excludeMatch = makeExcludeMatcher(layout.exclude);\n const out: LinkPlan[] = [];\n\n for (const abs of files) {\n const rel = path.relative(sourceAssetDir, abs);\n if (!includeMatch(rel)) continue;\n if (excludeMatch(rel)) continue;\n\n const targetName = applyRename(rel, layout, /* flatten */ true);\n out.push({\n source: abs,\n target: path.join(targetAssetDir, targetName),\n adapterName: adapter.name,\n assetType,\n flattened: true,\n });\n }\n return out;\n}\n\n/* ────────────────────────── flatten = false (default) ───────────────── */\n\nasync function planShallow(\n sourceAssetDir: string,\n targetAssetDir: string,\n layout: AssetLayout,\n adapter: Adapter,\n assetType: AssetType,\n): Promise<LinkPlan[]> {\n const items = await listFirstLevel(sourceAssetDir);\n const includeMatch = makeIncludeMatcher(layout.include);\n const excludeMatch = makeExcludeMatcher(layout.exclude);\n const out: LinkPlan[] = [];\n\n for (const entry of items) {\n if (!includeMatch(entry.name)) continue;\n if (excludeMatch(entry.name)) continue;\n\n const targetName = applyRename(entry.name, layout, /* flatten */ false);\n out.push({\n source: path.join(sourceAssetDir, entry.name),\n target: path.join(targetAssetDir, targetName),\n adapterName: adapter.name,\n assetType,\n flattened: false,\n });\n }\n return out;\n}\n\n/* ────────────────────────── Naming helpers ──────────────────────────── */\n\nconst PATH_SEPARATOR_RE = /[\\\\/]/g;\n\nfunction applyRename(relPath: string, layout: AssetLayout, flatten: boolean): string {\n if (layout.rename) return layout.rename(relPath);\n\n let name = flatten ? relPath.replace(PATH_SEPARATOR_RE, '__') : relPath;\n if (layout.ext) {\n const ext = path.extname(name);\n name = ext ? name.slice(0, -ext.length) + layout.ext : name + layout.ext;\n }\n return name;\n}\n\n/* ────────────────────────── Filesystem walkers ──────────────────────── */\n\nasync function walkFiles(root: string): Promise<string[]> {\n const out: string[] = [];\n await (async function descend(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n // Hidden entries (`.gitkeep`, `.DS_Store`, etc.) are placeholder/system\n // files, never real assets. Mirrors `listFirstLevel` behaviour.\n if (entry.name.startsWith('.')) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n await descend(full);\n } else if (entry.isFile() || entry.isSymbolicLink()) {\n out.push(full);\n }\n }\n })(root);\n return out;\n}\n\nasync function listFirstLevel(root: string): Promise<readonly { name: string; isDir: boolean }[]> {\n const entries = await fs.readdir(root, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith('.'))\n .map((e) => ({ name: e.name, isDir: e.isDirectory() }));\n}\n\nasync function isDir(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isDirectory() ?? false;\n}\n\n/* ────────────────────────── Glob matchers ───────────────────────────── */\n\n/**\n * `include` matcher: empty/missing list means \"everything passes\".\n */\nfunction makeIncludeMatcher(patterns: readonly string[] | undefined): (rel: string) => boolean {\n if (!patterns || patterns.length === 0) return () => true;\n const fns = patterns.map((p) => picomatch(p, { dot: true }));\n return (rel) => fns.some((fn) => fn(rel));\n}\n\n/**\n * `exclude` matcher: empty/missing list means \"nothing is excluded\".\n */\nfunction makeExcludeMatcher(patterns: readonly string[] | undefined): (rel: string) => boolean {\n if (!patterns || patterns.length === 0) return () => false;\n const fns = patterns.map((p) => picomatch(p, { dot: true }));\n return (rel) => fns.some((fn) => fn(rel));\n}\n\n/* ────────────────────────── Collision detection ─────────────────────── */\n\nfunction splitByCollision(plans: readonly LinkPlan[]): BuildResult {\n const byTarget = new Map<string, LinkPlan[]>();\n for (const plan of plans) {\n const bucket = byTarget.get(plan.target);\n if (bucket) bucket.push(plan);\n else byTarget.set(plan.target, [plan]);\n }\n\n const accepted: LinkPlan[] = [];\n const collisions: Conflict[] = [];\n for (const [target, bucket] of byTarget) {\n if (bucket.length === 1) {\n accepted.push(bucket[0]!);\n continue;\n }\n const head = bucket[0]!;\n collisions.push({\n target,\n sources: bucket.map((p) => p.source),\n adapterName: head.adapterName,\n assetType: head.assetType,\n });\n }\n return { plans: accepted, collisions };\n}\n","/**\n * `agentlink init` — interactively scaffold a `.agents/` directory and run\n * sync once so the user gets working symlinks immediately.\n *\n * Three knobs the user can tweak via prompts:\n * 1. **Target location** (only when neither `--local` nor `--source` is set):\n * `~/.agents` (recommended) vs `./.agents`.\n * 2. **Asset types** to include — multi-select; defaults to skills/rules/commands.\n * 3. **Adapters** to enable — multi-select; defaults to all three.\n *\n * Non-interactive degrade rules:\n * - `--yes / -y` ⇒ everything defaults, no prompts\n * - stdin not a TTY ⇒ same (suitable for CI / piping)\n * - any flag that already answers a question ⇒ skip that prompt\n *\n * Refuses to clobber a non-empty target unless `--force`.\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\nimport prompts from 'prompts';\n\nimport { adapterRegistry, type AdapterName } from '../adapters/index.js';\nimport { AgentlinkError } from '../core/errors.js';\nimport { runSync } from './sync.js';\nimport type { CommandFlags } from './_shared.js';\n\nexport interface InitFlags extends CommandFlags {\n local?: boolean;\n yes?: boolean;\n}\n\nexport class InitTargetExistsError extends AgentlinkError {\n constructor(targetPath: string) {\n super(`refusing to scaffold into a non-empty directory: ${targetPath}\\n use --force to merge into the existing files`);\n }\n}\n\nconst ALL_ASSET_TYPES = ['skills', 'rules', 'commands', 'prompts', 'templates', 'agents'] as const;\nconst DEFAULT_ASSET_TYPES = ['skills', 'rules', 'commands'] as const;\nconst ALL_ADAPTER_NAMES = Object.keys(adapterRegistry) as AdapterName[];\n\nconst HERE = path.dirname(fileURLToPath(import.meta.url));\nconst TEMPLATE_CANDIDATES = [\n path.resolve(HERE, '..', 'templates', 'v1'),\n path.resolve(HERE, '..', '..', 'templates', 'v1'),\n];\n\nasync function findTemplatesDir(): Promise<string> {\n for (const candidate of TEMPLATE_CANDIDATES) {\n const stat = await fs.stat(candidate).catch(() => null);\n if (stat?.isDirectory()) return candidate;\n }\n throw new AgentlinkError(\n `agentlink templates dir not found; searched:\\n ${TEMPLATE_CANDIDATES.join('\\n ')}`,\n );\n}\n\ninterface InitAnswers {\n /** Where the source `.agents/` directory is created. */\n target: string;\n targetCategory: 'home' | 'cwd' | 'custom';\n /** Where the `agentlink.config.json` is written (independent of source). */\n configPath: string;\n configCategory: 'home' | 'cwd';\n include: readonly string[];\n adapters: readonly AdapterName[];\n}\n\nexport async function runInit(flags: InitFlags = {}): Promise<void> {\n const answers = await collectAnswers(flags);\n\n if (!flags.quiet) {\n console.log('');\n console.log(pc.bold('[agentlink] init'));\n console.log(` target: ${answers.target}`);\n console.log('');\n }\n\n const created = await scaffoldInto(answers, {\n force: flags.force ?? false,\n quiet: flags.quiet ?? false,\n dryRun: flags.dryRun ?? false,\n });\n if (!created.touched && !flags.quiet) {\n console.log(pc.dim(' no files written; .agents/ already populated'));\n }\n\n if (answers.targetCategory === 'custom' && !flags.quiet) {\n printNonDefaultLocationHint(answers.target);\n }\n\n if (!flags.quiet) console.log('');\n\n // In dry-run mode the source directory was never actually created, so a\n // follow-up sync would just throw on resolveSource. Tell the user what\n // a real run would have done and exit cleanly instead.\n if (flags.dryRun) {\n if (!flags.quiet) {\n console.log(\n pc.dim(\n ` (dry-run) would run \\`agentlink sync\\` against ${answers.target} after scaffolding`,\n ),\n );\n }\n return;\n }\n\n // Best-effort follow-up sync so the user gets immediate symlinks if they\n // already have `.cursor` / `.claude` / `.codebuddy` in cwd. The adapter\n // gate makes this a no-op when none exist.\n await runSync({\n source: answers.target,\n ...(flags.target !== undefined ? { target: flags.target } : {}),\n ...(flags.user !== undefined ? { user: flags.user } : {}),\n ...(flags.quiet !== undefined ? { quiet: flags.quiet } : {}),\n });\n}\n\n/* ────────────────────────── Prompt orchestration ─────────────────────── */\n\nasync function collectAnswers(flags: InitFlags): Promise<InitAnswers> {\n const skipPrompts = flags.yes || !process.stdin.isTTY;\n\n // 1) Target location\n let target: string;\n let targetCategory: InitAnswers['targetCategory'];\n if (flags.source !== undefined && flags.source !== '') {\n target = path.resolve(expandTilde(flags.source));\n targetCategory = categorizeTarget(target);\n } else if (flags.local) {\n target = path.resolve(process.cwd(), '.agents');\n targetCategory = 'cwd';\n } else if (skipPrompts) {\n target = path.resolve(os.homedir(), '.agents');\n targetCategory = 'home';\n } else {\n const choice = await ask<{ kind: 'home' | 'cwd' }>({\n type: 'select',\n name: 'kind',\n message: 'Where should agentlink put your .agents/ directory?',\n choices: [\n {\n title: 'Personal global (~/.agents)',\n description: 'Recommended — share assets across every project',\n value: 'home',\n },\n {\n title: 'Repo-local (./.agents)',\n description: 'Ship a curated .agents/ inside this repository',\n value: 'cwd',\n },\n ],\n initial: 0,\n });\n target =\n choice.kind === 'home'\n ? path.resolve(os.homedir(), '.agents')\n : path.resolve(process.cwd(), '.agents');\n targetCategory = choice.kind;\n }\n\n // 2) Asset types\n let include: readonly string[];\n if (skipPrompts) {\n include = DEFAULT_ASSET_TYPES;\n } else {\n const { values } = await ask<{ values: string[] }>({\n type: 'multiselect',\n name: 'values',\n message: 'Which asset types do you want to manage?',\n hint: 'space to toggle, enter to confirm',\n choices: ALL_ASSET_TYPES.map((name) => ({\n title: name,\n value: name,\n selected: (DEFAULT_ASSET_TYPES as readonly string[]).includes(name),\n })),\n min: 1,\n instructions: false,\n });\n include = values;\n }\n\n // 3) Adapters\n let adapters: readonly AdapterName[];\n if (skipPrompts) {\n adapters = ALL_ADAPTER_NAMES;\n } else {\n const { values } = await ask<{ values: AdapterName[] }>({\n type: 'multiselect',\n name: 'values',\n message: 'Which AI agents do you want to target?',\n hint: 'space to toggle, enter to confirm',\n choices: ALL_ADAPTER_NAMES.map((name) => ({\n title: name,\n value: name,\n selected: true,\n })),\n min: 1,\n instructions: false,\n });\n adapters = values;\n }\n\n // Decide where the config file lands. Config is decoupled from source —\n // whichever location a future `agentlink sync` is most likely to run from.\n const configCategory: InitAnswers['configCategory'] =\n targetCategory === 'cwd' ? 'cwd' : 'home';\n const configPath =\n configCategory === 'home'\n ? path.resolve(os.homedir(), 'agentlink.config.json')\n : path.resolve(process.cwd(), 'agentlink.config.json');\n\n return { target, targetCategory, configPath, configCategory, include, adapters };\n}\n\n/**\n * Wrapper that turns user-cancellation (Ctrl-C) into a thrown error rather\n * than letting `prompts` resolve with `{}` and silently producing an empty\n * config.\n */\nasync function ask<T extends Record<string, unknown>>(\n question: prompts.PromptObject,\n): Promise<T> {\n let cancelled = false;\n const answer = await prompts(question, {\n onCancel: () => {\n cancelled = true;\n return false;\n },\n });\n if (cancelled) throw new AgentlinkError('init cancelled');\n return answer as T;\n}\n\nfunction categorizeTarget(target: string): InitAnswers['targetCategory'] {\n const home = path.resolve(os.homedir(), '.agents');\n const cwd = path.resolve(process.cwd(), '.agents');\n if (target === home) return 'home';\n if (target === cwd) return 'cwd';\n return 'custom';\n}\n\nfunction expandTilde(p: string): string {\n if (p === '~') return os.homedir();\n if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));\n return p;\n}\n\n/* ────────────────────────── Scaffolding ─────────────────────────────── */\n\ninterface ScaffoldResult {\n touched: boolean;\n}\n\ninterface ScaffoldOptions {\n force: boolean;\n quiet: boolean;\n /** When true: probe and report what would happen, never touch the filesystem. */\n dryRun: boolean;\n}\n\nasync function scaffoldInto(\n answers: InitAnswers,\n options: ScaffoldOptions,\n): Promise<ScaffoldResult> {\n const { force, quiet, dryRun } = options;\n const target = answers.target;\n const stat = await fs.stat(target).catch(() => null);\n if (stat && !stat.isDirectory()) {\n throw new AgentlinkError(`init target exists but is not a directory: ${target}`);\n }\n\n if (stat && !force) {\n const entries = await fs.readdir(target);\n if (entries.length > 0) throw new InitTargetExistsError(target);\n }\n\n if (!dryRun) {\n await fs.mkdir(target, { recursive: true });\n } else if (!stat && !quiet) {\n console.log(`${pc.dim('[DRY]')} would create ${target}/`);\n }\n\n const templatesDir = await findTemplatesDir();\n\n let written = 0;\n written += await copyStaticAssets(templatesDir, target, answers.include, quiet, dryRun);\n written += await writeConfigFile(answers, quiet, dryRun);\n return { touched: written > 0 };\n}\n\n/**\n * Copy README and `.gitkeep` placeholders for each user-selected asset type.\n * The config file is rendered separately by `writeConfigFile` because its\n * contents depend on the user's answers.\n */\nasync function copyStaticAssets(\n templatesDir: string,\n target: string,\n include: readonly string[],\n quiet: boolean,\n dryRun: boolean,\n): Promise<number> {\n let written = 0;\n\n // README — copy as-is if not already present.\n const readmeSrc = path.join(templatesDir, 'README.md');\n const readmeDest = path.join(target, 'README.md');\n if ((await fs.stat(readmeSrc).catch(() => null)) && !(await fs.stat(readmeDest).catch(() => null))) {\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${readmeDest}`);\n } else {\n await fs.copyFile(readmeSrc, readmeDest);\n if (!quiet) console.log(`${pc.green('[NEW]')} ${readmeDest}`);\n }\n written++;\n }\n\n // Per-asset-type empty directories with a placeholder so they survive `git add`.\n for (const assetType of include) {\n const dir = path.join(target, assetType);\n const keep = path.join(dir, '.gitkeep');\n const keepExists = await fs.stat(keep).catch(() => null);\n if (keepExists) continue;\n\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${keep}`);\n } else {\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(keep, '');\n if (!quiet) console.log(`${pc.green('[NEW]')} ${keep}`);\n }\n written++;\n }\n\n return written;\n}\n\nasync function writeConfigFile(\n answers: InitAnswers,\n quiet: boolean,\n dryRun: boolean,\n): Promise<number> {\n const configPath = answers.configPath;\n if (await fs.stat(configPath).catch(() => null)) {\n if (!quiet) console.log(`${pc.cyan('[SKIP]')} ${configPath} (already exists)`);\n return 0;\n }\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${configPath}`);\n return 1;\n }\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n await fs.writeFile(configPath, renderConfig(answers), 'utf8');\n if (!quiet) console.log(`${pc.green('[NEW]')} ${configPath}`);\n return 1;\n}\n\n/**\n * Render `agentlink.config.json` as JSONC with explanatory comments. We hand-\n * format this rather than `JSON.stringify`-ing because the comments are the\n * whole point — users learn the schema by reading the seed file.\n */\nexport function renderConfig(answers: InitAnswers): string {\n const includeJson = JSON.stringify(answers.include);\n const adapterLines = ALL_ADAPTER_NAMES.map((name) => {\n const value = answers.adapters.includes(name) ? 'true' : 'false';\n return ` \"${name}\": ${value}`;\n }).join(',\\n');\n\n return `{\n // Asset type allowlist. Default: [\"skills\", \"rules\", \"commands\"].\n // Add \"prompts\", \"templates\" or \"agents\" here to opt them in.\n \"include\": ${includeJson},\n\n // Asset type denylist (always wins over \\`include\\`).\n \"exclude\": [],\n\n // Per-adapter overrides. Each value can be:\n // - true : enable with built-in defaults\n // - false : disable even if its rootDir exists\n // - { \"layout\": { … } } : enable + override specific asset layouts\n //\n // Example: keep cursor commands nested instead of flattened\n // \"cursor\": { \"layout\": { \"commands\": { \"flatten\": false } } }\n \"adapters\": {\n${adapterLines}\n }\n}\n`;\n}\n\n/* ────────────────────────── Hints ───────────────────────────────────── */\n\nfunction printNonDefaultLocationHint(target: string): void {\n console.log('');\n console.log(pc.bold('Tip — your source is at a non-default location:'));\n console.log(` ${target}`);\n console.log('');\n console.log('Future invocations of `agentlink sync` need to know about it. Either:');\n console.log(` - pass ${pc.cyan(`--source ${target}`)} each time, or`);\n console.log(` - export ${pc.cyan(`AGENTLINK_SOURCE=${target}`)} in your shell rc, or`);\n console.log(` - symlink it: ${pc.cyan(`ln -s ${target} ~/.agents`)}`);\n}\n","import path from 'node:path';\nimport pc from 'picocolors';\n\nimport { buildLinkPlans, type Conflict } from '../core/layout.js';\nimport { applyPlans, findStaleLinks, removeLinks, type LinkOutcome } from '../core/linker.js';\nimport { AgentlinkError } from '../core/errors.js';\nimport {\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport class StrictModeViolation extends AgentlinkError {\n constructor(public readonly conflicts: readonly Conflict[]) {\n super(`${conflicts.length} link target collision(s) under --strict`);\n }\n}\n\nexport async function runSync(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'sync', flags);\n\n const { plans, collisions } = await buildLinkPlans({\n source: ctx.paths.source,\n destRoot: ctx.paths.destRoot,\n config: ctx.config,\n });\n\n if (collisions.length > 0) {\n reportCollisions(collisions, flags.quiet ?? false);\n if (flags.strict) {\n throw new StrictModeViolation(collisions);\n }\n }\n\n const outcomes = await applyPlans(plans, {\n ...(flags.dryRun !== undefined ? { dryRun: flags.dryRun } : {}),\n ...(flags.force !== undefined ? { force: flags.force } : {}),\n });\n\n // Sweep up dangling links left from previous syncs whose source files were\n // deleted. Mirrors the legacy init.sh behaviour where every run also cleans.\n const targetDirs = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targetDirs.map(findStaleLinks))).flat();\n const removed = await removeLinks(stale, flags.dryRun ? { dryRun: true } : {});\n\n reportOutcomes(outcomes, ctx.paths.destRoot, flags.quiet ?? false);\n reportRemovals(removed, flags.quiet ?? false);\n printSummary(outcomes, removed, collisions);\n\n // Any individual link operation that errored should fail the whole run so\n // CI / pre-commit hooks can detect a partially-broken sync. Conflicts are\n // already either warned (default) or thrown (via --strict above), so we\n // only consider link-level failures here.\n const errored =\n outcomes.filter((o) => o.status === 'errored').length +\n removed.filter((r) => r.status === 'errored').length;\n if (errored > 0) process.exitCode = 1;\n}\n\n/* ────────────────────────── Reporting helpers ────────────────────────── */\n\nfunction reportCollisions(collisions: readonly Conflict[], quiet: boolean): void {\n if (quiet) return;\n for (const c of collisions) {\n console.warn(\n pc.yellow(`[WARN] target collision under ${c.adapterName}/${c.assetType}: ${c.target}`),\n );\n for (const s of c.sources) console.warn(pc.dim(` source: ${s}`));\n }\n}\n\nfunction reportOutcomes(\n outcomes: readonly LinkOutcome[],\n destRoot: string,\n quiet: boolean,\n): void {\n for (const o of outcomes) {\n const display = path.relative(destRoot, o.plan.target);\n switch (o.status) {\n case 'created':\n if (!quiet) console.log(`${pc.green('[OK]')} ${display}`);\n break;\n case 'fixed':\n console.log(`${pc.green('[FIX]')} ${display} ${pc.dim(`(${o.message})`)}`);\n break;\n case 'skipped':\n if (!quiet) console.log(`${pc.cyan('[SKIP]')} ${display}`);\n break;\n case 'warned':\n console.warn(`${pc.yellow('[WARN]')} ${display} ${pc.dim(`(${o.message ?? ''})`)}`);\n break;\n case 'errored':\n console.error(`${pc.red('[ERR]')} ${display} ${pc.dim(`(${o.message ?? ''})`)}`);\n break;\n case 'dry-create':\n if (!quiet) console.log(`${pc.dim('[DRY]')} ${display}`);\n break;\n case 'dry-fix':\n console.log(`${pc.dim('[DRY]')} ${display} ${pc.dim(`(would fix: ${o.message})`)}`);\n break;\n }\n }\n}\n\nfunction reportRemovals(\n removals: readonly { path: string; status: string; message?: string }[],\n quiet: boolean,\n): void {\n for (const r of removals) {\n if (r.status === 'removed' && !quiet) {\n console.log(`${pc.yellow('[CLEAN]')} ${r.path}`);\n } else if (r.status === 'dry-remove' && !quiet) {\n console.log(`${pc.dim('[DRY]')} would clean ${r.path}`);\n } else if (r.status === 'errored') {\n console.error(`${pc.red('[ERR]')} ${r.path} ${pc.dim(`(${r.message ?? ''})`)}`);\n }\n }\n}\n\nfunction printSummary(\n outcomes: readonly LinkOutcome[],\n removals: readonly { status: string }[],\n collisions: readonly Conflict[],\n): void {\n const counts: Record<string, number> = {};\n for (const o of outcomes) counts[o.status] = (counts[o.status] ?? 0) + 1;\n const cleaned = removals.filter((r) => r.status === 'removed' || r.status === 'dry-remove').length;\n\n const parts: string[] = [];\n if (counts['created']) parts.push(pc.green(`${counts['created']} created`));\n if (counts['fixed']) parts.push(pc.green(`${counts['fixed']} fixed`));\n if (counts['skipped']) parts.push(pc.cyan(`${counts['skipped']} skipped`));\n if (counts['warned']) parts.push(pc.yellow(`${counts['warned']} warned`));\n if (counts['errored']) parts.push(pc.red(`${counts['errored']} errored`));\n if (counts['dry-create'] || counts['dry-fix']) {\n parts.push(pc.dim(`${(counts['dry-create'] ?? 0) + (counts['dry-fix'] ?? 0)} dry-run`));\n }\n if (cleaned) parts.push(pc.yellow(`${cleaned} cleaned`));\n if (collisions.length) parts.push(pc.yellow(`${collisions.length} collision(s)`));\n\n console.log('');\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n}\n","import pc from 'picocolors';\n\nimport { findManagedLinks, pruneEmptyDirs, removeLinks } from '../core/linker.js';\nimport {\n enumerateAllAdapterRoots,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runUnlink(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'unlink', flags);\n\n // `unlink` must be a \"remove everything we ever wrote\" operation. Walk\n // *all* built-in adapter rootDirs that exist under destRoot — not only\n // the ones currently enabled by config — and recurse into each so we\n // also catch links living in asset subdirs that the current `include`\n // list no longer mentions. Otherwise users who disabled an adapter or\n // narrowed `include` would leave orphan symlinks behind.\n const roots = await enumerateAllAdapterRoots(ctx.paths.destRoot);\n const sourceRoot = ctx.paths.source;\n\n const owned = (\n await Promise.all(\n roots.map(({ rootDir }) => findManagedLinks(rootDir, sourceRoot, { recursive: true })),\n )\n ).flat();\n\n if (owned.length === 0) {\n console.log(pc.dim(' no agentlink-managed links found'));\n return;\n }\n\n const outcomes = await removeLinks(owned, flags.dryRun ? { dryRun: true } : {});\n\n let removed = 0;\n let dry = 0;\n let errored = 0;\n for (const o of outcomes) {\n if (o.status === 'removed') {\n removed++;\n if (!flags.quiet) console.log(`${pc.yellow('[UNLINK]')} ${o.path}`);\n } else if (o.status === 'dry-remove') {\n dry++;\n if (!flags.quiet) console.log(`${pc.dim('[DRY]')} would remove ${o.path}`);\n } else if (o.status === 'errored') {\n errored++;\n console.error(`${pc.red('[ERR]')} ${o.path} ${pc.dim(`(${o.message ?? ''})`)}`);\n }\n }\n\n // Best-effort: prune now-empty adapter rootDirs. `pruneEmptyDirs` is silent\n // on non-empty / missing dirs, so we don't bother filtering.\n if (!flags.dryRun) {\n await pruneEmptyDirs(roots.map((r) => r.rootDir));\n }\n\n console.log('');\n const parts: string[] = [];\n if (removed) parts.push(pc.yellow(`${removed} removed`));\n if (dry) parts.push(pc.dim(`${dry} dry-run`));\n if (errored) parts.push(pc.red(`${errored} errored`));\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n\n if (errored > 0) process.exitCode = 1;\n}\n"],"mappings":"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","names":["pc","pc","fs","path","fs","path","path","fs","fs","os","path","isInside","os","expandTilde","path","fs","path","fs","pc","fs","path","pc","fs","path","isDir","pc","path","fs","fs","os","path","pc","path","pc","pc","path","path","fs","pc","expandTilde","os","pc","pc","pc"]}
1
+ {"version":3,"sources":["../package.json","../src/cli.ts","../src/commands/clean.ts","../src/core/linker.ts","../src/commands/_shared.ts","../src/adapters/claude.ts","../src/adapters/codebuddy.ts","../src/adapters/cursor.ts","../src/adapters/index.ts","../src/core/config.ts","../src/core/errors.ts","../src/core/types.ts","../src/core/resolve.ts","../src/commands/doctor.ts","../src/core/layout.ts","../src/commands/init.ts","../src/commands/sync.ts","../src/commands/unlink.ts"],"sourcesContent":["{\n \"name\": \"@cmkk/agentlink\",\n \"version\": \"0.1.0-beta.3\",\n \"description\": \"Symlink your .agents/ assets into .cursor / .claude / .codebuddy and other AI agent directories with a single npx.\",\n \"keywords\": [\n \"ai\",\n \"agent\",\n \"agents\",\n \"skills\",\n \"cursor\",\n \"claude\",\n \"codebuddy\",\n \"symlink\",\n \"cli\",\n \"dotfiles\"\n ],\n \"license\": \"MIT\",\n \"author\": \"rankangkang <rankangkang@foxmail.com>\",\n \"homepage\": \"https://github.com/rankangkang/agentlink#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rankangkang/agentlink.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/rankangkang/agentlink/issues\"\n },\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=18\"\n },\n \"bin\": {\n \"agentlink\": \"bin/agentlink.js\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"bin\",\n \"dist\",\n \"templates\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"preversion\": \"pnpm typecheck && pnpm test && pnpm build\",\n \"prepublishOnly\": \"pnpm build && pnpm test && pnpm typecheck\",\n \"publish:beta\": \"pnpm publish --tag beta --access public\",\n \"publish:latest\": \"pnpm publish --access public\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"dependencies\": {\n \"cac\": \"^7.0.0\",\n \"picocolors\": \"^1.1.1\",\n \"picomatch\": \"^4.0.4\",\n \"prompts\": \"^2.4.2\",\n \"strip-json-comments\": \"^5.0.3\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.6.2\",\n \"@types/picomatch\": \"^4.0.3\",\n \"@types/prompts\": \"^2.4.9\",\n \"@vitest/coverage-v8\": \"^4.1.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.5\"\n }\n}\n","import packageJson from '../package.json' with { type: 'json' };\n\nimport { cac } from 'cac';\nimport pc from 'picocolors';\n\nimport { runClean } from './commands/clean.js';\nimport { runDoctor } from './commands/doctor.js';\nimport { runInit } from './commands/init.js';\nimport { runSync } from './commands/sync.js';\nimport { runUnlink } from './commands/unlink.js';\nimport type { CommandFlags } from './commands/_shared.js';\nimport {\n AgentlinkError,\n ConflictError,\n InvalidPathError,\n SourceNotFoundError,\n} from './core/errors.js';\nimport { ConfigParseError } from './core/config.js';\nimport { StrictModeViolation } from './commands/sync.js';\n\nconst PKG_NAME = packageJson.name;\nconst PKG_VERSION = packageJson.version;\n\nfunction applyGlobalOptions(cli: ReturnType<typeof cac>): void {\n cli\n .option('--source <path>', 'Override the source .agents/ location')\n .option('-t, --target <dir>', 'Run against a specific destination root')\n .option('-u, --user', 'Link into $HOME (user-level install target)')\n .option('--config <path>', 'Load a specific agentlink.config.json')\n .option('-n, --dry-run', 'Preview changes without touching the filesystem')\n .option('-f, --force', 'Replace symlinks that point somewhere unexpected')\n .option('-q, --quiet', 'Only print changes and errors')\n .option('-v, --verbose', 'Print debug-level output')\n .option('--strict', 'Treat collisions as errors instead of warnings');\n}\n\nasync function main(): Promise<void> {\n const cli = cac('agentlink');\n\n cli\n .command('init', 'Create an empty .agents/ scaffold and run sync once')\n .option('--local', 'Scaffold into ./.agents instead of ~/.agents')\n .option('-y, --yes', 'Skip interactive prompts and use defaults (CI-friendly)')\n .action((flags: CommandFlags & { local?: boolean; yes?: boolean }) => runInit(flags));\n\n cli\n .command('sync', 'Refresh all symlinks (default command)')\n .action((flags: CommandFlags) => runSync(flags));\n\n cli\n .command('clean', 'Remove dangling agentlink-managed symlinks')\n .action((flags: CommandFlags) => runClean(flags));\n\n cli\n .command('unlink', 'Remove every symlink agentlink ever created')\n .action((flags: CommandFlags) => runUnlink(flags));\n\n cli\n .command('doctor', 'Diagnose configuration, adapters, and link health')\n .action((flags: CommandFlags) => runDoctor(flags));\n\n cli\n .command('', 'Default command (alias for `sync`)')\n .action((flags: CommandFlags) => runSync(flags));\n\n applyGlobalOptions(cli);\n cli.help();\n cli.version(PKG_VERSION);\n\n try {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n } catch (err) {\n renderError(err);\n process.exit(1);\n }\n}\n\nfunction renderError(err: unknown): void {\n if (err instanceof SourceNotFoundError) {\n console.error(pc.red(`[${PKG_NAME}] no source .agents/ directory found.\\n`));\n console.error('Searched:');\n for (const { origin, status } of err.searched) {\n console.error(` ${origin.padEnd(40)} ${pc.dim(status)}`);\n }\n console.error('');\n console.error('Hints:');\n console.error(' - run `agentlink init` to scaffold ~/.agents/');\n console.error(' - run `agentlink init --local` to scaffold ./.agents/');\n console.error(' - set `\"source\"` in `agentlink.config.json`');\n console.error(' - or pass `--source <path>` explicitly');\n return;\n }\n\n if (err instanceof StrictModeViolation) {\n console.error(pc.red(`[${PKG_NAME}] aborted: ${err.message}`));\n console.error(pc.dim(' rerun without --strict to accept the warnings, or fix the source.'));\n return;\n }\n\n if (err instanceof ConfigParseError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n if (err instanceof InvalidPathError || err instanceof ConflictError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n if (err instanceof AgentlinkError) {\n console.error(pc.red(`[${PKG_NAME}] ${err.message}`));\n return;\n }\n\n const msg = err instanceof Error ? err.message : String(err);\n console.error(pc.red(`[${PKG_NAME}] ${msg}`));\n if (process.env['AGENTLINK_DEBUG']) {\n console.error(err);\n }\n}\n\nawait main();\n","import pc from 'picocolors';\n\nimport { findStaleLinks, removeLinks } from '../core/linker.js';\nimport {\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runClean(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'clean', flags);\n\n const targets = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targets.map(findStaleLinks))).flat();\n\n if (stale.length === 0) {\n console.log(pc.dim(' no dangling symlinks found'));\n return;\n }\n\n const outcomes = await removeLinks(stale, flags.dryRun ? { dryRun: true } : {});\n\n let cleaned = 0;\n let dry = 0;\n let errored = 0;\n for (const o of outcomes) {\n if (o.status === 'removed') {\n cleaned++;\n if (!flags.quiet) console.log(`${pc.yellow('[CLEAN]')} ${o.path}`);\n } else if (o.status === 'dry-remove') {\n dry++;\n if (!flags.quiet) console.log(`${pc.dim('[DRY]')} would clean ${o.path}`);\n } else if (o.status === 'errored') {\n errored++;\n console.error(`${pc.red('[ERR]')} ${o.path} ${pc.dim(`(${o.message ?? ''})`)}`);\n }\n }\n\n console.log('');\n const parts: string[] = [];\n if (cleaned) parts.push(pc.yellow(`${cleaned} cleaned`));\n if (dry) parts.push(pc.dim(`${dry} dry-run`));\n if (errored) parts.push(pc.red(`${errored} errored`));\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n\n if (errored > 0) process.exitCode = 1;\n}\n","/**\n * Filesystem layer for agentlink. All symlink reads/writes funnel through this\n * module so command implementations stay declarative and the test suite can\n * exercise edge cases against a real tmpdir.\n *\n * Conventions:\n * - Symlinks are written **relatively** (`path.relative(targetDir, source)`)\n * so they survive moving the project root, mirroring the legacy\n * `init.sh` behaviour.\n * - Existing real files / directories are never overwritten — they always\n * produce a `warned` outcome so the user can decide.\n * - `dry-run` is a hard mode switch: no writes, but every check still runs\n * so the user sees exactly what `sync` _would_ do.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport type { LinkPlan } from './layout.js';\n\nexport type LinkStatus =\n | 'created' // new symlink written\n | 'skipped' // already pointed at the right place\n | 'fixed' // existed but pointed elsewhere; replaced (force)\n | 'warned' // exists with conflicting kind; left untouched\n | 'errored' // unexpected fs failure\n | 'dry-create' // dry-run: would create\n | 'dry-fix'; // dry-run: would replace\n\nexport interface LinkOutcome {\n plan: LinkPlan;\n status: LinkStatus;\n message?: string;\n}\n\nexport interface ApplyOptions {\n dryRun?: boolean;\n /** Replace symlinks that point somewhere unexpected. */\n force?: boolean;\n}\n\n/**\n * Apply each plan exactly once, returning per-plan outcomes in input order.\n * Never throws on per-plan errors; surfaces them as `errored` outcomes so a\n * single bad file does not halt a large sync.\n */\nexport async function applyPlans(\n plans: readonly LinkPlan[],\n options: ApplyOptions = {},\n): Promise<LinkOutcome[]> {\n const outcomes: LinkOutcome[] = [];\n for (const plan of plans) {\n outcomes.push(await applyOne(plan, options));\n }\n return outcomes;\n}\n\nasync function applyOne(plan: LinkPlan, options: ApplyOptions): Promise<LinkOutcome> {\n const { dryRun = false, force = false } = options;\n const targetDir = path.dirname(plan.target);\n const expected = path.relative(targetDir, plan.source);\n\n try {\n const lstat = await fs.lstat(plan.target).catch(() => null);\n\n if (lstat?.isSymbolicLink()) {\n const current = await fs.readlink(plan.target);\n if (current === expected) return { plan, status: 'skipped' };\n if (force) {\n if (dryRun) {\n return { plan, status: 'dry-fix', message: `${current} -> ${expected}` };\n }\n await fs.unlink(plan.target);\n await fs.symlink(expected, plan.target);\n return { plan, status: 'fixed', message: `${current} -> ${expected}` };\n }\n return {\n plan,\n status: 'warned',\n message: `points to ${current} (use --force to repair)`,\n };\n }\n\n if (lstat) {\n const kind = lstat.isDirectory() ? 'directory' : 'file';\n return { plan, status: 'warned', message: `${kind} already exists at target` };\n }\n\n if (dryRun) {\n return { plan, status: 'dry-create' };\n }\n\n await fs.mkdir(targetDir, { recursive: true });\n await fs.symlink(expected, plan.target);\n return { plan, status: 'created' };\n } catch (err) {\n return { plan, status: 'errored', message: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/* ────────────────────────── Stale link detection ─────────────────────── */\n\n/**\n * Inspect a directory and return the absolute paths of every entry that is a\n * symlink whose target no longer resolves (`fs.stat` fails — dangling).\n *\n * Non-recursive: only the top level of `targetDir` is scanned, matching the\n * legacy `init.sh` behaviour. Symlinks pointing to nested-but-existing files\n * are left alone.\n */\nexport async function findStaleLinks(targetDir: string): Promise<string[]> {\n const entries = await fs.readdir(targetDir, { withFileTypes: true }).catch(() => null);\n if (!entries) return [];\n\n const stale: string[] = [];\n for (const entry of entries) {\n if (!entry.isSymbolicLink()) continue;\n const full = path.join(targetDir, entry.name);\n const exists = await fs.stat(full).catch(() => null);\n if (!exists) stale.push(full);\n }\n return stale;\n}\n\n/* ────────────────────────── Managed-link detection (unlink) ──────────── */\n\n/**\n * Inspect a directory and return symlinks whose resolved target lives under\n * `sourceRoot`. Used by `agentlink unlink` to find every symlink we ever\n * created without requiring a \"manifest\" file.\n *\n * Resolves the symlink target lexically (no `realpath`) so the user can swap\n * the source directory at any time without bricking the unlink path.\n *\n * Defaults to a non-recursive single-directory scan (mirroring what sync\n * publishes one level deep). Pass `{ recursive: true }` to descend into every\n * subdirectory — used by `unlink` and `doctor` to catch links that live in\n * asset subdirs the current config has dropped.\n */\nexport async function findManagedLinks(\n targetDir: string,\n sourceRoot: string,\n options: { recursive?: boolean } = {},\n): Promise<string[]> {\n const sourceAbs = path.resolve(sourceRoot);\n const out: string[] = [];\n\n await (async function descend(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => null);\n if (!entries) return;\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) {\n const raw = await fs.readlink(full).catch(() => null);\n if (!raw) continue;\n const resolved = path.isAbsolute(raw) ? path.normalize(raw) : path.resolve(dir, raw);\n if (resolved === sourceAbs || resolved.startsWith(sourceAbs + path.sep)) {\n out.push(full);\n }\n } else if (options.recursive && entry.isDirectory()) {\n await descend(full);\n }\n }\n })(targetDir);\n\n return out;\n}\n\n/* ────────────────────────── Removal helpers ─────────────────────────── */\n\nexport type RemovalStatus = 'removed' | 'dry-remove' | 'errored';\n\nexport interface RemovalOutcome {\n path: string;\n status: RemovalStatus;\n message?: string;\n}\n\nexport interface RemoveOptions {\n dryRun?: boolean;\n}\n\n/**\n * Delete the supplied symlinks. Errors are returned per-path rather than\n * thrown, mirroring `applyPlans`.\n */\nexport async function removeLinks(\n paths: readonly string[],\n options: RemoveOptions = {},\n): Promise<RemovalOutcome[]> {\n const { dryRun = false } = options;\n const out: RemovalOutcome[] = [];\n for (const p of paths) {\n if (dryRun) {\n out.push({ path: p, status: 'dry-remove' });\n continue;\n }\n try {\n await fs.unlink(p);\n out.push({ path: p, status: 'removed' });\n } catch (err) {\n out.push({\n path: p,\n status: 'errored',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return out;\n}\n\n/**\n * Best-effort `rmdir` of empty managed directories left behind by `unlink`.\n * Failure to remove (e.g. user-owned siblings inside) is silent — the goal is\n * tidiness, not enforcement.\n */\nexport async function pruneEmptyDirs(dirs: readonly string[]): Promise<void> {\n for (const dir of dirs) {\n await fs.rmdir(dir).catch(() => undefined);\n }\n}\n","/**\n * Shared scaffolding for command implementations:\n * - flag plumbing (every command takes the same global flags)\n * - context loading (resolve paths + load config)\n * - common header printing\n * - target-directory enumeration used by clean / unlink\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nimport { adapterRegistry } from '../adapters/index.js';\nimport { loadConfigBundle, resolveConfigFromParsed } from '../core/config.js';\nimport { resolvePaths, type ResolvedPaths } from '../core/resolve.js';\nimport type { Adapter, AssetType, ResolvedConfig } from '../core/types.js';\n\nexport interface CommandFlags {\n source?: string;\n target?: string;\n user?: boolean;\n config?: string;\n dryRun?: boolean;\n force?: boolean;\n quiet?: boolean;\n verbose?: boolean;\n strict?: boolean;\n}\n\nexport interface CommandContext {\n paths: ResolvedPaths;\n config: ResolvedConfig;\n}\n\nexport async function loadContext(flags: CommandFlags): Promise<CommandContext> {\n const bundle = await loadConfigBundle({\n ...(flags.config !== undefined ? { config: flags.config } : {}),\n });\n\n const paths = await resolvePaths({\n ...(flags.source !== undefined ? { source: flags.source } : {}),\n ...(flags.target !== undefined ? { target: flags.target } : {}),\n ...(flags.user !== undefined ? { user: flags.user } : {}),\n ...(bundle.parsed.source !== undefined ? { configSource: bundle.parsed.source } : {}),\n ...(bundle.parsed.target !== undefined ? { configTarget: bundle.parsed.target } : {}),\n ...(bundle.parsed.user !== undefined ? { configUser: bundle.parsed.user } : {}),\n ...(bundle.configBase !== null ? { configBase: bundle.configBase } : {}),\n resolvedConfigPath: bundle.location.path,\n });\n\n const rawConfig = resolveConfigFromParsed(bundle.parsed, bundle.location, paths.source);\n const config = await gateAdapters(rawConfig, paths.destRoot);\n return { paths, config };\n}\n\n/**\n * Drop adapters whose `rootDir` does not exist under the destination root.\n *\n * This mirrors the legacy `init.sh` \"auto-detect\" behaviour: a missing\n * `.cursor` directory is treated as \"this user does not use cursor on this\n * machine\" rather than \"create one for them\". Users opt-in by `mkdir\n * .cursor` (or running their AI tool which does so).\n */\nasync function gateAdapters(config: ResolvedConfig, destRoot: string): Promise<ResolvedConfig> {\n const live: Adapter[] = [];\n for (const adapter of config.adapters) {\n const root = path.join(destRoot, adapter.rootDir);\n const stat = await fs.stat(root).catch(() => null);\n if (stat?.isDirectory()) live.push(adapter);\n }\n if (live.length === config.adapters.length) return config;\n return { ...config, adapters: live };\n}\n\nexport function printHeader(ctx: CommandContext, mode: string, flags: CommandFlags): void {\n if (flags.quiet) return;\n console.log('');\n console.log(pc.bold(`[agentlink] ${mode}`));\n console.log(` source: ${ctx.paths.source} ${pc.dim(`(${ctx.paths.sourceOrigin})`)}`);\n console.log(` target: ${ctx.paths.destRoot} ${pc.dim(`(${ctx.paths.destOrigin})`)}`);\n const configLine = ctx.config.configPath\n ? `${ctx.config.configPath} ${pc.dim(`(${ctx.config.configOrigin})`)}`\n : pc.dim('(defaults)');\n console.log(` config: ${configLine}`);\n console.log(` adapters: ${ctx.config.adapters.map((a) => a.name).join(', ') || pc.dim('(none)')}`);\n if (flags.dryRun) console.log(pc.yellow(' mode: dry-run'));\n console.log('');\n}\n\n/**\n * Walk the (adapter × assetType) combinations relevant for the run, returning\n * each adapter's set of `targetAssetDir`s. Used by clean / unlink to know\n * which directories to inspect without re-deriving the layout themselves.\n */\nexport function enumerateTargetDirs(ctx: CommandContext): {\n adapter: Adapter;\n assetType: AssetType;\n targetDir: string;\n rootDir: string;\n}[] {\n const out: { adapter: Adapter; assetType: AssetType; targetDir: string; rootDir: string }[] = [];\n const root = ctx.paths.destRoot;\n for (const adapter of ctx.config.adapters) {\n for (const assetType of ctx.config.assetTypes as ReadonlySet<AssetType>) {\n const slot = adapter.layout[assetType];\n if (slot === undefined || slot === false) continue;\n out.push({\n adapter,\n assetType,\n targetDir: path.join(root, adapter.rootDir, slot.targetSubdir),\n rootDir: path.join(root, adapter.rootDir),\n });\n }\n }\n return out;\n}\n\n/**\n * Return every built-in adapter rootDir that exists under `destRoot`,\n * regardless of whether the user has currently enabled it in config.\n *\n * Used by `unlink` and `doctor`'s orphan sweep: those operations must not\n * skip directories that the user just disabled — otherwise the legacy links\n * created when the adapter *was* enabled would be unreachable.\n *\n * `enumerateTargetDirs` (above) keeps gate semantics for sync / clean,\n * which legitimately operate only on what the current config selects.\n */\nexport async function enumerateAllAdapterRoots(\n destRoot: string,\n): Promise<{ name: string; rootDir: string }[]> {\n const out: { name: string; rootDir: string }[] = [];\n for (const [name, preset] of Object.entries(adapterRegistry)) {\n const rootDir = path.join(destRoot, preset.rootDir);\n const stat = await fs.stat(rootDir).catch(() => null);\n if (stat?.isDirectory()) out.push({ name, rootDir });\n }\n return out;\n}\n","import type { Adapter } from '../core/types.js';\n\n/**\n * Claude Code's conventions: nested directories are fine across all asset\n * types, no special suffix requirements.\n */\nexport const claude: Adapter = {\n name: 'claude',\n rootDir: '.claude',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules' },\n commands: { targetSubdir: 'commands' },\n },\n};\n","import type { Adapter } from '../core/types.js';\n\n/**\n * CodeBuddy supports nested commands and the same `<root>/<asset>/` shape as\n * claude. Kept symmetric with the claude adapter for now; will diverge if the\n * agent gets stricter conventions.\n */\nexport const codebuddy: Adapter = {\n name: 'codebuddy',\n rootDir: '.codebuddy',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules' },\n commands: { targetSubdir: 'commands' },\n },\n};\n","import type { Adapter } from '../core/types.js';\n\n/**\n * Cursor's filesystem conventions:\n * - `.cursor/skills/<name>/SKILL.md` recursive (nested OK)\n * - `.cursor/rules/<file>.mdc` flat, must use `.mdc` suffix\n * - `.cursor/commands/<file>.md` flat (no nested subdirs)\n * - prompts: not consumed; explicitly skipped\n */\nexport const cursor: Adapter = {\n name: 'cursor',\n rootDir: '.cursor',\n layout: {\n skills: { targetSubdir: 'skills' },\n rules: { targetSubdir: 'rules', flatten: true, ext: '.mdc' },\n commands: { targetSubdir: 'commands', flatten: true },\n prompts: false,\n },\n};\n","import type { Adapter } from '../core/types.js';\nimport { claude } from './claude.js';\nimport { codebuddy } from './codebuddy.js';\nimport { cursor } from './cursor.js';\n\n/**\n * v1 ships with three built-in adapters. The keys here are also the only valid\n * names accepted in `agentlink.config.json`'s `adapters` field — supporting a\n * new agent requires publishing a new package version.\n */\nexport const adapterRegistry = {\n cursor,\n claude,\n codebuddy,\n} as const satisfies Record<string, Adapter>;\n\nexport type AdapterName = keyof typeof adapterRegistry;\n\nexport { claude, codebuddy, cursor };\n","/**\n * Locate, validate, and merge `agentlink.config.json` with built-in adapter\n * presets to produce a {@link ResolvedConfig}.\n *\n * Config and source are mostly **decoupled** — config primarily describes _how_\n * to project assets, but may also persist optional `source` / `target` defaults\n * so users need not pass flags on every invocation.\n *\n * Config resolution chain (highest first):\n * 1. `--config <path>` flag\n * 2. nearest `agentlink.config.json` from cwd up to (but not past) the\n * home directory or filesystem root\n * 3. `~/agentlink.config.json`\n * 4. (none) — fall back to all defaults\n *\n * Validation philosophy:\n * - **Closed asset-type universe**: keys must be one of the literal\n * {@link AssetType} values. Unknown names yield a friendly zod error.\n * - **Closed adapter universe** (v1): `adapters` keys must match a built-in\n * name (cursor / claude / codebuddy).\n * - **Tolerant defaults**: every field is optional; missing config equals\n * an empty `{}`.\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport stripJsonComments from 'strip-json-comments';\nimport { z } from 'zod';\n\nimport { adapterRegistry, type AdapterName } from '../adapters/index.js';\nimport { AgentlinkError, InvalidPathError } from './errors.js';\nimport {\n DEFAULT_INCLUDE,\n type Adapter,\n type AssetLayout,\n type AssetType,\n type ResolvedConfig,\n} from './types.js';\n\nexport const CONFIG_FILENAME = 'agentlink.config.json';\n\nconst ASSET_TYPE_VALUES = ['skills', 'rules', 'commands', 'prompts', 'templates', 'agents'] as const;\nconst ASSET_TYPE_SET: ReadonlySet<AssetType> = new Set(ASSET_TYPE_VALUES);\n\nconst assetTypeSchema = z.enum(ASSET_TYPE_VALUES);\n\n/**\n * `targetSubdir` is `path.join`'d under each adapter's rootDir. Letting users\n * write `..`, absolute paths, or path separators here would let them escape\n * the rootDir sandbox (and silently smear symlinks across the destination).\n *\n * We reject the obviously bad shapes at the schema layer so zod produces a\n * focused, path-aware error message instead of a generic ConfigPatchError\n * later in mergeLayout.\n */\nconst targetSubdirSchema = z\n .string()\n .min(1)\n .refine((s) => !path.isAbsolute(s), {\n message: 'targetSubdir must be relative (no leading `/` or drive letter)',\n })\n .refine((s) => !s.split(/[\\\\/]/).some((seg) => seg === '..'), {\n message: 'targetSubdir cannot traverse upward (`..` segment forbidden)',\n });\n\nconst assetLayoutSchema = z.object({\n targetSubdir: targetSubdirSchema.optional(),\n flatten: z.boolean().optional(),\n include: z.array(z.string().min(1)).optional(),\n exclude: z.array(z.string().min(1)).optional(),\n ext: z.string().min(1).optional(),\n});\n\nconst adapterOverrideSchema = z.union([\n z.boolean(),\n z\n .object({\n // partialRecord: zod v4 z.record(enum,…) is exhaustive by default;\n // partialRecord lets each key be optional, which is what users expect.\n layout: z.partialRecord(assetTypeSchema, assetLayoutSchema).optional(),\n })\n .strict(),\n]);\n\nconst adapterNameSchema = z.enum(\n Object.keys(adapterRegistry) as [AdapterName, ...AdapterName[]],\n);\n\nconst rootPathSchema = z.string().min(1);\n\n/**\n * Strict closed-world schema. Unknown root keys, unknown adapter names, and\n * unknown asset types all surface as friendly zod errors.\n */\nconst configSchema = z\n .object({\n source: rootPathSchema.optional(),\n target: rootPathSchema.optional(),\n user: z.boolean().optional(),\n include: z.array(assetTypeSchema).optional(),\n exclude: z.array(assetTypeSchema).optional(),\n adapters: z.partialRecord(adapterNameSchema, adapterOverrideSchema).optional(),\n })\n .strict()\n .superRefine((val, ctx) => {\n if (val.target !== undefined && val.user === true) {\n ctx.addIssue({\n code: 'custom',\n message: '`target` and `user` are mutually exclusive',\n path: ['target'],\n });\n }\n });\n\ntype ParsedConfig = z.infer<typeof configSchema>;\n\nexport class ConfigParseError extends AgentlinkError {\n readonly issues: ReadonlyArray<{ path: string; message: string }>;\n\n constructor(filePath: string, issues: ReadonlyArray<{ path: string; message: string }>) {\n const lines = issues.map(({ path: p, message }) => ` at ${p || '<root>'}: ${message}`);\n super(`invalid agentlink config at ${filePath}\\n${lines.join('\\n')}`);\n this.issues = issues;\n }\n}\n\nexport type ConfigOrigin = 'flag' | 'cwd-ancestor' | 'home-global' | 'defaults';\n\nexport interface ResolveConfigOptions {\n /** `--config` flag value. */\n config?: string;\n /** Override `process.cwd()`. */\n cwd?: string;\n /** Override `os.homedir()`. */\n home?: string;\n}\n\nexport interface ConfigLocation {\n /** Absolute path that was loaded — `null` if no config file exists. */\n path: string | null;\n origin: ConfigOrigin;\n}\n\nexport interface LoadConfigOptions extends ResolveConfigOptions {\n /** Absolute path to the source `.agents/` — only used to populate ResolvedConfig. */\n source: string;\n}\n\nexport interface ConfigBundle {\n location: ConfigLocation;\n parsed: ParsedConfig;\n /** Directory containing the loaded config file; `null` when defaults apply. */\n configBase: string | null;\n}\n\n/**\n * Locate and parse the user config once. Used by {@link loadContext} to feed\n * both path resolution and adapter merging without reading the file twice.\n */\nexport async function loadConfigBundle(opts: ResolveConfigOptions = {}): Promise<ConfigBundle> {\n const location = await resolveConfigPath(opts);\n const parsed = location.path ? await readUserConfig(location.path) : ({} as ParsedConfig);\n const configBase = location.path ? path.dirname(location.path) : null;\n return { location, parsed, configBase };\n}\n\n/**\n * Merge a parsed config with built-in presets. The `source` argument is the\n * already-resolved `.agents/` path from {@link resolveSource}.\n */\nexport function resolveConfigFromParsed(\n userConfig: ParsedConfig,\n location: ConfigLocation,\n source: string,\n): ResolvedConfig {\n const adapters = mergeAdapters(userConfig.adapters);\n const assetTypes = resolveAssetTypes(userConfig.include, userConfig.exclude);\n\n return {\n source,\n adapters,\n assetTypes,\n configPath: location.path,\n configOrigin: location.origin,\n };\n}\n\n/**\n * Read + validate + merge the config. Returns a fully resolved view that is\n * safe to feed into command implementations.\n */\nexport async function loadConfig(opts: LoadConfigOptions): Promise<ResolvedConfig> {\n const bundle = await loadConfigBundle(opts);\n return resolveConfigFromParsed(bundle.parsed, bundle.location, opts.source);\n}\n\n/**\n * Resolve the location of the config file (independent of source). Pure with\n * respect to everything except `fs.stat` — easy to unit-test.\n */\nexport async function resolveConfigPath(opts: ResolveConfigOptions = {}): Promise<ConfigLocation> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n\n if (opts.config !== undefined && opts.config !== '') {\n const abs = await assertConfigFile(expandTilde(opts.config, home), '--config', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n const ancestor = await searchAncestors(path.resolve(cwd), home);\n if (ancestor) {\n return { path: ancestor, origin: 'cwd-ancestor' };\n }\n\n const homeConfig = path.join(home, CONFIG_FILENAME);\n if (await isFile(homeConfig)) {\n return { path: homeConfig, origin: 'home-global' };\n }\n\n return { path: null, origin: 'defaults' };\n}\n\n/**\n * Walk up the directory tree from `start`, looking for `agentlink.config.json`.\n * Stops as soon as we leave the home directory (or hit the filesystem root) so\n * configs from unrelated trees never leak in.\n */\nasync function searchAncestors(start: string, home: string): Promise<string | null> {\n const homeAbs = path.resolve(home);\n let current = start;\n while (true) {\n if (current === homeAbs) {\n // Don't probe `~/agentlink.config.json` here — it has its own dedicated\n // tier so the diagnostic origin reads as \"home-global\", not \"ancestor\".\n return null;\n }\n\n const candidate = path.join(current, CONFIG_FILENAME);\n if (await isFile(candidate)) return candidate;\n\n const parent = path.dirname(current);\n if (parent === current) return null; // hit filesystem root\n\n // Stop ascending if we are about to leave the home tree (only when start\n // was inside home). If start was outside home all along, keep walking up.\n if (isInside(current, homeAbs) && !isInside(parent, homeAbs) && parent !== homeAbs) {\n return null;\n }\n current = parent;\n }\n}\n\nasync function assertConfigFile(input: string, flag: string, cwd: string): Promise<string> {\n const abs = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) throw new InvalidPathError(flag, abs, 'missing');\n if (!stat.isFile()) throw new InvalidPathError(flag, abs, 'not-a-file');\n return abs;\n}\n\nasync function isFile(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isFile() ?? false;\n}\n\nfunction expandTilde(p: string, home: string): string {\n if (p === '~') return home;\n if (p.startsWith('~/')) return path.join(home, p.slice(2));\n return p;\n}\n\nfunction isInside(child: string, parent: string): boolean {\n const c = path.resolve(child);\n const p = path.resolve(parent);\n if (c === p) return true;\n const rel = path.relative(p, c);\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n\n/**\n * Read the *raw* user config and report which adapter names the user\n * explicitly opted into (i.e. anything not literally `false`). Best-effort —\n * returns an empty set on any IO/parse error so callers (e.g. doctor) can\n * fall back gracefully without hiding the real validation error from the\n * primary {@link loadConfig} pipeline.\n *\n * Centralised here so the JSONC tolerance stays consistent with `loadConfig`\n * (same comment + trailing-comma stripping) — earlier drafts had doctor.ts\n * hand-roll its own regex, which was both wrong on URLs and inconsistent\n * with the loader.\n */\nexport async function readExplicitAdapters(\n configPath: string | null,\n): Promise<ReadonlySet<string>> {\n if (!configPath) return new Set();\n const raw = await fs.readFile(configPath, 'utf8').catch(() => null);\n if (raw === null) return new Set();\n try {\n const parsed = JSON.parse(stripJsonComments(raw, { trailingCommas: true })) as {\n adapters?: Record<string, unknown>;\n };\n if (!parsed.adapters) return new Set();\n return new Set(Object.keys(parsed.adapters).filter((k) => parsed.adapters?.[k] !== false));\n } catch {\n return new Set();\n }\n}\n\nasync function readUserConfig(filePath: string): Promise<ParsedConfig> {\n const raw = await fs.readFile(filePath, 'utf8').catch((err: NodeJS.ErrnoException) => {\n if (err.code === 'ENOENT') return null;\n throw err;\n });\n if (raw === null) return {};\n\n let parsed: unknown;\n try {\n // JSONC: tolerate `//` and `/* */` comments plus trailing commas. The\n // template ships annotated so users can discover schema by reading.\n parsed = JSON.parse(stripJsonComments(raw, { trailingCommas: true }));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new ConfigParseError(filePath, [{ path: '', message: `not valid JSON: ${message}` }]);\n }\n\n const result = configSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues.map((issue) => ({\n path: issue.path.map((seg) => String(seg)).join('.'),\n message: issue.message,\n }));\n throw new ConfigParseError(filePath, issues);\n }\n return result.data;\n}\n\n/**\n * Apply user overrides to built-in adapter presets, returning only the adapters\n * that are enabled. Disabled adapters (`false` override) drop out entirely;\n * adapters not mentioned in user config keep their preset.\n */\nfunction mergeAdapters(\n overrides: ParsedConfig['adapters'] | undefined,\n): readonly Adapter[] {\n const result: Adapter[] = [];\n\n for (const [name, preset] of Object.entries(adapterRegistry) as Array<[AdapterName, Adapter]>) {\n const override = overrides?.[name];\n\n if (override === false) continue;\n\n if (override === undefined || override === true) {\n result.push(preset);\n continue;\n }\n\n result.push({\n name: preset.name,\n rootDir: preset.rootDir,\n layout: mergeLayout(preset.layout, override.layout),\n });\n }\n\n return result;\n}\n\n/**\n * Shape of a single `layout[<assetType>]` entry as it comes out of zod parse.\n * Differs from `Partial<AssetLayout>` because `exactOptionalPropertyTypes`\n * distinguishes \"may be omitted\" from \"may be `undefined`\".\n */\ninterface LayoutPatchValue {\n targetSubdir?: string | undefined;\n flatten?: boolean | undefined;\n include?: string[] | undefined;\n exclude?: string[] | undefined;\n ext?: string | undefined;\n}\n\ntype LayoutPatch = Partial<Record<AssetType, LayoutPatchValue>>;\n\nfunction mergeLayout(\n base: Adapter['layout'],\n patch: LayoutPatch | undefined,\n): Adapter['layout'] {\n if (!patch) return base;\n\n const merged: Adapter['layout'] = { ...base };\n for (const key of Object.keys(patch) as AssetType[]) {\n const value = patch[key];\n if (value === undefined) continue;\n\n const baseLayout = base[key];\n if (baseLayout === undefined || baseLayout === false) {\n const targetSubdir = value.targetSubdir;\n if (targetSubdir === undefined) {\n throw new ConfigPatchError(\n `adapter override for \"${key}\" needs a targetSubdir because the built-in adapter does not define one`,\n );\n }\n merged[key] = compactLayout(targetSubdir, value);\n continue;\n }\n merged[key] = mergeIntoBase(baseLayout, value);\n }\n return merged;\n}\n\n/** Strip `undefined` so the result respects exactOptionalPropertyTypes. */\nfunction compactLayout(targetSubdir: string, v: LayoutPatchValue): AssetLayout {\n const out: { -readonly [K in keyof AssetLayout]: AssetLayout[K] } = { targetSubdir };\n if (v.flatten !== undefined) out.flatten = v.flatten;\n if (v.include !== undefined) out.include = v.include;\n if (v.exclude !== undefined) out.exclude = v.exclude;\n if (v.ext !== undefined) out.ext = v.ext;\n return out;\n}\n\nfunction mergeIntoBase(base: AssetLayout, patch: LayoutPatchValue): AssetLayout {\n const out: { -readonly [K in keyof AssetLayout]: AssetLayout[K] } = { ...base };\n if (patch.targetSubdir !== undefined) out.targetSubdir = patch.targetSubdir;\n if (patch.flatten !== undefined) out.flatten = patch.flatten;\n if (patch.include !== undefined) out.include = patch.include;\n if (patch.exclude !== undefined) out.exclude = patch.exclude;\n if (patch.ext !== undefined) out.ext = patch.ext;\n return out;\n}\n\nclass ConfigPatchError extends AgentlinkError {}\n\n/**\n * Compute the set of asset types that should participate in this run.\n * `include` defaults to {@link DEFAULT_INCLUDE}; `exclude` is always a hard\n * subtraction applied last.\n */\nfunction resolveAssetTypes(\n include: readonly AssetType[] | undefined,\n exclude: readonly AssetType[] | undefined,\n): ReadonlySet<string> {\n const candidates = new Set<string>(include ?? DEFAULT_INCLUDE);\n for (const denied of exclude ?? []) {\n candidates.delete(denied);\n }\n return candidates;\n}\n\nexport const __test__ = {\n ASSET_TYPE_SET,\n CONFIG_FILENAME,\n};\n","/**\n * Domain-specific error types thrown by agentlink core modules.\n *\n * Using a small class hierarchy (rather than plain `Error` with codes) so the\n * CLI layer can `instanceof`-match and render targeted help text without\n * coupling to error message strings.\n */\n\nexport class AgentlinkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/**\n * No `.agents/` directory could be located via any resolution channel.\n * `searched` records every probe and its outcome so the CLI can render a\n * \"Searched: …\" diagnostic block.\n */\nexport class SourceNotFoundError extends AgentlinkError {\n readonly searched: ReadonlyArray<{ origin: string; status: string }>;\n\n constructor(searched: ReadonlyArray<{ origin: string; status: string }>) {\n super('no source .agents/ directory found');\n this.searched = searched;\n }\n}\n\n/**\n * A user-supplied path (via flag or env) is missing or has the wrong shape.\n * `flag` is the originating channel name as the user would recognize it\n * (e.g. `--source`, `config.source`).\n */\nexport class InvalidPathError extends AgentlinkError {\n readonly flag: string;\n readonly path: string;\n readonly reason: 'missing' | 'not-a-directory' | 'not-a-file';\n\n constructor(flag: string, p: string, reason: 'missing' | 'not-a-directory' | 'not-a-file') {\n super(InvalidPathError.message(flag, p, reason));\n this.flag = flag;\n this.path = p;\n this.reason = reason;\n }\n\n private static message(\n flag: string,\n p: string,\n reason: 'missing' | 'not-a-directory' | 'not-a-file',\n ): string {\n if (reason === 'missing') return `${flag} does not exist: ${p}`;\n if (reason === 'not-a-directory') return `${flag} is not a directory: ${p}`;\n return `${flag} is not a file: ${p}`;\n }\n}\n\n/** Two mutually exclusive options were supplied together (e.g. --target and --user). */\nexport class ConflictError extends AgentlinkError {}\n","/**\n * Asset categories agentlink knows how to symlink.\n * Extend cautiously — adding a value here is a breaking change for adapters.\n */\nexport type AssetType = 'skills' | 'rules' | 'commands' | 'prompts' | 'templates' | 'agents';\n\n/**\n * Per-asset-type projection rule. Sentinel `false` (\"skip this asset entirely\")\n * is represented at the {@link Adapter.layout} value level rather than inside\n * AssetLayout, so that `keyof AssetLayout` stays meaningful for code that maps\n * over its fields.\n */\nexport interface AssetLayout {\n /** Subdirectory under the adapter's `rootDir`, e.g. 'skills' / 'commands'. */\n targetSubdir: string;\n /**\n * If true, source files in nested subdirectories are flattened into the target\n * directory using `__` as the path separator (e.g. `git/commit.md` → `git__commit.md`).\n * Use this for agents that don't support nested command/rule directories (e.g. cursor).\n */\n flatten?: boolean;\n /** Glob patterns (relative to source asset dir) to include. Defaults to all files. */\n include?: readonly string[];\n /** Glob patterns to exclude. Applied after `include`. */\n exclude?: readonly string[];\n /** Force a specific file extension on the link target (e.g. `.mdc` for cursor rules). */\n ext?: string;\n /**\n * Custom rename hook. Receives the relative source path; returns the target file name\n * (without `targetSubdir`). v1: only used by built-in adapters; not exposed via JSON config.\n */\n rename?: (relPath: string) => string;\n}\n\n/** A layout slot is either a real layout or `false` to mean \"skip this asset type\". */\nexport type LayoutSlot = AssetLayout | false;\n\n/**\n * Built-in or user-supplied adapter describing how to project `.agents/` into one AI agent's\n * directory layout.\n */\nexport interface Adapter {\n /** Stable identifier, e.g. 'cursor' / 'claude' / 'codebuddy'. */\n name: string;\n /** Directory under target root, e.g. '.cursor'. */\n rootDir: string;\n /** Per-asset-type projection rules. */\n layout: Partial<Record<AssetType, LayoutSlot>>;\n}\n\n/**\n * Per-adapter overrides as written by the user in JSON config.\n * Value semantics:\n * - `true` : enable built-in adapter with default layout\n * - `false` : disable adapter even if its rootDir exists\n * - `{ layout }` : enable + deep-merge layout overrides onto built-in defaults\n */\nexport type AdapterOverride =\n | boolean\n | { layout?: Partial<Record<AssetType, AssetLayout>> };\n\n/**\n * User-facing JSON configuration (`agentlink.config.json`).\n * Every field is optional; sensible defaults apply.\n */\nexport interface AgentlinkConfig {\n /**\n * Persistent default for the `.agents/` source directory.\n * Resolved after `--source`, before `cwd/.agents` and `~/.agents`. When set, beats a sparse repo-local `.agents/` (e.g. a few\n * project-only commands). Relative paths are resolved against the config file directory.\n */\n source?: string;\n /**\n * Persistent default destination root (where adapter rootDirs like `.cursor`\n * are expected). Relative paths are resolved against the config file directory.\n * Mutually exclusive with {@link AgentlinkConfig.user}.\n */\n target?: string;\n /** When true, project symlinks into `$HOME` (equivalent to `--user`). */\n user?: boolean;\n /**\n * Asset type allowlist. When omitted, falls back to the built-in default\n * (`['skills', 'rules', 'commands']`). Use this to opt into less-common\n * asset types like `prompts` / `templates` / `agents`.\n */\n include?: readonly string[];\n /**\n * Asset type denylist applied AFTER `include`. Always wins over `include`,\n * useful for temporarily silencing one type without rewriting the allowlist.\n */\n exclude?: readonly string[];\n /** Per-adapter overrides; see {@link AdapterOverride}. */\n adapters?: Record<string, AdapterOverride>;\n}\n\n/**\n * Result of {@link loadConfig}: raw JSON has been validated, defaults filled,\n * and built-in adapter presets merged with user overrides. This is what every\n * runtime command (sync/clean/unlink/doctor) consumes.\n */\nexport interface ResolvedConfig {\n /** Absolute path to the source `.agents/` directory. */\n source: string;\n /** Adapters that are enabled, with overrides already applied to layouts. */\n adapters: readonly Adapter[];\n /** Asset type names that should participate in this run. */\n assetTypes: ReadonlySet<string>;\n /** Absolute path of the config file actually loaded; null when no file existed. */\n configPath: string | null;\n /** Where the config came from. `'defaults'` means no file was found. */\n configOrigin: 'flag' | 'cwd-ancestor' | 'home-global' | 'defaults';\n}\n\n/** Built-in default for {@link AgentlinkConfig.include}. */\nexport const DEFAULT_INCLUDE = ['skills', 'rules', 'commands'] as const;\n","/**\n * Locate the source `.agents/` directory and the destination root for a sync run.\n *\n * Two independent resolution chains share the same {@link ResolveOptions} and\n * produce a {@link ResolvedPaths} record. Both chains are pure with respect to\n * everything except `fs.stat` probes, so they are easy to unit-test with a\n * tmpdir + injected `cwd / home / env`.\n *\n * Source chain (highest first):\n * 1. `--source <path>` flag\n * 2. `config.source` — explicit config beats an incidental `cwd/.agents`\n * 3. `<cwd>/.agents/` — team repos with a full local source (no config.source)\n * 4. `<home>/.agents/` — recommended default for the npx workflow\n * 5. (none) → SourceNotFoundError\n *\n * Destination chain (highest first):\n * 1. `--target <path>` flag\n * 2. `--user` → home (user-level install target)\n * 3. `config.target` / `config.user`\n * 4. (default) cwd\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { ConflictError, InvalidPathError, SourceNotFoundError } from './errors.js';\n\nexport type SourceOrigin = 'flag' | 'cwd-local' | 'config' | 'home-global';\nexport type DestOrigin = 'flag' | 'user' | 'config' | 'cwd';\n\nexport interface ResolveOptions {\n /** `--source` flag value. */\n source?: string;\n /** `--target` flag value. */\n target?: string;\n /** `--user` flag value — link into $HOME. */\n user?: boolean;\n /** `source` field from the resolved config file. */\n configSource?: string;\n /** `target` field from the resolved config file. */\n configTarget?: string;\n /** `user` field from the resolved config file. */\n configUser?: boolean;\n /** Directory containing the loaded config; used to resolve relative config paths. */\n configBase?: string;\n /** Resolved config file path — diagnostics only (see {@link SourceNotFoundError}). */\n resolvedConfigPath?: string | null;\n /** Override `process.cwd()`. */\n cwd?: string;\n /** Override `os.homedir()`. */\n home?: string;\n}\n\nexport interface ResolvedPaths {\n source: string;\n sourceOrigin: SourceOrigin;\n destRoot: string;\n destOrigin: DestOrigin;\n}\n\nconst AGENTS_DIRNAME = '.agents';\n\n/**\n * Top-level entry. Resolves source and destination concurrently and emits a\n * Node warning if `destRoot` lives inside `source` (likely a self-link mistake).\n */\nexport async function resolvePaths(opts: ResolveOptions = {}): Promise<ResolvedPaths> {\n const [src, dst] = await Promise.all([resolveSource(opts), resolveDestRoot(opts)]);\n\n if (isInside(dst.path, src.path)) {\n process.emitWarning(\n `destination root \"${dst.path}\" lives inside source \"${src.path}\" — this may create self-references.`,\n { code: 'AGENTLINK_NESTED_DEST' },\n );\n }\n\n return {\n source: src.path,\n sourceOrigin: src.origin,\n destRoot: dst.path,\n destOrigin: dst.origin,\n };\n}\n\nexport async function resolveSource(\n opts: ResolveOptions = {},\n): Promise<{ path: string; origin: SourceOrigin }> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n\n if (opts.source !== undefined && opts.source !== '') {\n const abs = await assertDir(expandTilde(opts.source, home), '--source', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n const configSource = opts.configSource;\n if (configSource !== undefined && configSource !== '') {\n const base = opts.configBase ?? cwd;\n const abs = await assertDir(\n resolveConfigPathValue(configSource, base, home),\n 'config.source',\n cwd,\n );\n return { path: abs, origin: 'config' };\n }\n\n const local = path.join(cwd, AGENTS_DIRNAME);\n if (await isDir(local)) {\n return { path: local, origin: 'cwd-local' };\n }\n\n // Note: `homeAgents` is the source path under home; unrelated to the\n // destination `--user` flag (which maps the *target* root to home).\n const homeAgents = path.join(home, AGENTS_DIRNAME);\n if (await isDir(homeAgents)) {\n return { path: homeAgents, origin: 'home-global' };\n }\n\n throw new SourceNotFoundError([\n { origin: '--source flag', status: 'not provided' },\n { origin: 'config.source', status: configSourceStatus(opts) },\n { origin: local, status: localProbeStatus(local) },\n { origin: homeAgents, status: 'missing' },\n ]);\n}\n\nfunction localProbeStatus(_local: string): string {\n return 'missing (used when config.source is not set)';\n}\n\nfunction configSourceStatus(opts: ResolveOptions): string {\n if (opts.configSource !== undefined && opts.configSource !== '') {\n return 'not reached';\n }\n if (opts.resolvedConfigPath) {\n return `not set in ${opts.resolvedConfigPath}`;\n }\n return 'no config file loaded';\n}\n\nexport async function resolveDestRoot(\n opts: ResolveOptions = {},\n): Promise<{ path: string; origin: DestOrigin }> {\n const cwd = opts.cwd ?? process.cwd();\n const home = opts.home ?? os.homedir();\n\n if (opts.target !== undefined && opts.target !== '' && opts.user) {\n throw new ConflictError('--target and --user are mutually exclusive');\n }\n\n if (opts.target !== undefined && opts.target !== '') {\n const abs = await assertDir(expandTilde(opts.target, home), '--target', cwd);\n return { path: abs, origin: 'flag' };\n }\n\n if (opts.user) {\n return { path: home, origin: 'user' };\n }\n\n if (opts.configTarget !== undefined && opts.configTarget !== '' && opts.configUser) {\n throw new ConflictError('config `target` and `user` are mutually exclusive');\n }\n\n if (opts.configTarget !== undefined && opts.configTarget !== '') {\n const base = opts.configBase ?? cwd;\n const abs = await assertDir(\n resolveConfigPathValue(opts.configTarget, base, home),\n 'config.target',\n cwd,\n );\n return { path: abs, origin: 'config' };\n }\n\n if (opts.configUser) {\n return { path: home, origin: 'config' };\n }\n\n return { path: cwd, origin: 'cwd' };\n}\n\n/**\n * Resolve a path from config: tilde-expand, then absolute or relative to the\n * config file directory (not cwd).\n */\nexport function resolveConfigPathValue(input: string, configBase: string, home: string): string {\n const expanded = expandTilde(input, home);\n return path.isAbsolute(expanded) ? expanded : path.resolve(configBase, expanded);\n}\n\n/**\n * Expand a leading `~` or `~/` to the supplied home directory.\n * Intentionally narrower than shell tilde expansion (no `~user` lookup).\n */\nexport function expandTilde(p: string, home: string): string {\n if (p === '~') return home;\n if (p.startsWith('~/')) return path.join(home, p.slice(2));\n return p;\n}\n\nasync function assertDir(input: string, flag: string, cwd: string): Promise<string> {\n const abs = path.isAbsolute(input) ? input : path.resolve(cwd, input);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) throw new InvalidPathError(flag, abs, 'missing');\n if (!stat.isDirectory()) throw new InvalidPathError(flag, abs, 'not-a-directory');\n return abs;\n}\n\nasync function isDir(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isDirectory() ?? false;\n}\n\n/**\n * `true` iff `child` is inside `parent` (or equal).\n *\n * Compares lexically — neither path is realpath-resolved, matching the rest of\n * the resolver's \"preserve symlinks\" stance.\n */\nexport function isInside(child: string, parent: string): boolean {\n const c = path.resolve(child);\n const p = path.resolve(parent);\n if (c === p) return true;\n const rel = path.relative(p, c);\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n","/**\n * `agentlink doctor` — read-only health check for the current source/destination\n * pair. Designed to answer \"would `agentlink sync` do something useful here,\n * and would it run cleanly?\" without writing anything to disk.\n *\n * Reports four sections:\n * 1. Adapter availability (rootDir present / config-disabled / missing)\n * 2. Link plan (count + any target-path collisions)\n * 3. Existing links (dangling, orphan)\n * 4. Aggregate verdict — sets `process.exitCode = 1` only on errors;\n * warnings are non-blocking so doctor can be wired into pre-commit\n * hooks without false positives.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nimport { adapterRegistry } from '../adapters/index.js';\nimport { readExplicitAdapters } from '../core/config.js';\nimport { buildLinkPlans } from '../core/layout.js';\nimport { findManagedLinks, findStaleLinks } from '../core/linker.js';\nimport {\n enumerateAllAdapterRoots,\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runDoctor(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'doctor', flags);\n\n let warnings = 0;\n let errors = 0;\n\n // Read the *raw* user config so we can distinguish \"user explicitly opted\n // into this adapter\" (warn when its rootDir is missing) from \"default\n // pickup\" (dim when missing — most users don't have all three agents).\n const explicitlyEnabled = await readExplicitAdapters(ctx.config.configPath);\n\n // ── 1. Adapter availability ──────────────────────────────────────────────\n console.log(pc.bold('Adapters'));\n for (const [name, preset] of Object.entries(adapterRegistry)) {\n const root = path.join(ctx.paths.destRoot, preset.rootDir);\n const stat = await fs.stat(root).catch(() => null);\n if (stat?.isDirectory()) {\n console.log(\n ` ${pc.green('✓')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.dim('(active)')}`,\n );\n } else if (explicitlyEnabled.has(name)) {\n warnings++;\n console.log(\n ` ${pc.yellow('⚠')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.yellow('rootDir not found — sync will skip')}`,\n );\n } else {\n console.log(\n ` ${pc.dim('—')} ${name.padEnd(11)} ${pc.dim(preset.rootDir + '/')} ${pc.dim('not in use on this machine')}`,\n );\n }\n }\n console.log('');\n\n // ── 2. Link plan ────────────────────────────────────────────────────────\n const { plans, collisions } = await buildLinkPlans({\n source: ctx.paths.source,\n destRoot: ctx.paths.destRoot,\n config: ctx.config,\n });\n\n console.log(pc.bold('Link plan'));\n console.log(` ${plans.length} plan${plans.length === 1 ? '' : 's'}`);\n if (collisions.length === 0) {\n console.log(` ${pc.green('✓')} no collisions`);\n } else {\n warnings += collisions.length;\n console.log(` ${pc.yellow('⚠')} ${collisions.length} collision(s):`);\n for (const c of collisions) {\n console.log(` ${pc.dim(c.adapterName + '/' + c.assetType)} ${c.target}`);\n for (const s of c.sources) console.log(` ${pc.dim('←')} ${s}`);\n }\n }\n console.log('');\n\n // ── 3. Existing links ───────────────────────────────────────────────────\n const targetDirs = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targetDirs.map(findStaleLinks))).flat();\n\n // Recursive sweep — orphans can live in asset subdirs that the current\n // config no longer mentions, AND in adapter rootDirs the user has just\n // disabled. Walk every built-in adapter rootDir that exists, ignoring the\n // current `ctx.config.adapters` gate so doctor stays comprehensive.\n const allRoots = await enumerateAllAdapterRoots(ctx.paths.destRoot);\n const managed = (\n await Promise.all(\n allRoots.map((r) => findManagedLinks(r.rootDir, ctx.paths.source, { recursive: true })),\n )\n ).flat();\n const staleSet = new Set(stale);\n const planTargets = new Set(plans.map((p) => p.target));\n const orphans = managed.filter((p) => !planTargets.has(p) && !staleSet.has(p));\n\n console.log(pc.bold('Existing links'));\n if (stale.length === 0 && orphans.length === 0) {\n console.log(` ${pc.green('✓')} all clear`);\n } else {\n if (stale.length > 0) {\n warnings += stale.length;\n console.log(\n ` ${pc.yellow('⚠')} ${stale.length} dangling ${pc.dim('(run `agentlink clean` to drop):')}`,\n );\n for (const p of stale) console.log(` ${p}`);\n }\n if (orphans.length > 0) {\n warnings += orphans.length;\n console.log(\n ` ${pc.yellow('⚠')} ${orphans.length} orphan ${pc.dim('(linked into source but not in current plan; `unlink` then `sync` will rebuild):')}`,\n );\n for (const p of orphans) console.log(` ${p}`);\n }\n }\n console.log('');\n\n // ── 4. Verdict ──────────────────────────────────────────────────────────\n if (warnings + errors === 0) {\n console.log(pc.green('Healthy'));\n return;\n }\n const parts: string[] = [];\n if (warnings > 0) parts.push(pc.yellow(`${warnings} warning${warnings === 1 ? '' : 's'}`));\n if (errors > 0) parts.push(pc.red(`${errors} error${errors === 1 ? '' : 's'}`));\n console.log(`Issues: ${parts.join(', ')}`);\n if (errors > 0) process.exitCode = 1;\n}\n\n","/**\n * Translate a {@link ResolvedConfig} into a flat list of {@link LinkPlan}s\n * that the linker module can execute one symlink at a time.\n *\n * For each `(adapter, assetType)` pair this module:\n * - resolves the source asset directory under `<source>/<assetType>`\n * - resolves the target directory under `<destRoot>/<rootDir>/<targetSubdir>`\n * - applies `flatten` / `ext` / `rename` / `include` / `exclude`\n * - detects target-path collisions and surfaces them as {@link Conflict}s\n *\n * Conflict policy is intentionally _diagnostic only_ here — the caller decides\n * whether to warn (default) or fail (`--strict`).\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\n\nimport type {\n Adapter,\n AssetLayout,\n AssetType,\n ResolvedConfig,\n} from './types.js';\n\nexport interface LinkPlan {\n /** Absolute source path (file when flattened, file-or-directory otherwise). */\n source: string;\n /** Absolute target path the symlink will live at. */\n target: string;\n /** Asset type bucket this plan came from. */\n assetType: AssetType;\n /** Name of the adapter that produced this plan. */\n adapterName: string;\n /** True when source enumeration recursed into nested files. */\n flattened: boolean;\n}\n\nexport interface Conflict {\n /** Target path that two or more plans claim. */\n target: string;\n /** Source paths competing for the same target. */\n sources: readonly string[];\n /** Asset type / adapter the collision happened in (for diagnostics). */\n adapterName: string;\n assetType: AssetType;\n}\n\nexport interface BuildResult {\n /** Plans whose targets are unique. Safe to apply. */\n plans: readonly LinkPlan[];\n /** Plans dropped because their target collided with another (default policy). */\n collisions: readonly Conflict[];\n}\n\nexport interface BuildOptions {\n /** Absolute path to the source `.agents/` directory. */\n source: string;\n /** Absolute path to the destination root. */\n destRoot: string;\n /** Resolved config (loaded via {@link loadConfig}). */\n config: ResolvedConfig;\n}\n\n/**\n * Build the flat plan list. Pure function — only reads the filesystem; never\n * writes. Safe to call from `--dry-run`.\n */\nexport async function buildLinkPlans(opts: BuildOptions): Promise<BuildResult> {\n const { source, destRoot, config } = opts;\n const draft: LinkPlan[] = [];\n\n for (const adapter of config.adapters) {\n for (const assetType of config.assetTypes as ReadonlySet<AssetType>) {\n const slot = adapter.layout[assetType];\n if (slot === undefined || slot === false) continue;\n\n const sourceAssetDir = path.join(source, assetType);\n if (!(await isDir(sourceAssetDir))) continue;\n\n const targetAssetDir = path.join(destRoot, adapter.rootDir, slot.targetSubdir);\n const planned = slot.flatten\n ? await planFlattened(sourceAssetDir, targetAssetDir, slot, adapter, assetType)\n : await planShallow(sourceAssetDir, targetAssetDir, slot, adapter, assetType);\n\n draft.push(...planned);\n }\n }\n\n return splitByCollision(draft);\n}\n\n/* ────────────────────────── flatten = true ───────────────────────────── */\n\nasync function planFlattened(\n sourceAssetDir: string,\n targetAssetDir: string,\n layout: AssetLayout,\n adapter: Adapter,\n assetType: AssetType,\n): Promise<LinkPlan[]> {\n const files = await walkFiles(sourceAssetDir);\n const includeMatch = makeIncludeMatcher(layout.include);\n const excludeMatch = makeExcludeMatcher(layout.exclude);\n const out: LinkPlan[] = [];\n\n for (const abs of files) {\n const rel = path.relative(sourceAssetDir, abs);\n if (!includeMatch(rel)) continue;\n if (excludeMatch(rel)) continue;\n\n const targetName = applyRename(rel, layout, /* flatten */ true);\n out.push({\n source: abs,\n target: path.join(targetAssetDir, targetName),\n adapterName: adapter.name,\n assetType,\n flattened: true,\n });\n }\n return out;\n}\n\n/* ────────────────────────── flatten = false (default) ───────────────── */\n\nasync function planShallow(\n sourceAssetDir: string,\n targetAssetDir: string,\n layout: AssetLayout,\n adapter: Adapter,\n assetType: AssetType,\n): Promise<LinkPlan[]> {\n const items = await listFirstLevel(sourceAssetDir);\n const includeMatch = makeIncludeMatcher(layout.include);\n const excludeMatch = makeExcludeMatcher(layout.exclude);\n const out: LinkPlan[] = [];\n\n for (const entry of items) {\n if (!includeMatch(entry.name)) continue;\n if (excludeMatch(entry.name)) continue;\n\n const targetName = applyRename(entry.name, layout, /* flatten */ false);\n out.push({\n source: path.join(sourceAssetDir, entry.name),\n target: path.join(targetAssetDir, targetName),\n adapterName: adapter.name,\n assetType,\n flattened: false,\n });\n }\n return out;\n}\n\n/* ────────────────────────── Naming helpers ──────────────────────────── */\n\nconst PATH_SEPARATOR_RE = /[\\\\/]/g;\n\nfunction applyRename(relPath: string, layout: AssetLayout, flatten: boolean): string {\n if (layout.rename) return layout.rename(relPath);\n\n let name = flatten ? relPath.replace(PATH_SEPARATOR_RE, '__') : relPath;\n if (layout.ext) {\n const ext = path.extname(name);\n name = ext ? name.slice(0, -ext.length) + layout.ext : name + layout.ext;\n }\n return name;\n}\n\n/* ────────────────────────── Filesystem walkers ──────────────────────── */\n\nasync function walkFiles(root: string): Promise<string[]> {\n const out: string[] = [];\n await (async function descend(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n // Hidden entries (`.gitkeep`, `.DS_Store`, etc.) are placeholder/system\n // files, never real assets. Mirrors `listFirstLevel` behaviour.\n if (entry.name.startsWith('.')) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n await descend(full);\n } else if (entry.isFile() || entry.isSymbolicLink()) {\n out.push(full);\n }\n }\n })(root);\n return out;\n}\n\nasync function listFirstLevel(root: string): Promise<readonly { name: string; isDir: boolean }[]> {\n const entries = await fs.readdir(root, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith('.'))\n .map((e) => ({ name: e.name, isDir: e.isDirectory() }));\n}\n\nasync function isDir(p: string): Promise<boolean> {\n const stat = await fs.stat(p).catch(() => null);\n return stat?.isDirectory() ?? false;\n}\n\n/* ────────────────────────── Glob matchers ───────────────────────────── */\n\n/**\n * `include` matcher: empty/missing list means \"everything passes\".\n */\nfunction makeIncludeMatcher(patterns: readonly string[] | undefined): (rel: string) => boolean {\n if (!patterns || patterns.length === 0) return () => true;\n const fns = patterns.map((p) => picomatch(p, { dot: true }));\n return (rel) => fns.some((fn) => fn(rel));\n}\n\n/**\n * `exclude` matcher: empty/missing list means \"nothing is excluded\".\n */\nfunction makeExcludeMatcher(patterns: readonly string[] | undefined): (rel: string) => boolean {\n if (!patterns || patterns.length === 0) return () => false;\n const fns = patterns.map((p) => picomatch(p, { dot: true }));\n return (rel) => fns.some((fn) => fn(rel));\n}\n\n/* ────────────────────────── Collision detection ─────────────────────── */\n\nfunction splitByCollision(plans: readonly LinkPlan[]): BuildResult {\n const byTarget = new Map<string, LinkPlan[]>();\n for (const plan of plans) {\n const bucket = byTarget.get(plan.target);\n if (bucket) bucket.push(plan);\n else byTarget.set(plan.target, [plan]);\n }\n\n const accepted: LinkPlan[] = [];\n const collisions: Conflict[] = [];\n for (const [target, bucket] of byTarget) {\n if (bucket.length === 1) {\n accepted.push(bucket[0]!);\n continue;\n }\n const head = bucket[0]!;\n collisions.push({\n target,\n sources: bucket.map((p) => p.source),\n adapterName: head.adapterName,\n assetType: head.assetType,\n });\n }\n return { plans: accepted, collisions };\n}\n","/**\n * `agentlink init` — interactively scaffold a `.agents/` directory and run\n * sync once so the user gets working symlinks immediately.\n *\n * Three knobs the user can tweak via prompts:\n * 1. **Target location** (only when neither `--local` nor `--source` is set):\n * `~/.agents` (recommended) vs `./.agents`.\n * 2. **Asset types** to include — multi-select; defaults to skills/rules/commands.\n * 3. **Adapters** to enable — multi-select; defaults to all three.\n *\n * Non-interactive degrade rules:\n * - `--yes / -y` ⇒ everything defaults, no prompts\n * - stdin not a TTY ⇒ same (suitable for CI / piping)\n * - any flag that already answers a question ⇒ skip that prompt\n *\n * Refuses to clobber a non-empty target unless `--force`.\n */\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\nimport prompts from 'prompts';\n\nimport { adapterRegistry, type AdapterName } from '../adapters/index.js';\nimport { AgentlinkError } from '../core/errors.js';\nimport { runSync } from './sync.js';\nimport type { CommandFlags } from './_shared.js';\n\nexport interface InitFlags extends CommandFlags {\n local?: boolean;\n yes?: boolean;\n}\n\nexport class InitTargetExistsError extends AgentlinkError {\n constructor(targetPath: string) {\n super(`refusing to scaffold into a non-empty directory: ${targetPath}\\n use --force to merge into the existing files`);\n }\n}\n\nconst ALL_ASSET_TYPES = ['skills', 'rules', 'commands', 'prompts', 'templates', 'agents'] as const;\nconst DEFAULT_ASSET_TYPES = ['skills', 'rules', 'commands'] as const;\nconst ALL_ADAPTER_NAMES = Object.keys(adapterRegistry) as AdapterName[];\n\nconst HERE = path.dirname(fileURLToPath(import.meta.url));\nconst TEMPLATE_CANDIDATES = [\n path.resolve(HERE, '..', 'templates', 'v1'),\n path.resolve(HERE, '..', '..', 'templates', 'v1'),\n];\n\nasync function findTemplatesDir(): Promise<string> {\n for (const candidate of TEMPLATE_CANDIDATES) {\n const stat = await fs.stat(candidate).catch(() => null);\n if (stat?.isDirectory()) return candidate;\n }\n throw new AgentlinkError(\n `agentlink templates dir not found; searched:\\n ${TEMPLATE_CANDIDATES.join('\\n ')}`,\n );\n}\n\ninterface InitAnswers {\n /** Where the source `.agents/` directory is created. */\n target: string;\n targetCategory: 'home' | 'cwd' | 'custom';\n /** Where the `agentlink.config.json` is written (independent of source). */\n configPath: string;\n configCategory: 'home' | 'cwd';\n include: readonly string[];\n adapters: readonly AdapterName[];\n}\n\nexport async function runInit(flags: InitFlags = {}): Promise<void> {\n const answers = await collectAnswers(flags);\n\n if (!flags.quiet) {\n console.log('');\n console.log(pc.bold('[agentlink] init'));\n console.log(` target: ${answers.target}`);\n console.log('');\n }\n\n const created = await scaffoldInto(answers, {\n force: flags.force ?? false,\n quiet: flags.quiet ?? false,\n dryRun: flags.dryRun ?? false,\n });\n if (!created.touched && !flags.quiet) {\n console.log(pc.dim(' no files written; .agents/ already populated'));\n }\n\n if (answers.targetCategory === 'custom' && !flags.quiet) {\n printNonDefaultLocationHint(answers.target);\n }\n\n if (!flags.quiet) console.log('');\n\n // In dry-run mode the source directory was never actually created, so a\n // follow-up sync would just throw on resolveSource. Tell the user what\n // a real run would have done and exit cleanly instead.\n if (flags.dryRun) {\n if (!flags.quiet) {\n console.log(\n pc.dim(\n ` (dry-run) would run \\`agentlink sync\\` against ${answers.target} after scaffolding`,\n ),\n );\n }\n return;\n }\n\n // Best-effort follow-up sync so the user gets immediate symlinks if they\n // already have `.cursor` / `.claude` / `.codebuddy` in cwd. The adapter\n // gate makes this a no-op when none exist.\n await runSync({\n source: answers.target,\n ...(flags.target !== undefined ? { target: flags.target } : {}),\n ...(flags.user !== undefined ? { user: flags.user } : {}),\n ...(flags.quiet !== undefined ? { quiet: flags.quiet } : {}),\n });\n}\n\n/* ────────────────────────── Prompt orchestration ─────────────────────── */\n\nasync function collectAnswers(flags: InitFlags): Promise<InitAnswers> {\n const skipPrompts = flags.yes || !process.stdin.isTTY;\n\n // 1) Target location\n let target: string;\n let targetCategory: InitAnswers['targetCategory'];\n if (flags.source !== undefined && flags.source !== '') {\n target = path.resolve(expandTilde(flags.source));\n targetCategory = categorizeTarget(target);\n } else if (flags.local) {\n target = path.resolve(process.cwd(), '.agents');\n targetCategory = 'cwd';\n } else if (skipPrompts) {\n target = path.resolve(os.homedir(), '.agents');\n targetCategory = 'home';\n } else {\n const choice = await ask<{ kind: 'home' | 'cwd' }>({\n type: 'select',\n name: 'kind',\n message: 'Where should agentlink put your .agents/ directory?',\n choices: [\n {\n title: 'Personal global (~/.agents)',\n description: 'Recommended — share assets across every project',\n value: 'home',\n },\n {\n title: 'Repo-local (./.agents)',\n description: 'Ship a curated .agents/ inside this repository',\n value: 'cwd',\n },\n ],\n initial: 0,\n });\n target =\n choice.kind === 'home'\n ? path.resolve(os.homedir(), '.agents')\n : path.resolve(process.cwd(), '.agents');\n targetCategory = choice.kind;\n }\n\n // 2) Asset types\n let include: readonly string[];\n if (skipPrompts) {\n include = DEFAULT_ASSET_TYPES;\n } else {\n const { values } = await ask<{ values: string[] }>({\n type: 'multiselect',\n name: 'values',\n message: 'Which asset types do you want to manage?',\n hint: 'space to toggle, enter to confirm',\n choices: ALL_ASSET_TYPES.map((name) => ({\n title: name,\n value: name,\n selected: (DEFAULT_ASSET_TYPES as readonly string[]).includes(name),\n })),\n min: 1,\n instructions: false,\n });\n include = values;\n }\n\n // 3) Adapters\n let adapters: readonly AdapterName[];\n if (skipPrompts) {\n adapters = ALL_ADAPTER_NAMES;\n } else {\n const { values } = await ask<{ values: AdapterName[] }>({\n type: 'multiselect',\n name: 'values',\n message: 'Which AI agents do you want to target?',\n hint: 'space to toggle, enter to confirm',\n choices: ALL_ADAPTER_NAMES.map((name) => ({\n title: name,\n value: name,\n selected: true,\n })),\n min: 1,\n instructions: false,\n });\n adapters = values;\n }\n\n // Decide where the config file lands. Config is decoupled from source —\n // whichever location a future `agentlink sync` is most likely to run from.\n const configCategory: InitAnswers['configCategory'] =\n targetCategory === 'cwd' ? 'cwd' : 'home';\n const configPath =\n configCategory === 'home'\n ? path.resolve(os.homedir(), 'agentlink.config.json')\n : path.resolve(process.cwd(), 'agentlink.config.json');\n\n return { target, targetCategory, configPath, configCategory, include, adapters };\n}\n\n/**\n * Wrapper that turns user-cancellation (Ctrl-C) into a thrown error rather\n * than letting `prompts` resolve with `{}` and silently producing an empty\n * config.\n */\nasync function ask<T extends Record<string, unknown>>(\n question: prompts.PromptObject,\n): Promise<T> {\n let cancelled = false;\n const answer = await prompts(question, {\n onCancel: () => {\n cancelled = true;\n return false;\n },\n });\n if (cancelled) throw new AgentlinkError('init cancelled');\n return answer as T;\n}\n\nfunction categorizeTarget(target: string): InitAnswers['targetCategory'] {\n const home = path.resolve(os.homedir(), '.agents');\n const cwd = path.resolve(process.cwd(), '.agents');\n if (target === home) return 'home';\n if (target === cwd) return 'cwd';\n return 'custom';\n}\n\nfunction expandTilde(p: string): string {\n if (p === '~') return os.homedir();\n if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));\n return p;\n}\n\n/* ────────────────────────── Scaffolding ─────────────────────────────── */\n\ninterface ScaffoldResult {\n touched: boolean;\n}\n\ninterface ScaffoldOptions {\n force: boolean;\n quiet: boolean;\n /** When true: probe and report what would happen, never touch the filesystem. */\n dryRun: boolean;\n}\n\nasync function scaffoldInto(\n answers: InitAnswers,\n options: ScaffoldOptions,\n): Promise<ScaffoldResult> {\n const { force, quiet, dryRun } = options;\n const target = answers.target;\n const stat = await fs.stat(target).catch(() => null);\n if (stat && !stat.isDirectory()) {\n throw new AgentlinkError(`init target exists but is not a directory: ${target}`);\n }\n\n if (stat && !force) {\n const entries = await fs.readdir(target);\n if (entries.length > 0) throw new InitTargetExistsError(target);\n }\n\n if (!dryRun) {\n await fs.mkdir(target, { recursive: true });\n } else if (!stat && !quiet) {\n console.log(`${pc.dim('[DRY]')} would create ${target}/`);\n }\n\n const templatesDir = await findTemplatesDir();\n\n let written = 0;\n written += await copyStaticAssets(templatesDir, target, answers.include, quiet, dryRun);\n written += await writeConfigFile(answers, quiet, dryRun);\n return { touched: written > 0 };\n}\n\n/**\n * Copy README and `.gitkeep` placeholders for each user-selected asset type.\n * The config file is rendered separately by `writeConfigFile` because its\n * contents depend on the user's answers.\n */\nasync function copyStaticAssets(\n templatesDir: string,\n target: string,\n include: readonly string[],\n quiet: boolean,\n dryRun: boolean,\n): Promise<number> {\n let written = 0;\n\n // README — copy as-is if not already present.\n const readmeSrc = path.join(templatesDir, 'README.md');\n const readmeDest = path.join(target, 'README.md');\n if ((await fs.stat(readmeSrc).catch(() => null)) && !(await fs.stat(readmeDest).catch(() => null))) {\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${readmeDest}`);\n } else {\n await fs.copyFile(readmeSrc, readmeDest);\n if (!quiet) console.log(`${pc.green('[NEW]')} ${readmeDest}`);\n }\n written++;\n }\n\n // Per-asset-type empty directories with a placeholder so they survive `git add`.\n for (const assetType of include) {\n const dir = path.join(target, assetType);\n const keep = path.join(dir, '.gitkeep');\n const keepExists = await fs.stat(keep).catch(() => null);\n if (keepExists) continue;\n\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${keep}`);\n } else {\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(keep, '');\n if (!quiet) console.log(`${pc.green('[NEW]')} ${keep}`);\n }\n written++;\n }\n\n return written;\n}\n\nasync function writeConfigFile(\n answers: InitAnswers,\n quiet: boolean,\n dryRun: boolean,\n): Promise<number> {\n const configPath = answers.configPath;\n if (await fs.stat(configPath).catch(() => null)) {\n if (!quiet) console.log(`${pc.cyan('[SKIP]')} ${configPath} (already exists)`);\n return 0;\n }\n if (dryRun) {\n if (!quiet) console.log(`${pc.dim('[DRY]')} would create ${configPath}`);\n return 1;\n }\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n await fs.writeFile(configPath, renderConfig(answers), 'utf8');\n if (!quiet) console.log(`${pc.green('[NEW]')} ${configPath}`);\n return 1;\n}\n\n/**\n * Pick a portable `source` value for config: prefer a path relative to the\n * config file; otherwise `~/…` when under home; fall back to absolute.\n */\nexport function formatSourceForConfig(target: string, configPath: string): string {\n const resolved = path.resolve(target);\n const configDir = path.resolve(path.dirname(configPath));\n const home = path.resolve(os.homedir());\n const rel = path.relative(configDir, resolved);\n if (rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel)) {\n return rel;\n }\n if (resolved === home || resolved.startsWith(home + path.sep)) {\n const tail = path.relative(home, resolved);\n return tail === '' ? '~' : `~/${tail}`;\n }\n return resolved;\n}\n\n/**\n * Render `agentlink.config.json` as JSONC with explanatory comments. We hand-\n * format this rather than `JSON.stringify`-ing because the comments are the\n * whole point — users learn the schema by reading the seed file.\n */\nexport function renderConfig(answers: InitAnswers): string {\n const includeJson = JSON.stringify(answers.include);\n const adapterLines = ALL_ADAPTER_NAMES.map((name) => {\n const value = answers.adapters.includes(name) ? 'true' : 'false';\n return ` \"${name}\": ${value}`;\n }).join(',\\n');\n const sourceBlock =\n answers.targetCategory === 'custom'\n ? ` // Persistent default for \\`agentlink sync\\` (relative paths resolve from this file).\n \"source\": ${JSON.stringify(formatSourceForConfig(answers.target, answers.configPath))},\n\n`\n : '';\n\n return `{\n${sourceBlock} // Asset type allowlist. Default: [\"skills\", \"rules\", \"commands\"].\n // Add \"prompts\", \"templates\" or \"agents\" here to opt them in.\n \"include\": ${includeJson},\n\n // Asset type denylist (always wins over \\`include\\`).\n \"exclude\": [],\n\n // Per-adapter overrides. Each value can be:\n // - true : enable with built-in defaults\n // - false : disable even if its rootDir exists\n // - { \"layout\": { … } } : enable + override specific asset layouts\n //\n // Example: keep cursor commands nested instead of flattened\n // \"cursor\": { \"layout\": { \"commands\": { \"flatten\": false } } }\n \"adapters\": {\n${adapterLines}\n }\n}\n`;\n}\n\n/* ────────────────────────── Hints ───────────────────────────────────── */\n\nfunction printNonDefaultLocationHint(target: string): void {\n console.log('');\n console.log(pc.bold('Tip — your source is at a non-default location:'));\n console.log(` ${target}`);\n console.log('');\n console.log('Future invocations of `agentlink sync` will read `source` from your');\n console.log('`agentlink.config.json` (written during init). You can also:');\n console.log(` - pass ${pc.cyan(`--source ${target}`)} to override, or`);\n console.log(` - symlink it: ${pc.cyan(`ln -s ${target} ~/.agents`)}`);\n}\n","import path from 'node:path';\nimport pc from 'picocolors';\n\nimport { buildLinkPlans, type Conflict } from '../core/layout.js';\nimport { applyPlans, findStaleLinks, removeLinks, type LinkOutcome } from '../core/linker.js';\nimport { AgentlinkError } from '../core/errors.js';\nimport {\n enumerateTargetDirs,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport class StrictModeViolation extends AgentlinkError {\n constructor(public readonly conflicts: readonly Conflict[]) {\n super(`${conflicts.length} link target collision(s) under --strict`);\n }\n}\n\nexport async function runSync(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'sync', flags);\n\n const { plans, collisions } = await buildLinkPlans({\n source: ctx.paths.source,\n destRoot: ctx.paths.destRoot,\n config: ctx.config,\n });\n\n if (collisions.length > 0) {\n reportCollisions(collisions, flags.quiet ?? false);\n if (flags.strict) {\n throw new StrictModeViolation(collisions);\n }\n }\n\n const outcomes = await applyPlans(plans, {\n ...(flags.dryRun !== undefined ? { dryRun: flags.dryRun } : {}),\n ...(flags.force !== undefined ? { force: flags.force } : {}),\n });\n\n // Sweep up dangling links left from previous syncs whose source files were\n // deleted. Mirrors the legacy init.sh behaviour where every run also cleans.\n const targetDirs = enumerateTargetDirs(ctx).map((t) => t.targetDir);\n const stale = (await Promise.all(targetDirs.map(findStaleLinks))).flat();\n const removed = await removeLinks(stale, flags.dryRun ? { dryRun: true } : {});\n\n reportOutcomes(outcomes, ctx.paths.destRoot, flags.quiet ?? false);\n reportRemovals(removed, flags.quiet ?? false);\n printSummary(outcomes, removed, collisions);\n\n // Any individual link operation that errored should fail the whole run so\n // CI / pre-commit hooks can detect a partially-broken sync. Conflicts are\n // already either warned (default) or thrown (via --strict above), so we\n // only consider link-level failures here.\n const errored =\n outcomes.filter((o) => o.status === 'errored').length +\n removed.filter((r) => r.status === 'errored').length;\n if (errored > 0) process.exitCode = 1;\n}\n\n/* ────────────────────────── Reporting helpers ────────────────────────── */\n\nfunction reportCollisions(collisions: readonly Conflict[], quiet: boolean): void {\n if (quiet) return;\n for (const c of collisions) {\n console.warn(\n pc.yellow(`[WARN] target collision under ${c.adapterName}/${c.assetType}: ${c.target}`),\n );\n for (const s of c.sources) console.warn(pc.dim(` source: ${s}`));\n }\n}\n\nfunction reportOutcomes(\n outcomes: readonly LinkOutcome[],\n destRoot: string,\n quiet: boolean,\n): void {\n for (const o of outcomes) {\n const display = path.relative(destRoot, o.plan.target);\n switch (o.status) {\n case 'created':\n if (!quiet) console.log(`${pc.green('[OK]')} ${display}`);\n break;\n case 'fixed':\n console.log(`${pc.green('[FIX]')} ${display} ${pc.dim(`(${o.message})`)}`);\n break;\n case 'skipped':\n if (!quiet) console.log(`${pc.cyan('[SKIP]')} ${display}`);\n break;\n case 'warned':\n console.warn(`${pc.yellow('[WARN]')} ${display} ${pc.dim(`(${o.message ?? ''})`)}`);\n break;\n case 'errored':\n console.error(`${pc.red('[ERR]')} ${display} ${pc.dim(`(${o.message ?? ''})`)}`);\n break;\n case 'dry-create':\n if (!quiet) console.log(`${pc.dim('[DRY]')} ${display}`);\n break;\n case 'dry-fix':\n console.log(`${pc.dim('[DRY]')} ${display} ${pc.dim(`(would fix: ${o.message})`)}`);\n break;\n }\n }\n}\n\nfunction reportRemovals(\n removals: readonly { path: string; status: string; message?: string }[],\n quiet: boolean,\n): void {\n for (const r of removals) {\n if (r.status === 'removed' && !quiet) {\n console.log(`${pc.yellow('[CLEAN]')} ${r.path}`);\n } else if (r.status === 'dry-remove' && !quiet) {\n console.log(`${pc.dim('[DRY]')} would clean ${r.path}`);\n } else if (r.status === 'errored') {\n console.error(`${pc.red('[ERR]')} ${r.path} ${pc.dim(`(${r.message ?? ''})`)}`);\n }\n }\n}\n\nfunction printSummary(\n outcomes: readonly LinkOutcome[],\n removals: readonly { status: string }[],\n collisions: readonly Conflict[],\n): void {\n const counts: Record<string, number> = {};\n for (const o of outcomes) counts[o.status] = (counts[o.status] ?? 0) + 1;\n const cleaned = removals.filter((r) => r.status === 'removed' || r.status === 'dry-remove').length;\n\n const parts: string[] = [];\n if (counts['created']) parts.push(pc.green(`${counts['created']} created`));\n if (counts['fixed']) parts.push(pc.green(`${counts['fixed']} fixed`));\n if (counts['skipped']) parts.push(pc.cyan(`${counts['skipped']} skipped`));\n if (counts['warned']) parts.push(pc.yellow(`${counts['warned']} warned`));\n if (counts['errored']) parts.push(pc.red(`${counts['errored']} errored`));\n if (counts['dry-create'] || counts['dry-fix']) {\n parts.push(pc.dim(`${(counts['dry-create'] ?? 0) + (counts['dry-fix'] ?? 0)} dry-run`));\n }\n if (cleaned) parts.push(pc.yellow(`${cleaned} cleaned`));\n if (collisions.length) parts.push(pc.yellow(`${collisions.length} collision(s)`));\n\n console.log('');\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n}\n","import pc from 'picocolors';\n\nimport { findManagedLinks, pruneEmptyDirs, removeLinks } from '../core/linker.js';\nimport {\n enumerateAllAdapterRoots,\n loadContext,\n printHeader,\n type CommandFlags,\n} from './_shared.js';\n\nexport async function runUnlink(flags: CommandFlags = {}): Promise<void> {\n const ctx = await loadContext(flags);\n printHeader(ctx, 'unlink', flags);\n\n // `unlink` must be a \"remove everything we ever wrote\" operation. Walk\n // *all* built-in adapter rootDirs that exist under destRoot — not only\n // the ones currently enabled by config — and recurse into each so we\n // also catch links living in asset subdirs that the current `include`\n // list no longer mentions. Otherwise users who disabled an adapter or\n // narrowed `include` would leave orphan symlinks behind.\n const roots = await enumerateAllAdapterRoots(ctx.paths.destRoot);\n const sourceRoot = ctx.paths.source;\n\n const owned = (\n await Promise.all(\n roots.map(({ rootDir }) => findManagedLinks(rootDir, sourceRoot, { recursive: true })),\n )\n ).flat();\n\n if (owned.length === 0) {\n console.log(pc.dim(' no agentlink-managed links found'));\n return;\n }\n\n const outcomes = await removeLinks(owned, flags.dryRun ? { dryRun: true } : {});\n\n let removed = 0;\n let dry = 0;\n let errored = 0;\n for (const o of outcomes) {\n if (o.status === 'removed') {\n removed++;\n if (!flags.quiet) console.log(`${pc.yellow('[UNLINK]')} ${o.path}`);\n } else if (o.status === 'dry-remove') {\n dry++;\n if (!flags.quiet) console.log(`${pc.dim('[DRY]')} would remove ${o.path}`);\n } else if (o.status === 'errored') {\n errored++;\n console.error(`${pc.red('[ERR]')} ${o.path} ${pc.dim(`(${o.message ?? ''})`)}`);\n }\n }\n\n // Best-effort: prune now-empty adapter rootDirs. `pruneEmptyDirs` is silent\n // on non-empty / missing dirs, so we don't bother filtering.\n if (!flags.dryRun) {\n await pruneEmptyDirs(roots.map((r) => r.rootDir));\n }\n\n console.log('');\n const parts: string[] = [];\n if (removed) parts.push(pc.yellow(`${removed} removed`));\n if (dry) parts.push(pc.dim(`${dry} dry-run`));\n if (errored) parts.push(pc.red(`${errored} errored`));\n console.log(parts.length === 0 ? pc.dim(' no changes') : ` ${parts.join(', ')}`);\n\n if (errored > 0) process.exitCode = 1;\n}\n"],"mappings":";AAAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,EACX,QAAU;AAAA,EACV,UAAY;AAAA,EACZ,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,EACR,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,KAAO;AAAA,IACL,WAAa;AAAA,EACf;AAAA,EACA,MAAQ;AAAA,EACR,QAAU;AAAA,EACV,OAAS;AAAA,EACT,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,QAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAa;AAAA,IACb,YAAc;AAAA,IACd,gBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,EACpB;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AAAA,EACA,cAAgB;AAAA,IACd,KAAO;AAAA,IACP,YAAc;AAAA,IACd,WAAa;AAAA,IACb,SAAW;AAAA,IACX,uBAAuB;AAAA,IACvB,KAAO;AAAA,EACT;AAAA,EACA,iBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,QAAU;AAAA,EACZ;AACF;;;AC/EA,SAAS,WAAW;AACpB,OAAOA,SAAQ;;;ACHf,OAAOC,SAAQ;;;ACef,SAAS,YAAY,UAAU;AAC/B,OAAO,UAAU;AA8BjB,eAAsB,WACpB,OACA,UAAwB,CAAC,GACD;AACxB,QAAM,WAA0B,CAAC;AACjC,aAAW,QAAQ,OAAO;AACxB,aAAS,KAAK,MAAM,SAAS,MAAM,OAAO,CAAC;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,eAAe,SAAS,MAAgB,SAA6C;AACnF,QAAM,EAAE,SAAS,OAAO,QAAQ,MAAM,IAAI;AAC1C,QAAM,YAAY,KAAK,QAAQ,KAAK,MAAM;AAC1C,QAAM,WAAW,KAAK,SAAS,WAAW,KAAK,MAAM;AAErD,MAAI;AACF,UAAM,QAAQ,MAAM,GAAG,MAAM,KAAK,MAAM,EAAE,MAAM,MAAM,IAAI;AAE1D,QAAI,OAAO,eAAe,GAAG;AAC3B,YAAM,UAAU,MAAM,GAAG,SAAS,KAAK,MAAM;AAC7C,UAAI,YAAY,SAAU,QAAO,EAAE,MAAM,QAAQ,UAAU;AAC3D,UAAI,OAAO;AACT,YAAI,QAAQ;AACV,iBAAO,EAAE,MAAM,QAAQ,WAAW,SAAS,GAAG,OAAO,OAAO,QAAQ,GAAG;AAAA,QACzE;AACA,cAAM,GAAG,OAAO,KAAK,MAAM;AAC3B,cAAM,GAAG,QAAQ,UAAU,KAAK,MAAM;AACtC,eAAO,EAAE,MAAM,QAAQ,SAAS,SAAS,GAAG,OAAO,OAAO,QAAQ,GAAG;AAAA,MACvE;AACA,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,QACR,SAAS,aAAa,OAAO;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI,OAAO;AACT,YAAM,OAAO,MAAM,YAAY,IAAI,cAAc;AACjD,aAAO,EAAE,MAAM,QAAQ,UAAU,SAAS,GAAG,IAAI,4BAA4B;AAAA,IAC/E;AAEA,QAAI,QAAQ;AACV,aAAO,EAAE,MAAM,QAAQ,aAAa;AAAA,IACtC;AAEA,UAAM,GAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,GAAG,QAAQ,UAAU,KAAK,MAAM;AACtC,WAAO,EAAE,MAAM,QAAQ,UAAU;AAAA,EACnC,SAAS,KAAK;AACZ,WAAO,EAAE,MAAM,QAAQ,WAAW,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,EAC9F;AACF;AAYA,eAAsB,eAAe,WAAsC;AACzE,QAAM,UAAU,MAAM,GAAG,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AACrF,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,eAAe,EAAG;AAC7B,UAAM,OAAO,KAAK,KAAK,WAAW,MAAM,IAAI;AAC5C,UAAM,SAAS,MAAM,GAAG,KAAK,IAAI,EAAE,MAAM,MAAM,IAAI;AACnD,QAAI,CAAC,OAAQ,OAAM,KAAK,IAAI;AAAA,EAC9B;AACA,SAAO;AACT;AAiBA,eAAsB,iBACpB,WACA,YACA,UAAmC,CAAC,GACjB;AACnB,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,QAAM,MAAgB,CAAC;AAEvB,SAAO,eAAe,QAAQ,KAA4B;AACxD,UAAM,UAAU,MAAM,GAAG,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AAC/E,QAAI,CAAC,QAAS;AACd,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;AACtC,UAAI,MAAM,eAAe,GAAG;AAC1B,cAAM,MAAM,MAAM,GAAG,SAAS,IAAI,EAAE,MAAM,MAAM,IAAI;AACpD,YAAI,CAAC,IAAK;AACV,cAAM,WAAW,KAAK,WAAW,GAAG,IAAI,KAAK,UAAU,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACnF,YAAI,aAAa,aAAa,SAAS,WAAW,YAAY,KAAK,GAAG,GAAG;AACvE,cAAI,KAAK,IAAI;AAAA,QACf;AAAA,MACF,WAAW,QAAQ,aAAa,MAAM,YAAY,GAAG;AACnD,cAAM,QAAQ,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF,GAAG,SAAS;AAEZ,SAAO;AACT;AAoBA,eAAsB,YACpB,OACA,UAAyB,CAAC,GACC;AAC3B,QAAM,EAAE,SAAS,MAAM,IAAI;AAC3B,QAAM,MAAwB,CAAC;AAC/B,aAAW,KAAK,OAAO;AACrB,QAAI,QAAQ;AACV,UAAI,KAAK,EAAE,MAAM,GAAG,QAAQ,aAAa,CAAC;AAC1C;AAAA,IACF;AACA,QAAI;AACF,YAAM,GAAG,OAAO,CAAC;AACjB,UAAI,KAAK,EAAE,MAAM,GAAG,QAAQ,UAAU,CAAC;AAAA,IACzC,SAAS,KAAK;AACZ,UAAI,KAAK;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAOA,eAAsB,eAAe,MAAwC;AAC3E,aAAW,OAAO,MAAM;AACtB,UAAM,GAAG,MAAM,GAAG,EAAE,MAAM,MAAM,MAAS;AAAA,EAC3C;AACF;;;ACpNA,SAAS,YAAYC,WAAU;AAC/B,OAAOC,WAAU;AACjB,OAAO,QAAQ;;;ACJR,IAAM,SAAkB;AAAA,EAC7B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,QAAQ,EAAE,cAAc,SAAS;AAAA,IACjC,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,UAAU,EAAE,cAAc,WAAW;AAAA,EACvC;AACF;;;ACPO,IAAM,YAAqB;AAAA,EAChC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,QAAQ,EAAE,cAAc,SAAS;AAAA,IACjC,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,UAAU,EAAE,cAAc,WAAW;AAAA,EACvC;AACF;;;ACNO,IAAM,SAAkB;AAAA,EAC7B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,QAAQ,EAAE,cAAc,SAAS;AAAA,IACjC,OAAO,EAAE,cAAc,SAAS,SAAS,MAAM,KAAK,OAAO;AAAA,IAC3D,UAAU,EAAE,cAAc,YAAY,SAAS,KAAK;AAAA,IACpD,SAAS;AAAA,EACX;AACF;;;ACRO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF;;;ACUA,SAAS,YAAYC,WAAU;AAC/B,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,uBAAuB;AAC9B,SAAS,SAAS;;;ACpBX,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AAAA,EACzB;AACF;AAOO,IAAM,sBAAN,cAAkC,eAAe;AAAA,EAC7C;AAAA,EAET,YAAY,UAA6D;AACvE,UAAM,oCAAoC;AAC1C,SAAK,WAAW;AAAA,EAClB;AACF;AAOO,IAAM,mBAAN,MAAM,0BAAyB,eAAe;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAAc,GAAW,QAAsD;AACzF,UAAM,kBAAiB,QAAQ,MAAM,GAAG,MAAM,CAAC;AAC/C,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAe,QACb,MACA,GACA,QACQ;AACR,QAAI,WAAW,UAAW,QAAO,GAAG,IAAI,oBAAoB,CAAC;AAC7D,QAAI,WAAW,kBAAmB,QAAO,GAAG,IAAI,wBAAwB,CAAC;AACzE,WAAO,GAAG,IAAI,mBAAmB,CAAC;AAAA,EACpC;AACF;AAGO,IAAM,gBAAN,cAA4B,eAAe;AAAC;;;ACwD5C,IAAM,kBAAkB,CAAC,UAAU,SAAS,UAAU;;;AF1EtD,IAAM,kBAAkB;AAE/B,IAAM,oBAAoB,CAAC,UAAU,SAAS,YAAY,WAAW,aAAa,QAAQ;AAC1F,IAAM,iBAAyC,IAAI,IAAI,iBAAiB;AAExE,IAAM,kBAAkB,EAAE,KAAK,iBAAiB;AAWhD,IAAM,qBAAqB,EACxB,OAAO,EACP,IAAI,CAAC,EACL,OAAO,CAAC,MAAM,CAACC,MAAK,WAAW,CAAC,GAAG;AAAA,EAClC,SAAS;AACX,CAAC,EACA,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,OAAO,EAAE,KAAK,CAAC,QAAQ,QAAQ,IAAI,GAAG;AAAA,EAC5D,SAAS;AACX,CAAC;AAEH,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACjC,cAAc,mBAAmB,SAAS;AAAA,EAC1C,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC9B,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,EAC7C,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,EAC7C,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAClC,CAAC;AAED,IAAM,wBAAwB,EAAE,MAAM;AAAA,EACpC,EAAE,QAAQ;AAAA,EACV,EACG,OAAO;AAAA;AAAA;AAAA,IAGN,QAAQ,EAAE,cAAc,iBAAiB,iBAAiB,EAAE,SAAS;AAAA,EACvE,CAAC,EACA,OAAO;AACZ,CAAC;AAED,IAAM,oBAAoB,EAAE;AAAA,EAC1B,OAAO,KAAK,eAAe;AAC7B;AAEA,IAAM,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC;AAMvC,IAAM,eAAe,EAClB,OAAO;AAAA,EACN,QAAQ,eAAe,SAAS;AAAA,EAChC,QAAQ,eAAe,SAAS;AAAA,EAChC,MAAM,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC3B,SAAS,EAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EAC3C,SAAS,EAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EAC3C,UAAU,EAAE,cAAc,mBAAmB,qBAAqB,EAAE,SAAS;AAC/E,CAAC,EACA,OAAO,EACP,YAAY,CAAC,KAAK,QAAQ;AACzB,MAAI,IAAI,WAAW,UAAa,IAAI,SAAS,MAAM;AACjD,QAAI,SAAS;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,CAAC,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AACF,CAAC;AAII,IAAM,mBAAN,cAA+B,eAAe;AAAA,EAC1C;AAAA,EAET,YAAY,UAAkB,QAA0D;AACtF,UAAM,QAAQ,OAAO,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,OAAO,EAAE;AACtF,UAAM,+BAA+B,QAAQ;AAAA,EAAK,MAAM,KAAK,IAAI,CAAC,EAAE;AACpE,SAAK,SAAS;AAAA,EAChB;AACF;AAmCA,eAAsB,iBAAiB,OAA6B,CAAC,GAA0B;AAC7F,QAAM,WAAW,MAAM,kBAAkB,IAAI;AAC7C,QAAM,SAAS,SAAS,OAAO,MAAM,eAAe,SAAS,IAAI,IAAK,CAAC;AACvE,QAAM,aAAa,SAAS,OAAOA,MAAK,QAAQ,SAAS,IAAI,IAAI;AACjE,SAAO,EAAE,UAAU,QAAQ,WAAW;AACxC;AAMO,SAAS,wBACd,YACA,UACA,QACgB;AAChB,QAAM,WAAW,cAAc,WAAW,QAAQ;AAClD,QAAM,aAAa,kBAAkB,WAAW,SAAS,WAAW,OAAO;AAE3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,SAAS;AAAA,IACrB,cAAc,SAAS;AAAA,EACzB;AACF;AAeA,eAAsB,kBAAkB,OAA6B,CAAC,GAA4B;AAChG,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,QAAM,OAAO,KAAK,QAAQ,GAAG,QAAQ;AAErC,MAAI,KAAK,WAAW,UAAa,KAAK,WAAW,IAAI;AACnD,UAAM,MAAM,MAAM,iBAAiB,YAAY,KAAK,QAAQ,IAAI,GAAG,YAAY,GAAG;AAClF,WAAO,EAAE,MAAM,KAAK,QAAQ,OAAO;AAAA,EACrC;AAEA,QAAM,WAAW,MAAM,gBAAgBC,MAAK,QAAQ,GAAG,GAAG,IAAI;AAC9D,MAAI,UAAU;AACZ,WAAO,EAAE,MAAM,UAAU,QAAQ,eAAe;AAAA,EAClD;AAEA,QAAM,aAAaA,MAAK,KAAK,MAAM,eAAe;AAClD,MAAI,MAAM,OAAO,UAAU,GAAG;AAC5B,WAAO,EAAE,MAAM,YAAY,QAAQ,cAAc;AAAA,EACnD;AAEA,SAAO,EAAE,MAAM,MAAM,QAAQ,WAAW;AAC1C;AAOA,eAAe,gBAAgB,OAAe,MAAsC;AAClF,QAAM,UAAUA,MAAK,QAAQ,IAAI;AACjC,MAAI,UAAU;AACd,SAAO,MAAM;AACX,QAAI,YAAY,SAAS;AAGvB,aAAO;AAAA,IACT;AAEA,UAAM,YAAYA,MAAK,KAAK,SAAS,eAAe;AACpD,QAAI,MAAM,OAAO,SAAS,EAAG,QAAO;AAEpC,UAAM,SAASA,MAAK,QAAQ,OAAO;AACnC,QAAI,WAAW,QAAS,QAAO;AAI/B,QAAI,SAAS,SAAS,OAAO,KAAK,CAAC,SAAS,QAAQ,OAAO,KAAK,WAAW,SAAS;AAClF,aAAO;AAAA,IACT;AACA,cAAU;AAAA,EACZ;AACF;AAEA,eAAe,iBAAiB,OAAe,MAAc,KAA8B;AACzF,QAAM,MAAMA,MAAK,WAAW,KAAK,IAAI,QAAQA,MAAK,QAAQ,KAAK,KAAK;AACpE,QAAM,OAAO,MAAMC,IAAG,KAAK,GAAG,EAAE,MAAM,MAAM,IAAI;AAChD,MAAI,CAAC,KAAM,OAAM,IAAI,iBAAiB,MAAM,KAAK,SAAS;AAC1D,MAAI,CAAC,KAAK,OAAO,EAAG,OAAM,IAAI,iBAAiB,MAAM,KAAK,YAAY;AACtE,SAAO;AACT;AAEA,eAAe,OAAO,GAA6B;AACjD,QAAM,OAAO,MAAMA,IAAG,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AAC9C,SAAO,MAAM,OAAO,KAAK;AAC3B;AAEA,SAAS,YAAY,GAAW,MAAsB;AACpD,MAAI,MAAM,IAAK,QAAO;AACtB,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOD,MAAK,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,SAAO;AACT;AAEA,SAAS,SAAS,OAAe,QAAyB;AACxD,QAAM,IAAIA,MAAK,QAAQ,KAAK;AAC5B,QAAM,IAAIA,MAAK,QAAQ,MAAM;AAC7B,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,MAAMA,MAAK,SAAS,GAAG,CAAC;AAC9B,SAAO,QAAQ,MAAM,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,MAAK,WAAW,GAAG;AACpE;AAcA,eAAsB,qBACpB,YAC8B;AAC9B,MAAI,CAAC,WAAY,QAAO,oBAAI,IAAI;AAChC,QAAM,MAAM,MAAMC,IAAG,SAAS,YAAY,MAAM,EAAE,MAAM,MAAM,IAAI;AAClE,MAAI,QAAQ,KAAM,QAAO,oBAAI,IAAI;AACjC,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,kBAAkB,KAAK,EAAE,gBAAgB,KAAK,CAAC,CAAC;AAG1E,QAAI,CAAC,OAAO,SAAU,QAAO,oBAAI,IAAI;AACrC,WAAO,IAAI,IAAI,OAAO,KAAK,OAAO,QAAQ,EAAE,OAAO,CAAC,MAAM,OAAO,WAAW,CAAC,MAAM,KAAK,CAAC;AAAA,EAC3F,QAAQ;AACN,WAAO,oBAAI,IAAI;AAAA,EACjB;AACF;AAEA,eAAe,eAAe,UAAyC;AACrE,QAAM,MAAM,MAAMA,IAAG,SAAS,UAAU,MAAM,EAAE,MAAM,CAAC,QAA+B;AACpF,QAAI,IAAI,SAAS,SAAU,QAAO;AAClC,UAAM;AAAA,EACR,CAAC;AACD,MAAI,QAAQ,KAAM,QAAO,CAAC;AAE1B,MAAI;AACJ,MAAI;AAGF,aAAS,KAAK,MAAM,kBAAkB,KAAK,EAAE,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAM,IAAI,iBAAiB,UAAU,CAAC,EAAE,MAAM,IAAI,SAAS,mBAAmB,OAAO,GAAG,CAAC,CAAC;AAAA,EAC5F;AAEA,QAAM,SAAS,aAAa,UAAU,MAAM;AAC5C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,MACjD,MAAM,MAAM,KAAK,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC,EAAE,KAAK,GAAG;AAAA,MACnD,SAAS,MAAM;AAAA,IACjB,EAAE;AACF,UAAM,IAAI,iBAAiB,UAAU,MAAM;AAAA,EAC7C;AACA,SAAO,OAAO;AAChB;AAOA,SAAS,cACP,WACoB;AACpB,QAAM,SAAoB,CAAC;AAE3B,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,eAAe,GAAoC;AAC7F,UAAM,WAAW,YAAY,IAAI;AAEjC,QAAI,aAAa,MAAO;AAExB,QAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,aAAO,KAAK,MAAM;AAClB;AAAA,IACF;AAEA,WAAO,KAAK;AAAA,MACV,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,QAAQ,YAAY,OAAO,QAAQ,SAAS,MAAM;AAAA,IACpD,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAiBA,SAAS,YACP,MACA,OACmB;AACnB,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,SAA4B,EAAE,GAAG,KAAK;AAC5C,aAAW,OAAO,OAAO,KAAK,KAAK,GAAkB;AACnD,UAAM,QAAQ,MAAM,GAAG;AACvB,QAAI,UAAU,OAAW;AAEzB,UAAM,aAAa,KAAK,GAAG;AAC3B,QAAI,eAAe,UAAa,eAAe,OAAO;AACpD,YAAM,eAAe,MAAM;AAC3B,UAAI,iBAAiB,QAAW;AAC9B,cAAM,IAAI;AAAA,UACR,yBAAyB,GAAG;AAAA,QAC9B;AAAA,MACF;AACA,aAAO,GAAG,IAAI,cAAc,cAAc,KAAK;AAC/C;AAAA,IACF;AACA,WAAO,GAAG,IAAI,cAAc,YAAY,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAGA,SAAS,cAAc,cAAsB,GAAkC;AAC7E,QAAM,MAA8D,EAAE,aAAa;AACnF,MAAI,EAAE,YAAY,OAAW,KAAI,UAAU,EAAE;AAC7C,MAAI,EAAE,YAAY,OAAW,KAAI,UAAU,EAAE;AAC7C,MAAI,EAAE,YAAY,OAAW,KAAI,UAAU,EAAE;AAC7C,MAAI,EAAE,QAAQ,OAAW,KAAI,MAAM,EAAE;AACrC,SAAO;AACT;AAEA,SAAS,cAAc,MAAmB,OAAsC;AAC9E,QAAM,MAA8D,EAAE,GAAG,KAAK;AAC9E,MAAI,MAAM,iBAAiB,OAAW,KAAI,eAAe,MAAM;AAC/D,MAAI,MAAM,YAAY,OAAW,KAAI,UAAU,MAAM;AACrD,MAAI,MAAM,YAAY,OAAW,KAAI,UAAU,MAAM;AACrD,MAAI,MAAM,YAAY,OAAW,KAAI,UAAU,MAAM;AACrD,MAAI,MAAM,QAAQ,OAAW,KAAI,MAAM,MAAM;AAC7C,SAAO;AACT;AAEA,IAAM,mBAAN,cAA+B,eAAe;AAAC;AAO/C,SAAS,kBACP,SACA,SACqB;AACrB,QAAM,aAAa,IAAI,IAAY,WAAW,eAAe;AAC7D,aAAW,UAAU,WAAW,CAAC,GAAG;AAClC,eAAW,OAAO,MAAM;AAAA,EAC1B;AACA,SAAO;AACT;;;AGvaA,SAAS,YAAYC,WAAU;AAC/B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAqCjB,IAAM,iBAAiB;AAMvB,eAAsB,aAAa,OAAuB,CAAC,GAA2B;AACpF,QAAM,CAAC,KAAK,GAAG,IAAI,MAAM,QAAQ,IAAI,CAAC,cAAc,IAAI,GAAG,gBAAgB,IAAI,CAAC,CAAC;AAEjF,MAAIC,UAAS,IAAI,MAAM,IAAI,IAAI,GAAG;AAChC,YAAQ;AAAA,MACN,qBAAqB,IAAI,IAAI,0BAA0B,IAAI,IAAI;AAAA,MAC/D,EAAE,MAAM,wBAAwB;AAAA,IAClC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,cAAc,IAAI;AAAA,IAClB,UAAU,IAAI;AAAA,IACd,YAAY,IAAI;AAAA,EAClB;AACF;AAEA,eAAsB,cACpB,OAAuB,CAAC,GACyB;AACjD,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,QAAM,OAAO,KAAK,QAAQC,IAAG,QAAQ;AAErC,MAAI,KAAK,WAAW,UAAa,KAAK,WAAW,IAAI;AACnD,UAAM,MAAM,MAAM,UAAUC,aAAY,KAAK,QAAQ,IAAI,GAAG,YAAY,GAAG;AAC3E,WAAO,EAAE,MAAM,KAAK,QAAQ,OAAO;AAAA,EACrC;AAEA,QAAM,eAAe,KAAK;AAC1B,MAAI,iBAAiB,UAAa,iBAAiB,IAAI;AACrD,UAAM,OAAO,KAAK,cAAc;AAChC,UAAM,MAAM,MAAM;AAAA,MAChB,uBAAuB,cAAc,MAAM,IAAI;AAAA,MAC/C;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,MAAM,KAAK,QAAQ,SAAS;AAAA,EACvC;AAEA,QAAM,QAAQC,MAAK,KAAK,KAAK,cAAc;AAC3C,MAAI,MAAM,MAAM,KAAK,GAAG;AACtB,WAAO,EAAE,MAAM,OAAO,QAAQ,YAAY;AAAA,EAC5C;AAIA,QAAM,aAAaA,MAAK,KAAK,MAAM,cAAc;AACjD,MAAI,MAAM,MAAM,UAAU,GAAG;AAC3B,WAAO,EAAE,MAAM,YAAY,QAAQ,cAAc;AAAA,EACnD;AAEA,QAAM,IAAI,oBAAoB;AAAA,IAC5B,EAAE,QAAQ,iBAAiB,QAAQ,eAAe;AAAA,IAClD,EAAE,QAAQ,iBAAiB,QAAQ,mBAAmB,IAAI,EAAE;AAAA,IAC5D,EAAE,QAAQ,OAAO,QAAQ,iBAAiB,KAAK,EAAE;AAAA,IACjD,EAAE,QAAQ,YAAY,QAAQ,UAAU;AAAA,EAC1C,CAAC;AACH;AAEA,SAAS,iBAAiB,QAAwB;AAChD,SAAO;AACT;AAEA,SAAS,mBAAmB,MAA8B;AACxD,MAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,IAAI;AAC/D,WAAO;AAAA,EACT;AACA,MAAI,KAAK,oBAAoB;AAC3B,WAAO,cAAc,KAAK,kBAAkB;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,eAAsB,gBACpB,OAAuB,CAAC,GACuB;AAC/C,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,QAAM,OAAO,KAAK,QAAQF,IAAG,QAAQ;AAErC,MAAI,KAAK,WAAW,UAAa,KAAK,WAAW,MAAM,KAAK,MAAM;AAChE,UAAM,IAAI,cAAc,4CAA4C;AAAA,EACtE;AAEA,MAAI,KAAK,WAAW,UAAa,KAAK,WAAW,IAAI;AACnD,UAAM,MAAM,MAAM,UAAUC,aAAY,KAAK,QAAQ,IAAI,GAAG,YAAY,GAAG;AAC3E,WAAO,EAAE,MAAM,KAAK,QAAQ,OAAO;AAAA,EACrC;AAEA,MAAI,KAAK,MAAM;AACb,WAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AAAA,EACtC;AAEA,MAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,MAAM,KAAK,YAAY;AAClF,UAAM,IAAI,cAAc,mDAAmD;AAAA,EAC7E;AAEA,MAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,IAAI;AAC/D,UAAM,OAAO,KAAK,cAAc;AAChC,UAAM,MAAM,MAAM;AAAA,MAChB,uBAAuB,KAAK,cAAc,MAAM,IAAI;AAAA,MACpD;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,MAAM,KAAK,QAAQ,SAAS;AAAA,EACvC;AAEA,MAAI,KAAK,YAAY;AACnB,WAAO,EAAE,MAAM,MAAM,QAAQ,SAAS;AAAA,EACxC;AAEA,SAAO,EAAE,MAAM,KAAK,QAAQ,MAAM;AACpC;AAMO,SAAS,uBAAuB,OAAe,YAAoB,MAAsB;AAC9F,QAAM,WAAWA,aAAY,OAAO,IAAI;AACxC,SAAOC,MAAK,WAAW,QAAQ,IAAI,WAAWA,MAAK,QAAQ,YAAY,QAAQ;AACjF;AAMO,SAASD,aAAY,GAAW,MAAsB;AAC3D,MAAI,MAAM,IAAK,QAAO;AACtB,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOC,MAAK,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,SAAO;AACT;AAEA,eAAe,UAAU,OAAe,MAAc,KAA8B;AAClF,QAAM,MAAMA,MAAK,WAAW,KAAK,IAAI,QAAQA,MAAK,QAAQ,KAAK,KAAK;AACpE,QAAM,OAAO,MAAMC,IAAG,KAAK,GAAG,EAAE,MAAM,MAAM,IAAI;AAChD,MAAI,CAAC,KAAM,OAAM,IAAI,iBAAiB,MAAM,KAAK,SAAS;AAC1D,MAAI,CAAC,KAAK,YAAY,EAAG,OAAM,IAAI,iBAAiB,MAAM,KAAK,iBAAiB;AAChF,SAAO;AACT;AAEA,eAAe,MAAM,GAA6B;AAChD,QAAM,OAAO,MAAMA,IAAG,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AAC9C,SAAO,MAAM,YAAY,KAAK;AAChC;AAQO,SAASJ,UAAS,OAAe,QAAyB;AAC/D,QAAM,IAAIG,MAAK,QAAQ,KAAK;AAC5B,QAAM,IAAIA,MAAK,QAAQ,MAAM;AAC7B,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,MAAMA,MAAK,SAAS,GAAG,CAAC;AAC9B,SAAO,QAAQ,MAAM,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,MAAK,WAAW,GAAG;AACpE;;;AR/LA,eAAsB,YAAY,OAA8C;AAC9E,QAAM,SAAS,MAAM,iBAAiB;AAAA,IACpC,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,EAC/D,CAAC;AAED,QAAM,QAAQ,MAAM,aAAa;AAAA,IAC/B,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7D,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7D,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACvD,GAAI,OAAO,OAAO,WAAW,SAAY,EAAE,cAAc,OAAO,OAAO,OAAO,IAAI,CAAC;AAAA,IACnF,GAAI,OAAO,OAAO,WAAW,SAAY,EAAE,cAAc,OAAO,OAAO,OAAO,IAAI,CAAC;AAAA,IACnF,GAAI,OAAO,OAAO,SAAS,SAAY,EAAE,YAAY,OAAO,OAAO,KAAK,IAAI,CAAC;AAAA,IAC7E,GAAI,OAAO,eAAe,OAAO,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;AAAA,IACtE,oBAAoB,OAAO,SAAS;AAAA,EACtC,CAAC;AAED,QAAM,YAAY,wBAAwB,OAAO,QAAQ,OAAO,UAAU,MAAM,MAAM;AACtF,QAAM,SAAS,MAAM,aAAa,WAAW,MAAM,QAAQ;AAC3D,SAAO,EAAE,OAAO,OAAO;AACzB;AAUA,eAAe,aAAa,QAAwB,UAA2C;AAC7F,QAAM,OAAkB,CAAC;AACzB,aAAW,WAAW,OAAO,UAAU;AACrC,UAAM,OAAOE,MAAK,KAAK,UAAU,QAAQ,OAAO;AAChD,UAAM,OAAO,MAAMC,IAAG,KAAK,IAAI,EAAE,MAAM,MAAM,IAAI;AACjD,QAAI,MAAM,YAAY,EAAG,MAAK,KAAK,OAAO;AAAA,EAC5C;AACA,MAAI,KAAK,WAAW,OAAO,SAAS,OAAQ,QAAO;AACnD,SAAO,EAAE,GAAG,QAAQ,UAAU,KAAK;AACrC;AAEO,SAAS,YAAY,KAAqB,MAAc,OAA2B;AACxF,MAAI,MAAM,MAAO;AACjB,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,GAAG,KAAK,eAAe,IAAI,EAAE,CAAC;AAC1C,UAAQ,IAAI,eAAe,IAAI,MAAM,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,YAAY,GAAG,CAAC,EAAE;AACtF,UAAQ,IAAI,eAAe,IAAI,MAAM,QAAQ,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,UAAU,GAAG,CAAC,EAAE;AACtF,QAAM,aAAa,IAAI,OAAO,aAC1B,GAAG,IAAI,OAAO,UAAU,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,YAAY,GAAG,CAAC,KAClE,GAAG,IAAI,YAAY;AACvB,UAAQ,IAAI,eAAe,UAAU,EAAE;AACvC,UAAQ,IAAI,eAAe,IAAI,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE;AAClG,MAAI,MAAM,OAAQ,SAAQ,IAAI,GAAG,OAAO,qBAAqB,CAAC;AAC9D,UAAQ,IAAI,EAAE;AAChB;AAOO,SAAS,oBAAoB,KAKhC;AACF,QAAM,MAAwF,CAAC;AAC/F,QAAM,OAAO,IAAI,MAAM;AACvB,aAAW,WAAW,IAAI,OAAO,UAAU;AACzC,eAAW,aAAa,IAAI,OAAO,YAAsC;AACvE,YAAM,OAAO,QAAQ,OAAO,SAAS;AACrC,UAAI,SAAS,UAAa,SAAS,MAAO;AAC1C,UAAI,KAAK;AAAA,QACP;AAAA,QACA;AAAA,QACA,WAAWD,MAAK,KAAK,MAAM,QAAQ,SAAS,KAAK,YAAY;AAAA,QAC7D,SAASA,MAAK,KAAK,MAAM,QAAQ,OAAO;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAaA,eAAsB,yBACpB,UAC8C;AAC9C,QAAM,MAA2C,CAAC;AAClD,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC5D,UAAM,UAAUA,MAAK,KAAK,UAAU,OAAO,OAAO;AAClD,UAAM,OAAO,MAAMC,IAAG,KAAK,OAAO,EAAE,MAAM,MAAM,IAAI;AACpD,QAAI,MAAM,YAAY,EAAG,KAAI,KAAK,EAAE,MAAM,QAAQ,CAAC;AAAA,EACrD;AACA,SAAO;AACT;;;AFhIA,eAAsB,SAAS,QAAsB,CAAC,GAAkB;AACtE,QAAM,MAAM,MAAM,YAAY,KAAK;AACnC,cAAY,KAAK,SAAS,KAAK;AAE/B,QAAM,UAAU,oBAAoB,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS;AAC/D,QAAM,SAAS,MAAM,QAAQ,IAAI,QAAQ,IAAI,cAAc,CAAC,GAAG,KAAK;AAEpE,MAAI,MAAM,WAAW,GAAG;AACtB,YAAQ,IAAIC,IAAG,IAAI,8BAA8B,CAAC;AAClD;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,YAAY,OAAO,MAAM,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC;AAE9E,MAAI,UAAU;AACd,MAAI,MAAM;AACV,MAAI,UAAU;AACd,aAAW,KAAK,UAAU;AACxB,QAAI,EAAE,WAAW,WAAW;AAC1B;AACA,UAAI,CAAC,MAAM,MAAO,SAAQ,IAAI,GAAGA,IAAG,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE;AAAA,IACnE,WAAW,EAAE,WAAW,cAAc;AACpC;AACA,UAAI,CAAC,MAAM,MAAO,SAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,kBAAkB,EAAE,IAAI,EAAE;AAAA,IAC5E,WAAW,EAAE,WAAW,WAAW;AACjC;AACA,cAAQ,MAAM,GAAGA,IAAG,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,IAAIA,IAAG,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;AAAA,IAClF;AAAA,EACF;AAEA,UAAQ,IAAI,EAAE;AACd,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAS,OAAM,KAAKA,IAAG,OAAO,GAAG,OAAO,UAAU,CAAC;AACvD,MAAI,IAAK,OAAM,KAAKA,IAAG,IAAI,GAAG,GAAG,UAAU,CAAC;AAC5C,MAAI,QAAS,OAAM,KAAKA,IAAG,IAAI,GAAG,OAAO,UAAU,CAAC;AACpD,UAAQ,IAAI,MAAM,WAAW,IAAIA,IAAG,IAAI,cAAc,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE;AAEjF,MAAI,UAAU,EAAG,SAAQ,WAAW;AACtC;;;AWlCA,SAAS,YAAYC,WAAU;AAC/B,OAAOC,WAAU;AACjB,OAAOC,SAAQ;;;ACFf,SAAS,YAAYC,WAAU;AAC/B,OAAOC,WAAU;AACjB,OAAO,eAAe;AAoDtB,eAAsB,eAAe,MAA0C;AAC7E,QAAM,EAAE,QAAQ,UAAU,OAAO,IAAI;AACrC,QAAM,QAAoB,CAAC;AAE3B,aAAW,WAAW,OAAO,UAAU;AACrC,eAAW,aAAa,OAAO,YAAsC;AACnE,YAAM,OAAO,QAAQ,OAAO,SAAS;AACrC,UAAI,SAAS,UAAa,SAAS,MAAO;AAE1C,YAAM,iBAAiBA,MAAK,KAAK,QAAQ,SAAS;AAClD,UAAI,CAAE,MAAMC,OAAM,cAAc,EAAI;AAEpC,YAAM,iBAAiBD,MAAK,KAAK,UAAU,QAAQ,SAAS,KAAK,YAAY;AAC7E,YAAM,UAAU,KAAK,UACjB,MAAM,cAAc,gBAAgB,gBAAgB,MAAM,SAAS,SAAS,IAC5E,MAAM,YAAY,gBAAgB,gBAAgB,MAAM,SAAS,SAAS;AAE9E,YAAM,KAAK,GAAG,OAAO;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,iBAAiB,KAAK;AAC/B;AAIA,eAAe,cACb,gBACA,gBACA,QACA,SACA,WACqB;AACrB,QAAM,QAAQ,MAAM,UAAU,cAAc;AAC5C,QAAM,eAAe,mBAAmB,OAAO,OAAO;AACtD,QAAM,eAAe,mBAAmB,OAAO,OAAO;AACtD,QAAM,MAAkB,CAAC;AAEzB,aAAW,OAAO,OAAO;AACvB,UAAM,MAAMA,MAAK,SAAS,gBAAgB,GAAG;AAC7C,QAAI,CAAC,aAAa,GAAG,EAAG;AACxB,QAAI,aAAa,GAAG,EAAG;AAEvB,UAAM,aAAa;AAAA,MAAY;AAAA,MAAK;AAAA;AAAA,MAAsB;AAAA,IAAI;AAC9D,QAAI,KAAK;AAAA,MACP,QAAQ;AAAA,MACR,QAAQA,MAAK,KAAK,gBAAgB,UAAU;AAAA,MAC5C,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAIA,eAAe,YACb,gBACA,gBACA,QACA,SACA,WACqB;AACrB,QAAM,QAAQ,MAAM,eAAe,cAAc;AACjD,QAAM,eAAe,mBAAmB,OAAO,OAAO;AACtD,QAAM,eAAe,mBAAmB,OAAO,OAAO;AACtD,QAAM,MAAkB,CAAC;AAEzB,aAAW,SAAS,OAAO;AACzB,QAAI,CAAC,aAAa,MAAM,IAAI,EAAG;AAC/B,QAAI,aAAa,MAAM,IAAI,EAAG;AAE9B,UAAM,aAAa;AAAA,MAAY,MAAM;AAAA,MAAM;AAAA;AAAA,MAAsB;AAAA,IAAK;AACtE,QAAI,KAAK;AAAA,MACP,QAAQA,MAAK,KAAK,gBAAgB,MAAM,IAAI;AAAA,MAC5C,QAAQA,MAAK,KAAK,gBAAgB,UAAU;AAAA,MAC5C,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAIA,IAAM,oBAAoB;AAE1B,SAAS,YAAY,SAAiB,QAAqB,SAA0B;AACnF,MAAI,OAAO,OAAQ,QAAO,OAAO,OAAO,OAAO;AAE/C,MAAI,OAAO,UAAU,QAAQ,QAAQ,mBAAmB,IAAI,IAAI;AAChE,MAAI,OAAO,KAAK;AACd,UAAM,MAAMA,MAAK,QAAQ,IAAI;AAC7B,WAAO,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,OAAO;AAAA,EACvE;AACA,SAAO;AACT;AAIA,eAAe,UAAU,MAAiC;AACxD,QAAM,MAAgB,CAAC;AACvB,SAAO,eAAe,QAAQ,KAA4B;AACxD,UAAM,UAAU,MAAMD,IAAG,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAC7D,eAAW,SAAS,SAAS;AAG3B,UAAI,MAAM,KAAK,WAAW,GAAG,EAAG;AAChC,YAAM,OAAOC,MAAK,KAAK,KAAK,MAAM,IAAI;AACtC,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,QAAQ,IAAI;AAAA,MACpB,WAAW,MAAM,OAAO,KAAK,MAAM,eAAe,GAAG;AACnD,YAAI,KAAK,IAAI;AAAA,MACf;AAAA,IACF;AAAA,EACF,GAAG,IAAI;AACP,SAAO;AACT;AAEA,eAAe,eAAe,MAAoE;AAChG,QAAM,UAAU,MAAMD,IAAG,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC9D,SAAO,QACJ,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,WAAW,GAAG,CAAC,EACrC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,YAAY,EAAE,EAAE;AAC1D;AAEA,eAAeE,OAAM,GAA6B;AAChD,QAAM,OAAO,MAAMF,IAAG,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AAC9C,SAAO,MAAM,YAAY,KAAK;AAChC;AAOA,SAAS,mBAAmB,UAAmE;AAC7F,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO,MAAM;AACrD,QAAM,MAAM,SAAS,IAAI,CAAC,MAAM,UAAU,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC;AAC3D,SAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;AAC1C;AAKA,SAAS,mBAAmB,UAAmE;AAC7F,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO,MAAM;AACrD,QAAM,MAAM,SAAS,IAAI,CAAC,MAAM,UAAU,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC;AAC3D,SAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;AAC1C;AAIA,SAAS,iBAAiB,OAAyC;AACjE,QAAM,WAAW,oBAAI,IAAwB;AAC7C,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,SAAS,IAAI,KAAK,MAAM;AACvC,QAAI,OAAQ,QAAO,KAAK,IAAI;AAAA,QACvB,UAAS,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC;AAAA,EACvC;AAEA,QAAM,WAAuB,CAAC;AAC9B,QAAM,aAAyB,CAAC;AAChC,aAAW,CAAC,QAAQ,MAAM,KAAK,UAAU;AACvC,QAAI,OAAO,WAAW,GAAG;AACvB,eAAS,KAAK,OAAO,CAAC,CAAE;AACxB;AAAA,IACF;AACA,UAAM,OAAO,OAAO,CAAC;AACrB,eAAW,KAAK;AAAA,MACd;AAAA,MACA,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACnC,aAAa,KAAK;AAAA,MAClB,WAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACH;AACA,SAAO,EAAE,OAAO,UAAU,WAAW;AACvC;;;ADzNA,eAAsB,UAAU,QAAsB,CAAC,GAAkB;AACvE,QAAM,MAAM,MAAM,YAAY,KAAK;AACnC,cAAY,KAAK,UAAU,KAAK;AAEhC,MAAI,WAAW;AACf,MAAI,SAAS;AAKb,QAAM,oBAAoB,MAAM,qBAAqB,IAAI,OAAO,UAAU;AAG1E,UAAQ,IAAIG,IAAG,KAAK,UAAU,CAAC;AAC/B,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC5D,UAAM,OAAOC,MAAK,KAAK,IAAI,MAAM,UAAU,OAAO,OAAO;AACzD,UAAM,OAAO,MAAMC,IAAG,KAAK,IAAI,EAAE,MAAM,MAAM,IAAI;AACjD,QAAI,MAAM,YAAY,GAAG;AACvB,cAAQ;AAAA,QACN,KAAKF,IAAG,MAAM,QAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,IAAIA,IAAG,IAAI,OAAO,UAAU,GAAG,CAAC,IAAIA,IAAG,IAAI,UAAU,CAAC;AAAA,MAC7F;AAAA,IACF,WAAW,kBAAkB,IAAI,IAAI,GAAG;AACtC;AACA,cAAQ;AAAA,QACN,KAAKA,IAAG,OAAO,QAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,IAAIA,IAAG,IAAI,OAAO,UAAU,GAAG,CAAC,IAAIA,IAAG,OAAO,yCAAoC,CAAC;AAAA,MAC3H;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN,KAAKA,IAAG,IAAI,QAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,IAAIA,IAAG,IAAI,OAAO,UAAU,GAAG,CAAC,IAAIA,IAAG,IAAI,4BAA4B,CAAC;AAAA,MAC7G;AAAA,IACF;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAGd,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,eAAe;AAAA,IACjD,QAAQ,IAAI,MAAM;AAAA,IAClB,UAAU,IAAI,MAAM;AAAA,IACpB,QAAQ,IAAI;AAAA,EACd,CAAC;AAED,UAAQ,IAAIA,IAAG,KAAK,WAAW,CAAC;AAChC,UAAQ,IAAI,KAAK,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG,EAAE;AACpE,MAAI,WAAW,WAAW,GAAG;AAC3B,YAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,gBAAgB;AAAA,EAChD,OAAO;AACL,gBAAY,WAAW;AACvB,YAAQ,IAAI,KAAKA,IAAG,OAAO,QAAG,CAAC,IAAI,WAAW,MAAM,gBAAgB;AACpE,eAAW,KAAK,YAAY;AAC1B,cAAQ,IAAI,QAAQA,IAAG,IAAI,EAAE,cAAc,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE;AAC5E,iBAAW,KAAK,EAAE,QAAS,SAAQ,IAAI,UAAUA,IAAG,IAAI,QAAG,CAAC,IAAI,CAAC,EAAE;AAAA,IACrE;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAGd,QAAM,aAAa,oBAAoB,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS;AAClE,QAAM,SAAS,MAAM,QAAQ,IAAI,WAAW,IAAI,cAAc,CAAC,GAAG,KAAK;AAMvE,QAAM,WAAW,MAAM,yBAAyB,IAAI,MAAM,QAAQ;AAClE,QAAM,WACJ,MAAM,QAAQ;AAAA,IACZ,SAAS,IAAI,CAAC,MAAM,iBAAiB,EAAE,SAAS,IAAI,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC,CAAC;AAAA,EACxF,GACA,KAAK;AACP,QAAM,WAAW,IAAI,IAAI,KAAK;AAC9B,QAAM,cAAc,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AACtD,QAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;AAE7E,UAAQ,IAAIA,IAAG,KAAK,gBAAgB,CAAC;AACrC,MAAI,MAAM,WAAW,KAAK,QAAQ,WAAW,GAAG;AAC9C,YAAQ,IAAI,KAAKA,IAAG,MAAM,QAAG,CAAC,YAAY;AAAA,EAC5C,OAAO;AACL,QAAI,MAAM,SAAS,GAAG;AACpB,kBAAY,MAAM;AAClB,cAAQ;AAAA,QACN,KAAKA,IAAG,OAAO,QAAG,CAAC,IAAI,MAAM,MAAM,aAAaA,IAAG,IAAI,kCAAkC,CAAC;AAAA,MAC5F;AACA,iBAAW,KAAK,MAAO,SAAQ,IAAI,QAAQ,CAAC,EAAE;AAAA,IAChD;AACA,QAAI,QAAQ,SAAS,GAAG;AACtB,kBAAY,QAAQ;AACpB,cAAQ;AAAA,QACN,KAAKA,IAAG,OAAO,QAAG,CAAC,IAAI,QAAQ,MAAM,WAAWA,IAAG,IAAI,kFAAkF,CAAC;AAAA,MAC5I;AACA,iBAAW,KAAK,QAAS,SAAQ,IAAI,QAAQ,CAAC,EAAE;AAAA,IAClD;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAGd,MAAI,WAAW,WAAW,GAAG;AAC3B,YAAQ,IAAIA,IAAG,MAAM,SAAS,CAAC;AAC/B;AAAA,EACF;AACA,QAAM,QAAkB,CAAC;AACzB,MAAI,WAAW,EAAG,OAAM,KAAKA,IAAG,OAAO,GAAG,QAAQ,WAAW,aAAa,IAAI,KAAK,GAAG,EAAE,CAAC;AACzF,MAAI,SAAS,EAAG,OAAM,KAAKA,IAAG,IAAI,GAAG,MAAM,SAAS,WAAW,IAAI,KAAK,GAAG,EAAE,CAAC;AAC9E,UAAQ,IAAI,WAAW,MAAM,KAAK,IAAI,CAAC,EAAE;AACzC,MAAI,SAAS,EAAG,SAAQ,WAAW;AACrC;;;AEpHA,SAAS,YAAYG,WAAU;AAC/B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,qBAAqB;AAC9B,OAAOC,SAAQ;AACf,OAAO,aAAa;;;ACvBpB,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AAYR,IAAM,sBAAN,cAAkC,eAAe;AAAA,EACtD,YAA4B,WAAgC;AAC1D,UAAM,GAAG,UAAU,MAAM,0CAA0C;AADzC;AAAA,EAE5B;AAAA,EAF4B;AAG9B;AAEA,eAAsB,QAAQ,QAAsB,CAAC,GAAkB;AACrE,QAAM,MAAM,MAAM,YAAY,KAAK;AACnC,cAAY,KAAK,QAAQ,KAAK;AAE9B,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,eAAe;AAAA,IACjD,QAAQ,IAAI,MAAM;AAAA,IAClB,UAAU,IAAI,MAAM;AAAA,IACpB,QAAQ,IAAI;AAAA,EACd,CAAC;AAED,MAAI,WAAW,SAAS,GAAG;AACzB,qBAAiB,YAAY,MAAM,SAAS,KAAK;AACjD,QAAI,MAAM,QAAQ;AAChB,YAAM,IAAI,oBAAoB,UAAU;AAAA,IAC1C;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,WAAW,OAAO;AAAA,IACvC,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7D,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,EAC5D,CAAC;AAID,QAAM,aAAa,oBAAoB,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS;AAClE,QAAM,SAAS,MAAM,QAAQ,IAAI,WAAW,IAAI,cAAc,CAAC,GAAG,KAAK;AACvE,QAAM,UAAU,MAAM,YAAY,OAAO,MAAM,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC;AAE7E,iBAAe,UAAU,IAAI,MAAM,UAAU,MAAM,SAAS,KAAK;AACjE,iBAAe,SAAS,MAAM,SAAS,KAAK;AAC5C,eAAa,UAAU,SAAS,UAAU;AAM1C,QAAM,UACJ,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE,SAC/C,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAChD,MAAI,UAAU,EAAG,SAAQ,WAAW;AACtC;AAIA,SAAS,iBAAiB,YAAiC,OAAsB;AAC/E,MAAI,MAAO;AACX,aAAW,KAAK,YAAY;AAC1B,YAAQ;AAAA,MACNC,IAAG,OAAO,iCAAiC,EAAE,WAAW,IAAI,EAAE,SAAS,KAAK,EAAE,MAAM,EAAE;AAAA,IACxF;AACA,eAAW,KAAK,EAAE,QAAS,SAAQ,KAAKA,IAAG,IAAI,mBAAmB,CAAC,EAAE,CAAC;AAAA,EACxE;AACF;AAEA,SAAS,eACP,UACA,UACA,OACM;AACN,aAAW,KAAK,UAAU;AACxB,UAAM,UAAUC,MAAK,SAAS,UAAU,EAAE,KAAK,MAAM;AACrD,YAAQ,EAAE,QAAQ;AAAA,MAChB,KAAK;AACH,YAAI,CAAC,MAAO,SAAQ,IAAI,GAAGD,IAAG,MAAM,MAAM,CAAC,OAAO,OAAO,EAAE;AAC3D;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,GAAGA,IAAG,MAAM,OAAO,CAAC,MAAM,OAAO,IAAIA,IAAG,IAAI,IAAI,EAAE,OAAO,GAAG,CAAC,EAAE;AAC3E;AAAA,MACF,KAAK;AACH,YAAI,CAAC,MAAO,SAAQ,IAAI,GAAGA,IAAG,KAAK,QAAQ,CAAC,KAAK,OAAO,EAAE;AAC1D;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,GAAGA,IAAG,OAAO,QAAQ,CAAC,KAAK,OAAO,IAAIA,IAAG,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;AACnF;AAAA,MACF,KAAK;AACH,gBAAQ,MAAM,GAAGA,IAAG,IAAI,OAAO,CAAC,MAAM,OAAO,IAAIA,IAAG,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;AACjF;AAAA,MACF,KAAK;AACH,YAAI,CAAC,MAAO,SAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,MAAM,OAAO,EAAE;AACzD;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,MAAM,OAAO,IAAIA,IAAG,IAAI,eAAe,EAAE,OAAO,GAAG,CAAC,EAAE;AACpF;AAAA,IACJ;AAAA,EACF;AACF;AAEA,SAAS,eACP,UACA,OACM;AACN,aAAW,KAAK,UAAU;AACxB,QAAI,EAAE,WAAW,aAAa,CAAC,OAAO;AACpC,cAAQ,IAAI,GAAGA,IAAG,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE;AAAA,IACjD,WAAW,EAAE,WAAW,gBAAgB,CAAC,OAAO;AAC9C,cAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,kBAAkB,EAAE,IAAI,EAAE;AAAA,IAC1D,WAAW,EAAE,WAAW,WAAW;AACjC,cAAQ,MAAM,GAAGA,IAAG,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,IAAIA,IAAG,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;AAAA,IAClF;AAAA,EACF;AACF;AAEA,SAAS,aACP,UACA,UACA,YACM;AACN,QAAM,SAAiC,CAAC;AACxC,aAAW,KAAK,SAAU,QAAO,EAAE,MAAM,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK;AACvE,QAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY,EAAE;AAE5F,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO,SAAS,EAAG,OAAM,KAAKA,IAAG,MAAM,GAAG,OAAO,SAAS,CAAC,UAAU,CAAC;AAC1E,MAAI,OAAO,OAAO,EAAG,OAAM,KAAKA,IAAG,MAAM,GAAG,OAAO,OAAO,CAAC,QAAQ,CAAC;AACpE,MAAI,OAAO,SAAS,EAAG,OAAM,KAAKA,IAAG,KAAK,GAAG,OAAO,SAAS,CAAC,UAAU,CAAC;AACzE,MAAI,OAAO,QAAQ,EAAG,OAAM,KAAKA,IAAG,OAAO,GAAG,OAAO,QAAQ,CAAC,SAAS,CAAC;AACxE,MAAI,OAAO,SAAS,EAAG,OAAM,KAAKA,IAAG,IAAI,GAAG,OAAO,SAAS,CAAC,UAAU,CAAC;AACxE,MAAI,OAAO,YAAY,KAAK,OAAO,SAAS,GAAG;AAC7C,UAAM,KAAKA,IAAG,IAAI,IAAI,OAAO,YAAY,KAAK,MAAM,OAAO,SAAS,KAAK,EAAE,UAAU,CAAC;AAAA,EACxF;AACA,MAAI,QAAS,OAAM,KAAKA,IAAG,OAAO,GAAG,OAAO,UAAU,CAAC;AACvD,MAAI,WAAW,OAAQ,OAAM,KAAKA,IAAG,OAAO,GAAG,WAAW,MAAM,eAAe,CAAC;AAEhF,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,MAAM,WAAW,IAAIA,IAAG,IAAI,cAAc,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE;AACnF;;;AD7GO,IAAM,wBAAN,cAAoC,eAAe;AAAA,EACxD,YAAY,YAAoB;AAC9B,UAAM,oDAAoD,UAAU;AAAA,+CAAkD;AAAA,EACxH;AACF;AAEA,IAAM,kBAAkB,CAAC,UAAU,SAAS,YAAY,WAAW,aAAa,QAAQ;AACxF,IAAM,sBAAsB,CAAC,UAAU,SAAS,UAAU;AAC1D,IAAM,oBAAoB,OAAO,KAAK,eAAe;AAErD,IAAM,OAAOE,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAM,sBAAsB;AAAA,EAC1BA,MAAK,QAAQ,MAAM,MAAM,aAAa,IAAI;AAAA,EAC1CA,MAAK,QAAQ,MAAM,MAAM,MAAM,aAAa,IAAI;AAClD;AAEA,eAAe,mBAAoC;AACjD,aAAW,aAAa,qBAAqB;AAC3C,UAAM,OAAO,MAAMC,IAAG,KAAK,SAAS,EAAE,MAAM,MAAM,IAAI;AACtD,QAAI,MAAM,YAAY,EAAG,QAAO;AAAA,EAClC;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IAAmD,oBAAoB,KAAK,MAAM,CAAC;AAAA,EACrF;AACF;AAaA,eAAsB,QAAQ,QAAmB,CAAC,GAAkB;AAClE,QAAM,UAAU,MAAM,eAAe,KAAK;AAE1C,MAAI,CAAC,MAAM,OAAO;AAChB,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAIC,IAAG,KAAK,kBAAkB,CAAC;AACvC,YAAQ,IAAI,eAAe,QAAQ,MAAM,EAAE;AAC3C,YAAQ,IAAI,EAAE;AAAA,EAChB;AAEA,QAAM,UAAU,MAAM,aAAa,SAAS;AAAA,IAC1C,OAAO,MAAM,SAAS;AAAA,IACtB,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM,UAAU;AAAA,EAC1B,CAAC;AACD,MAAI,CAAC,QAAQ,WAAW,CAAC,MAAM,OAAO;AACpC,YAAQ,IAAIA,IAAG,IAAI,gDAAgD,CAAC;AAAA,EACtE;AAEA,MAAI,QAAQ,mBAAmB,YAAY,CAAC,MAAM,OAAO;AACvD,gCAA4B,QAAQ,MAAM;AAAA,EAC5C;AAEA,MAAI,CAAC,MAAM,MAAO,SAAQ,IAAI,EAAE;AAKhC,MAAI,MAAM,QAAQ;AAChB,QAAI,CAAC,MAAM,OAAO;AAChB,cAAQ;AAAA,QACNA,IAAG;AAAA,UACD,oDAAoD,QAAQ,MAAM;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAKA,QAAM,QAAQ;AAAA,IACZ,QAAQ,QAAQ;AAAA,IAChB,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7D,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACvD,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,EAC5D,CAAC;AACH;AAIA,eAAe,eAAe,OAAwC;AACpE,QAAM,cAAc,MAAM,OAAO,CAAC,QAAQ,MAAM;AAGhD,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,aAASF,MAAK,QAAQG,aAAY,MAAM,MAAM,CAAC;AAC/C,qBAAiB,iBAAiB,MAAM;AAAA,EAC1C,WAAW,MAAM,OAAO;AACtB,aAASH,MAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;AAC9C,qBAAiB;AAAA,EACnB,WAAW,aAAa;AACtB,aAASA,MAAK,QAAQI,IAAG,QAAQ,GAAG,SAAS;AAC7C,qBAAiB;AAAA,EACnB,OAAO;AACL,UAAM,SAAS,MAAM,IAA8B;AAAA,MACjD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,aACE,OAAO,SAAS,SACZJ,MAAK,QAAQI,IAAG,QAAQ,GAAG,SAAS,IACpCJ,MAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;AAC3C,qBAAiB,OAAO;AAAA,EAC1B;AAGA,MAAI;AACJ,MAAI,aAAa;AACf,cAAU;AAAA,EACZ,OAAO;AACL,UAAM,EAAE,OAAO,IAAI,MAAM,IAA0B;AAAA,MACjD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,SAAS,gBAAgB,IAAI,CAAC,UAAU;AAAA,QACtC,OAAO;AAAA,QACP,OAAO;AAAA,QACP,UAAW,oBAA0C,SAAS,IAAI;AAAA,MACpE,EAAE;AAAA,MACF,KAAK;AAAA,MACL,cAAc;AAAA,IAChB,CAAC;AACD,cAAU;AAAA,EACZ;AAGA,MAAI;AACJ,MAAI,aAAa;AACf,eAAW;AAAA,EACb,OAAO;AACL,UAAM,EAAE,OAAO,IAAI,MAAM,IAA+B;AAAA,MACtD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,SAAS,kBAAkB,IAAI,CAAC,UAAU;AAAA,QACxC,OAAO;AAAA,QACP,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,EAAE;AAAA,MACF,KAAK;AAAA,MACL,cAAc;AAAA,IAChB,CAAC;AACD,eAAW;AAAA,EACb;AAIA,QAAM,iBACJ,mBAAmB,QAAQ,QAAQ;AACrC,QAAM,aACJ,mBAAmB,SACfA,MAAK,QAAQI,IAAG,QAAQ,GAAG,uBAAuB,IAClDJ,MAAK,QAAQ,QAAQ,IAAI,GAAG,uBAAuB;AAEzD,SAAO,EAAE,QAAQ,gBAAgB,YAAY,gBAAgB,SAAS,SAAS;AACjF;AAOA,eAAe,IACb,UACY;AACZ,MAAI,YAAY;AAChB,QAAM,SAAS,MAAM,QAAQ,UAAU;AAAA,IACrC,UAAU,MAAM;AACd,kBAAY;AACZ,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,MAAI,UAAW,OAAM,IAAI,eAAe,gBAAgB;AACxD,SAAO;AACT;AAEA,SAAS,iBAAiB,QAA+C;AACvE,QAAM,OAAOA,MAAK,QAAQI,IAAG,QAAQ,GAAG,SAAS;AACjD,QAAM,MAAMJ,MAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;AACjD,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,WAAW,IAAK,QAAO;AAC3B,SAAO;AACT;AAEA,SAASG,aAAY,GAAmB;AACtC,MAAI,MAAM,IAAK,QAAOC,IAAG,QAAQ;AACjC,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOJ,MAAK,KAAKI,IAAG,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AACjE,SAAO;AACT;AAeA,eAAe,aACb,SACA,SACyB;AACzB,QAAM,EAAE,OAAO,OAAO,OAAO,IAAI;AACjC,QAAM,SAAS,QAAQ;AACvB,QAAM,OAAO,MAAMH,IAAG,KAAK,MAAM,EAAE,MAAM,MAAM,IAAI;AACnD,MAAI,QAAQ,CAAC,KAAK,YAAY,GAAG;AAC/B,UAAM,IAAI,eAAe,8CAA8C,MAAM,EAAE;AAAA,EACjF;AAEA,MAAI,QAAQ,CAAC,OAAO;AAClB,UAAM,UAAU,MAAMA,IAAG,QAAQ,MAAM;AACvC,QAAI,QAAQ,SAAS,EAAG,OAAM,IAAI,sBAAsB,MAAM;AAAA,EAChE;AAEA,MAAI,CAAC,QAAQ;AACX,UAAMA,IAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,EAC5C,WAAW,CAAC,QAAQ,CAAC,OAAO;AAC1B,YAAQ,IAAI,GAAGC,IAAG,IAAI,OAAO,CAAC,mBAAmB,MAAM,GAAG;AAAA,EAC5D;AAEA,QAAM,eAAe,MAAM,iBAAiB;AAE5C,MAAI,UAAU;AACd,aAAW,MAAM,iBAAiB,cAAc,QAAQ,QAAQ,SAAS,OAAO,MAAM;AACtF,aAAW,MAAM,gBAAgB,SAAS,OAAO,MAAM;AACvD,SAAO,EAAE,SAAS,UAAU,EAAE;AAChC;AAOA,eAAe,iBACb,cACA,QACA,SACA,OACA,QACiB;AACjB,MAAI,UAAU;AAGd,QAAM,YAAYF,MAAK,KAAK,cAAc,WAAW;AACrD,QAAM,aAAaA,MAAK,KAAK,QAAQ,WAAW;AAChD,MAAK,MAAMC,IAAG,KAAK,SAAS,EAAE,MAAM,MAAM,IAAI,KAAM,CAAE,MAAMA,IAAG,KAAK,UAAU,EAAE,MAAM,MAAM,IAAI,GAAI;AAClG,QAAI,QAAQ;AACV,UAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,IAAI,OAAO,CAAC,mBAAmB,UAAU,EAAE;AAAA,IAC3E,OAAO;AACL,YAAMD,IAAG,SAAS,WAAW,UAAU;AACvC,UAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,MAAM,OAAO,CAAC,MAAM,UAAU,EAAE;AAAA,IAChE;AACA;AAAA,EACF;AAGA,aAAW,aAAa,SAAS;AAC/B,UAAM,MAAMF,MAAK,KAAK,QAAQ,SAAS;AACvC,UAAM,OAAOA,MAAK,KAAK,KAAK,UAAU;AACtC,UAAM,aAAa,MAAMC,IAAG,KAAK,IAAI,EAAE,MAAM,MAAM,IAAI;AACvD,QAAI,WAAY;AAEhB,QAAI,QAAQ;AACV,UAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,IAAI,OAAO,CAAC,mBAAmB,IAAI,EAAE;AAAA,IACrE,OAAO;AACL,YAAMD,IAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC,YAAMA,IAAG,UAAU,MAAM,EAAE;AAC3B,UAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,MAAM,OAAO,CAAC,MAAM,IAAI,EAAE;AAAA,IAC1D;AACA;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,gBACb,SACA,OACA,QACiB;AACjB,QAAM,aAAa,QAAQ;AAC3B,MAAI,MAAMD,IAAG,KAAK,UAAU,EAAE,MAAM,MAAM,IAAI,GAAG;AAC/C,QAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,KAAK,QAAQ,CAAC,KAAK,UAAU,mBAAmB;AAC9E,WAAO;AAAA,EACT;AACA,MAAI,QAAQ;AACV,QAAI,CAAC,MAAO,SAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,mBAAmB,UAAU,EAAE;AACzE,WAAO;AAAA,EACT;AACA,QAAMD,IAAG,MAAMD,MAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5D,QAAMC,IAAG,UAAU,YAAY,aAAa,OAAO,GAAG,MAAM;AAC5D,MAAI,CAAC,MAAO,SAAQ,IAAI,GAAGC,IAAG,MAAM,OAAO,CAAC,MAAM,UAAU,EAAE;AAC9D,SAAO;AACT;AAMO,SAAS,sBAAsB,QAAgB,YAA4B;AAChF,QAAM,WAAWF,MAAK,QAAQ,MAAM;AACpC,QAAM,YAAYA,MAAK,QAAQA,MAAK,QAAQ,UAAU,CAAC;AACvD,QAAM,OAAOA,MAAK,QAAQI,IAAG,QAAQ,CAAC;AACtC,QAAM,MAAMJ,MAAK,SAAS,WAAW,QAAQ;AAC7C,MAAI,QAAQ,MAAM,CAAC,IAAI,WAAW,IAAI,KAAK,CAACA,MAAK,WAAW,GAAG,GAAG;AAChE,WAAO;AAAA,EACT;AACA,MAAI,aAAa,QAAQ,SAAS,WAAW,OAAOA,MAAK,GAAG,GAAG;AAC7D,UAAM,OAAOA,MAAK,SAAS,MAAM,QAAQ;AACzC,WAAO,SAAS,KAAK,MAAM,KAAK,IAAI;AAAA,EACtC;AACA,SAAO;AACT;AAOO,SAAS,aAAa,SAA8B;AACzD,QAAM,cAAc,KAAK,UAAU,QAAQ,OAAO;AAClD,QAAM,eAAe,kBAAkB,IAAI,CAAC,SAAS;AACnD,UAAM,QAAQ,QAAQ,SAAS,SAAS,IAAI,IAAI,SAAS;AACzD,WAAO,QAAQ,IAAI,MAAM,KAAK;AAAA,EAChC,CAAC,EAAE,KAAK,KAAK;AACb,QAAM,cACJ,QAAQ,mBAAmB,WACvB;AAAA,cACM,KAAK,UAAU,sBAAsB,QAAQ,QAAQ,QAAQ,UAAU,CAAC,CAAC;AAAA;AAAA,IAG/E;AAEN,SAAO;AAAA,EACP,WAAW;AAAA;AAAA,eAEE,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaxB,YAAY;AAAA;AAAA;AAAA;AAId;AAIA,SAAS,4BAA4B,QAAsB;AACzD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAIE,IAAG,KAAK,sDAAiD,CAAC;AACtE,UAAQ,IAAI,KAAK,MAAM,EAAE;AACzB,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,qEAAqE;AACjF,UAAQ,IAAI,8DAA8D;AAC1E,UAAQ,IAAI,YAAYA,IAAG,KAAK,YAAY,MAAM,EAAE,CAAC,kBAAkB;AACvE,UAAQ,IAAI,mBAAmBA,IAAG,KAAK,SAAS,MAAM,YAAY,CAAC,EAAE;AACvE;;;AEjbA,OAAOG,SAAQ;AAUf,eAAsB,UAAU,QAAsB,CAAC,GAAkB;AACvE,QAAM,MAAM,MAAM,YAAY,KAAK;AACnC,cAAY,KAAK,UAAU,KAAK;AAQhC,QAAM,QAAQ,MAAM,yBAAyB,IAAI,MAAM,QAAQ;AAC/D,QAAM,aAAa,IAAI,MAAM;AAE7B,QAAM,SACJ,MAAM,QAAQ;AAAA,IACZ,MAAM,IAAI,CAAC,EAAE,QAAQ,MAAM,iBAAiB,SAAS,YAAY,EAAE,WAAW,KAAK,CAAC,CAAC;AAAA,EACvF,GACA,KAAK;AAEP,MAAI,MAAM,WAAW,GAAG;AACtB,YAAQ,IAAIC,IAAG,IAAI,oCAAoC,CAAC;AACxD;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,YAAY,OAAO,MAAM,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC;AAE9E,MAAI,UAAU;AACd,MAAI,MAAM;AACV,MAAI,UAAU;AACd,aAAW,KAAK,UAAU;AACxB,QAAI,EAAE,WAAW,WAAW;AAC1B;AACA,UAAI,CAAC,MAAM,MAAO,SAAQ,IAAI,GAAGA,IAAG,OAAO,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE;AAAA,IACpE,WAAW,EAAE,WAAW,cAAc;AACpC;AACA,UAAI,CAAC,MAAM,MAAO,SAAQ,IAAI,GAAGA,IAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE,IAAI,EAAE;AAAA,IAC9E,WAAW,EAAE,WAAW,WAAW;AACjC;AACA,cAAQ,MAAM,GAAGA,IAAG,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,IAAIA,IAAG,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;AAAA,IACnF;AAAA,EACF;AAIA,MAAI,CAAC,MAAM,QAAQ;AACjB,UAAM,eAAe,MAAM,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,EAClD;AAEA,UAAQ,IAAI,EAAE;AACd,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAS,OAAM,KAAKA,IAAG,OAAO,GAAG,OAAO,UAAU,CAAC;AACvD,MAAI,IAAK,OAAM,KAAKA,IAAG,IAAI,GAAG,GAAG,UAAU,CAAC;AAC5C,MAAI,QAAS,OAAM,KAAKA,IAAG,IAAI,GAAG,OAAO,UAAU,CAAC;AACpD,UAAQ,IAAI,MAAM,WAAW,IAAIA,IAAG,IAAI,cAAc,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE;AAEjF,MAAI,UAAU,EAAG,SAAQ,WAAW;AACtC;;;AhB9CA,IAAM,WAAW,gBAAY;AAC7B,IAAM,cAAc,gBAAY;AAEhC,SAAS,mBAAmB,KAAmC;AAC7D,MACG,OAAO,mBAAmB,uCAAuC,EACjE,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,cAAc,6CAA6C,EAClE,OAAO,mBAAmB,uCAAuC,EACjE,OAAO,iBAAiB,iDAAiD,EACzE,OAAO,eAAe,kDAAkD,EACxE,OAAO,eAAe,+BAA+B,EACrD,OAAO,iBAAiB,0BAA0B,EAClD,OAAO,YAAY,gDAAgD;AACxE;AAEA,eAAe,OAAsB;AACnC,QAAM,MAAM,IAAI,WAAW;AAE3B,MACG,QAAQ,QAAQ,qDAAqD,EACrE,OAAO,WAAW,8CAA8C,EAChE,OAAO,aAAa,yDAAyD,EAC7E,OAAO,CAAC,UAA6D,QAAQ,KAAK,CAAC;AAEtF,MACG,QAAQ,QAAQ,wCAAwC,EACxD,OAAO,CAAC,UAAwB,QAAQ,KAAK,CAAC;AAEjD,MACG,QAAQ,SAAS,4CAA4C,EAC7D,OAAO,CAAC,UAAwB,SAAS,KAAK,CAAC;AAElD,MACG,QAAQ,UAAU,6CAA6C,EAC/D,OAAO,CAAC,UAAwB,UAAU,KAAK,CAAC;AAEnD,MACG,QAAQ,UAAU,mDAAmD,EACrE,OAAO,CAAC,UAAwB,UAAU,KAAK,CAAC;AAEnD,MACG,QAAQ,IAAI,oCAAoC,EAChD,OAAO,CAAC,UAAwB,QAAQ,KAAK,CAAC;AAEjD,qBAAmB,GAAG;AACtB,MAAI,KAAK;AACT,MAAI,QAAQ,WAAW;AAEvB,MAAI;AACF,QAAI,MAAM,QAAQ,MAAM,EAAE,KAAK,MAAM,CAAC;AACtC,UAAM,IAAI,kBAAkB;AAAA,EAC9B,SAAS,KAAK;AACZ,gBAAY,GAAG;AACf,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,YAAY,KAAoB;AACvC,MAAI,eAAe,qBAAqB;AACtC,YAAQ,MAAMC,IAAG,IAAI,IAAI,QAAQ;AAAA,CAAyC,CAAC;AAC3E,YAAQ,MAAM,WAAW;AACzB,eAAW,EAAE,QAAQ,OAAO,KAAK,IAAI,UAAU;AAC7C,cAAQ,MAAM,KAAK,OAAO,OAAO,EAAE,CAAC,IAAIA,IAAG,IAAI,MAAM,CAAC,EAAE;AAAA,IAC1D;AACA,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,QAAQ;AACtB,YAAQ,MAAM,iDAAiD;AAC/D,YAAQ,MAAM,yDAAyD;AACvE,YAAQ,MAAM,+CAA+C;AAC7D,YAAQ,MAAM,0CAA0C;AACxD;AAAA,EACF;AAEA,MAAI,eAAe,qBAAqB;AACtC,YAAQ,MAAMA,IAAG,IAAI,IAAI,QAAQ,cAAc,IAAI,OAAO,EAAE,CAAC;AAC7D,YAAQ,MAAMA,IAAG,IAAI,qEAAqE,CAAC;AAC3F;AAAA,EACF;AAEA,MAAI,eAAe,kBAAkB;AACnC,YAAQ,MAAMA,IAAG,IAAI,IAAI,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC;AACpD;AAAA,EACF;AAEA,MAAI,eAAe,oBAAoB,eAAe,eAAe;AACnE,YAAQ,MAAMA,IAAG,IAAI,IAAI,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC;AACpD;AAAA,EACF;AAEA,MAAI,eAAe,gBAAgB;AACjC,YAAQ,MAAMA,IAAG,IAAI,IAAI,QAAQ,KAAK,IAAI,OAAO,EAAE,CAAC;AACpD;AAAA,EACF;AAEA,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAQ,MAAMA,IAAG,IAAI,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;AAC5C,MAAI,QAAQ,IAAI,iBAAiB,GAAG;AAClC,YAAQ,MAAM,GAAG;AAAA,EACnB;AACF;AAEA,MAAM,KAAK;","names":["pc","pc","fs","path","fs","path","path","path","fs","fs","os","path","isInside","os","expandTilde","path","fs","path","fs","pc","fs","path","pc","fs","path","isDir","pc","path","fs","fs","os","path","pc","path","pc","pc","path","path","fs","pc","expandTilde","os","pc","pc","pc"]}
package/dist/index.d.ts CHANGED
@@ -55,10 +55,24 @@ type AdapterOverride = boolean | {
55
55
  layout?: Partial<Record<AssetType, AssetLayout>>;
56
56
  };
57
57
  /**
58
- * User-facing JSON configuration loaded from `<source>/agentlink.config.json`.
58
+ * User-facing JSON configuration (`agentlink.config.json`).
59
59
  * Every field is optional; sensible defaults apply.
60
60
  */
61
61
  interface AgentlinkConfig {
62
+ /**
63
+ * Persistent default for the `.agents/` source directory.
64
+ * Resolved after `--source`, before `cwd/.agents` and `~/.agents`. When set, beats a sparse repo-local `.agents/` (e.g. a few
65
+ * project-only commands). Relative paths are resolved against the config file directory.
66
+ */
67
+ source?: string;
68
+ /**
69
+ * Persistent default destination root (where adapter rootDirs like `.cursor`
70
+ * are expected). Relative paths are resolved against the config file directory.
71
+ * Mutually exclusive with {@link AgentlinkConfig.user}.
72
+ */
73
+ target?: string;
74
+ /** When true, project symlinks into `$HOME` (equivalent to `--user`). */
75
+ user?: boolean;
62
76
  /**
63
77
  * Asset type allowlist. When omitted, falls back to the built-in default
64
78
  * (`['skills', 'rules', 'commands']`). Use this to opt into less-common
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmkk/agentlink",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.3",
4
4
  "description": "Symlink your .agents/ assets into .cursor / .claude / .codebuddy and other AI agent directories with a single npx.",
5
5
  "keywords": [
6
6
  "ai",
@@ -16,14 +16,13 @@
16
16
  ],
17
17
  "license": "MIT",
18
18
  "author": "rankangkang <rankangkang@foxmail.com>",
19
- "homepage": "https://github.com/rankangkang/dot-agents/tree/main/packages/agentlink#readme",
19
+ "homepage": "https://github.com/rankangkang/agentlink#readme",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+https://github.com/rankangkang/dot-agents.git",
23
- "directory": "packages/agentlink"
22
+ "url": "git+https://github.com/rankangkang/agentlink.git"
24
23
  },
25
24
  "bugs": {
26
- "url": "https://github.com/rankangkang/dot-agents/issues"
25
+ "url": "https://github.com/rankangkang/agentlink/issues"
27
26
  },
28
27
  "type": "module",
29
28
  "engines": {
@@ -49,15 +48,6 @@
49
48
  "CHANGELOG.md",
50
49
  "LICENSE"
51
50
  ],
52
- "scripts": {
53
- "build": "tsup",
54
- "dev": "tsup --watch",
55
- "test": "vitest run",
56
- "test:watch": "vitest",
57
- "typecheck": "tsc --noEmit",
58
- "prepublishOnly": "pnpm build && pnpm test && pnpm typecheck",
59
- "publish:beta": "pnpm publish --tag beta"
60
- },
61
51
  "publishConfig": {
62
52
  "access": "public"
63
53
  },
@@ -77,5 +67,15 @@
77
67
  "tsup": "^8.5.1",
78
68
  "typescript": "^6.0.3",
79
69
  "vitest": "^4.1.5"
70
+ },
71
+ "scripts": {
72
+ "build": "tsup",
73
+ "dev": "tsup --watch",
74
+ "test": "vitest run",
75
+ "test:watch": "vitest",
76
+ "typecheck": "tsc --noEmit",
77
+ "preversion": "pnpm typecheck && pnpm test && pnpm build",
78
+ "publish:beta": "pnpm publish --tag beta --access public",
79
+ "publish:latest": "pnpm publish --access public"
80
80
  }
81
- }
81
+ }