@iannuttall/dotagents 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +32 -8
  2. package/dist/cli.js +2119 -1517
  3. package/package.json +5 -9
package/dist/cli.js CHANGED
@@ -19,6 +19,134 @@ var __toESM = (mod, isNodeMode, target) => {
19
19
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
20
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
21
 
22
+ // node_modules/sisteransi/src/index.js
23
+ var require_src = __commonJS((exports, module) => {
24
+ var ESC = "\x1B";
25
+ var CSI = `${ESC}[`;
26
+ var beep = "\x07";
27
+ var cursor = {
28
+ to(x, y) {
29
+ if (!y)
30
+ return `${CSI}${x + 1}G`;
31
+ return `${CSI}${y + 1};${x + 1}H`;
32
+ },
33
+ move(x, y) {
34
+ let ret = "";
35
+ if (x < 0)
36
+ ret += `${CSI}${-x}D`;
37
+ else if (x > 0)
38
+ ret += `${CSI}${x}C`;
39
+ if (y < 0)
40
+ ret += `${CSI}${-y}A`;
41
+ else if (y > 0)
42
+ ret += `${CSI}${y}B`;
43
+ return ret;
44
+ },
45
+ up: (count = 1) => `${CSI}${count}A`,
46
+ down: (count = 1) => `${CSI}${count}B`,
47
+ forward: (count = 1) => `${CSI}${count}C`,
48
+ backward: (count = 1) => `${CSI}${count}D`,
49
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
50
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
51
+ left: `${CSI}G`,
52
+ hide: `${CSI}?25l`,
53
+ show: `${CSI}?25h`,
54
+ save: `${ESC}7`,
55
+ restore: `${ESC}8`
56
+ };
57
+ var scroll = {
58
+ up: (count = 1) => `${CSI}S`.repeat(count),
59
+ down: (count = 1) => `${CSI}T`.repeat(count)
60
+ };
61
+ var erase = {
62
+ screen: `${CSI}2J`,
63
+ up: (count = 1) => `${CSI}1J`.repeat(count),
64
+ down: (count = 1) => `${CSI}J`.repeat(count),
65
+ line: `${CSI}2K`,
66
+ lineEnd: `${CSI}K`,
67
+ lineStart: `${CSI}1K`,
68
+ lines(count) {
69
+ let clear = "";
70
+ for (let i = 0;i < count; i++)
71
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
72
+ if (count)
73
+ clear += cursor.left;
74
+ return clear;
75
+ }
76
+ };
77
+ module.exports = { cursor, scroll, erase, beep };
78
+ });
79
+
80
+ // node_modules/picocolors/picocolors.js
81
+ var require_picocolors = __commonJS((exports, module) => {
82
+ var p = process || {};
83
+ var argv = p.argv || [];
84
+ var env2 = p.env || {};
85
+ var isColorSupported = !(!!env2.NO_COLOR || argv.includes("--no-color")) && (!!env2.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env2.TERM !== "dumb" || !!env2.CI);
86
+ var formatter = (open, close, replace = open) => (input) => {
87
+ let string = "" + input, index = string.indexOf(close, open.length);
88
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
89
+ };
90
+ var replaceClose = (string, close, replace, index) => {
91
+ let result = "", cursor = 0;
92
+ do {
93
+ result += string.substring(cursor, index) + replace;
94
+ cursor = index + close.length;
95
+ index = string.indexOf(close, cursor);
96
+ } while (~index);
97
+ return result + string.substring(cursor);
98
+ };
99
+ var createColors = (enabled = isColorSupported) => {
100
+ let f = enabled ? formatter : () => String;
101
+ return {
102
+ isColorSupported: enabled,
103
+ reset: f("\x1B[0m", "\x1B[0m"),
104
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
105
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
106
+ italic: f("\x1B[3m", "\x1B[23m"),
107
+ underline: f("\x1B[4m", "\x1B[24m"),
108
+ inverse: f("\x1B[7m", "\x1B[27m"),
109
+ hidden: f("\x1B[8m", "\x1B[28m"),
110
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
111
+ black: f("\x1B[30m", "\x1B[39m"),
112
+ red: f("\x1B[31m", "\x1B[39m"),
113
+ green: f("\x1B[32m", "\x1B[39m"),
114
+ yellow: f("\x1B[33m", "\x1B[39m"),
115
+ blue: f("\x1B[34m", "\x1B[39m"),
116
+ magenta: f("\x1B[35m", "\x1B[39m"),
117
+ cyan: f("\x1B[36m", "\x1B[39m"),
118
+ white: f("\x1B[37m", "\x1B[39m"),
119
+ gray: f("\x1B[90m", "\x1B[39m"),
120
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
121
+ bgRed: f("\x1B[41m", "\x1B[49m"),
122
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
123
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
124
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
125
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
126
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
127
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
128
+ blackBright: f("\x1B[90m", "\x1B[39m"),
129
+ redBright: f("\x1B[91m", "\x1B[39m"),
130
+ greenBright: f("\x1B[92m", "\x1B[39m"),
131
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
132
+ blueBright: f("\x1B[94m", "\x1B[39m"),
133
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
134
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
135
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
136
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
137
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
138
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
139
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
140
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
141
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
142
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
143
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
144
+ };
145
+ };
146
+ module.exports = createColors();
147
+ module.exports.createColors = createColors;
148
+ });
149
+
22
150
  // node_modules/kind-of/index.js
23
151
  var require_kind_of = __commonJS((exports, module) => {
24
152
  var toString = Object.prototype.toString;
@@ -164,23 +292,23 @@ var require_is_extendable = __commonJS((exports, module) => {
164
292
  // node_modules/extend-shallow/index.js
165
293
  var require_extend_shallow = __commonJS((exports, module) => {
166
294
  var isObject = require_is_extendable();
167
- module.exports = function extend(o) {
168
- if (!isObject(o)) {
169
- o = {};
295
+ module.exports = function extend(o2) {
296
+ if (!isObject(o2)) {
297
+ o2 = {};
170
298
  }
171
299
  var len = arguments.length;
172
300
  for (var i = 1;i < len; i++) {
173
301
  var obj = arguments[i];
174
302
  if (isObject(obj)) {
175
- assign(o, obj);
303
+ assign(o2, obj);
176
304
  }
177
305
  }
178
- return o;
306
+ return o2;
179
307
  };
180
- function assign(a, b) {
181
- for (var key in b) {
182
- if (hasOwn(b, key)) {
183
- a[key] = b[key];
308
+ function assign(a3, b3) {
309
+ for (var key in b3) {
310
+ if (hasOwn(b3, key)) {
311
+ a3[key] = b3[key];
184
312
  }
185
313
  }
186
314
  }
@@ -790,13 +918,13 @@ var require_int = __commonJS((exports, module) => {
790
918
  return sign * parseInt(value, 8);
791
919
  }
792
920
  if (value.indexOf(":") !== -1) {
793
- value.split(":").forEach(function(v) {
794
- digits.unshift(parseInt(v, 10));
921
+ value.split(":").forEach(function(v2) {
922
+ digits.unshift(parseInt(v2, 10));
795
923
  });
796
924
  value = 0;
797
925
  base = 1;
798
- digits.forEach(function(d) {
799
- value += d * base;
926
+ digits.forEach(function(d3) {
927
+ value += d3 * base;
800
928
  base *= 60;
801
929
  });
802
930
  return sign * value;
@@ -861,13 +989,13 @@ var require_float = __commonJS((exports, module) => {
861
989
  } else if (value === ".nan") {
862
990
  return NaN;
863
991
  } else if (value.indexOf(":") >= 0) {
864
- value.split(":").forEach(function(v) {
865
- digits.unshift(parseFloat(v, 10));
992
+ value.split(":").forEach(function(v2) {
993
+ digits.unshift(parseFloat(v2, 10));
866
994
  });
867
995
  value = 0;
868
996
  base = 1;
869
- digits.forEach(function(d) {
870
- value += d * base;
997
+ digits.forEach(function(d3) {
998
+ value += d3 * base;
871
999
  base *= 60;
872
1000
  });
873
1001
  return sign * value;
@@ -1321,7 +1449,7 @@ var require_function = __commonJS((exports, module) => {
1321
1449
  try {
1322
1450
  _require = __require;
1323
1451
  esprima = _require("esprima");
1324
- } catch (_) {
1452
+ } catch (_3) {
1325
1453
  if (typeof window !== "undefined")
1326
1454
  esprima = window.esprima;
1327
1455
  }
@@ -3378,7 +3506,7 @@ var require_parse = __commonJS((exports, module) => {
3378
3506
 
3379
3507
  // node_modules/gray-matter/index.js
3380
3508
  var require_gray_matter = __commonJS((exports, module) => {
3381
- var fs5 = __require("fs");
3509
+ var fs4 = __require("fs");
3382
3510
  var sections = require_section_matter();
3383
3511
  var defaults = require_defaults();
3384
3512
  var stringify = require_stringify();
@@ -3465,7 +3593,7 @@ var require_gray_matter = __commonJS((exports, module) => {
3465
3593
  return stringify(file, data, options2);
3466
3594
  };
3467
3595
  matter.read = function(filepath, options2) {
3468
- const str2 = fs5.readFileSync(filepath, "utf8");
3596
+ const str2 = fs4.readFileSync(filepath, "utf8");
3469
3597
  const file = matter(str2, options2);
3470
3598
  file.path = filepath;
3471
3599
  return file;
@@ -3493,292 +3621,1346 @@ var require_gray_matter = __commonJS((exports, module) => {
3493
3621
  });
3494
3622
 
3495
3623
  // src/cli.tsx
3496
- import { render } from "ink";
3497
-
3498
- // src/tui/App.tsx
3499
- import { useEffect as useEffect2, useMemo, useState } from "react";
3500
- import fs10 from "fs";
3501
- import { Box as Box4, Text as Text2, useApp, useInput as useInput2, useStdout as useStdout3 } from "ink";
3502
- import SelectInput from "ink-select-input";
3503
- import TextInput from "ink-text-input";
3504
- import Spinner from "ink-spinner";
3505
-
3506
- // src/core/plan.ts
3507
- import fs2 from "fs";
3508
- import path4 from "path";
3509
-
3510
- // src/core/mappings.ts
3511
- import path2 from "path";
3624
+ import path12 from "path";
3512
3625
 
3513
- // src/core/paths.ts
3514
- import os from "os";
3515
- import path from "path";
3516
- function resolveRoots(opts) {
3517
- const homeDir = opts.homeDir || os.homedir();
3518
- const projectRoot = path.resolve(opts.projectRoot || process.cwd());
3519
- if (opts.scope === "global") {
3520
- return {
3521
- canonicalRoot: path.join(homeDir, ".agents"),
3522
- claudeRoot: path.join(homeDir, ".claude"),
3523
- factoryRoot: path.join(homeDir, ".factory"),
3524
- codexRoot: path.join(homeDir, ".codex"),
3525
- projectRoot,
3526
- homeDir
3527
- };
3626
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
3627
+ var ANSI_BACKGROUND_OFFSET = 10;
3628
+ var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
3629
+ var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
3630
+ var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
3631
+ var styles = {
3632
+ modifier: {
3633
+ reset: [0, 0],
3634
+ bold: [1, 22],
3635
+ dim: [2, 22],
3636
+ italic: [3, 23],
3637
+ underline: [4, 24],
3638
+ overline: [53, 55],
3639
+ inverse: [7, 27],
3640
+ hidden: [8, 28],
3641
+ strikethrough: [9, 29]
3642
+ },
3643
+ color: {
3644
+ black: [30, 39],
3645
+ red: [31, 39],
3646
+ green: [32, 39],
3647
+ yellow: [33, 39],
3648
+ blue: [34, 39],
3649
+ magenta: [35, 39],
3650
+ cyan: [36, 39],
3651
+ white: [37, 39],
3652
+ blackBright: [90, 39],
3653
+ gray: [90, 39],
3654
+ grey: [90, 39],
3655
+ redBright: [91, 39],
3656
+ greenBright: [92, 39],
3657
+ yellowBright: [93, 39],
3658
+ blueBright: [94, 39],
3659
+ magentaBright: [95, 39],
3660
+ cyanBright: [96, 39],
3661
+ whiteBright: [97, 39]
3662
+ },
3663
+ bgColor: {
3664
+ bgBlack: [40, 49],
3665
+ bgRed: [41, 49],
3666
+ bgGreen: [42, 49],
3667
+ bgYellow: [43, 49],
3668
+ bgBlue: [44, 49],
3669
+ bgMagenta: [45, 49],
3670
+ bgCyan: [46, 49],
3671
+ bgWhite: [47, 49],
3672
+ bgBlackBright: [100, 49],
3673
+ bgGray: [100, 49],
3674
+ bgGrey: [100, 49],
3675
+ bgRedBright: [101, 49],
3676
+ bgGreenBright: [102, 49],
3677
+ bgYellowBright: [103, 49],
3678
+ bgBlueBright: [104, 49],
3679
+ bgMagentaBright: [105, 49],
3680
+ bgCyanBright: [106, 49],
3681
+ bgWhiteBright: [107, 49]
3528
3682
  }
3529
- return {
3530
- canonicalRoot: path.join(projectRoot, ".agents"),
3531
- claudeRoot: path.join(projectRoot, ".claude"),
3532
- factoryRoot: path.join(projectRoot, ".factory"),
3533
- codexRoot: path.join(projectRoot, ".codex"),
3534
- projectRoot,
3535
- homeDir
3536
- };
3537
- }
3538
-
3539
- // src/core/mappings.ts
3540
- function getMappings(opts) {
3541
- const roots = resolveRoots(opts);
3542
- const canonical = roots.canonicalRoot;
3543
- return [
3544
- {
3545
- name: "agents-md",
3546
- source: path2.join(canonical, "AGENTS.md"),
3547
- targets: [path2.join(roots.claudeRoot, "CLAUDE.md")],
3548
- kind: "file"
3683
+ };
3684
+ var modifierNames = Object.keys(styles.modifier);
3685
+ var foregroundColorNames = Object.keys(styles.color);
3686
+ var backgroundColorNames = Object.keys(styles.bgColor);
3687
+ var colorNames = [...foregroundColorNames, ...backgroundColorNames];
3688
+ function assembleStyles() {
3689
+ const codes = new Map;
3690
+ for (const [groupName, group] of Object.entries(styles)) {
3691
+ for (const [styleName, style] of Object.entries(group)) {
3692
+ styles[styleName] = {
3693
+ open: `\x1B[${style[0]}m`,
3694
+ close: `\x1B[${style[1]}m`
3695
+ };
3696
+ group[styleName] = styles[styleName];
3697
+ codes.set(style[0], style[1]);
3698
+ }
3699
+ Object.defineProperty(styles, groupName, {
3700
+ value: group,
3701
+ enumerable: false
3702
+ });
3703
+ }
3704
+ Object.defineProperty(styles, "codes", {
3705
+ value: codes,
3706
+ enumerable: false
3707
+ });
3708
+ styles.color.close = "\x1B[39m";
3709
+ styles.bgColor.close = "\x1B[49m";
3710
+ styles.color.ansi = wrapAnsi16();
3711
+ styles.color.ansi256 = wrapAnsi256();
3712
+ styles.color.ansi16m = wrapAnsi16m();
3713
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
3714
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
3715
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
3716
+ Object.defineProperties(styles, {
3717
+ rgbToAnsi256: {
3718
+ value(red, green, blue) {
3719
+ if (red === green && green === blue) {
3720
+ if (red < 8) {
3721
+ return 16;
3722
+ }
3723
+ if (red > 248) {
3724
+ return 231;
3725
+ }
3726
+ return Math.round((red - 8) / 247 * 24) + 232;
3727
+ }
3728
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
3729
+ },
3730
+ enumerable: false
3731
+ },
3732
+ hexToRgb: {
3733
+ value(hex) {
3734
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
3735
+ if (!matches) {
3736
+ return [0, 0, 0];
3737
+ }
3738
+ let [colorString] = matches;
3739
+ if (colorString.length === 3) {
3740
+ colorString = [...colorString].map((character) => character + character).join("");
3741
+ }
3742
+ const integer = Number.parseInt(colorString, 16);
3743
+ return [
3744
+ integer >> 16 & 255,
3745
+ integer >> 8 & 255,
3746
+ integer & 255
3747
+ ];
3748
+ },
3749
+ enumerable: false
3750
+ },
3751
+ hexToAnsi256: {
3752
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
3753
+ enumerable: false
3549
3754
  },
3550
- {
3551
- name: "commands",
3552
- source: path2.join(canonical, "commands"),
3553
- targets: [
3554
- path2.join(roots.claudeRoot, "commands"),
3555
- path2.join(roots.factoryRoot, "commands"),
3556
- path2.join(roots.codexRoot, "prompts")
3557
- ],
3558
- kind: "dir"
3755
+ ansi256ToAnsi: {
3756
+ value(code) {
3757
+ if (code < 8) {
3758
+ return 30 + code;
3759
+ }
3760
+ if (code < 16) {
3761
+ return 90 + (code - 8);
3762
+ }
3763
+ let red;
3764
+ let green;
3765
+ let blue;
3766
+ if (code >= 232) {
3767
+ red = ((code - 232) * 10 + 8) / 255;
3768
+ green = red;
3769
+ blue = red;
3770
+ } else {
3771
+ code -= 16;
3772
+ const remainder = code % 36;
3773
+ red = Math.floor(code / 36) / 5;
3774
+ green = Math.floor(remainder / 6) / 5;
3775
+ blue = remainder % 6 / 5;
3776
+ }
3777
+ const value = Math.max(red, green, blue) * 2;
3778
+ if (value === 0) {
3779
+ return 30;
3780
+ }
3781
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
3782
+ if (value === 2) {
3783
+ result += 60;
3784
+ }
3785
+ return result;
3786
+ },
3787
+ enumerable: false
3559
3788
  },
3560
- {
3561
- name: "hooks",
3562
- source: path2.join(canonical, "hooks"),
3563
- targets: [
3564
- path2.join(roots.claudeRoot, "hooks"),
3565
- path2.join(roots.factoryRoot, "hooks")
3566
- ],
3567
- kind: "dir"
3789
+ rgbToAnsi: {
3790
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
3791
+ enumerable: false
3568
3792
  },
3569
- {
3570
- name: "skills",
3571
- source: path2.join(canonical, "skills"),
3572
- targets: [
3573
- path2.join(roots.claudeRoot, "skills"),
3574
- path2.join(roots.factoryRoot, "skills")
3575
- ],
3576
- kind: "dir"
3793
+ hexToAnsi: {
3794
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
3795
+ enumerable: false
3577
3796
  }
3578
- ];
3797
+ });
3798
+ return styles;
3579
3799
  }
3800
+ var ansiStyles = assembleStyles();
3801
+ var ansi_styles_default = ansiStyles;
3580
3802
 
3581
- // src/utils/fs.ts
3582
- import fs from "fs";
3583
- import path3 from "path";
3584
- async function pathExists(p) {
3585
- try {
3586
- await fs.promises.lstat(p);
3587
- return true;
3588
- } catch (err) {
3589
- if (err && err.code === "ENOENT")
3590
- return false;
3591
- throw err;
3592
- }
3593
- }
3594
- async function ensureDir(dir) {
3595
- await fs.promises.mkdir(dir, { recursive: true });
3596
- }
3597
- async function ensureFile(filePath, content) {
3598
- await ensureDir(path3.dirname(filePath));
3599
- await fs.promises.writeFile(filePath, content, "utf8");
3600
- }
3601
- async function readText(filePath) {
3602
- return await fs.promises.readFile(filePath, "utf8");
3603
- }
3604
- async function copyFile(src, dest, force = false) {
3605
- if (!force && await pathExists(dest))
3606
- return "skipped";
3607
- await ensureDir(path3.dirname(dest));
3608
- await fs.promises.copyFile(src, dest);
3609
- return "written";
3803
+ // node_modules/chalk/source/vendor/supports-color/index.js
3804
+ import process2 from "node:process";
3805
+ import os from "node:os";
3806
+ import tty from "node:tty";
3807
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
3808
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
3809
+ const position = argv.indexOf(prefix + flag);
3810
+ const terminatorPosition = argv.indexOf("--");
3811
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
3610
3812
  }
3611
- async function copyDir(src, dest, force = false) {
3612
- if (!force && await pathExists(dest))
3613
- return "skipped";
3614
- await ensureDir(path3.dirname(dest));
3615
- await fs.promises.cp(src, dest, { recursive: true, force });
3616
- return "written";
3813
+ var { env } = process2;
3814
+ var flagForceColor;
3815
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
3816
+ flagForceColor = 0;
3817
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
3818
+ flagForceColor = 1;
3617
3819
  }
3618
- async function removePath(target) {
3619
- if (!await pathExists(target))
3620
- return;
3621
- const stat = await fs.promises.lstat(target);
3622
- if (stat.isDirectory() && !stat.isSymbolicLink()) {
3623
- await fs.promises.rm(target, { recursive: true, force: true });
3624
- } else {
3625
- await fs.promises.unlink(target);
3820
+ function envForceColor() {
3821
+ if ("FORCE_COLOR" in env) {
3822
+ if (env.FORCE_COLOR === "true") {
3823
+ return 1;
3824
+ }
3825
+ if (env.FORCE_COLOR === "false") {
3826
+ return 0;
3827
+ }
3828
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
3626
3829
  }
3627
3830
  }
3628
- async function listFiles(dir) {
3629
- try {
3630
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
3631
- return entries.filter((e) => e.isFile()).map((e) => path3.join(dir, e.name));
3632
- } catch (err) {
3633
- if (err && err.code === "ENOENT")
3634
- return [];
3635
- throw err;
3831
+ function translateLevel(level) {
3832
+ if (level === 0) {
3833
+ return false;
3636
3834
  }
3835
+ return {
3836
+ level,
3837
+ hasBasic: true,
3838
+ has256: level >= 2,
3839
+ has16m: level >= 3
3840
+ };
3637
3841
  }
3638
- async function listMarkdownFiles(dir) {
3639
- const files = await listFiles(dir);
3640
- return files.filter((f) => f.toLowerCase().endsWith(".md"));
3641
- }
3642
- async function listDirs(dir) {
3643
- try {
3644
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
3645
- return entries.filter((e) => e.isDirectory()).map((e) => path3.join(dir, e.name));
3646
- } catch (err) {
3647
- if (err && err.code === "ENOENT")
3648
- return [];
3649
- throw err;
3842
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
3843
+ const noFlagForceColor = envForceColor();
3844
+ if (noFlagForceColor !== undefined) {
3845
+ flagForceColor = noFlagForceColor;
3650
3846
  }
3651
- }
3652
-
3653
- // src/core/plan.ts
3654
- async function getLinkTargetAbsolute(targetPath) {
3655
- try {
3656
- const link = await fs2.promises.readlink(targetPath);
3657
- if (!path4.isAbsolute(link)) {
3658
- return path4.resolve(path4.dirname(targetPath), link);
3847
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
3848
+ if (forceColor === 0) {
3849
+ return 0;
3850
+ }
3851
+ if (sniffFlags) {
3852
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
3853
+ return 3;
3854
+ }
3855
+ if (hasFlag("color=256")) {
3856
+ return 2;
3659
3857
  }
3660
- return link;
3661
- } catch {
3662
- return null;
3663
3858
  }
3664
- }
3665
- async function ensureSourceTask(source, kind) {
3666
- const exists = await pathExists(source);
3667
- if (!exists)
3668
- return [{ type: "ensure-source", path: source, kind }];
3669
- const stat = await fs2.promises.lstat(source);
3670
- if (kind === "file" && stat.isDirectory()) {
3671
- return [{ type: "conflict", source, target: source, reason: "Expected file but found directory", kind }];
3859
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
3860
+ return 1;
3672
3861
  }
3673
- if (kind === "dir" && !stat.isDirectory()) {
3674
- return [{ type: "conflict", source, target: source, reason: "Expected directory but found file", kind }];
3862
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
3863
+ return 0;
3675
3864
  }
3676
- return [];
3677
- }
3678
- async function analyzeTarget(source, target, kind) {
3679
- const exists = await pathExists(target);
3680
- if (!exists)
3681
- return { type: "link", source, target, kind };
3682
- const stat = await fs2.promises.lstat(target);
3683
- if (stat.isSymbolicLink()) {
3684
- const resolved = await getLinkTargetAbsolute(target);
3685
- if (resolved && path4.resolve(resolved) === path4.resolve(source)) {
3686
- return { type: "noop", source, target };
3865
+ const min = forceColor || 0;
3866
+ if (env.TERM === "dumb") {
3867
+ return min;
3868
+ }
3869
+ if (process2.platform === "win32") {
3870
+ const osRelease = os.release().split(".");
3871
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
3872
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
3687
3873
  }
3688
- const detail = resolved ? `Symlink points elsewhere: ${resolved}` : "Symlink points elsewhere";
3689
- return { type: "conflict", source, target, reason: detail, kind };
3874
+ return 1;
3690
3875
  }
3691
- const targetKind = stat.isDirectory() ? "directory" : stat.isFile() ? "file" : "path";
3692
- return { type: "conflict", source, target, reason: `Target exists and is not a symlink (${targetKind})`, kind };
3693
- }
3694
- async function buildLinkPlan(opts) {
3695
- const mappings = getMappings(opts);
3696
- const tasks = [];
3697
- for (const mapping of mappings) {
3698
- tasks.push(...await ensureSourceTask(mapping.source, mapping.kind));
3699
- for (const target of mapping.targets) {
3700
- tasks.push(await analyzeTarget(mapping.source, target, mapping.kind));
3876
+ if ("CI" in env) {
3877
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => (key in env))) {
3878
+ return 3;
3879
+ }
3880
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => (sign in env)) || env.CI_NAME === "codeship") {
3881
+ return 1;
3701
3882
  }
3883
+ return min;
3702
3884
  }
3703
- const conflicts = tasks.filter((t) => t.type === "conflict");
3704
- const changes = tasks.filter((t) => t.type === "link" || t.type === "ensure-source");
3705
- return { tasks, conflicts, changes };
3885
+ if ("TEAMCITY_VERSION" in env) {
3886
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
3887
+ }
3888
+ if (env.COLORTERM === "truecolor") {
3889
+ return 3;
3890
+ }
3891
+ if (env.TERM === "xterm-kitty") {
3892
+ return 3;
3893
+ }
3894
+ if (env.TERM === "xterm-ghostty") {
3895
+ return 3;
3896
+ }
3897
+ if (env.TERM === "wezterm") {
3898
+ return 3;
3899
+ }
3900
+ if ("TERM_PROGRAM" in env) {
3901
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
3902
+ switch (env.TERM_PROGRAM) {
3903
+ case "iTerm.app": {
3904
+ return version >= 3 ? 3 : 2;
3905
+ }
3906
+ case "Apple_Terminal": {
3907
+ return 2;
3908
+ }
3909
+ }
3910
+ }
3911
+ if (/-256(color)?$/i.test(env.TERM)) {
3912
+ return 2;
3913
+ }
3914
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
3915
+ return 1;
3916
+ }
3917
+ if ("COLORTERM" in env) {
3918
+ return 1;
3919
+ }
3920
+ return min;
3921
+ }
3922
+ function createSupportsColor(stream, options2 = {}) {
3923
+ const level = _supportsColor(stream, {
3924
+ streamIsTTY: stream && stream.isTTY,
3925
+ ...options2
3926
+ });
3927
+ return translateLevel(level);
3706
3928
  }
3929
+ var supportsColor = {
3930
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
3931
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
3932
+ };
3933
+ var supports_color_default = supportsColor;
3707
3934
 
3708
- // src/core/apply.ts
3709
- import fs3 from "fs";
3710
- import path5 from "path";
3711
- var DEFAULT_AGENTS = `# AGENTS
3935
+ // node_modules/chalk/source/utilities.js
3936
+ function stringReplaceAll(string, substring, replacer) {
3937
+ let index = string.indexOf(substring);
3938
+ if (index === -1) {
3939
+ return string;
3940
+ }
3941
+ const substringLength = substring.length;
3942
+ let endIndex = 0;
3943
+ let returnValue = "";
3944
+ do {
3945
+ returnValue += string.slice(endIndex, index) + substring + replacer;
3946
+ endIndex = index + substringLength;
3947
+ index = string.indexOf(substring, endIndex);
3948
+ } while (index !== -1);
3949
+ returnValue += string.slice(endIndex);
3950
+ return returnValue;
3951
+ }
3952
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
3953
+ let endIndex = 0;
3954
+ let returnValue = "";
3955
+ do {
3956
+ const gotCR = string[index - 1] === "\r";
3957
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? `\r
3958
+ ` : `
3959
+ `) + postfix;
3960
+ endIndex = index + 1;
3961
+ index = string.indexOf(`
3962
+ `, endIndex);
3963
+ } while (index !== -1);
3964
+ returnValue += string.slice(endIndex);
3965
+ return returnValue;
3966
+ }
3712
3967
 
3713
- Add shared agent instructions here.
3714
- `;
3715
- async function createSource(task) {
3716
- if (task.kind === "dir") {
3717
- await ensureDir(task.path);
3718
- return;
3719
- }
3720
- await ensureFile(task.path, DEFAULT_AGENTS);
3968
+ // node_modules/chalk/source/index.js
3969
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
3970
+ var GENERATOR = Symbol("GENERATOR");
3971
+ var STYLER = Symbol("STYLER");
3972
+ var IS_EMPTY = Symbol("IS_EMPTY");
3973
+ var levelMapping = [
3974
+ "ansi",
3975
+ "ansi",
3976
+ "ansi256",
3977
+ "ansi16m"
3978
+ ];
3979
+ var styles2 = Object.create(null);
3980
+ var applyOptions = (object, options2 = {}) => {
3981
+ if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) {
3982
+ throw new Error("The `level` option should be an integer from 0 to 3");
3983
+ }
3984
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
3985
+ object.level = options2.level === undefined ? colorLevel : options2.level;
3986
+ };
3987
+ var chalkFactory = (options2) => {
3988
+ const chalk = (...strings) => strings.join(" ");
3989
+ applyOptions(chalk, options2);
3990
+ Object.setPrototypeOf(chalk, createChalk.prototype);
3991
+ return chalk;
3992
+ };
3993
+ function createChalk(options2) {
3994
+ return chalkFactory(options2);
3721
3995
  }
3722
- async function createLink(source, target, kind, force) {
3723
- if (await pathExists(target)) {
3724
- if (!force)
3725
- return;
3726
- await removePath(target);
3727
- }
3728
- await ensureDir(path5.dirname(target));
3729
- const type = kind === "dir" ? "junction" : "file";
3730
- await fs3.promises.symlink(source, target, type);
3996
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
3997
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
3998
+ styles2[styleName] = {
3999
+ get() {
4000
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
4001
+ Object.defineProperty(this, styleName, { value: builder });
4002
+ return builder;
4003
+ }
4004
+ };
3731
4005
  }
3732
- async function applyLinkPlan(plan, opts) {
3733
- const force = !!opts?.force;
3734
- let applied = 0;
3735
- let skipped = 0;
3736
- let conflicts = 0;
3737
- for (const task of plan.tasks) {
3738
- if (task.type === "conflict") {
3739
- conflicts += 1;
3740
- if (force && task.target !== task.source && task.kind) {
3741
- await createLink(task.source, task.target, task.kind, true);
3742
- applied += 1;
3743
- }
3744
- continue;
4006
+ styles2.visible = {
4007
+ get() {
4008
+ const builder = createBuilder(this, this[STYLER], true);
4009
+ Object.defineProperty(this, "visible", { value: builder });
4010
+ return builder;
4011
+ }
4012
+ };
4013
+ var getModelAnsi = (model, level, type, ...arguments_) => {
4014
+ if (model === "rgb") {
4015
+ if (level === "ansi16m") {
4016
+ return ansi_styles_default[type].ansi16m(...arguments_);
3745
4017
  }
3746
- if (task.type === "noop") {
3747
- skipped += 1;
3748
- continue;
4018
+ if (level === "ansi256") {
4019
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
3749
4020
  }
3750
- if (task.type === "ensure-source") {
3751
- await createSource(task);
3752
- applied += 1;
3753
- continue;
4021
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
4022
+ }
4023
+ if (model === "hex") {
4024
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
4025
+ }
4026
+ return ansi_styles_default[type][model](...arguments_);
4027
+ };
4028
+ var usedModels = ["rgb", "hex", "ansi256"];
4029
+ for (const model of usedModels) {
4030
+ styles2[model] = {
4031
+ get() {
4032
+ const { level } = this;
4033
+ return function(...arguments_) {
4034
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
4035
+ return createBuilder(this, styler, this[IS_EMPTY]);
4036
+ };
3754
4037
  }
3755
- if (task.type === "link") {
3756
- const before = await pathExists(task.target);
3757
- await createLink(task.source, task.target, task.kind, force);
3758
- if (before && !force)
3759
- skipped += 1;
3760
- else
3761
- applied += 1;
4038
+ };
4039
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
4040
+ styles2[bgModel] = {
4041
+ get() {
4042
+ const { level } = this;
4043
+ return function(...arguments_) {
4044
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
4045
+ return createBuilder(this, styler, this[IS_EMPTY]);
4046
+ };
3762
4047
  }
3763
- }
3764
- return { applied, skipped, conflicts };
4048
+ };
3765
4049
  }
3766
-
3767
- // src/core/status.ts
3768
- import fs4 from "fs";
3769
- import path6 from "path";
4050
+ var proto = Object.defineProperties(() => {}, {
4051
+ ...styles2,
4052
+ level: {
4053
+ enumerable: true,
4054
+ get() {
4055
+ return this[GENERATOR].level;
4056
+ },
4057
+ set(level) {
4058
+ this[GENERATOR].level = level;
4059
+ }
4060
+ }
4061
+ });
4062
+ var createStyler = (open, close, parent) => {
4063
+ let openAll;
4064
+ let closeAll;
4065
+ if (parent === undefined) {
4066
+ openAll = open;
4067
+ closeAll = close;
4068
+ } else {
4069
+ openAll = parent.openAll + open;
4070
+ closeAll = close + parent.closeAll;
4071
+ }
4072
+ return {
4073
+ open,
4074
+ close,
4075
+ openAll,
4076
+ closeAll,
4077
+ parent
4078
+ };
4079
+ };
4080
+ var createBuilder = (self, _styler, _isEmpty) => {
4081
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
4082
+ Object.setPrototypeOf(builder, proto);
4083
+ builder[GENERATOR] = self;
4084
+ builder[STYLER] = _styler;
4085
+ builder[IS_EMPTY] = _isEmpty;
4086
+ return builder;
4087
+ };
4088
+ var applyStyle = (self, string) => {
4089
+ if (self.level <= 0 || !string) {
4090
+ return self[IS_EMPTY] ? "" : string;
4091
+ }
4092
+ let styler = self[STYLER];
4093
+ if (styler === undefined) {
4094
+ return string;
4095
+ }
4096
+ const { openAll, closeAll } = styler;
4097
+ if (string.includes("\x1B")) {
4098
+ while (styler !== undefined) {
4099
+ string = stringReplaceAll(string, styler.close, styler.open);
4100
+ styler = styler.parent;
4101
+ }
4102
+ }
4103
+ const lfIndex = string.indexOf(`
4104
+ `);
4105
+ if (lfIndex !== -1) {
4106
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
4107
+ }
4108
+ return openAll + string + closeAll;
4109
+ };
4110
+ Object.defineProperties(createChalk.prototype, styles2);
4111
+ var chalk = createChalk();
4112
+ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
4113
+ var source_default = chalk;
4114
+
4115
+ // node_modules/@clack/core/dist/index.mjs
4116
+ var import_sisteransi = __toESM(require_src(), 1);
4117
+ import { stdin as $, stdout as k } from "node:process";
4118
+ import * as f from "node:readline";
4119
+ import _ from "node:readline";
4120
+ import { WriteStream as U } from "node:tty";
4121
+ function q({ onlyFirst: e = false } = {}) {
4122
+ const F = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
4123
+ return new RegExp(F, e ? undefined : "g");
4124
+ }
4125
+ var J = q();
4126
+ function S(e) {
4127
+ if (typeof e != "string")
4128
+ throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);
4129
+ return e.replace(J, "");
4130
+ }
4131
+ function T(e) {
4132
+ return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
4133
+ }
4134
+ var j = { exports: {} };
4135
+ (function(e) {
4136
+ var u = {};
4137
+ e.exports = u, u.eastAsianWidth = function(t) {
4138
+ var s = t.charCodeAt(0), C = t.length == 2 ? t.charCodeAt(1) : 0, D = s;
4139
+ return 55296 <= s && s <= 56319 && 56320 <= C && C <= 57343 && (s &= 1023, C &= 1023, D = s << 10 | C, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
4140
+ }, u.characterLength = function(t) {
4141
+ var s = this.eastAsianWidth(t);
4142
+ return s == "F" || s == "W" || s == "A" ? 2 : 1;
4143
+ };
4144
+ function F(t) {
4145
+ return t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
4146
+ }
4147
+ u.length = function(t) {
4148
+ for (var s = F(t), C = 0, D = 0;D < s.length; D++)
4149
+ C = C + this.characterLength(s[D]);
4150
+ return C;
4151
+ }, u.slice = function(t, s, C) {
4152
+ textLen = u.length(t), s = s || 0, C = C || 1, s < 0 && (s = textLen + s), C < 0 && (C = textLen + C);
4153
+ for (var D = "", i = 0, n = F(t), E = 0;E < n.length; E++) {
4154
+ var h = n[E], o = u.length(h);
4155
+ if (i >= s - (o == 2 ? 1 : 0))
4156
+ if (i + o <= C)
4157
+ D += h;
4158
+ else
4159
+ break;
4160
+ i += o;
4161
+ }
4162
+ return D;
4163
+ };
4164
+ })(j);
4165
+ var Q = j.exports;
4166
+ var X = T(Q);
4167
+ var DD = function() {
4168
+ return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
4169
+ };
4170
+ var uD = T(DD);
4171
+ function A(e, u = {}) {
4172
+ if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: true, ...u }, e = S(e), e.length === 0))
4173
+ return 0;
4174
+ e = e.replace(uD(), " ");
4175
+ const F = u.ambiguousIsNarrow ? 1 : 2;
4176
+ let t = 0;
4177
+ for (const s of e) {
4178
+ const C = s.codePointAt(0);
4179
+ if (C <= 31 || C >= 127 && C <= 159 || C >= 768 && C <= 879)
4180
+ continue;
4181
+ switch (X.eastAsianWidth(s)) {
4182
+ case "F":
4183
+ case "W":
4184
+ t += 2;
4185
+ break;
4186
+ case "A":
4187
+ t += F;
4188
+ break;
4189
+ default:
4190
+ t += 1;
4191
+ }
4192
+ }
4193
+ return t;
4194
+ }
4195
+ var d = 10;
4196
+ var M = (e = 0) => (u) => `\x1B[${u + e}m`;
4197
+ var P = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`;
4198
+ var W = (e = 0) => (u, F, t) => `\x1B[${38 + e};2;${u};${F};${t}m`;
4199
+ var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
4200
+ Object.keys(r.modifier);
4201
+ var FD = Object.keys(r.color);
4202
+ var eD = Object.keys(r.bgColor);
4203
+ [...FD, ...eD];
4204
+ function tD() {
4205
+ const e = new Map;
4206
+ for (const [u, F] of Object.entries(r)) {
4207
+ for (const [t, s] of Object.entries(F))
4208
+ r[t] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, F[t] = r[t], e.set(s[0], s[1]);
4209
+ Object.defineProperty(r, u, { value: F, enumerable: false });
4210
+ }
4211
+ return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = M(), r.color.ansi256 = P(), r.color.ansi16m = W(), r.bgColor.ansi = M(d), r.bgColor.ansi256 = P(d), r.bgColor.ansi16m = W(d), Object.defineProperties(r, { rgbToAnsi256: { value: (u, F, t) => u === F && F === t ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(F / 255 * 5) + Math.round(t / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
4212
+ const F = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
4213
+ if (!F)
4214
+ return [0, 0, 0];
4215
+ let [t] = F;
4216
+ t.length === 3 && (t = [...t].map((C) => C + C).join(""));
4217
+ const s = Number.parseInt(t, 16);
4218
+ return [s >> 16 & 255, s >> 8 & 255, s & 255];
4219
+ }, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
4220
+ if (u < 8)
4221
+ return 30 + u;
4222
+ if (u < 16)
4223
+ return 90 + (u - 8);
4224
+ let F, t, s;
4225
+ if (u >= 232)
4226
+ F = ((u - 232) * 10 + 8) / 255, t = F, s = F;
4227
+ else {
4228
+ u -= 16;
4229
+ const i = u % 36;
4230
+ F = Math.floor(u / 36) / 5, t = Math.floor(i / 6) / 5, s = i % 6 / 5;
4231
+ }
4232
+ const C = Math.max(F, t, s) * 2;
4233
+ if (C === 0)
4234
+ return 30;
4235
+ let D = 30 + (Math.round(s) << 2 | Math.round(t) << 1 | Math.round(F));
4236
+ return C === 2 && (D += 60), D;
4237
+ }, enumerable: false }, rgbToAnsi: { value: (u, F, t) => r.ansi256ToAnsi(r.rgbToAnsi256(u, F, t)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
4238
+ }
4239
+ var sD = tD();
4240
+ var g = new Set(["\x1B", "›"]);
4241
+ var CD = 39;
4242
+ var b = "\x07";
4243
+ var O = "[";
4244
+ var iD = "]";
4245
+ var I = "m";
4246
+ var w = `${iD}8;;`;
4247
+ var N = (e) => `${g.values().next().value}${O}${e}${I}`;
4248
+ var L = (e) => `${g.values().next().value}${w}${e}${b}`;
4249
+ var rD = (e) => e.split(" ").map((u) => A(u));
4250
+ var y = (e, u, F) => {
4251
+ const t = [...u];
4252
+ let s = false, C = false, D = A(S(e[e.length - 1]));
4253
+ for (const [i, n] of t.entries()) {
4254
+ const E = A(n);
4255
+ if (D + E <= F ? e[e.length - 1] += n : (e.push(n), D = 0), g.has(n) && (s = true, C = t.slice(i + 1).join("").startsWith(w)), s) {
4256
+ C ? n === b && (s = false, C = false) : n === I && (s = false);
4257
+ continue;
4258
+ }
4259
+ D += E, D === F && i < t.length - 1 && (e.push(""), D = 0);
4260
+ }
4261
+ !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
4262
+ };
4263
+ var ED = (e) => {
4264
+ const u = e.split(" ");
4265
+ let F = u.length;
4266
+ for (;F > 0 && !(A(u[F - 1]) > 0); )
4267
+ F--;
4268
+ return F === u.length ? e : u.slice(0, F).join(" ") + u.slice(F).join("");
4269
+ };
4270
+ var oD = (e, u, F = {}) => {
4271
+ if (F.trim !== false && e.trim() === "")
4272
+ return "";
4273
+ let t = "", s, C;
4274
+ const D = rD(e);
4275
+ let i = [""];
4276
+ for (const [E, h] of e.split(" ").entries()) {
4277
+ F.trim !== false && (i[i.length - 1] = i[i.length - 1].trimStart());
4278
+ let o = A(i[i.length - 1]);
4279
+ if (E !== 0 && (o >= u && (F.wordWrap === false || F.trim === false) && (i.push(""), o = 0), (o > 0 || F.trim === false) && (i[i.length - 1] += " ", o++)), F.hard && D[E] > u) {
4280
+ const B = u - o, p = 1 + Math.floor((D[E] - B - 1) / u);
4281
+ Math.floor((D[E] - 1) / u) < p && i.push(""), y(i, h, u);
4282
+ continue;
4283
+ }
4284
+ if (o + D[E] > u && o > 0 && D[E] > 0) {
4285
+ if (F.wordWrap === false && o < u) {
4286
+ y(i, h, u);
4287
+ continue;
4288
+ }
4289
+ i.push("");
4290
+ }
4291
+ if (o + D[E] > u && F.wordWrap === false) {
4292
+ y(i, h, u);
4293
+ continue;
4294
+ }
4295
+ i[i.length - 1] += h;
4296
+ }
4297
+ F.trim !== false && (i = i.map((E) => ED(E)));
4298
+ const n = [...i.join(`
4299
+ `)];
4300
+ for (const [E, h] of n.entries()) {
4301
+ if (t += h, g.has(h)) {
4302
+ const { groups: B } = new RegExp(`(?:\\${O}(?<code>\\d+)m|\\${w}(?<uri>.*)${b})`).exec(n.slice(E).join("")) || { groups: {} };
4303
+ if (B.code !== undefined) {
4304
+ const p = Number.parseFloat(B.code);
4305
+ s = p === CD ? undefined : p;
4306
+ } else
4307
+ B.uri !== undefined && (C = B.uri.length === 0 ? undefined : B.uri);
4308
+ }
4309
+ const o = sD.codes.get(Number(s));
4310
+ n[E + 1] === `
4311
+ ` ? (C && (t += L("")), s && o && (t += N(o))) : h === `
4312
+ ` && (s && o && (t += N(s)), C && (t += L(C)));
4313
+ }
4314
+ return t;
4315
+ };
4316
+ function R(e, u, F) {
4317
+ return String(e).normalize().replace(/\r\n/g, `
4318
+ `).split(`
4319
+ `).map((t) => oD(t, u, F)).join(`
4320
+ `);
4321
+ }
4322
+ var nD = Object.defineProperty;
4323
+ var aD = (e, u, F) => (u in e) ? nD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
4324
+ var a = (e, u, F) => (aD(e, typeof u != "symbol" ? u + "" : u, F), F);
4325
+ function hD(e, u) {
4326
+ if (e === u)
4327
+ return;
4328
+ const F = e.split(`
4329
+ `), t = u.split(`
4330
+ `), s = [];
4331
+ for (let C = 0;C < Math.max(F.length, t.length); C++)
4332
+ F[C] !== t[C] && s.push(C);
4333
+ return s;
4334
+ }
4335
+ var V = Symbol("clack:cancel");
4336
+ function lD(e) {
4337
+ return e === V;
4338
+ }
4339
+ function v(e, u) {
4340
+ e.isTTY && e.setRawMode(u);
4341
+ }
4342
+ var z = new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"]]);
4343
+ var xD = new Set(["up", "down", "left", "right", "space", "enter"]);
4344
+
4345
+ class x {
4346
+ constructor({ render: u, input: F = $, output: t = k, ...s }, C = true) {
4347
+ a(this, "input"), a(this, "output"), a(this, "rl"), a(this, "opts"), a(this, "_track", false), a(this, "_render"), a(this, "_cursor", 0), a(this, "state", "initial"), a(this, "value"), a(this, "error", ""), a(this, "subscribers", new Map), a(this, "_prevFrame", ""), this.opts = s, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = u.bind(this), this._track = C, this.input = F, this.output = t;
4348
+ }
4349
+ prompt() {
4350
+ const u = new U(0);
4351
+ return u._write = (F, t, s) => {
4352
+ this._track && (this.value = this.rl.line.replace(/\t/g, ""), this._cursor = this.rl.cursor, this.emit("value", this.value)), s();
4353
+ }, this.input.pipe(u), this.rl = _.createInterface({ input: this.input, output: u, tabSize: 2, prompt: "", escapeCodeTimeout: 50 }), _.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== undefined && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), v(this.input, true), this.output.on("resize", this.render), this.render(), new Promise((F, t) => {
4354
+ this.once("submit", () => {
4355
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), v(this.input, false), F(this.value);
4356
+ }), this.once("cancel", () => {
4357
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), v(this.input, false), F(V);
4358
+ });
4359
+ });
4360
+ }
4361
+ on(u, F) {
4362
+ const t = this.subscribers.get(u) ?? [];
4363
+ t.push({ cb: F }), this.subscribers.set(u, t);
4364
+ }
4365
+ once(u, F) {
4366
+ const t = this.subscribers.get(u) ?? [];
4367
+ t.push({ cb: F, once: true }), this.subscribers.set(u, t);
4368
+ }
4369
+ emit(u, ...F) {
4370
+ const t = this.subscribers.get(u) ?? [], s = [];
4371
+ for (const C of t)
4372
+ C.cb(...F), C.once && s.push(() => t.splice(t.indexOf(C), 1));
4373
+ for (const C of s)
4374
+ C();
4375
+ }
4376
+ unsubscribe() {
4377
+ this.subscribers.clear();
4378
+ }
4379
+ onKeypress(u, F) {
4380
+ if (this.state === "error" && (this.state = "active"), F?.name && !this._track && z.has(F.name) && this.emit("cursor", z.get(F.name)), F?.name && xD.has(F.name) && this.emit("cursor", F.name), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), F?.name === "return") {
4381
+ if (this.opts.validate) {
4382
+ const t = this.opts.validate(this.value);
4383
+ t && (this.error = t, this.state = "error", this.rl.write(this.value));
4384
+ }
4385
+ this.state !== "error" && (this.state = "submit");
4386
+ }
4387
+ u === "\x03" && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
4388
+ }
4389
+ close() {
4390
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
4391
+ `), v(this.input, false), this.rl.close(), this.emit(`${this.state}`, this.value), this.unsubscribe();
4392
+ }
4393
+ restoreCursor() {
4394
+ const u = R(this._prevFrame, process.stdout.columns, { hard: true }).split(`
4395
+ `).length - 1;
4396
+ this.output.write(import_sisteransi.cursor.move(-999, u * -1));
4397
+ }
4398
+ render() {
4399
+ const u = R(this._render(this) ?? "", process.stdout.columns, { hard: true });
4400
+ if (u !== this._prevFrame) {
4401
+ if (this.state === "initial")
4402
+ this.output.write(import_sisteransi.cursor.hide);
4403
+ else {
4404
+ const F = hD(this._prevFrame, u);
4405
+ if (this.restoreCursor(), F && F?.length === 1) {
4406
+ const t = F[0];
4407
+ this.output.write(import_sisteransi.cursor.move(0, t)), this.output.write(import_sisteransi.erase.lines(1));
4408
+ const s = u.split(`
4409
+ `);
4410
+ this.output.write(s[t]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - t - 1));
4411
+ return;
4412
+ } else if (F && F?.length > 1) {
4413
+ const t = F[0];
4414
+ this.output.write(import_sisteransi.cursor.move(0, t)), this.output.write(import_sisteransi.erase.down());
4415
+ const s = u.split(`
4416
+ `).slice(t);
4417
+ this.output.write(s.join(`
4418
+ `)), this._prevFrame = u;
4419
+ return;
4420
+ }
4421
+ this.output.write(import_sisteransi.erase.down());
4422
+ }
4423
+ this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
4424
+ }
4425
+ }
4426
+ }
4427
+
4428
+ class BD extends x {
4429
+ get cursor() {
4430
+ return this.value ? 0 : 1;
4431
+ }
4432
+ get _value() {
4433
+ return this.cursor === 0;
4434
+ }
4435
+ constructor(u) {
4436
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
4437
+ this.value = this._value;
4438
+ }), this.on("confirm", (F) => {
4439
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = F, this.state = "submit", this.close();
4440
+ }), this.on("cursor", () => {
4441
+ this.value = !this.value;
4442
+ });
4443
+ }
4444
+ }
4445
+ var fD = Object.defineProperty;
4446
+ var gD = (e, u, F) => (u in e) ? fD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
4447
+ var K = (e, u, F) => (gD(e, typeof u != "symbol" ? u + "" : u, F), F);
4448
+ var vD = class extends x {
4449
+ constructor(u) {
4450
+ super(u, false), K(this, "options"), K(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: F }) => F === u.cursorAt), 0), this.on("key", (F) => {
4451
+ F === "a" && this.toggleAll();
4452
+ }), this.on("cursor", (F) => {
4453
+ switch (F) {
4454
+ case "left":
4455
+ case "up":
4456
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
4457
+ break;
4458
+ case "down":
4459
+ case "right":
4460
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
4461
+ break;
4462
+ case "space":
4463
+ this.toggleValue();
4464
+ break;
4465
+ }
4466
+ });
4467
+ }
4468
+ get _value() {
4469
+ return this.options[this.cursor].value;
4470
+ }
4471
+ toggleAll() {
4472
+ const u = this.value.length === this.options.length;
4473
+ this.value = u ? [] : this.options.map((F) => F.value);
4474
+ }
4475
+ toggleValue() {
4476
+ const u = this.value.includes(this._value);
4477
+ this.value = u ? this.value.filter((F) => F !== this._value) : [...this.value, this._value];
4478
+ }
4479
+ };
4480
+ var wD = Object.defineProperty;
4481
+ var yD = (e, u, F) => (u in e) ? wD(e, u, { enumerable: true, configurable: true, writable: true, value: F }) : e[u] = F;
4482
+ var Z = (e, u, F) => (yD(e, typeof u != "symbol" ? u + "" : u, F), F);
4483
+ var $D = class extends x {
4484
+ constructor(u) {
4485
+ super(u, false), Z(this, "options"), Z(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: F }) => F === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (F) => {
4486
+ switch (F) {
4487
+ case "left":
4488
+ case "up":
4489
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
4490
+ break;
4491
+ case "down":
4492
+ case "right":
4493
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
4494
+ break;
4495
+ }
4496
+ this.changeValue();
4497
+ });
4498
+ }
4499
+ get _value() {
4500
+ return this.options[this.cursor];
4501
+ }
4502
+ changeValue() {
4503
+ this.value = this._value.value;
4504
+ }
4505
+ };
4506
+ var WD = globalThis.process.platform.startsWith("win");
4507
+ function OD({ input: e = $, output: u = k, overwrite: F = true, hideCursor: t = true } = {}) {
4508
+ const s = f.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
4509
+ f.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
4510
+ const C = (D, { name: i }) => {
4511
+ if (String(D) === "\x03") {
4512
+ t && u.write(import_sisteransi.cursor.show), process.exit(0);
4513
+ return;
4514
+ }
4515
+ if (!F)
4516
+ return;
4517
+ let n = i === "return" ? 0 : -1, E = i === "return" ? -1 : 0;
4518
+ f.moveCursor(u, n, E, () => {
4519
+ f.clearLine(u, 1, () => {
4520
+ e.once("keypress", C);
4521
+ });
4522
+ });
4523
+ };
4524
+ return t && u.write(import_sisteransi.cursor.hide), e.once("keypress", C), () => {
4525
+ e.off("keypress", C), t && u.write(import_sisteransi.cursor.show), e.isTTY && !WD && e.setRawMode(false), s.terminal = false, s.close();
4526
+ };
4527
+ }
4528
+
4529
+ // node_modules/@clack/prompts/dist/index.mjs
4530
+ var import_picocolors = __toESM(require_picocolors(), 1);
4531
+ var import_sisteransi2 = __toESM(require_src(), 1);
4532
+ import h from "node:process";
4533
+ function q2() {
4534
+ return h.platform !== "win32" ? h.env.TERM !== "linux" : Boolean(h.env.CI) || Boolean(h.env.WT_SESSION) || Boolean(h.env.TERMINUS_SUBLIME) || h.env.ConEmuTask === "{cmd::Cmder}" || h.env.TERM_PROGRAM === "Terminus-Sublime" || h.env.TERM_PROGRAM === "vscode" || h.env.TERM === "xterm-256color" || h.env.TERM === "alacritty" || h.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
4535
+ }
4536
+ var _2 = q2();
4537
+ var o = (r2, n) => _2 ? r2 : n;
4538
+ var H = o("◆", "*");
4539
+ var I2 = o("■", "x");
4540
+ var x2 = o("▲", "x");
4541
+ var S2 = o("◇", "o");
4542
+ var K2 = o("┌", "T");
4543
+ var a2 = o("│", "|");
4544
+ var d2 = o("└", "—");
4545
+ var b2 = o("●", ">");
4546
+ var E = o("○", " ");
4547
+ var C = o("◻", "[•]");
4548
+ var w2 = o("◼", "[+]");
4549
+ var M2 = o("◻", "[ ]");
4550
+ var U2 = o("▪", "•");
4551
+ var B = o("─", "-");
4552
+ var Z2 = o("╮", "+");
4553
+ var z2 = o("├", "+");
4554
+ var X2 = o("╯", "+");
4555
+ var J2 = o("●", "•");
4556
+ var Y = o("◆", "*");
4557
+ var Q2 = o("▲", "!");
4558
+ var ee = o("■", "x");
4559
+ var y2 = (r2) => {
4560
+ switch (r2) {
4561
+ case "initial":
4562
+ case "active":
4563
+ return import_picocolors.default.cyan(H);
4564
+ case "cancel":
4565
+ return import_picocolors.default.red(I2);
4566
+ case "error":
4567
+ return import_picocolors.default.yellow(x2);
4568
+ case "submit":
4569
+ return import_picocolors.default.green(S2);
4570
+ }
4571
+ };
4572
+ var se = (r2) => {
4573
+ const n = r2.active ?? "Yes", i = r2.inactive ?? "No";
4574
+ return new BD({ active: n, inactive: i, initialValue: r2.initialValue ?? true, render() {
4575
+ const t = `${import_picocolors.default.gray(a2)}
4576
+ ${y2(this.state)} ${r2.message}
4577
+ `, s = this.value ? n : i;
4578
+ switch (this.state) {
4579
+ case "submit":
4580
+ return `${t}${import_picocolors.default.gray(a2)} ${import_picocolors.default.dim(s)}`;
4581
+ case "cancel":
4582
+ return `${t}${import_picocolors.default.gray(a2)} ${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}
4583
+ ${import_picocolors.default.gray(a2)}`;
4584
+ default:
4585
+ return `${t}${import_picocolors.default.cyan(a2)} ${this.value ? `${import_picocolors.default.green(b2)} ${n}` : `${import_picocolors.default.dim(E)} ${import_picocolors.default.dim(n)}`} ${import_picocolors.default.dim("/")} ${this.value ? `${import_picocolors.default.dim(E)} ${import_picocolors.default.dim(i)}` : `${import_picocolors.default.green(b2)} ${i}`}
4586
+ ${import_picocolors.default.cyan(d2)}
4587
+ `;
4588
+ }
4589
+ } }).prompt();
4590
+ };
4591
+ var ie = (r2) => {
4592
+ const n = (t, s) => {
4593
+ const c = t.label ?? String(t.value);
4594
+ return s === "active" ? `${import_picocolors.default.green(b2)} ${c} ${t.hint ? import_picocolors.default.dim(`(${t.hint})`) : ""}` : s === "selected" ? `${import_picocolors.default.dim(c)}` : s === "cancelled" ? `${import_picocolors.default.strikethrough(import_picocolors.default.dim(c))}` : `${import_picocolors.default.dim(E)} ${import_picocolors.default.dim(c)}`;
4595
+ };
4596
+ let i = 0;
4597
+ return new $D({ options: r2.options, initialValue: r2.initialValue, render() {
4598
+ const t = `${import_picocolors.default.gray(a2)}
4599
+ ${y2(this.state)} ${r2.message}
4600
+ `;
4601
+ switch (this.state) {
4602
+ case "submit":
4603
+ return `${t}${import_picocolors.default.gray(a2)} ${n(this.options[this.cursor], "selected")}`;
4604
+ case "cancel":
4605
+ return `${t}${import_picocolors.default.gray(a2)} ${n(this.options[this.cursor], "cancelled")}
4606
+ ${import_picocolors.default.gray(a2)}`;
4607
+ default: {
4608
+ const s = r2.maxItems === undefined ? 1 / 0 : Math.max(r2.maxItems, 5);
4609
+ this.cursor >= i + s - 3 ? i = Math.max(Math.min(this.cursor - s + 3, this.options.length - s), 0) : this.cursor < i + 2 && (i = Math.max(this.cursor - 2, 0));
4610
+ const c = s < this.options.length && i > 0, l2 = s < this.options.length && i + s < this.options.length;
4611
+ return `${t}${import_picocolors.default.cyan(a2)} ${this.options.slice(i, i + s).map((u, m2, $2) => m2 === 0 && c ? import_picocolors.default.dim("...") : m2 === $2.length - 1 && l2 ? import_picocolors.default.dim("...") : n(u, m2 + i === this.cursor ? "active" : "inactive")).join(`
4612
+ ${import_picocolors.default.cyan(a2)} `)}
4613
+ ${import_picocolors.default.cyan(d2)}
4614
+ `;
4615
+ }
4616
+ }
4617
+ } }).prompt();
4618
+ };
4619
+ var ae = (r2) => {
4620
+ const n = (i, t) => {
4621
+ const s = i.label ?? String(i.value);
4622
+ return t === "active" ? `${import_picocolors.default.cyan(C)} ${s} ${i.hint ? import_picocolors.default.dim(`(${i.hint})`) : ""}` : t === "selected" ? `${import_picocolors.default.green(w2)} ${import_picocolors.default.dim(s)}` : t === "cancelled" ? `${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}` : t === "active-selected" ? `${import_picocolors.default.green(w2)} ${s} ${i.hint ? import_picocolors.default.dim(`(${i.hint})`) : ""}` : t === "submitted" ? `${import_picocolors.default.dim(s)}` : `${import_picocolors.default.dim(M2)} ${import_picocolors.default.dim(s)}`;
4623
+ };
4624
+ return new vD({ options: r2.options, initialValues: r2.initialValues, required: r2.required ?? true, cursorAt: r2.cursorAt, validate(i) {
4625
+ if (this.required && i.length === 0)
4626
+ return `Please select at least one option.
4627
+ ${import_picocolors.default.reset(import_picocolors.default.dim(`Press ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" space ")))} to select, ${import_picocolors.default.gray(import_picocolors.default.bgWhite(import_picocolors.default.inverse(" enter ")))} to submit`))}`;
4628
+ }, render() {
4629
+ let i = `${import_picocolors.default.gray(a2)}
4630
+ ${y2(this.state)} ${r2.message}
4631
+ `;
4632
+ switch (this.state) {
4633
+ case "submit":
4634
+ return `${i}${import_picocolors.default.gray(a2)} ${this.options.filter(({ value: t }) => this.value.includes(t)).map((t) => n(t, "submitted")).join(import_picocolors.default.dim(", ")) || import_picocolors.default.dim("none")}`;
4635
+ case "cancel": {
4636
+ const t = this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "cancelled")).join(import_picocolors.default.dim(", "));
4637
+ return `${i}${import_picocolors.default.gray(a2)} ${t.trim() ? `${t}
4638
+ ${import_picocolors.default.gray(a2)}` : ""}`;
4639
+ }
4640
+ case "error": {
4641
+ const t = this.error.split(`
4642
+ `).map((s, c) => c === 0 ? `${import_picocolors.default.yellow(d2)} ${import_picocolors.default.yellow(s)}` : ` ${s}`).join(`
4643
+ `);
4644
+ return i + import_picocolors.default.yellow(a2) + " " + this.options.map((s, c) => {
4645
+ const l2 = this.value.includes(s.value), u = c === this.cursor;
4646
+ return u && l2 ? n(s, "active-selected") : l2 ? n(s, "selected") : n(s, u ? "active" : "inactive");
4647
+ }).join(`
4648
+ ${import_picocolors.default.yellow(a2)} `) + `
4649
+ ` + t + `
4650
+ `;
4651
+ }
4652
+ default:
4653
+ return `${i}${import_picocolors.default.cyan(a2)} ${this.options.map((t, s) => {
4654
+ const c = this.value.includes(t.value), l2 = s === this.cursor;
4655
+ return l2 && c ? n(t, "active-selected") : c ? n(t, "selected") : n(t, l2 ? "active" : "inactive");
4656
+ }).join(`
4657
+ ${import_picocolors.default.cyan(a2)} `)}
4658
+ ${import_picocolors.default.cyan(d2)}
4659
+ `;
4660
+ }
4661
+ } }).prompt();
4662
+ };
4663
+ var R2 = (r2) => r2.replace(me(), "");
4664
+ var le = (r2 = "", n = "") => {
4665
+ const i = `
4666
+ ${r2}
4667
+ `.split(`
4668
+ `), t = R2(n).length, s = Math.max(i.reduce((l2, u) => (u = R2(u), u.length > l2 ? u.length : l2), 0), t) + 2, c = i.map((l2) => `${import_picocolors.default.gray(a2)} ${import_picocolors.default.dim(l2)}${" ".repeat(s - R2(l2).length)}${import_picocolors.default.gray(a2)}`).join(`
4669
+ `);
4670
+ process.stdout.write(`${import_picocolors.default.gray(a2)}
4671
+ ${import_picocolors.default.green(S2)} ${import_picocolors.default.reset(n)} ${import_picocolors.default.gray(B.repeat(Math.max(s - t - 1, 1)) + Z2)}
4672
+ ${c}
4673
+ ${import_picocolors.default.gray(z2 + B.repeat(s + 2) + X2)}
4674
+ `);
4675
+ };
4676
+ var ue = (r2 = "") => {
4677
+ process.stdout.write(`${import_picocolors.default.gray(d2)} ${import_picocolors.default.red(r2)}
4678
+
4679
+ `);
4680
+ };
4681
+ var oe = (r2 = "") => {
4682
+ process.stdout.write(`${import_picocolors.default.gray(K2)} ${r2}
4683
+ `);
4684
+ };
4685
+ var $e = (r2 = "") => {
4686
+ process.stdout.write(`${import_picocolors.default.gray(a2)}
4687
+ ${import_picocolors.default.gray(d2)} ${r2}
4688
+
4689
+ `);
4690
+ };
4691
+ var de = () => {
4692
+ const r2 = _2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], n = _2 ? 80 : 120;
4693
+ let i, t, s = false, c = "";
4694
+ const l2 = (v2 = "") => {
4695
+ s = true, i = OD(), c = v2.replace(/\.+$/, ""), process.stdout.write(`${import_picocolors.default.gray(a2)}
4696
+ `);
4697
+ let g2 = 0, p = 0;
4698
+ t = setInterval(() => {
4699
+ const O2 = import_picocolors.default.magenta(r2[g2]), P2 = ".".repeat(Math.floor(p)).slice(0, 3);
4700
+ process.stdout.write(import_sisteransi2.cursor.move(-999, 0)), process.stdout.write(import_sisteransi2.erase.down(1)), process.stdout.write(`${O2} ${c}${P2}`), g2 = g2 + 1 < r2.length ? g2 + 1 : 0, p = p < r2.length ? p + 0.125 : 0;
4701
+ }, n);
4702
+ }, u = (v2 = "", g2 = 0) => {
4703
+ c = v2 ?? c, s = false, clearInterval(t);
4704
+ const p = g2 === 0 ? import_picocolors.default.green(S2) : g2 === 1 ? import_picocolors.default.red(I2) : import_picocolors.default.red(x2);
4705
+ process.stdout.write(import_sisteransi2.cursor.move(-999, 0)), process.stdout.write(import_sisteransi2.erase.down(1)), process.stdout.write(`${p} ${c}
4706
+ `), i();
4707
+ }, m2 = (v2 = "") => {
4708
+ c = v2 ?? c;
4709
+ }, $2 = (v2) => {
4710
+ const g2 = v2 > 1 ? "Something went wrong" : "Canceled";
4711
+ s && u(g2, v2);
4712
+ };
4713
+ return process.on("uncaughtExceptionMonitor", () => $2(2)), process.on("unhandledRejection", () => $2(2)), process.on("SIGINT", () => $2(1)), process.on("SIGTERM", () => $2(1)), process.on("exit", $2), { start: l2, stop: u, message: m2 };
4714
+ };
4715
+ function me() {
4716
+ const r2 = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
4717
+ return new RegExp(r2, "g");
4718
+ }
4719
+
4720
+ // src/core/plan.ts
4721
+ import fs2 from "fs";
4722
+ import path4 from "path";
4723
+
4724
+ // src/core/mappings.ts
4725
+ import path3 from "path";
4726
+
4727
+ // src/core/paths.ts
4728
+ import os2 from "os";
4729
+ import path from "path";
4730
+ function resolveRoots(opts) {
4731
+ const homeDir = opts.homeDir || os2.homedir();
4732
+ const projectRoot = path.resolve(opts.projectRoot || process.cwd());
4733
+ if (opts.scope === "global") {
4734
+ return {
4735
+ canonicalRoot: path.join(homeDir, ".agents"),
4736
+ claudeRoot: path.join(homeDir, ".claude"),
4737
+ factoryRoot: path.join(homeDir, ".factory"),
4738
+ codexRoot: path.join(homeDir, ".codex"),
4739
+ cursorRoot: path.join(homeDir, ".cursor"),
4740
+ opencodeRoot: path.join(homeDir, ".opencode"),
4741
+ opencodeConfigRoot: path.join(homeDir, ".config", "opencode"),
4742
+ projectRoot,
4743
+ homeDir
4744
+ };
4745
+ }
4746
+ return {
4747
+ canonicalRoot: path.join(projectRoot, ".agents"),
4748
+ claudeRoot: path.join(projectRoot, ".claude"),
4749
+ factoryRoot: path.join(projectRoot, ".factory"),
4750
+ codexRoot: path.join(projectRoot, ".codex"),
4751
+ cursorRoot: path.join(projectRoot, ".cursor"),
4752
+ opencodeRoot: path.join(projectRoot, ".opencode"),
4753
+ opencodeConfigRoot: path.join(homeDir, ".config", "opencode"),
4754
+ projectRoot,
4755
+ homeDir
4756
+ };
4757
+ }
4758
+
4759
+ // src/utils/fs.ts
4760
+ import fs from "fs";
4761
+ import path2 from "path";
4762
+ async function pathExists(p) {
4763
+ try {
4764
+ await fs.promises.lstat(p);
4765
+ return true;
4766
+ } catch (err) {
4767
+ if (err && err.code === "ENOENT")
4768
+ return false;
4769
+ throw err;
4770
+ }
4771
+ }
4772
+ async function ensureDir(dir) {
4773
+ await fs.promises.mkdir(dir, { recursive: true });
4774
+ }
4775
+ async function ensureFile(filePath, content) {
4776
+ await ensureDir(path2.dirname(filePath));
4777
+ await fs.promises.writeFile(filePath, content, "utf8");
4778
+ }
4779
+ async function readText(filePath) {
4780
+ return await fs.promises.readFile(filePath, "utf8");
4781
+ }
4782
+ async function copyFile(src, dest, force = false) {
4783
+ if (!force && await pathExists(dest))
4784
+ return "skipped";
4785
+ await ensureDir(path2.dirname(dest));
4786
+ await fs.promises.copyFile(src, dest);
4787
+ return "written";
4788
+ }
4789
+ async function copyDir(src, dest, force = false) {
4790
+ if (!force && await pathExists(dest))
4791
+ return "skipped";
4792
+ await ensureDir(path2.dirname(dest));
4793
+ await fs.promises.cp(src, dest, { recursive: true, force });
4794
+ return "written";
4795
+ }
4796
+ async function removePath(target) {
4797
+ if (!await pathExists(target))
4798
+ return;
4799
+ const stat = await fs.promises.lstat(target);
4800
+ if (stat.isDirectory() && !stat.isSymbolicLink()) {
4801
+ await fs.promises.rm(target, { recursive: true, force: true });
4802
+ } else {
4803
+ await fs.promises.unlink(target);
4804
+ }
4805
+ }
4806
+ async function listDirs(dir) {
4807
+ try {
4808
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
4809
+ return entries.filter((e2) => e2.isDirectory()).map((e2) => path2.join(dir, e2.name));
4810
+ } catch (err) {
4811
+ if (err && err.code === "ENOENT")
4812
+ return [];
4813
+ throw err;
4814
+ }
4815
+ }
4816
+
4817
+ // src/core/mappings.ts
4818
+ async function getMappings(opts) {
4819
+ const roots = resolveRoots(opts);
4820
+ const canonical = roots.canonicalRoot;
4821
+ const claudeOverride = path3.join(canonical, "CLAUDE.md");
4822
+ const agentsFallback = path3.join(canonical, "AGENTS.md");
4823
+ const agentsSource = await pathExists(claudeOverride) ? claudeOverride : agentsFallback;
4824
+ const clients = new Set(opts.clients ?? ["claude", "factory", "codex", "cursor", "opencode"]);
4825
+ const mappings = [];
4826
+ const includeAgentFiles = opts.scope === "global";
4827
+ if (includeAgentFiles && clients.has("claude")) {
4828
+ mappings.push({
4829
+ name: "claude-md",
4830
+ source: agentsSource,
4831
+ targets: [path3.join(roots.claudeRoot, "CLAUDE.md")],
4832
+ kind: "file"
4833
+ });
4834
+ }
4835
+ if (includeAgentFiles) {
4836
+ const agentTargets = [
4837
+ clients.has("factory") ? path3.join(roots.factoryRoot, "AGENTS.md") : null,
4838
+ clients.has("codex") ? path3.join(roots.codexRoot, "AGENTS.md") : null,
4839
+ clients.has("opencode") ? path3.join(roots.opencodeConfigRoot, "AGENTS.md") : null
4840
+ ].filter(Boolean);
4841
+ if (agentTargets.length > 0) {
4842
+ mappings.push({
4843
+ name: "agents-md",
4844
+ source: agentsFallback,
4845
+ targets: agentTargets,
4846
+ kind: "file"
4847
+ });
4848
+ }
4849
+ }
4850
+ mappings.push({
4851
+ name: "commands",
4852
+ source: path3.join(canonical, "commands"),
4853
+ targets: [
4854
+ clients.has("claude") ? path3.join(roots.claudeRoot, "commands") : null,
4855
+ clients.has("factory") ? path3.join(roots.factoryRoot, "commands") : null,
4856
+ clients.has("codex") ? path3.join(roots.codexRoot, "prompts") : null,
4857
+ clients.has("opencode") ? path3.join(roots.opencodeRoot, "commands") : null,
4858
+ clients.has("cursor") ? path3.join(roots.cursorRoot, "commands") : null
4859
+ ].filter(Boolean),
4860
+ kind: "dir"
4861
+ }, {
4862
+ name: "hooks",
4863
+ source: path3.join(canonical, "hooks"),
4864
+ targets: [
4865
+ clients.has("claude") ? path3.join(roots.claudeRoot, "hooks") : null,
4866
+ clients.has("factory") ? path3.join(roots.factoryRoot, "hooks") : null
4867
+ ].filter(Boolean),
4868
+ kind: "dir"
4869
+ }, {
4870
+ name: "skills",
4871
+ source: path3.join(canonical, "skills"),
4872
+ targets: [
4873
+ clients.has("claude") ? path3.join(roots.claudeRoot, "skills") : null,
4874
+ clients.has("factory") ? path3.join(roots.factoryRoot, "skills") : null,
4875
+ clients.has("codex") ? path3.join(roots.codexRoot, "skills") : null,
4876
+ clients.has("opencode") ? path3.join(roots.opencodeRoot, "skills") : null,
4877
+ clients.has("cursor") ? path3.join(roots.cursorRoot, "skills") : null
4878
+ ].filter(Boolean),
4879
+ kind: "dir"
4880
+ });
4881
+ return mappings;
4882
+ }
4883
+
4884
+ // src/core/plan.ts
4885
+ async function getLinkTargetAbsolute(targetPath) {
4886
+ try {
4887
+ const link = await fs2.promises.readlink(targetPath);
4888
+ if (!path4.isAbsolute(link)) {
4889
+ return path4.resolve(path4.dirname(targetPath), link);
4890
+ }
4891
+ return link;
4892
+ } catch {
4893
+ return null;
4894
+ }
4895
+ }
4896
+ async function ensureSourceTask(source, kind) {
4897
+ const exists = await pathExists(source);
4898
+ if (!exists)
4899
+ return [{ type: "ensure-source", path: source, kind }];
4900
+ const stat = await fs2.promises.lstat(source);
4901
+ if (kind === "file" && stat.isDirectory()) {
4902
+ return [{ type: "conflict", source, target: source, reason: "Expected file but found directory", kind }];
4903
+ }
4904
+ if (kind === "dir" && !stat.isDirectory()) {
4905
+ return [{ type: "conflict", source, target: source, reason: "Expected directory but found file", kind }];
4906
+ }
4907
+ return [];
4908
+ }
4909
+ async function analyzeTarget(source, target, kind, opts) {
4910
+ const exists = await pathExists(target);
4911
+ if (!exists)
4912
+ return { type: "link", source, target, kind };
4913
+ const stat = await fs2.promises.lstat(target);
4914
+ if (stat.isSymbolicLink()) {
4915
+ const resolved = await getLinkTargetAbsolute(target);
4916
+ if (resolved && path4.resolve(resolved) === path4.resolve(source)) {
4917
+ return { type: "noop", source, target };
4918
+ }
4919
+ if (resolved && opts?.relinkableSources) {
4920
+ const relinkable = new Set(opts.relinkableSources.map((p) => path4.resolve(p)));
4921
+ if (relinkable.has(path4.resolve(resolved))) {
4922
+ return { type: "link", source, target, kind, replaceSymlink: true };
4923
+ }
4924
+ }
4925
+ const detail = resolved ? `Symlink points elsewhere: ${resolved}` : "Symlink points elsewhere";
4926
+ return { type: "conflict", source, target, reason: detail, kind };
4927
+ }
4928
+ const targetKind = stat.isDirectory() ? "directory" : stat.isFile() ? "file" : "path";
4929
+ return { type: "conflict", source, target, reason: `Target exists and is not a symlink (${targetKind})`, kind };
4930
+ }
4931
+ async function buildLinkPlan(opts) {
4932
+ const mappings = await getMappings(opts);
4933
+ const tasks = [];
4934
+ for (const mapping of mappings) {
4935
+ tasks.push(...await ensureSourceTask(mapping.source, mapping.kind));
4936
+ const relinkableSources = mapping.name === "claude-md" ? [
4937
+ path4.join(path4.dirname(mapping.source), "AGENTS.md"),
4938
+ path4.join(path4.dirname(mapping.source), "CLAUDE.md")
4939
+ ] : undefined;
4940
+ for (const target of mapping.targets) {
4941
+ tasks.push(await analyzeTarget(mapping.source, target, mapping.kind, { relinkableSources }));
4942
+ }
4943
+ }
4944
+ const conflicts = tasks.filter((t) => t.type === "conflict");
4945
+ const changes = tasks.filter((t) => t.type === "link" || t.type === "ensure-source");
4946
+ return { tasks, conflicts, changes };
4947
+ }
4948
+
4949
+ // src/core/status.ts
4950
+ import fs3 from "fs";
4951
+ import path5 from "path";
3770
4952
  async function resolveLinkTarget(targetPath) {
3771
4953
  try {
3772
- const link = await fs4.promises.readlink(targetPath);
3773
- if (!path6.isAbsolute(link))
3774
- return path6.resolve(path6.dirname(targetPath), link);
4954
+ const link = await fs3.promises.readlink(targetPath);
4955
+ if (!path5.isAbsolute(link))
4956
+ return path5.resolve(path5.dirname(targetPath), link);
3775
4957
  return link;
3776
4958
  } catch {
3777
4959
  return null;
3778
4960
  }
3779
4961
  }
3780
4962
  async function getLinkStatus(opts) {
3781
- const mappings = getMappings(opts);
4963
+ const mappings = await getMappings(opts);
3782
4964
  const statuses = [];
3783
4965
  for (const mapping of mappings) {
3784
4966
  const targets = [];
@@ -3788,10 +4970,10 @@ async function getLinkStatus(opts) {
3788
4970
  targets.push({ path: target, status: "missing" });
3789
4971
  continue;
3790
4972
  }
3791
- const stat = await fs4.promises.lstat(target);
4973
+ const stat = await fs3.promises.lstat(target);
3792
4974
  if (stat.isSymbolicLink()) {
3793
4975
  const resolved = await resolveLinkTarget(target);
3794
- if (resolved && path6.resolve(resolved) === path6.resolve(mapping.source)) {
4976
+ if (resolved && path5.resolve(resolved) === path5.resolve(mapping.source)) {
3795
4977
  targets.push({ path: target, status: "linked" });
3796
4978
  } else {
3797
4979
  targets.push({ path: target, status: "conflict" });
@@ -3806,12 +4988,12 @@ async function getLinkStatus(opts) {
3806
4988
  }
3807
4989
 
3808
4990
  // src/core/migrate.ts
3809
- import fs5 from "fs";
3810
- import path8 from "path";
4991
+ import fs6 from "fs";
4992
+ import path9 from "path";
3811
4993
 
3812
4994
  // src/core/skills.ts
3813
4995
  var import_gray_matter = __toESM(require_gray_matter(), 1);
3814
- import path7 from "path";
4996
+ import path6 from "path";
3815
4997
  var NAME_RE = /^[a-z0-9-]{1,64}$/;
3816
4998
  async function parseSkillFile(skillFile) {
3817
4999
  const raw = await readText(skillFile);
@@ -3833,13 +5015,13 @@ async function parseSkillFile(skillFile) {
3833
5015
  };
3834
5016
  }
3835
5017
  async function isSkillDir(dir) {
3836
- return await pathExists(path7.join(dir, "SKILL.md"));
5018
+ return await pathExists(path6.join(dir, "SKILL.md"));
3837
5019
  }
3838
5020
  async function findSkillDirs(root) {
3839
5021
  const direct = await isSkillDir(root);
3840
5022
  if (direct)
3841
5023
  return [root];
3842
- const skillsDir = path7.join(root, "skills");
5024
+ const skillsDir = path6.join(root, "skills");
3843
5025
  const skillsDirExists = await pathExists(skillsDir);
3844
5026
  if (skillsDirExists) {
3845
5027
  const children2 = await listDirs(skillsDir);
@@ -3857,77 +5039,258 @@ async function findSkillDirs(root) {
3857
5039
  if (await isSkillDir(child))
3858
5040
  matches.push(child);
3859
5041
  }
3860
- return matches;
5042
+ return matches;
5043
+ }
5044
+
5045
+ // src/core/apply.ts
5046
+ import fs5 from "fs";
5047
+ import path8 from "path";
5048
+
5049
+ // src/core/backup.ts
5050
+ import fs4 from "fs";
5051
+ import path7 from "path";
5052
+ var MANIFEST_NAME = "manifest.json";
5053
+ function backupPathFor(target, backupRoot) {
5054
+ const root = path7.parse(target).root || path7.sep;
5055
+ const rel = path7.relative(root, target);
5056
+ return path7.join(backupRoot, rel);
5057
+ }
5058
+ function hasParentPath(target, seen) {
5059
+ const resolved = path7.resolve(target);
5060
+ for (const parent of seen) {
5061
+ if (resolved === parent)
5062
+ return true;
5063
+ if (resolved.startsWith(parent + path7.sep))
5064
+ return true;
5065
+ }
5066
+ return false;
5067
+ }
5068
+ async function backupSymlink(target, dest) {
5069
+ const link = await fs4.promises.readlink(target);
5070
+ await ensureDir(path7.dirname(dest));
5071
+ await fs4.promises.symlink(link, dest);
5072
+ await fs4.promises.unlink(target);
5073
+ }
5074
+ async function backupPathImpl(target, dest, kind) {
5075
+ await ensureDir(path7.dirname(dest));
5076
+ try {
5077
+ await fs4.promises.rename(target, dest);
5078
+ return;
5079
+ } catch (err) {
5080
+ if (err?.code !== "EXDEV")
5081
+ throw err;
5082
+ }
5083
+ if (kind === "dir") {
5084
+ await copyDir(target, dest, true);
5085
+ } else {
5086
+ await copyFile(target, dest, true);
5087
+ }
5088
+ await removePath(target);
5089
+ }
5090
+ async function createBackupSession(opts) {
5091
+ const timestamp = opts.timestamp || new Date().toISOString().replace(/[:.]/g, "-");
5092
+ const dir = path7.join(opts.canonicalRoot, "backup", timestamp);
5093
+ await ensureDir(dir);
5094
+ return {
5095
+ dir,
5096
+ manifestPath: path7.join(dir, MANIFEST_NAME),
5097
+ createdAt: new Date().toISOString(),
5098
+ scope: opts.scope,
5099
+ operation: opts.operation,
5100
+ entries: [],
5101
+ _seen: new Set
5102
+ };
5103
+ }
5104
+ async function backupPath(target, session) {
5105
+ if (!await pathExists(target))
5106
+ return false;
5107
+ const resolved = path7.resolve(target);
5108
+ if (hasParentPath(resolved, session._seen))
5109
+ return false;
5110
+ const stat = await fs4.promises.lstat(target);
5111
+ const kind = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "dir" : "file";
5112
+ const dest = backupPathFor(target, session.dir);
5113
+ if (stat.isSymbolicLink()) {
5114
+ await backupSymlink(target, dest);
5115
+ } else {
5116
+ await backupPathImpl(target, dest, kind);
5117
+ }
5118
+ session.entries.push({ originalPath: resolved, backupPath: dest, kind, action: "backup" });
5119
+ session._seen.add(resolved);
5120
+ return true;
5121
+ }
5122
+ function recordCreatedPath(target, kind, session) {
5123
+ const resolved = path7.resolve(target);
5124
+ if (hasParentPath(resolved, session._seen))
5125
+ return;
5126
+ session.entries.push({ originalPath: resolved, kind, action: "create" });
5127
+ session._seen.add(resolved);
5128
+ }
5129
+ async function finalizeBackup(session) {
5130
+ const manifest = {
5131
+ version: 1,
5132
+ createdAt: session.createdAt,
5133
+ scope: session.scope,
5134
+ operation: session.operation,
5135
+ entries: session.entries
5136
+ };
5137
+ await fs4.promises.writeFile(session.manifestPath, JSON.stringify(manifest, null, 2), "utf8");
5138
+ }
5139
+ async function loadBackupManifest(dir) {
5140
+ const manifestPath = path7.join(dir, MANIFEST_NAME);
5141
+ if (!await pathExists(manifestPath))
5142
+ return null;
5143
+ const raw = await fs4.promises.readFile(manifestPath, "utf8");
5144
+ return JSON.parse(raw);
5145
+ }
5146
+
5147
+ // src/core/apply.ts
5148
+ var DEFAULT_AGENTS = `# AGENTS
5149
+
5150
+ Add shared agent instructions here.
5151
+ `;
5152
+ async function createSource(task) {
5153
+ if (task.kind === "dir") {
5154
+ await ensureDir(task.path);
5155
+ return;
5156
+ }
5157
+ await ensureFile(task.path, DEFAULT_AGENTS);
5158
+ }
5159
+ async function createLink(source, target, kind, overwrite, backup) {
5160
+ if (await pathExists(target)) {
5161
+ if (!overwrite)
5162
+ return { created: false, backedUp: false };
5163
+ const backedUp = backup ? await backupPath(target, backup) : false;
5164
+ if (await pathExists(target))
5165
+ await removePath(target);
5166
+ await ensureDir(path8.dirname(target));
5167
+ const type2 = kind === "dir" ? "junction" : "file";
5168
+ await fs5.promises.symlink(source, target, type2);
5169
+ return { created: true, backedUp };
5170
+ }
5171
+ await ensureDir(path8.dirname(target));
5172
+ const type = kind === "dir" ? "junction" : "file";
5173
+ await fs5.promises.symlink(source, target, type);
5174
+ return { created: true, backedUp: false };
3861
5175
  }
3862
- function skillDestDir(canonicalSkillsRoot, name) {
3863
- return path7.join(canonicalSkillsRoot, name);
5176
+ async function applyLinkPlan(plan, opts) {
5177
+ const force = !!opts?.force;
5178
+ const backup = opts.backup;
5179
+ if (!backup)
5180
+ throw new Error("Backup session required.");
5181
+ let applied = 0;
5182
+ let skipped = 0;
5183
+ let conflicts = 0;
5184
+ let backedUp = 0;
5185
+ for (const task of plan.tasks) {
5186
+ if (task.type === "conflict") {
5187
+ conflicts += 1;
5188
+ if (force && task.target !== task.source && task.kind) {
5189
+ const result = await createLink(task.source, task.target, task.kind, true, backup);
5190
+ if (result.backedUp)
5191
+ backedUp += 1;
5192
+ applied += 1;
5193
+ }
5194
+ continue;
5195
+ }
5196
+ if (task.type === "noop") {
5197
+ skipped += 1;
5198
+ continue;
5199
+ }
5200
+ if (task.type === "ensure-source") {
5201
+ await createSource(task);
5202
+ recordCreatedPath(task.path, task.kind, backup);
5203
+ applied += 1;
5204
+ continue;
5205
+ }
5206
+ if (task.type === "link") {
5207
+ const before = await pathExists(task.target);
5208
+ let useForce = force;
5209
+ if (!useForce && task.replaceSymlink && before) {
5210
+ try {
5211
+ const stat = await fs5.promises.lstat(task.target);
5212
+ if (stat.isSymbolicLink())
5213
+ useForce = true;
5214
+ } catch {}
5215
+ }
5216
+ const result = await createLink(task.source, task.target, task.kind, useForce, backup);
5217
+ if (result.backedUp)
5218
+ backedUp += 1;
5219
+ if (!before && result.created) {
5220
+ recordCreatedPath(task.target, "symlink", backup);
5221
+ }
5222
+ if (before && !useForce)
5223
+ skipped += 1;
5224
+ else
5225
+ applied += 1;
5226
+ }
5227
+ }
5228
+ return { applied, skipped, conflicts, backupDir: backup.dir, backedUp };
3864
5229
  }
3865
5230
 
3866
5231
  // src/core/migrate.ts
3867
5232
  async function isSymlink(p) {
3868
5233
  try {
3869
- const stat = await fs5.promises.lstat(p);
5234
+ const stat = await fs6.promises.lstat(p);
3870
5235
  return stat.isSymbolicLink();
3871
5236
  } catch {
3872
5237
  return false;
3873
5238
  }
3874
5239
  }
3875
- async function listFiles2(dir) {
5240
+ async function listFiles(dir) {
3876
5241
  try {
3877
- const entries = await fs5.promises.readdir(dir, { withFileTypes: true });
3878
- return entries.filter((e) => e.isFile()).map((e) => path8.join(dir, e.name));
5242
+ const entries = await fs6.promises.readdir(dir, { withFileTypes: true });
5243
+ return entries.filter((e2) => e2.isFile()).map((e2) => path9.join(dir, e2.name));
3879
5244
  } catch {
3880
5245
  return [];
3881
5246
  }
3882
5247
  }
3883
- async function movePath(src, dest, kind) {
3884
- await ensureDir(path8.dirname(dest));
3885
- try {
3886
- await fs5.promises.rename(src, dest);
3887
- return;
3888
- } catch (err) {
3889
- if (err?.code !== "EXDEV")
3890
- throw err;
3891
- }
3892
- if (kind === "file") {
3893
- await copyFile(src, dest, true);
3894
- } else {
3895
- await copyDir(src, dest, true);
3896
- }
3897
- await removePath(src);
3898
- }
3899
5248
  function conflictLabel(targetPath, canonicalRoot) {
3900
5249
  if (targetPath.startsWith(canonicalRoot)) {
3901
- const rel = path8.relative(canonicalRoot, targetPath);
3902
- return rel || path8.basename(targetPath);
5250
+ const rel = path9.relative(canonicalRoot, targetPath);
5251
+ return rel || path9.basename(targetPath);
3903
5252
  }
3904
- return path8.basename(targetPath);
5253
+ return path9.basename(targetPath);
3905
5254
  }
3906
5255
  async function scanMigration(opts) {
3907
5256
  const roots = resolveRoots(opts);
3908
5257
  const canonicalRoot = roots.canonicalRoot;
3909
5258
  const candidatesByTarget = new Map;
3910
- const canonicalCommands = path8.join(canonicalRoot, "commands");
3911
- const canonicalHooks = path8.join(canonicalRoot, "hooks");
3912
- const canonicalSkills = path8.join(canonicalRoot, "skills");
3913
- const canonicalAgents = path8.join(canonicalRoot, "AGENTS.md");
5259
+ const clients = new Set(opts.clients ?? ["claude", "factory", "codex", "cursor", "opencode"]);
5260
+ const includeAgentFiles = opts.scope === "global";
5261
+ const canonicalCommands = path9.join(canonicalRoot, "commands");
5262
+ const canonicalHooks = path9.join(canonicalRoot, "hooks");
5263
+ const canonicalSkills = path9.join(canonicalRoot, "skills");
5264
+ const canonicalAgents = path9.join(canonicalRoot, "AGENTS.md");
5265
+ const canonicalClaude = path9.join(canonicalRoot, "CLAUDE.md");
3914
5266
  const sources = {
3915
5267
  commands: [
3916
- { label: "Claude commands", dir: path8.join(roots.claudeRoot, "commands") },
3917
- { label: "Factory commands", dir: path8.join(roots.factoryRoot, "commands") },
3918
- { label: "Codex prompts", dir: path8.join(roots.codexRoot, "prompts") }
3919
- ],
5268
+ clients.has("claude") ? { label: "Claude commands", dir: path9.join(roots.claudeRoot, "commands") } : null,
5269
+ clients.has("factory") ? { label: "Factory commands", dir: path9.join(roots.factoryRoot, "commands") } : null,
5270
+ clients.has("codex") ? { label: "Codex prompts", dir: path9.join(roots.codexRoot, "prompts") } : null,
5271
+ clients.has("cursor") ? { label: "Cursor commands", dir: path9.join(roots.cursorRoot, "commands") } : null,
5272
+ clients.has("opencode") ? { label: "OpenCode commands", dir: path9.join(roots.opencodeRoot, "commands") } : null
5273
+ ].filter(Boolean),
3920
5274
  hooks: [
3921
- { label: "Claude hooks", dir: path8.join(roots.claudeRoot, "hooks") },
3922
- { label: "Factory hooks", dir: path8.join(roots.factoryRoot, "hooks") }
3923
- ],
5275
+ clients.has("claude") ? { label: "Claude hooks", dir: path9.join(roots.claudeRoot, "hooks") } : null,
5276
+ clients.has("factory") ? { label: "Factory hooks", dir: path9.join(roots.factoryRoot, "hooks") } : null
5277
+ ].filter(Boolean),
3924
5278
  skills: [
3925
- { label: "Claude skills", dir: path8.join(roots.claudeRoot, "skills") },
3926
- { label: "Factory skills", dir: path8.join(roots.factoryRoot, "skills") }
3927
- ],
3928
- agents: [
3929
- { label: "Claude CLAUDE.md", file: path8.join(roots.claudeRoot, "CLAUDE.md") }
3930
- ]
5279
+ clients.has("claude") ? { label: "Claude skills", dir: path9.join(roots.claudeRoot, "skills") } : null,
5280
+ clients.has("factory") ? { label: "Factory skills", dir: path9.join(roots.factoryRoot, "skills") } : null,
5281
+ clients.has("codex") ? { label: "Codex skills", dir: path9.join(roots.codexRoot, "skills") } : null,
5282
+ clients.has("cursor") ? { label: "Cursor skills", dir: path9.join(roots.cursorRoot, "skills") } : null,
5283
+ clients.has("opencode") ? { label: "OpenCode skills", dir: path9.join(roots.opencodeRoot, "skills") } : null
5284
+ ].filter(Boolean),
5285
+ agents: includeAgentFiles ? [
5286
+ clients.has("claude") ? { label: "Claude AGENTS.md", file: path9.join(roots.claudeRoot, "AGENTS.md") } : null,
5287
+ clients.has("factory") ? { label: "Factory AGENTS.md", file: path9.join(roots.factoryRoot, "AGENTS.md") } : null,
5288
+ clients.has("codex") ? { label: "Codex AGENTS.md", file: path9.join(roots.codexRoot, "AGENTS.md") } : null,
5289
+ clients.has("opencode") ? { label: "OpenCode AGENTS.md", file: path9.join(roots.opencodeConfigRoot, "AGENTS.md") } : null
5290
+ ].filter(Boolean) : [],
5291
+ claude: includeAgentFiles ? [
5292
+ clients.has("claude") ? { label: "Claude CLAUDE.md", file: path9.join(roots.claudeRoot, "CLAUDE.md") } : null
5293
+ ].filter(Boolean) : []
3931
5294
  };
3932
5295
  const addCandidate = (candidate) => {
3933
5296
  const list = candidatesByTarget.get(candidate.targetPath) || [];
@@ -3937,18 +5300,18 @@ async function scanMigration(opts) {
3937
5300
  for (const src of sources.commands) {
3938
5301
  if (!await pathExists(src.dir) || await isSymlink(src.dir))
3939
5302
  continue;
3940
- const files = await listFiles2(src.dir);
5303
+ const files = await listFiles(src.dir);
3941
5304
  for (const file of files) {
3942
- const targetPath = path8.join(canonicalCommands, path8.basename(file));
5305
+ const targetPath = path9.join(canonicalCommands, path9.basename(file));
3943
5306
  addCandidate({ label: src.label, targetPath, kind: "file", action: "copy", sourcePath: file });
3944
5307
  }
3945
5308
  }
3946
5309
  for (const src of sources.hooks) {
3947
5310
  if (!await pathExists(src.dir) || await isSymlink(src.dir))
3948
5311
  continue;
3949
- const files = await listFiles2(src.dir);
5312
+ const files = await listFiles(src.dir);
3950
5313
  for (const file of files) {
3951
- const targetPath = path8.join(canonicalHooks, path8.basename(file));
5314
+ const targetPath = path9.join(canonicalHooks, path9.basename(file));
3952
5315
  addCandidate({ label: src.label, targetPath, kind: "file", action: "copy", sourcePath: file });
3953
5316
  }
3954
5317
  }
@@ -3958,8 +5321,8 @@ async function scanMigration(opts) {
3958
5321
  const skillDirs = await findSkillDirs(src.dir);
3959
5322
  for (const dir of skillDirs) {
3960
5323
  try {
3961
- const meta = await parseSkillFile(path8.join(dir, "SKILL.md"));
3962
- const targetPath = path8.join(canonicalSkills, meta.name);
5324
+ const meta = await parseSkillFile(path9.join(dir, "SKILL.md"));
5325
+ const targetPath = path9.join(canonicalSkills, meta.name);
3963
5326
  addCandidate({ label: src.label, targetPath, kind: "dir", action: "copy", sourcePath: dir });
3964
5327
  } catch {}
3965
5328
  }
@@ -3969,6 +5332,11 @@ async function scanMigration(opts) {
3969
5332
  continue;
3970
5333
  addCandidate({ label: src.label, targetPath: canonicalAgents, kind: "file", action: "copy", sourcePath: src.file });
3971
5334
  }
5335
+ for (const src of sources.claude) {
5336
+ if (!await pathExists(src.file) || await isSymlink(src.file))
5337
+ continue;
5338
+ addCandidate({ label: src.label, targetPath: canonicalClaude, kind: "file", action: "copy", sourcePath: src.file });
5339
+ }
3972
5340
  const auto = [];
3973
5341
  const conflicts = [];
3974
5342
  for (const [targetPath, list] of candidatesByTarget.entries()) {
@@ -3976,7 +5344,7 @@ async function scanMigration(opts) {
3976
5344
  if (canonicalExists) {
3977
5345
  let kind = "file";
3978
5346
  try {
3979
- const stat = await fs5.promises.lstat(targetPath);
5347
+ const stat = await fs6.promises.lstat(targetPath);
3980
5348
  kind = stat.isDirectory() ? "dir" : "file";
3981
5349
  } catch {}
3982
5350
  list.unshift({
@@ -3998,27 +5366,23 @@ async function scanMigration(opts) {
3998
5366
  candidates: list
3999
5367
  });
4000
5368
  }
4001
- const backupPaths = [
4002
- { label: "claude/commands", path: path8.join(roots.claudeRoot, "commands"), kind: "dir" },
4003
- { label: "factory/commands", path: path8.join(roots.factoryRoot, "commands"), kind: "dir" },
4004
- { label: "codex/prompts", path: path8.join(roots.codexRoot, "prompts"), kind: "dir" },
4005
- { label: "claude/hooks", path: path8.join(roots.claudeRoot, "hooks"), kind: "dir" },
4006
- { label: "factory/hooks", path: path8.join(roots.factoryRoot, "hooks"), kind: "dir" },
4007
- { label: "claude/skills", path: path8.join(roots.claudeRoot, "skills"), kind: "dir" },
4008
- { label: "factory/skills", path: path8.join(roots.factoryRoot, "skills"), kind: "dir" },
4009
- { label: "claude/CLAUDE.md", path: path8.join(roots.claudeRoot, "CLAUDE.md"), kind: "file" }
4010
- ];
4011
- return { auto, conflicts, backupPaths, canonicalRoot };
5369
+ return { auto, conflicts, canonicalRoot };
4012
5370
  }
4013
5371
  async function applyMigration(plan, selections, opts) {
4014
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
4015
- const backupDir = path8.join(plan.canonicalRoot, "backup", timestamp);
4016
- await ensureDir(backupDir);
5372
+ const backup = opts.backup;
5373
+ if (!backup)
5374
+ throw new Error("Backup session required.");
4017
5375
  let copied = 0;
4018
5376
  let skipped = 0;
4019
5377
  const copyCandidate = async (candidate) => {
4020
5378
  if (candidate.action !== "copy" || !candidate.sourcePath)
4021
5379
  return false;
5380
+ const existed = await pathExists(candidate.targetPath);
5381
+ if (existed) {
5382
+ await backupPath(candidate.targetPath, backup);
5383
+ } else {
5384
+ recordCreatedPath(candidate.targetPath, candidate.kind === "dir" ? "dir" : "file", backup);
5385
+ }
4022
5386
  if (candidate.kind === "file") {
4023
5387
  await copyFile(candidate.sourcePath, candidate.targetPath, true);
4024
5388
  } else {
@@ -4043,1229 +5407,467 @@ async function applyMigration(plan, selections, opts) {
4043
5407
  else
4044
5408
  skipped += 1;
4045
5409
  }
4046
- for (const item of plan.backupPaths) {
4047
- if (!await pathExists(item.path))
4048
- continue;
4049
- if (await isSymlink(item.path))
4050
- continue;
4051
- const dest = path8.join(backupDir, item.label);
4052
- await movePath(item.path, dest, item.kind);
4053
- }
4054
5410
  const linkPlan = await buildLinkPlan(opts);
4055
- await applyLinkPlan(linkPlan);
4056
- return { copied, skipped, backupDir };
5411
+ const linkResult = await applyLinkPlan(linkPlan, { force: !!opts.forceLinks, backup });
5412
+ return {
5413
+ copied,
5414
+ skipped,
5415
+ backupDir: backup.dir,
5416
+ links: {
5417
+ applied: linkResult.applied,
5418
+ skipped: linkResult.skipped,
5419
+ conflicts: linkResult.conflicts,
5420
+ backedUp: linkResult.backedUp
5421
+ }
5422
+ };
4057
5423
  }
4058
5424
 
4059
- // src/installers/skills.ts
4060
- import fs8 from "fs";
4061
- import path13 from "path";
4062
-
4063
- // src/installers/source.ts
5425
+ // src/core/undo.ts
4064
5426
  import fs7 from "fs";
4065
- import os3 from "os";
4066
- import path12 from "path";
4067
-
4068
- // src/utils/paths.ts
4069
- import os2 from "os";
4070
- import path9 from "path";
4071
- function expandHome(p) {
4072
- if (!p)
4073
- return p;
4074
- if (p === "~")
4075
- return os2.homedir();
4076
- if (p.startsWith("~/"))
4077
- return path9.join(os2.homedir(), p.slice(2));
4078
- return p;
4079
- }
4080
- function isUrl(input) {
4081
- return /^https?:\/\//i.test(input);
4082
- }
4083
- function isGitUrl(input) {
4084
- return /^(git@|https?:\/\/).+\.git$/i.test(input) || input.startsWith("git://");
4085
- }
4086
- function isFileUrl(input) {
4087
- return /^file:\/\//i.test(input);
4088
- }
4089
- function normalizeFileUrl(input) {
4090
- if (!isFileUrl(input))
4091
- return input;
4092
- const url = new URL(input);
4093
- return url.pathname;
4094
- }
4095
-
4096
- // src/utils/http.ts
4097
- import fs6 from "fs";
4098
5427
  import path10 from "path";
4099
- async function fetchText(url) {
4100
- const res = await fetch(url, { headers: { "User-Agent": "dotagents" } });
4101
- if (!res.ok)
4102
- throw new Error(`HTTP ${res.status} for ${url}`);
4103
- return await res.text();
4104
- }
4105
- async function fetchJson(url) {
4106
- const text = await fetchText(url);
4107
- return JSON.parse(text);
5428
+ async function listBackupDirs(canonicalRoot) {
5429
+ const root = path10.join(canonicalRoot, "backup");
5430
+ if (!await pathExists(root))
5431
+ return [];
5432
+ const entries = await fs7.promises.readdir(root, { withFileTypes: true });
5433
+ return entries.filter((e2) => e2.isDirectory()).map((e2) => path10.join(root, e2.name));
4108
5434
  }
4109
- async function downloadToFile(url, dest) {
4110
- const res = await fetch(url, { headers: { "User-Agent": "dotagents" } });
4111
- if (!res.ok)
4112
- throw new Error(`HTTP ${res.status} for ${url}`);
4113
- const buf = new Uint8Array(await res.arrayBuffer());
4114
- await ensureDir(path10.dirname(dest));
4115
- await fs6.promises.writeFile(dest, buf);
5435
+ async function findLatestBackup(canonicalRoot) {
5436
+ const dirs = await listBackupDirs(canonicalRoot);
5437
+ const manifests = [];
5438
+ for (const dir of dirs) {
5439
+ const manifest = await loadBackupManifest(dir);
5440
+ if (manifest)
5441
+ manifests.push({ dir, manifest });
5442
+ }
5443
+ if (!manifests.length)
5444
+ return null;
5445
+ manifests.sort((a3, b3) => a3.manifest.createdAt.localeCompare(b3.manifest.createdAt));
5446
+ return manifests[manifests.length - 1] || null;
4116
5447
  }
4117
-
4118
- // src/utils/archive.ts
4119
- import path11 from "path";
4120
-
4121
- // src/utils/run.ts
4122
- import { spawn } from "child_process";
4123
- async function runCommand(cmd, args, opts) {
4124
- return await new Promise((resolve, reject) => {
4125
- const child = spawn(cmd, args, { cwd: opts?.cwd, stdio: ["ignore", "pipe", "pipe"] });
4126
- let stdout = "";
4127
- let stderr = "";
4128
- child.stdout.on("data", (d) => stdout += d.toString());
4129
- child.stderr.on("data", (d) => stderr += d.toString());
4130
- child.on("error", reject);
4131
- child.on("close", (code) => {
4132
- if (code === 0)
4133
- resolve({ stdout, stderr });
4134
- else
4135
- reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}: ${stderr || stdout}`));
4136
- });
4137
- });
5448
+ async function restoreSymlink(entry) {
5449
+ if (!entry.backupPath)
5450
+ return;
5451
+ const link = await fs7.promises.readlink(entry.backupPath);
5452
+ await ensureDir(path10.dirname(entry.originalPath));
5453
+ await fs7.promises.symlink(link, entry.originalPath);
5454
+ await fs7.promises.unlink(entry.backupPath);
4138
5455
  }
4139
-
4140
- // src/utils/archive.ts
4141
- async function extractArchive(archivePath, destDir) {
4142
- const lower = archivePath.toLowerCase();
4143
- if (lower.endsWith(".zip")) {
4144
- await runCommand("unzip", ["-q", archivePath, "-d", destDir]);
5456
+ async function restorePath(entry) {
5457
+ if (entry.action === "create") {
5458
+ await removePath(entry.originalPath);
4145
5459
  return;
4146
5460
  }
4147
- if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz")) {
4148
- await runCommand("tar", ["-xzf", archivePath, "-C", destDir]);
5461
+ if (!entry.backupPath)
5462
+ return;
5463
+ if (entry.kind === "symlink") {
5464
+ await restoreSymlink(entry);
4149
5465
  return;
4150
5466
  }
4151
- if (lower.endsWith(".tar")) {
4152
- await runCommand("tar", ["-xf", archivePath, "-C", destDir]);
5467
+ await ensureDir(path10.dirname(entry.originalPath));
5468
+ try {
5469
+ await fs7.promises.rename(entry.backupPath, entry.originalPath);
4153
5470
  return;
5471
+ } catch (err) {
5472
+ if (err?.code !== "EXDEV")
5473
+ throw err;
4154
5474
  }
4155
- throw new Error(`Unsupported archive format: ${path11.basename(archivePath)}`);
4156
- }
4157
-
4158
- // src/installers/source.ts
4159
- async function makeTempDir(prefix) {
4160
- return await fs7.promises.mkdtemp(path12.join(os3.tmpdir(), prefix));
4161
- }
4162
- async function cloneGitRepo(repo, dest, ref) {
4163
- await runCommand("git", ["clone", "--depth", "1", repo, dest]);
4164
- if (ref) {
4165
- await runCommand("git", ["checkout", ref], { cwd: dest });
5475
+ if (entry.kind === "dir") {
5476
+ await fs7.promises.cp(entry.backupPath, entry.originalPath, { recursive: true, force: true });
5477
+ } else {
5478
+ await fs7.promises.copyFile(entry.backupPath, entry.originalPath);
4166
5479
  }
5480
+ await removePath(entry.backupPath);
4167
5481
  }
4168
- function detectSourceType(source) {
4169
- if (isFileUrl(source))
4170
- return "local";
4171
- if (isGitUrl(source))
4172
- return "git";
4173
- if (isUrl(source))
4174
- return "url";
4175
- return "local";
5482
+ async function backupExistingOriginals(entries, session) {
5483
+ for (const entry of entries) {
5484
+ if (!await pathExists(entry.originalPath))
5485
+ continue;
5486
+ await backupPath(entry.originalPath, session);
5487
+ }
4176
5488
  }
4177
- async function resolveSource(source, type = "auto", opts) {
4178
- const inferred = type === "auto" ? detectSourceType(source) : type;
4179
- const input = expandHome(source);
4180
- if (inferred === "local") {
4181
- const p = isFileUrl(input) ? normalizeFileUrl(input) : input;
4182
- if (!fs7.existsSync(p))
4183
- throw new Error(`Source path not found: ${p}`);
4184
- return { dir: p, cleanup: async () => {} };
4185
- }
4186
- const tempDir = await makeTempDir("dotagents-src-");
4187
- if (inferred === "git") {
4188
- await cloneGitRepo(input, tempDir, opts?.ref);
4189
- return { dir: tempDir, cleanup: async () => {
4190
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4191
- } };
4192
- }
4193
- if (inferred === "url") {
4194
- const lower = input.toLowerCase();
4195
- if (lower.endsWith(".zip") || lower.endsWith(".tar.gz") || lower.endsWith(".tgz") || lower.endsWith(".tar")) {
4196
- const archivePath = path12.join(tempDir, path12.basename(lower));
4197
- await downloadToFile(input, archivePath);
4198
- await ensureDir(tempDir);
4199
- await extractArchive(archivePath, tempDir);
4200
- return { dir: tempDir, cleanup: async () => {
4201
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4202
- } };
4203
- }
4204
- if (lower.endsWith("skill.md")) {
4205
- const skillDir = path12.join(tempDir, "skill");
4206
- await ensureDir(skillDir);
4207
- const dest = path12.join(skillDir, "SKILL.md");
4208
- await downloadToFile(input, dest);
4209
- return { dir: skillDir, cleanup: async () => {
4210
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4211
- } };
4212
- }
4213
- throw new Error("Unsupported URL source. Provide a git URL, archive (.zip/.tar.gz), or direct SKILL.md URL.");
4214
- }
4215
- throw new Error(`Unsupported source type: ${inferred}`);
5489
+ async function undoLastChange(opts) {
5490
+ const roots = resolveRoots(opts);
5491
+ const latest = await findLatestBackup(roots.canonicalRoot);
5492
+ if (!latest)
5493
+ throw new Error("No backups found to undo.");
5494
+ const undoSession = await createBackupSession({
5495
+ canonicalRoot: roots.canonicalRoot,
5496
+ scope: opts.scope,
5497
+ operation: "undo"
5498
+ });
5499
+ const entries = latest.manifest.entries || [];
5500
+ await backupExistingOriginals(entries, undoSession);
5501
+ let restored = 0;
5502
+ let restoredBackups = 0;
5503
+ let removedCreated = 0;
5504
+ let removedSymlinks = 0;
5505
+ for (const entry of entries) {
5506
+ if (entry.action === "create") {
5507
+ if (await pathExists(entry.originalPath)) {
5508
+ await restorePath(entry);
5509
+ restored += 1;
5510
+ removedCreated += 1;
5511
+ if (entry.kind === "symlink")
5512
+ removedSymlinks += 1;
5513
+ }
5514
+ continue;
5515
+ }
5516
+ if (!entry.backupPath)
5517
+ continue;
5518
+ if (!await pathExists(entry.backupPath))
5519
+ continue;
5520
+ await restorePath(entry);
5521
+ restored += 1;
5522
+ restoredBackups += 1;
5523
+ }
5524
+ await finalizeBackup(undoSession);
5525
+ return { restored, restoredBackups, removedCreated, removedSymlinks, backupDir: undoSession.dir, undoneDir: latest.dir };
4216
5526
  }
4217
5527
 
4218
- // src/installers/skills.ts
4219
- function parseGitHubUrl(input) {
5528
+ // src/core/preflight.ts
5529
+ import fs8 from "fs";
5530
+ import path11 from "path";
5531
+ async function needsLinkBackup(task, forceLinks) {
5532
+ if (task.type === "conflict")
5533
+ return forceLinks && task.target !== task.source;
5534
+ if (task.type !== "link")
5535
+ return false;
5536
+ if (!await pathExists(task.target))
5537
+ return false;
5538
+ if (forceLinks)
5539
+ return true;
5540
+ if (!task.replaceSymlink)
5541
+ return false;
4220
5542
  try {
4221
- const url = new URL(input);
4222
- if (url.hostname === "raw.githubusercontent.com") {
4223
- const parts2 = url.pathname.split("/").filter(Boolean);
4224
- if (parts2.length < 4)
4225
- return null;
4226
- const [owner2, repo2, ref2, ...rest2] = parts2;
4227
- const filePath2 = rest2.join("/");
4228
- const subdir2 = filePath2.toLowerCase().endsWith("skill.md") ? filePath2.split("/").slice(0, -1).join("/") : filePath2;
4229
- return { repoUrl: `https://github.com/${owner2}/${repo2}.git`, ref: ref2, subdir: subdir2 };
4230
- }
4231
- if (url.hostname !== "github.com")
4232
- return null;
4233
- const parts = url.pathname.split("/").filter(Boolean);
4234
- if (parts.length < 4)
4235
- return null;
4236
- const [owner, repo, kind, ref, ...rest] = parts;
4237
- if (kind !== "blob" && kind !== "tree")
4238
- return null;
4239
- const filePath = rest.join("/");
4240
- const subdir = filePath.toLowerCase().endsWith("skill.md") ? filePath.split("/").slice(0, -1).join("/") : filePath;
4241
- return { repoUrl: `https://github.com/${owner}/${repo}.git`, ref, subdir };
5543
+ const stat = await fs8.promises.lstat(task.target);
5544
+ return stat.isSymbolicLink();
4242
5545
  } catch {
4243
- return null;
5546
+ return false;
4244
5547
  }
4245
5548
  }
4246
- function parseGitLabUrl(input) {
4247
- try {
4248
- const url = new URL(input);
4249
- if (url.hostname !== "gitlab.com")
4250
- return null;
4251
- const parts = url.pathname.split("/").filter(Boolean);
4252
- const dash = parts.indexOf("-");
4253
- if (dash === -1)
4254
- return null;
4255
- const kind = parts[dash + 1];
4256
- if (kind !== "blob" && kind !== "tree" && kind !== "raw")
4257
- return null;
4258
- const ref = parts[dash + 2];
4259
- const rest = parts.slice(dash + 3).join("/");
4260
- const namespacePath = parts.slice(0, dash).join("/");
4261
- if (!namespacePath)
4262
- return null;
4263
- const subdir = rest.toLowerCase().endsWith("skill.md") ? rest.split("/").slice(0, -1).join("/") : rest;
4264
- return { repoUrl: `https://gitlab.com/${namespacePath}.git`, ref, subdir };
4265
- } catch {
4266
- return null;
5549
+ function collectMigrationCandidates(plan, selections) {
5550
+ const candidates = [...plan.auto];
5551
+ for (const conflict of plan.conflicts) {
5552
+ const choice = selections.get(conflict.targetPath);
5553
+ if (choice && choice.action === "copy")
5554
+ candidates.push(choice);
4267
5555
  }
5556
+ return candidates;
4268
5557
  }
4269
- function inferRepoFromUrl(input) {
4270
- return parseGitHubUrl(input) || parseGitLabUrl(input);
4271
- }
4272
- async function installSkillsFromSource(opts) {
4273
- const roots = resolveRoots({ scope: opts.scope, projectRoot: opts.projectRoot, homeDir: opts.homeDir });
4274
- const canonicalSkills = path13.join(roots.canonicalRoot, "skills");
4275
- await ensureDir(canonicalSkills);
4276
- const sourceType = opts.sourceType || "auto";
4277
- const isHttp = isUrl(opts.source);
4278
- const inferred = (sourceType === "auto" || sourceType === "url") && isHttp ? inferRepoFromUrl(opts.source) : null;
4279
- const resolved = inferred ? await resolveSource(inferred.repoUrl, "git", { ref: inferred.ref }) : await resolveSource(opts.source, sourceType);
4280
- try {
4281
- let rootDir = inferred?.subdir ? path13.join(resolved.dir, inferred.subdir) : resolved.dir;
4282
- try {
4283
- const stat = await fs8.promises.lstat(rootDir);
4284
- if (stat.isFile()) {
4285
- if (path13.basename(rootDir).toLowerCase() !== "skill.md") {
4286
- throw new Error("Expected a skills folder or SKILL.md file");
4287
- }
4288
- rootDir = path13.dirname(rootDir);
4289
- }
4290
- } catch {}
4291
- const skillDirs = await findSkillDirs(rootDir);
4292
- if (!skillDirs.length)
4293
- throw new Error("No SKILL.md found in source");
4294
- const installed = [];
4295
- const skipped = [];
4296
- const metas = [];
4297
- for (const dir of skillDirs) {
4298
- const skillFile = path13.join(dir, "SKILL.md");
4299
- const meta = await parseSkillFile(skillFile);
4300
- metas.push(meta);
4301
- const dest = skillDestDir(canonicalSkills, meta.name);
4302
- const exists = await pathExists(dest);
4303
- if (exists && !opts.force) {
4304
- skipped.push(meta.name);
4305
- continue;
4306
- }
4307
- await copyDir(dir, dest, true);
4308
- installed.push(meta.name);
5558
+ async function preflightBackup(opts) {
5559
+ const targets = new Set;
5560
+ for (const task of opts.linkPlan.tasks) {
5561
+ if (await needsLinkBackup(task, opts.forceLinks)) {
5562
+ targets.add(path11.resolve(task.target));
5563
+ }
5564
+ }
5565
+ const migrationCandidates = collectMigrationCandidates(opts.migratePlan, opts.selections);
5566
+ for (const candidate of migrationCandidates) {
5567
+ if (!candidate.sourcePath)
5568
+ continue;
5569
+ if (await pathExists(candidate.targetPath)) {
5570
+ targets.add(path11.resolve(candidate.targetPath));
4309
5571
  }
4310
- return { installed, skipped, skills: metas };
4311
- } finally {
4312
- await resolved.cleanup();
4313
5572
  }
5573
+ for (const target of targets) {
5574
+ const exists = await pathExists(target);
5575
+ if (!exists)
5576
+ continue;
5577
+ const stat = await fs8.promises.lstat(target);
5578
+ if (stat.isSymbolicLink()) {
5579
+ await fs8.promises.readlink(target);
5580
+ }
5581
+ const dest = backupPathFor(target, opts.backup.dir);
5582
+ await ensureDir(path11.dirname(dest));
5583
+ await fs8.promises.access(path11.dirname(dest), fs8.constants.W_OK);
5584
+ }
5585
+ return { targets: targets.size };
4314
5586
  }
4315
5587
 
4316
- // src/installers/marketplace.ts
4317
- import fs9 from "fs";
4318
- import path14 from "path";
4319
- function parseGitHubRawUrl(input) {
4320
- try {
4321
- const url = new URL(input);
4322
- if (url.hostname !== "raw.githubusercontent.com")
4323
- return null;
4324
- const parts = url.pathname.split("/").filter(Boolean);
4325
- if (parts.length < 4)
4326
- return null;
4327
- const [owner, repo, ref, ...rest] = parts;
4328
- const filePath = rest.join("/");
4329
- return { kind: "github", owner, repo, ref, basePath: path14.posix.dirname(filePath) };
4330
- } catch {
4331
- return null;
4332
- }
5588
+ // src/cli.tsx
5589
+ var appTitle = "dotagents";
5590
+ function exitCancelled() {
5591
+ ue("Cancelled");
5592
+ process.exit(0);
4333
5593
  }
4334
- function parseGitHubBlobUrl(input) {
4335
- try {
4336
- const url = new URL(input);
4337
- if (url.hostname !== "github.com")
4338
- return null;
4339
- const parts = url.pathname.split("/").filter(Boolean);
4340
- if (parts.length < 5)
4341
- return null;
4342
- const [owner, repo, blob, ref, ...rest] = parts;
4343
- if (blob !== "blob")
4344
- return null;
4345
- const filePath = rest.join("/");
4346
- return { kind: "github", owner, repo, ref, basePath: path14.posix.dirname(filePath) };
4347
- } catch {
4348
- return null;
4349
- }
5594
+ function mergeAgentStatus(items) {
5595
+ const claudeEntry = items.find((s) => s.name === "claude-md") || null;
5596
+ const agentsEntry = items.find((s) => s.name === "agents-md") || null;
5597
+ if (!claudeEntry && !agentsEntry)
5598
+ return items;
5599
+ const merged = {
5600
+ name: "agents-md",
5601
+ source: claudeEntry?.source || agentsEntry?.source || "",
5602
+ targets: [
5603
+ ...claudeEntry?.targets || [],
5604
+ ...agentsEntry?.targets || []
5605
+ ]
5606
+ };
5607
+ const withoutAgents = items.filter((s) => s.name !== "claude-md" && s.name !== "agents-md");
5608
+ return [merged, ...withoutAgents];
4350
5609
  }
4351
- async function loadMarketplace(input) {
4352
- if (isUrl(input)) {
4353
- const json2 = await fetchJson(input);
4354
- const gh = parseGitHubRawUrl(input) || parseGitHubBlobUrl(input);
4355
- return { json: json2, context: gh || {} };
4356
- }
4357
- const resolved = path14.resolve(input);
4358
- let file = resolved;
4359
- if (fs9.existsSync(resolved) && fs9.statSync(resolved).isDirectory()) {
4360
- file = path14.join(resolved, ".claude-plugin", "marketplace.json");
4361
- }
4362
- if (!fs9.existsSync(file))
4363
- throw new Error(`marketplace.json not found: ${file}`);
4364
- const raw = await fs9.promises.readFile(file, "utf8");
4365
- const json = JSON.parse(raw);
4366
- return { json, context: { baseDir: path14.dirname(file) } };
5610
+ function displayName(entry) {
5611
+ if (entry.name === "agents-md") {
5612
+ const sourceFile = path12.basename(entry.source);
5613
+ if (sourceFile === "CLAUDE.md")
5614
+ return "AGENTS.md (Claude override)";
5615
+ return "AGENTS.md";
5616
+ }
5617
+ return entry.name;
4367
5618
  }
4368
- function resolvePluginPath(entry, ctx, pluginRoot) {
4369
- const base = ctx.baseDir || process.cwd();
4370
- const root = pluginRoot ? path14.resolve(base, pluginRoot) : base;
4371
- if (typeof entry.source === "string") {
4372
- if (isUrl(entry.source))
4373
- return { source: entry.source, type: "url" };
4374
- if (ctx.kind === "github" && ctx.owner && ctx.repo) {
4375
- const repoRoot = pluginRoot ? pluginRoot : "";
4376
- const primary = path14.posix.normalize(path14.posix.join(repoRoot, entry.source));
4377
- const candidates = [primary];
4378
- if (ctx.basePath) {
4379
- candidates.push(path14.posix.normalize(path14.posix.join(ctx.basePath, entry.source)));
4380
- }
4381
- return { source: `https://github.com/${ctx.owner}/${ctx.repo}.git`, type: "git", subdirCandidates: candidates, ref: ctx.ref };
4382
- }
4383
- const candidate = path14.resolve(root, entry.source);
4384
- return { source: candidate, type: "local" };
4385
- }
4386
- const src = entry.source;
4387
- if (src.source === "github" && src.repo) {
4388
- return { source: `https://github.com/${src.repo}.git`, type: "git", ref: src.ref };
4389
- }
4390
- if (src.source === "git" && src.url) {
4391
- return { source: src.url, type: "git", ref: src.ref };
4392
- }
4393
- if (src.source === "url" && src.url) {
4394
- return { source: src.url, type: "url" };
4395
- }
4396
- throw new Error(`Unsupported plugin source for ${entry.name}`);
5619
+ function buildStatusSummary(status) {
5620
+ return status.map((s) => {
5621
+ const linked = s.targets.filter((t) => t.status === "linked").length;
5622
+ const missing = s.targets.filter((t) => t.status === "missing").length;
5623
+ const conflict = s.targets.filter((t) => t.status === "conflict").length;
5624
+ return { name: displayName(s), linked, missing, conflict };
5625
+ });
4397
5626
  }
4398
- async function scanPluginDir(dir) {
4399
- const commandsDir = path14.join(dir, "commands");
4400
- const hooksDir = path14.join(dir, "hooks");
4401
- const skillsDir = path14.join(dir, "skills");
4402
- const commands = await listMarkdownFiles(commandsDir);
4403
- const hooks = await listFiles(hooksDir);
4404
- const skillsExists = await pathExists(skillsDir);
4405
- return { commands, hooks, skillsDir: skillsExists ? skillsDir : undefined };
5627
+ function formatSummaryTable(rows) {
5628
+ const header = { name: "Section", conflict: "Conflicts", missing: "Need link", linked: "Linked" };
5629
+ const width = {
5630
+ name: Math.max(header.name.length, ...rows.map((r2) => r2.name.length)),
5631
+ conflict: Math.max(header.conflict.length, ...rows.map((r2) => String(r2.conflict).length)),
5632
+ missing: Math.max(header.missing.length, ...rows.map((r2) => String(r2.missing).length)),
5633
+ linked: Math.max(header.linked.length, ...rows.map((r2) => String(r2.linked).length))
5634
+ };
5635
+ const pad = (value, len) => value.padEnd(len, " ");
5636
+ const lines = [
5637
+ `${pad(header.name, width.name)} ${pad(header.conflict, width.conflict)} ${pad(header.missing, width.missing)} ${pad(header.linked, width.linked)}`,
5638
+ ...rows.map((r2) => `${pad(r2.name, width.name)} ${pad(String(r2.conflict), width.conflict)} ${pad(String(r2.missing), width.missing)} ${pad(String(r2.linked), width.linked)}`)
5639
+ ];
5640
+ return lines;
4406
5641
  }
4407
- async function installMarketplace(opts) {
4408
- const roots = resolveRoots({ scope: opts.scope, projectRoot: opts.projectRoot, homeDir: opts.homeDir });
4409
- const canonicalRoot = roots.canonicalRoot;
4410
- const commandsDest = path14.join(canonicalRoot, "commands");
4411
- const hooksDest = path14.join(canonicalRoot, "hooks");
4412
- await ensureDir(commandsDest);
4413
- await ensureDir(hooksDest);
4414
- const { json, context } = await loadMarketplace(opts.marketplace);
4415
- const selected = opts.plugins === "all" ? json.plugins : json.plugins.filter((p) => opts.plugins.includes(p.name));
4416
- const installedCommands = [];
4417
- const installedHooks = [];
4418
- const installedSkills = [];
4419
- const skippedCommands = [];
4420
- const skippedHooks = [];
4421
- const skippedSkills = [];
4422
- for (const plugin of selected) {
4423
- const { source, type, subdir, subdirCandidates, ref } = resolvePluginPath(plugin, context, json.pluginRoot);
4424
- const resolved = await resolveSource(source, type, { ref });
4425
- try {
4426
- let pluginDir = resolved.dir;
4427
- if (subdirCandidates && subdirCandidates.length) {
4428
- const found = subdirCandidates.map((candidate) => path14.join(resolved.dir, candidate)).find((candidate) => fs9.existsSync(candidate));
4429
- if (!found) {
4430
- throw new Error(`Plugin path not found in repo: ${subdirCandidates.join(", ")}`);
4431
- }
4432
- pluginDir = found;
4433
- } else if (subdir) {
4434
- pluginDir = path14.join(resolved.dir, subdir);
4435
- }
4436
- const scan = await scanPluginDir(pluginDir);
4437
- for (const cmd of scan.commands) {
4438
- const name = path14.basename(cmd);
4439
- const dest = path14.join(commandsDest, name);
4440
- const result = await copyFile(cmd, dest, !!opts.force);
4441
- if (result === "written")
4442
- installedCommands.push(`${plugin.name}:${name}`);
4443
- else
4444
- skippedCommands.push(`${plugin.name}:${name}`);
4445
- }
4446
- for (const hook of scan.hooks) {
4447
- const name = path14.basename(hook);
4448
- const dest = path14.join(hooksDest, name);
4449
- const result = await copyFile(hook, dest, !!opts.force);
4450
- if (result === "written")
4451
- installedHooks.push(`${plugin.name}:${name}`);
4452
- else
4453
- skippedHooks.push(`${plugin.name}:${name}`);
4454
- }
4455
- if (scan.skillsDir) {
4456
- const skillResult = await installSkillsFromSource({
4457
- source: scan.skillsDir,
4458
- sourceType: "local",
4459
- scope: opts.scope,
4460
- projectRoot: opts.projectRoot,
4461
- homeDir: opts.homeDir,
4462
- force: opts.force
4463
- });
4464
- installedSkills.push(...skillResult.installed.map((n) => `${plugin.name}:${n}`));
4465
- skippedSkills.push(...skillResult.skipped.map((n) => `${plugin.name}:${n}`));
4466
- }
4467
- } finally {
4468
- await resolved.cleanup();
5642
+ function renderStatusLines(status, conflictReasons) {
5643
+ const lines = [];
5644
+ for (const entry of status) {
5645
+ lines.push(source_default.cyan(displayName(entry)));
5646
+ for (const target of entry.targets) {
5647
+ const icon = target.status === "linked" ? source_default.green("✓") : target.status === "missing" ? source_default.yellow("•") : source_default.red("⚠");
5648
+ const reason = target.status === "conflict" ? conflictReasons.get(target.path) : undefined;
5649
+ lines.push(` ${icon} ${target.path}${reason ? source_default.dim(` — ${reason}`) : ""}`);
4469
5650
  }
4470
5651
  }
4471
- return {
4472
- installedCommands,
4473
- installedHooks,
4474
- installedSkills,
4475
- skippedCommands,
4476
- skippedHooks,
4477
- skippedSkills
4478
- };
4479
- }
4480
-
4481
- // src/tui/ui/HelpBar.tsx
4482
- import { Box, Text } from "ink";
4483
- import { jsxDEV } from "react/jsx-dev-runtime";
4484
- function HelpBar({ text }) {
4485
- return /* @__PURE__ */ jsxDEV(Box, {
4486
- marginTop: 1,
4487
- children: /* @__PURE__ */ jsxDEV(Text, {
4488
- dimColor: true,
4489
- children: text
4490
- }, undefined, false, undefined, this)
4491
- }, undefined, false, undefined, this);
5652
+ return lines;
4492
5653
  }
4493
-
4494
- // src/tui/ui/ScrollArea.tsx
4495
- import { useEffect, useReducer, useRef } from "react";
4496
- import { Box as Box2, measureElement, useInput, useStdout } from "ink";
4497
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
4498
- var reducer = (s, a) => {
4499
- switch (a.type) {
4500
- case "SET_INNER": {
4501
- const max = Math.max(0, a.h - s.height);
4502
- const nextScrollTop = Math.min(s.scrollTop, max);
4503
- if (s.innerHeight === a.h && nextScrollTop === s.scrollTop)
4504
- return s;
4505
- return { ...s, innerHeight: a.h, scrollTop: nextScrollTop };
4506
- }
4507
- case "SET_HEIGHT": {
4508
- const max = Math.max(0, s.innerHeight - a.h);
4509
- const nextScrollTop = Math.min(s.scrollTop, max);
4510
- if (s.height === a.h && nextScrollTop === s.scrollTop)
4511
- return s;
4512
- return { ...s, height: a.h, scrollTop: nextScrollTop };
4513
- }
4514
- case "SCROLL": {
4515
- const max = Math.max(0, s.innerHeight - s.height);
4516
- const nextScrollTop = Math.max(0, Math.min(max, s.scrollTop + a.delta));
4517
- if (nextScrollTop === s.scrollTop)
4518
- return s;
4519
- return { ...s, scrollTop: nextScrollTop };
4520
- }
4521
- case "TOP": {
4522
- if (s.scrollTop === 0)
4523
- return s;
4524
- return { ...s, scrollTop: 0 };
4525
- }
4526
- case "BOTTOM": {
4527
- const max = Math.max(0, s.innerHeight - s.height);
4528
- if (s.scrollTop === max)
4529
- return s;
4530
- return { ...s, scrollTop: max };
4531
- }
4532
- default:
4533
- return s;
4534
- }
4535
- };
4536
- function ScrollArea({ height, children }) {
4537
- const innerRef = useRef(null);
4538
- const { stdout } = useStdout();
4539
- const [state, dispatch] = useReducer(reducer, { innerHeight: 0, height, scrollTop: 0 });
4540
- useEffect(() => {
4541
- dispatch({ type: "SET_HEIGHT", h: height });
4542
- }, [height]);
4543
- useEffect(() => {
4544
- if (!innerRef.current)
4545
- return;
4546
- const dim = measureElement(innerRef.current);
4547
- dispatch({ type: "SET_INNER", h: dim.height });
4548
- });
4549
- useEffect(() => {
4550
- const onResize = () => dispatch({ type: "SET_HEIGHT", h: stdout.rows });
4551
- return () => void onResize();
4552
- }, [stdout]);
4553
- useInput((input, key) => {
4554
- if (key.pageDown || key.downArrow && key.meta)
4555
- dispatch({ type: "SCROLL", delta: Math.max(1, Math.floor(state.height * 0.8)) });
4556
- if (key.pageUp || key.upArrow && key.meta)
4557
- dispatch({ type: "SCROLL", delta: -Math.max(1, Math.floor(state.height * 0.8)) });
4558
- if (input === "g")
4559
- dispatch({ type: "TOP" });
4560
- if (input === "G")
4561
- dispatch({ type: "BOTTOM" });
5654
+ async function selectScope() {
5655
+ const scope = await ie({
5656
+ message: "Choose a workspace",
5657
+ options: [
5658
+ { label: "Global (~/.agents)", value: "global" },
5659
+ { label: "Project (.agents)", value: "project" },
5660
+ { label: "Exit", value: "exit" }
5661
+ ]
4562
5662
  });
4563
- return /* @__PURE__ */ jsxDEV2(Box2, {
4564
- height,
4565
- flexDirection: "column",
4566
- overflow: "hidden",
4567
- children: /* @__PURE__ */ jsxDEV2(Box2, {
4568
- ref: innerRef,
4569
- flexShrink: 0,
4570
- flexDirection: "column",
4571
- marginTop: -state.scrollTop,
4572
- children
4573
- }, undefined, false, undefined, this)
4574
- }, undefined, false, undefined, this);
5663
+ if (lD(scope))
5664
+ exitCancelled();
5665
+ if (scope === "exit") {
5666
+ $e("Bye");
5667
+ process.exit(0);
5668
+ }
5669
+ return scope;
4575
5670
  }
4576
-
4577
- // src/tui/ui/Screen.tsx
4578
- import { Box as Box3, useStdout as useStdout2 } from "ink";
4579
- import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
4580
- function Screen({ children }) {
4581
- const { stdout } = useStdout2();
4582
- const height = stdout?.rows;
4583
- return /* @__PURE__ */ jsxDEV3(Box3, {
4584
- flexDirection: "column",
4585
- height,
4586
- children
4587
- }, undefined, false, undefined, this);
5671
+ function scopeLabel(scope) {
5672
+ return scope === "global" ? "Global (~/.agents)" : "Project (.agents)";
4588
5673
  }
4589
-
4590
- // src/tui/App.tsx
4591
- import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
4592
- var appTitle = "dotagents";
4593
- var App = () => {
4594
- const { exit } = useApp();
4595
- const [step, setStep] = useState("scope");
4596
- const [scope, setScope] = useState(null);
4597
- const [plan, setPlan] = useState(null);
4598
- const [status, setStatus] = useState([]);
4599
- const [message, setMessage] = useState("");
4600
- const [busy, setBusy] = useState(null);
4601
- const [migratePlan, setMigratePlan] = useState(null);
4602
- const [migrateIndex, setMigrateIndex] = useState(0);
4603
- const [migrateSelections, setMigrateSelections] = useState(new Map);
4604
- const [skillType, setSkillType] = useState("local");
4605
- const [skillInput, setSkillInput] = useState("");
4606
- const [marketplaceInput, setMarketplaceInput] = useState("");
4607
- const [marketplacePlugins, setMarketplacePlugins] = useState([]);
4608
- const [showDetails, setShowDetails] = useState(false);
4609
- const [conflictsOnly, setConflictsOnly] = useState(false);
4610
- const { stdout } = useStdout3();
4611
- useInput2((input, key) => {
4612
- if (input === "q")
4613
- exit();
4614
- if (step === "status" && input === "d")
4615
- setShowDetails((prev) => !prev);
4616
- if (step === "status" && input === "c")
4617
- setConflictsOnly(true);
4618
- if (step === "status" && input === "a")
4619
- setConflictsOnly(false);
4620
- if (key.escape) {
4621
- if (step === "action")
4622
- return setStep("scope");
4623
- if (step === "status")
4624
- return setStep("action");
4625
- if (step === "migrate-choice") {
4626
- setMigratePlan(null);
4627
- setMigrateSelections(new Map);
4628
- return setStep("action");
4629
- }
4630
- if (step === "skill-source-type")
4631
- return setStep("action");
4632
- if (step === "skill-input")
4633
- return setStep("skill-source-type");
4634
- if (step === "plugin-marketplace-input")
4635
- return setStep("action");
4636
- if (step === "plugin-select")
4637
- return setStep("plugin-marketplace-input");
4638
- if (step === "done")
4639
- return setStep("action");
4640
- }
4641
- if (step === "done" && key.return)
4642
- setStep("action");
5674
+ function pluralize(count, singular, plural) {
5675
+ return count === 1 ? singular : plural || `${singular}s`;
5676
+ }
5677
+ function formatCount(count, singular, plural) {
5678
+ return `${count} ${pluralize(count, singular, plural)}`;
5679
+ }
5680
+ async function selectClients() {
5681
+ const options2 = [
5682
+ { label: "Claude", value: "claude" },
5683
+ { label: "Factory", value: "factory" },
5684
+ { label: "Codex", value: "codex" },
5685
+ { label: "Cursor", value: "cursor" },
5686
+ { label: "OpenCode", value: "opencode" }
5687
+ ];
5688
+ const selected = await ae({
5689
+ message: "Select clients to manage",
5690
+ options: options2.map((opt) => ({ label: opt.label, value: opt.value })),
5691
+ initialValues: options2.map((opt) => opt.value),
5692
+ required: true
4643
5693
  });
4644
- const scopeLabel = scope === "global" ? "Global (~/.agents)" : scope === "project" ? "Project (.agents)" : "";
4645
- const refreshStatus = async (nextScope) => {
4646
- const s = await getLinkStatus({ scope: nextScope });
4647
- setStatus(s);
4648
- const p = await buildLinkPlan({ scope: nextScope });
4649
- setPlan(p);
4650
- };
4651
- useEffect2(() => {
4652
- if (scope)
4653
- refreshStatus(scope);
4654
- }, [scope]);
4655
- const conflicts = plan?.conflicts.length || 0;
4656
- const changes = plan?.changes.length || 0;
4657
- const actionItems = useMemo(() => {
4658
- const items = [
4659
- { label: "Apply/repair links", value: "apply" }
4660
- ];
4661
- if (conflicts > 0)
4662
- items.push({ label: "Force apply (overwrite conflicts)", value: "force-apply" });
4663
- items.push({ label: "View status", value: "view-status" });
4664
- items.push({ label: "Migrate existing content", value: "migrate" });
4665
- items.push({ label: "Add skill", value: "add-skill" });
4666
- items.push({ label: "Install plugin", value: "install-plugin" });
4667
- items.push({ label: "Exit", value: "exit" });
4668
- return items;
4669
- }, [conflicts]);
4670
- const displayName = (name) => {
4671
- if (name === "agents-md")
4672
- return "AGENTS.md";
4673
- return name;
5694
+ if (lD(selected))
5695
+ exitCancelled();
5696
+ return selected;
5697
+ }
5698
+ function formatClients(clients) {
5699
+ const names = {
5700
+ claude: "Claude",
5701
+ factory: "Factory",
5702
+ codex: "Codex",
5703
+ cursor: "Cursor",
5704
+ opencode: "OpenCode"
4674
5705
  };
4675
- const statusSummary = useMemo(() => {
4676
- return status.map((s) => {
4677
- const linked = s.targets.filter((t) => t.status === "linked").length;
4678
- const missing = s.targets.filter((t) => t.status === "missing").length;
4679
- const conflict = s.targets.filter((t) => t.status === "conflict").length;
4680
- return { name: displayName(s.name), linked, missing, conflict };
5706
+ return clients.map((c) => names[c]).join(", ");
5707
+ }
5708
+ async function showStatus(scope, clients, status, planConflicts) {
5709
+ const conflicts = new Map(planConflicts.map((c) => [c.target, c.reason]));
5710
+ const lines = renderStatusLines(mergeAgentStatus(status), conflicts);
5711
+ le(lines.join(`
5712
+ `), `Status · ${scopeLabel(scope)} · ${formatClients(clients)}`);
5713
+ }
5714
+ async function resolveMigrationConflicts(plan) {
5715
+ const selections = new Map;
5716
+ for (let i = 0;i < plan.conflicts.length; i += 1) {
5717
+ const conflict = plan.conflicts[i];
5718
+ const choice = await ie({
5719
+ message: `Resolve migration conflict ${i + 1} of ${plan.conflicts.length}: ${conflict.label}`,
5720
+ options: conflict.candidates.map((c) => ({ label: c.label, value: c }))
4681
5721
  });
4682
- }, [status]);
4683
- const summaryTable = useMemo(() => {
4684
- const rows = statusSummary.map((s) => ({
4685
- name: s.name,
4686
- conflict: String(s.conflict),
4687
- missing: String(s.missing),
4688
- linked: String(s.linked)
4689
- }));
4690
- const header = { name: "Section", conflict: "Conflicts", missing: "Need link", linked: "Linked" };
4691
- const width = {
4692
- name: Math.max(header.name.length, ...rows.map((r) => r.name.length)),
4693
- conflict: Math.max(header.conflict.length, ...rows.map((r) => r.conflict.length)),
4694
- missing: Math.max(header.missing.length, ...rows.map((r) => r.missing.length)),
4695
- linked: Math.max(header.linked.length, ...rows.map((r) => r.linked.length))
4696
- };
4697
- const pad = (value, len) => value.padEnd(len, " ");
4698
- const lines = [
4699
- `${pad(header.name, width.name)} ${pad(header.conflict, width.conflict)} ${pad(header.missing, width.missing)} ${pad(header.linked, width.linked)}`,
4700
- ...rows.map((r) => `${pad(r.name, width.name)} ${pad(r.conflict, width.conflict)} ${pad(r.missing, width.missing)} ${pad(r.linked, width.linked)}`)
4701
- ];
4702
- return lines;
4703
- }, [statusSummary]);
4704
- const [conflictDetails, setConflictDetails] = useState(new Map);
4705
- useEffect2(() => {
4706
- let cancelled = false;
4707
- const load = async () => {
4708
- if (!plan)
4709
- return;
4710
- const map = new Map;
4711
- for (const task of plan.conflicts) {
4712
- map.set(task.target, { reason: task.reason });
4713
- try {
4714
- const stat = await fs10.promises.lstat(task.target);
4715
- if (stat.isDirectory() && !stat.isSymbolicLink()) {
4716
- const entries = await fs10.promises.readdir(task.target);
4717
- const shown = entries.slice(0, 6);
4718
- const more = entries.length > 6 ? `… +${entries.length - 6} more` : "";
4719
- const contents = entries.length === 0 ? "(empty)" : `${shown.join(", ")}${more ? `, ${more}` : ""}`;
4720
- map.set(task.target, { reason: task.reason, contents: `Contains: ${contents}` });
4721
- }
4722
- } catch {}
4723
- }
4724
- if (!cancelled)
4725
- setConflictDetails(map);
4726
- };
4727
- load();
4728
- return () => {
4729
- cancelled = true;
4730
- };
4731
- }, [plan]);
4732
- const renderStatusList = () => {
4733
- const sections = status.map((s) => {
4734
- const targets = conflictsOnly ? s.targets.filter((t) => t.status === "conflict") : s.targets;
4735
- if (conflictsOnly && targets.length === 0)
4736
- return null;
4737
- return /* @__PURE__ */ jsxDEV4(Box4, {
4738
- flexDirection: "column",
4739
- marginTop: 1,
4740
- children: [
4741
- /* @__PURE__ */ jsxDEV4(Text2, {
4742
- color: "cyan",
4743
- children: displayName(s.name)
4744
- }, undefined, false, undefined, this),
4745
- targets.map((t) => /* @__PURE__ */ jsxDEV4(Box4, {
4746
- flexDirection: "column",
4747
- children: [
4748
- /* @__PURE__ */ jsxDEV4(Text2, {
4749
- children: [
4750
- t.status === "linked" ? "✓" : t.status === "missing" ? "•" : "⚠",
4751
- " ",
4752
- t.path
4753
- ]
4754
- }, undefined, true, undefined, this),
4755
- showDetails && t.status === "conflict" && conflictDetails.has(t.path) ? /* @__PURE__ */ jsxDEV4(Fragment, {
4756
- children: [
4757
- /* @__PURE__ */ jsxDEV4(Text2, {
4758
- color: "red",
4759
- children: [
4760
- " ",
4761
- conflictDetails.get(t.path)?.reason
4762
- ]
4763
- }, undefined, true, undefined, this),
4764
- conflictDetails.get(t.path)?.contents ? /* @__PURE__ */ jsxDEV4(Text2, {
4765
- dimColor: true,
4766
- children: [
4767
- " ",
4768
- conflictDetails.get(t.path)?.contents
4769
- ]
4770
- }, undefined, true, undefined, this) : null
4771
- ]
4772
- }, undefined, true, undefined, this) : null
4773
- ]
4774
- }, t.path, true, undefined, this))
4775
- ]
4776
- }, s.name, true, undefined, this);
4777
- }).filter(Boolean);
4778
- if (!sections.length) {
4779
- return /* @__PURE__ */ jsxDEV4(Box4, {
4780
- marginTop: 1,
4781
- children: /* @__PURE__ */ jsxDEV4(Text2, {
4782
- dimColor: true,
4783
- children: "No conflicts found."
4784
- }, undefined, false, undefined, this)
4785
- }, undefined, false, undefined, this);
4786
- }
4787
- return /* @__PURE__ */ jsxDEV4(Box4, {
4788
- flexDirection: "column",
4789
- children: sections
4790
- }, undefined, false, undefined, this);
4791
- };
4792
- if (step === "scope") {
4793
- return /* @__PURE__ */ jsxDEV4(Screen, {
4794
- children: [
4795
- /* @__PURE__ */ jsxDEV4(Text2, {
4796
- color: "green",
4797
- children: appTitle
4798
- }, undefined, false, undefined, this),
4799
- /* @__PURE__ */ jsxDEV4(Text2, {
4800
- children: "Choose a workspace:"
4801
- }, undefined, false, undefined, this),
4802
- /* @__PURE__ */ jsxDEV4(SelectInput, {
4803
- items: [
4804
- { label: "Global home", value: "global" },
4805
- { label: "Project folder", value: "project" },
4806
- { label: "Exit", value: "exit" }
4807
- ],
4808
- onSelect: (item) => {
4809
- if (item.value === "exit")
4810
- return exit();
4811
- setScope(item.value);
4812
- setStep("action");
4813
- }
4814
- }, undefined, false, undefined, this)
4815
- ]
4816
- }, undefined, true, undefined, this);
4817
- }
4818
- if (step === "action") {
4819
- return /* @__PURE__ */ jsxDEV4(Screen, {
4820
- children: [
4821
- /* @__PURE__ */ jsxDEV4(Text2, {
4822
- color: "green",
4823
- children: appTitle
4824
- }, undefined, false, undefined, this),
4825
- /* @__PURE__ */ jsxDEV4(Box4, {
4826
- flexDirection: "column",
4827
- marginTop: 1,
4828
- children: [
4829
- /* @__PURE__ */ jsxDEV4(Text2, {
4830
- children: [
4831
- "Scope: ",
4832
- scopeLabel
4833
- ]
4834
- }, undefined, true, undefined, this),
4835
- /* @__PURE__ */ jsxDEV4(Text2, {
4836
- children: [
4837
- "Pending changes: ",
4838
- changes,
4839
- " · Conflicts: ",
4840
- conflicts
4841
- ]
4842
- }, undefined, true, undefined, this),
4843
- summaryTable.map((line) => /* @__PURE__ */ jsxDEV4(Text2, {
4844
- children: line
4845
- }, line, false, undefined, this))
4846
- ]
4847
- }, undefined, true, undefined, this),
4848
- /* @__PURE__ */ jsxDEV4(Box4, {
4849
- marginTop: 1,
4850
- flexDirection: "column",
4851
- children: [
4852
- /* @__PURE__ */ jsxDEV4(Text2, {
4853
- children: "Choose an action:"
4854
- }, undefined, false, undefined, this),
4855
- /* @__PURE__ */ jsxDEV4(SelectInput, {
4856
- items: actionItems,
4857
- onSelect: (item) => {
4858
- if (item.value === "exit")
4859
- return exit();
4860
- if (item.value === "view-status") {
4861
- setStep("status");
4862
- return;
4863
- }
4864
- if (item.value === "migrate") {
4865
- if (!scope)
4866
- return;
4867
- setBusy("Scanning existing content...");
4868
- setStep("applying");
4869
- (async () => {
4870
- try {
4871
- const plan2 = await scanMigration({ scope });
4872
- setMigratePlan(plan2);
4873
- setMigrateIndex(0);
4874
- setMigrateSelections(new Map);
4875
- if (plan2.conflicts.length > 0) {
4876
- setBusy(null);
4877
- setStep("migrate-choice");
4878
- return;
4879
- }
4880
- setBusy("Migrating...");
4881
- const result = await applyMigration(plan2, new Map, { scope });
4882
- setMessage(`Migrated ${result.copied} items. Backup: ${result.backupDir}`);
4883
- await refreshStatus(scope);
4884
- setStep("done");
4885
- } catch (err) {
4886
- setMessage(err?.message || String(err));
4887
- setStep("done");
4888
- } finally {
4889
- setBusy(null);
4890
- }
4891
- })();
4892
- return;
4893
- }
4894
- if (item.value === "apply" || item.value === "force-apply") {
4895
- setBusy(item.value === "force-apply" ? "Applying (force)..." : "Applying...");
4896
- setStep("applying");
4897
- (async () => {
4898
- try {
4899
- if (!plan || !scope)
4900
- return;
4901
- const result = await applyLinkPlan(plan, { force: item.value === "force-apply" });
4902
- setMessage(`Applied: ${result.applied}, Skipped: ${result.skipped}, Conflicts: ${result.conflicts}`);
4903
- await refreshStatus(scope);
4904
- } catch (err) {
4905
- setMessage(err?.message || String(err));
4906
- } finally {
4907
- setBusy(null);
4908
- setStep("done");
4909
- }
4910
- })();
4911
- return;
4912
- }
4913
- if (item.value === "add-skill") {
4914
- setSkillInput("");
4915
- setStep("skill-source-type");
4916
- return;
4917
- }
4918
- if (item.value === "install-plugin") {
4919
- setMarketplaceInput("");
4920
- setStep("plugin-marketplace-input");
4921
- return;
4922
- }
4923
- }
4924
- }, undefined, false, undefined, this),
4925
- /* @__PURE__ */ jsxDEV4(HelpBar, {
4926
- text: "Use ↑↓ to navigate, Enter to select, Esc to go back, q to quit"
4927
- }, undefined, false, undefined, this)
4928
- ]
4929
- }, undefined, true, undefined, this)
4930
- ]
4931
- }, undefined, true, undefined, this);
4932
- }
4933
- if (step === "status") {
4934
- const listHeight = Math.max(6, (stdout?.rows ?? 24) - 8);
4935
- return /* @__PURE__ */ jsxDEV4(Screen, {
4936
- children: [
4937
- /* @__PURE__ */ jsxDEV4(Text2, {
4938
- color: "green",
4939
- children: appTitle
4940
- }, undefined, false, undefined, this),
4941
- /* @__PURE__ */ jsxDEV4(Box4, {
4942
- flexDirection: "column",
4943
- marginTop: 1,
4944
- children: [
4945
- /* @__PURE__ */ jsxDEV4(Text2, {
4946
- children: [
4947
- "Scope: ",
4948
- scopeLabel
4949
- ]
4950
- }, undefined, true, undefined, this),
4951
- /* @__PURE__ */ jsxDEV4(Text2, {
4952
- children: [
4953
- "Pending changes: ",
4954
- changes,
4955
- " · Conflicts: ",
4956
- conflicts
4957
- ]
4958
- }, undefined, true, undefined, this),
4959
- /* @__PURE__ */ jsxDEV4(Text2, {
4960
- dimColor: true,
4961
- children: "Legend: ✓ linked • need link ⚠ conflict"
4962
- }, undefined, false, undefined, this),
4963
- /* @__PURE__ */ jsxDEV4(Text2, {
4964
- dimColor: true,
4965
- children: [
4966
- "Mode: ",
4967
- conflictsOnly ? "Conflicts only" : "All",
4968
- " · Details: ",
4969
- showDetails ? "On" : "Off"
4970
- ]
4971
- }, undefined, true, undefined, this)
4972
- ]
4973
- }, undefined, true, undefined, this),
4974
- /* @__PURE__ */ jsxDEV4(ScrollArea, {
4975
- height: listHeight,
4976
- children: renderStatusList()
4977
- }, undefined, false, undefined, this),
4978
- /* @__PURE__ */ jsxDEV4(HelpBar, {
4979
- text: "d: details · c: conflicts only · a: show all · Esc: back · q: quit"
4980
- }, undefined, false, undefined, this)
4981
- ]
4982
- }, undefined, true, undefined, this);
4983
- }
4984
- if (step === "migrate-choice" && migratePlan) {
4985
- const conflict = migratePlan.conflicts[migrateIndex];
4986
- if (!conflict) {
4987
- return /* @__PURE__ */ jsxDEV4(Screen, {
4988
- children: [
4989
- /* @__PURE__ */ jsxDEV4(Text2, {
4990
- color: "green",
4991
- children: appTitle
4992
- }, undefined, false, undefined, this),
4993
- /* @__PURE__ */ jsxDEV4(Text2, {
4994
- dimColor: true,
4995
- children: "No conflicts to resolve."
4996
- }, undefined, false, undefined, this),
4997
- /* @__PURE__ */ jsxDEV4(HelpBar, {
4998
- text: "Esc: back · q: quit"
4999
- }, undefined, false, undefined, this)
5000
- ]
5001
- }, undefined, true, undefined, this);
5002
- }
5003
- const items = conflict.candidates.map((c) => ({
5004
- label: c.label,
5005
- value: c
5006
- }));
5007
- return /* @__PURE__ */ jsxDEV4(Screen, {
5008
- children: [
5009
- /* @__PURE__ */ jsxDEV4(Text2, {
5010
- color: "green",
5011
- children: appTitle
5012
- }, undefined, false, undefined, this),
5013
- /* @__PURE__ */ jsxDEV4(Box4, {
5014
- flexDirection: "column",
5015
- marginTop: 1,
5016
- children: [
5017
- /* @__PURE__ */ jsxDEV4(Text2, {
5018
- children: [
5019
- "Resolve conflict ",
5020
- migrateIndex + 1,
5021
- " of ",
5022
- migratePlan.conflicts.length
5023
- ]
5024
- }, undefined, true, undefined, this),
5025
- /* @__PURE__ */ jsxDEV4(Text2, {
5026
- dimColor: true,
5027
- children: conflict.label
5028
- }, undefined, false, undefined, this)
5029
- ]
5030
- }, undefined, true, undefined, this),
5031
- /* @__PURE__ */ jsxDEV4(Box4, {
5032
- marginTop: 1,
5033
- flexDirection: "column",
5034
- children: [
5035
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5036
- items,
5037
- onSelect: (item) => {
5038
- if (!scope)
5039
- return;
5040
- const next = new Map(migrateSelections);
5041
- next.set(conflict.targetPath, item.value);
5042
- setMigrateSelections(next);
5043
- if (migrateIndex + 1 < migratePlan.conflicts.length) {
5044
- setMigrateIndex(migrateIndex + 1);
5045
- return;
5046
- }
5047
- setBusy("Migrating...");
5048
- setStep("applying");
5049
- (async () => {
5050
- try {
5051
- const result = await applyMigration(migratePlan, next, { scope });
5052
- setMessage(`Migrated ${result.copied} items. Backup: ${result.backupDir}`);
5053
- await refreshStatus(scope);
5054
- } catch (err) {
5055
- setMessage(err?.message || String(err));
5056
- } finally {
5057
- setBusy(null);
5058
- setMigratePlan(null);
5059
- setMigrateIndex(0);
5060
- setMigrateSelections(new Map);
5061
- setStep("done");
5062
- }
5063
- })();
5064
- }
5065
- }, undefined, false, undefined, this),
5066
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5067
- text: "Use ↑↓ to choose, Enter to select, Esc to cancel"
5068
- }, undefined, false, undefined, this)
5069
- ]
5070
- }, undefined, true, undefined, this)
5071
- ]
5072
- }, undefined, true, undefined, this);
5073
- }
5074
- if (step === "applying") {
5075
- return /* @__PURE__ */ jsxDEV4(Screen, {
5076
- children: /* @__PURE__ */ jsxDEV4(Text2, {
5077
- color: "yellow",
5078
- children: [
5079
- /* @__PURE__ */ jsxDEV4(Spinner, {
5080
- type: "dots"
5081
- }, undefined, false, undefined, this),
5082
- " ",
5083
- busy || "Working..."
5084
- ]
5085
- }, undefined, true, undefined, this)
5086
- }, undefined, false, undefined, this);
5087
- }
5088
- if (step === "skill-source-type") {
5089
- return /* @__PURE__ */ jsxDEV4(Screen, {
5090
- children: [
5091
- /* @__PURE__ */ jsxDEV4(Text2, {
5092
- children: "Select skill source type:"
5093
- }, undefined, false, undefined, this),
5094
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5095
- items: [
5096
- { label: "Local path", value: "local" },
5097
- { label: "URL", value: "url" },
5098
- { label: "Back", value: "back" }
5099
- ],
5100
- onSelect: (item) => {
5101
- if (item.value === "back") {
5102
- setStep("action");
5103
- return;
5104
- }
5105
- setSkillType(item.value);
5106
- setStep("skill-input");
5107
- }
5108
- }, undefined, false, undefined, this),
5109
- /* @__PURE__ */ jsxDEV4(Text2, {
5110
- dimColor: true,
5111
- children: "Press Esc to go back, or q to quit."
5112
- }, undefined, false, undefined, this)
5113
- ]
5114
- }, undefined, true, undefined, this);
5115
- }
5116
- if (step === "skill-input") {
5117
- return /* @__PURE__ */ jsxDEV4(Screen, {
5118
- children: [
5119
- skillType === "local" ? /* @__PURE__ */ jsxDEV4(Fragment, {
5120
- children: [
5121
- /* @__PURE__ */ jsxDEV4(Text2, {
5122
- children: "Paste a skills folder path and we’ll install all skills inside."
5123
- }, undefined, false, undefined, this),
5124
- /* @__PURE__ */ jsxDEV4(Text2, {
5125
- children: "Or paste a SKILL.md file and we’ll install the full skill."
5126
- }, undefined, false, undefined, this)
5127
- ]
5128
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV4(Fragment, {
5129
- children: [
5130
- /* @__PURE__ */ jsxDEV4(Text2, {
5131
- children: "Paste a skills folder URL and we’ll fetch all skills inside."
5132
- }, undefined, false, undefined, this),
5133
- /* @__PURE__ */ jsxDEV4(Text2, {
5134
- children: "Or paste a SKILL.md URL and we’ll install the full skill."
5135
- }, undefined, false, undefined, this)
5136
- ]
5137
- }, undefined, true, undefined, this),
5138
- /* @__PURE__ */ jsxDEV4(TextInput, {
5139
- value: skillInput,
5140
- onChange: setSkillInput,
5141
- onSubmit: () => {
5142
- if (!scope)
5143
- return;
5144
- setBusy("Installing skill(s)...");
5145
- setStep("applying");
5146
- (async () => {
5147
- try {
5148
- const result = await installSkillsFromSource({
5149
- source: skillInput,
5150
- sourceType: skillType,
5151
- scope
5152
- });
5153
- setMessage(`Installed: ${result.installed.join(", ") || "none"} · Skipped: ${result.skipped.join(", ") || "none"}`);
5154
- await refreshStatus(scope);
5155
- } catch (err) {
5156
- setMessage(err?.message || String(err));
5157
- } finally {
5158
- setBusy(null);
5159
- setStep("done");
5160
- }
5161
- })();
5162
- }
5163
- }, undefined, false, undefined, this),
5164
- /* @__PURE__ */ jsxDEV4(Text2, {
5165
- dimColor: true,
5166
- children: "Press Enter to continue, Esc to go back, or q to quit."
5167
- }, undefined, false, undefined, this)
5168
- ]
5169
- }, undefined, true, undefined, this);
5170
- }
5171
- if (step === "plugin-marketplace-input") {
5172
- return /* @__PURE__ */ jsxDEV4(Screen, {
5173
- children: [
5174
- /* @__PURE__ */ jsxDEV4(Text2, {
5175
- children: "Enter marketplace path or URL:"
5176
- }, undefined, false, undefined, this),
5177
- /* @__PURE__ */ jsxDEV4(TextInput, {
5178
- value: marketplaceInput,
5179
- onChange: setMarketplaceInput,
5180
- onSubmit: () => {
5181
- if (!scope)
5182
- return;
5183
- setBusy("Loading marketplace...");
5184
- setStep("applying");
5185
- (async () => {
5186
- try {
5187
- const loaded = await loadMarketplace(marketplaceInput);
5188
- const plugins = loaded.json.plugins.map((p) => p.name);
5189
- setMarketplacePlugins(plugins);
5190
- setBusy(null);
5191
- setStep("plugin-select");
5192
- } catch (err) {
5193
- setMessage(err?.message || String(err));
5194
- setBusy(null);
5195
- setStep("done");
5196
- }
5197
- })();
5198
- }
5199
- }, undefined, false, undefined, this),
5200
- /* @__PURE__ */ jsxDEV4(Text2, {
5201
- dimColor: true,
5202
- children: "Press Enter to continue, Esc to go back, or q to quit."
5203
- }, undefined, false, undefined, this)
5204
- ]
5205
- }, undefined, true, undefined, this);
5206
- }
5207
- if (step === "plugin-select") {
5208
- return /* @__PURE__ */ jsxDEV4(Screen, {
5209
- children: [
5210
- /* @__PURE__ */ jsxDEV4(Text2, {
5211
- children: "Select plugin to install:"
5212
- }, undefined, false, undefined, this),
5213
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5214
- items: [
5215
- { label: "All plugins", value: "all" },
5216
- ...marketplacePlugins.map((p) => ({ label: p, value: p })),
5217
- { label: "Back", value: "back" }
5218
- ],
5219
- onSelect: (item) => {
5220
- if (!scope)
5221
- return;
5222
- if (item.value === "back") {
5223
- setStep("action");
5224
- return;
5225
- }
5226
- setBusy("Installing plugin(s)...");
5227
- setStep("applying");
5228
- (async () => {
5229
- try {
5230
- const result = await installMarketplace({
5231
- marketplace: marketplaceInput,
5232
- plugins: item.value === "all" ? "all" : [String(item.value)],
5233
- scope
5234
- });
5235
- setMessage(`Installed commands: ${result.installedCommands.length}, hooks: ${result.installedHooks.length}, skills: ${result.installedSkills.length}`);
5236
- await refreshStatus(scope);
5237
- } catch (err) {
5238
- setMessage(err?.message || String(err));
5239
- } finally {
5240
- setBusy(null);
5241
- setStep("done");
5242
- }
5243
- })();
5244
- }
5245
- }, undefined, false, undefined, this),
5246
- /* @__PURE__ */ jsxDEV4(Text2, {
5247
- dimColor: true,
5248
- children: "Press Esc to go back, or q to quit."
5249
- }, undefined, false, undefined, this)
5250
- ]
5251
- }, undefined, true, undefined, this);
5252
- }
5253
- if (step === "done") {
5254
- return /* @__PURE__ */ jsxDEV4(Screen, {
5255
- children: [
5256
- /* @__PURE__ */ jsxDEV4(Text2, {
5257
- children: message || "Done."
5258
- }, undefined, false, undefined, this),
5259
- /* @__PURE__ */ jsxDEV4(Text2, {
5260
- dimColor: true,
5261
- children: "Press Enter to continue, Esc to go back, or q to quit."
5262
- }, undefined, false, undefined, this)
5722
+ if (lD(choice))
5723
+ return null;
5724
+ selections.set(conflict.targetPath, choice);
5725
+ }
5726
+ return selections;
5727
+ }
5728
+ async function runChange(scope, clients) {
5729
+ const spin = de();
5730
+ spin.start("Scanning current setup...");
5731
+ const roots = resolveRoots({ scope });
5732
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
5733
+ const migrate = await scanMigration({ scope, clients });
5734
+ const link = await buildLinkPlan({ scope, clients });
5735
+ const backupDir = path12.join(roots.canonicalRoot, "backup", timestamp);
5736
+ spin.stop("Scan complete");
5737
+ const planSummary = [
5738
+ `Migration: ${migrate.auto.length} auto · ${migrate.conflicts.length} conflicts (choose sources)`,
5739
+ `Links: ${link.changes.length} changes · ${link.conflicts.length} conflicts (existing files/dirs)`,
5740
+ `Backup: ${backupDir}`,
5741
+ 'Undo: Use "Undo last change" after this completes.'
5742
+ ].join(`
5743
+ `);
5744
+ le(planSummary, "Plan summary");
5745
+ let overwriteConflicts = true;
5746
+ if (link.conflicts.length > 0) {
5747
+ const choice = await ie({
5748
+ message: "Apply changes",
5749
+ options: [
5750
+ { label: "Apply changes + overwrite conflicts", value: "force" },
5751
+ { label: "Apply changes (leave conflicts)", value: "skip" },
5752
+ { label: "Back", value: "back" }
5263
5753
  ]
5264
- }, undefined, true, undefined, this);
5754
+ });
5755
+ if (lD(choice))
5756
+ return;
5757
+ if (choice === "back")
5758
+ return;
5759
+ overwriteConflicts = choice === "force";
5760
+ } else {
5761
+ const ok = await se({ message: "Apply changes now?" });
5762
+ if (lD(ok) || !ok)
5763
+ return;
5265
5764
  }
5266
- return null;
5267
- };
5268
-
5269
- // src/cli.tsx
5270
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
5271
- render(/* @__PURE__ */ jsxDEV5(App, {}, undefined, false, undefined, this));
5765
+ let selections = new Map;
5766
+ if (migrate.conflicts.length > 0) {
5767
+ const resolved = await resolveMigrationConflicts(migrate);
5768
+ if (!resolved)
5769
+ return;
5770
+ selections = resolved;
5771
+ }
5772
+ const applySpinner = de();
5773
+ applySpinner.start("Applying changes...");
5774
+ try {
5775
+ const backup = await createBackupSession({
5776
+ canonicalRoot: roots.canonicalRoot,
5777
+ scope,
5778
+ operation: "change-to-agents",
5779
+ timestamp
5780
+ });
5781
+ await preflightBackup({
5782
+ backup,
5783
+ linkPlan: link,
5784
+ migratePlan: migrate,
5785
+ selections,
5786
+ forceLinks: overwriteConflicts
5787
+ });
5788
+ const result = await applyMigration(migrate, selections, { scope, clients, backup, forceLinks: overwriteConflicts });
5789
+ await finalizeBackup(backup);
5790
+ const migrationSummary = `Migrated ${formatCount(result.copied, "item")}`;
5791
+ const linkSummary = `Linked ${formatCount(result.links.applied, "path")}`;
5792
+ const conflictSummary = result.links.conflicts > 0 ? overwriteConflicts ? `overwrote ${formatCount(result.links.conflicts, "conflict")}` : `left ${formatCount(result.links.conflicts, "conflict")} untouched` : "";
5793
+ const pieces = [migrationSummary, linkSummary];
5794
+ if (conflictSummary)
5795
+ pieces.push(conflictSummary);
5796
+ applySpinner.stop(`${pieces.join(" · ")}. Backup: ${result.backupDir}`);
5797
+ } catch (err) {
5798
+ applySpinner.stop("Change failed");
5799
+ le(String(err?.message || err), "Error");
5800
+ }
5801
+ }
5802
+ async function run() {
5803
+ oe(source_default.cyan(appTitle));
5804
+ const scope = await selectScope();
5805
+ let clients = await selectClients();
5806
+ while (true) {
5807
+ const status = mergeAgentStatus(await getLinkStatus({ scope, clients }));
5808
+ const plan = await buildLinkPlan({ scope, clients });
5809
+ const conflicts = plan.conflicts.length || 0;
5810
+ const changes = plan.changes.length || 0;
5811
+ const summary = buildStatusSummary(status);
5812
+ const summaryLines = formatSummaryTable(summary);
5813
+ le([
5814
+ `Scope: ${scopeLabel(scope)}`,
5815
+ `Clients: ${formatClients(clients)}`,
5816
+ `Pending changes: ${changes} · Conflicts: ${conflicts}`,
5817
+ ...summaryLines
5818
+ ].join(`
5819
+ `), "Overview");
5820
+ const options2 = [];
5821
+ if (changes > 0)
5822
+ options2.push({ label: `Apply ${changes} changes to .agents`, value: "change" });
5823
+ options2.push({ label: "View status", value: "status" });
5824
+ options2.push({ label: "Change clients", value: "clients" });
5825
+ options2.push({ label: "Undo last change", value: "undo" });
5826
+ options2.push({ label: "Exit", value: "exit" });
5827
+ const action = await ie({ message: "Choose an action", options: options2 });
5828
+ if (lD(action))
5829
+ exitCancelled();
5830
+ if (action === "exit")
5831
+ break;
5832
+ if (action === "status") {
5833
+ await showStatus(scope, clients, status, plan.conflicts);
5834
+ continue;
5835
+ }
5836
+ if (action === "clients") {
5837
+ clients = await selectClients();
5838
+ continue;
5839
+ }
5840
+ if (action === "undo") {
5841
+ const spin = de();
5842
+ spin.start("Undoing last change...");
5843
+ try {
5844
+ const result = await undoLastChange({ scope });
5845
+ const restoredSummary = `Restored ${formatCount(result.restoredBackups, "backup")}`;
5846
+ const removedSummary = `Removed ${formatCount(result.removedCreated, "created path")}`;
5847
+ const symlinkSummary = result.removedSymlinks > 0 ? `${formatCount(result.removedSymlinks, "symlink")} removed` : "";
5848
+ let totalSummary = "";
5849
+ if (result.restoredBackups === 0 && result.removedCreated === 0) {
5850
+ totalSummary = "Nothing to undo.";
5851
+ } else if (result.restoredBackups === 0) {
5852
+ totalSummary = [removedSummary, symlinkSummary, "No backups to restore."].filter(Boolean).join(" · ");
5853
+ } else {
5854
+ totalSummary = [restoredSummary, removedSummary, symlinkSummary].filter(Boolean).join(" · ");
5855
+ }
5856
+ spin.stop(`${totalSummary} Reverted: ${result.undoneDir}`);
5857
+ le(`Undo backup: ${result.backupDir}`, "Undo log");
5858
+ } catch (err) {
5859
+ spin.stop("Undo failed");
5860
+ le(String(err?.message || err), "Error");
5861
+ }
5862
+ continue;
5863
+ }
5864
+ if (action === "change") {
5865
+ await runChange(scope, clients);
5866
+ }
5867
+ }
5868
+ $e("Bye");
5869
+ }
5870
+ run().catch((err) => {
5871
+ le(String(err?.message || err), "Fatal error");
5872
+ process.exit(1);
5873
+ });