@iannuttall/dotagents 0.1.1 → 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 +30 -8
  2. package/dist/cli.js +2117 -1673
  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,361 +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 path15 from "path";
3502
- import { Box as Box4, Text as Text2, useApp, useInput as useInput2, useStdout as useStdout3 } from "ink";
3503
- import SelectInput from "ink-select-input";
3504
- import TextInput from "ink-text-input";
3505
- import Spinner from "ink-spinner";
3506
-
3507
- // src/core/plan.ts
3508
- import fs2 from "fs";
3509
- import path4 from "path";
3510
-
3511
- // src/core/mappings.ts
3512
- import path2 from "path";
3624
+ import path12 from "path";
3513
3625
 
3514
- // src/core/paths.ts
3515
- import os from "os";
3516
- import path from "path";
3517
- function resolveRoots(opts) {
3518
- const homeDir = opts.homeDir || os.homedir();
3519
- const projectRoot = path.resolve(opts.projectRoot || process.cwd());
3520
- if (opts.scope === "global") {
3521
- return {
3522
- canonicalRoot: path.join(homeDir, ".agents"),
3523
- claudeRoot: path.join(homeDir, ".claude"),
3524
- factoryRoot: path.join(homeDir, ".factory"),
3525
- codexRoot: path.join(homeDir, ".codex"),
3526
- projectRoot,
3527
- homeDir
3528
- };
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]
3529
3682
  }
3530
- return {
3531
- canonicalRoot: path.join(projectRoot, ".agents"),
3532
- claudeRoot: path.join(projectRoot, ".claude"),
3533
- factoryRoot: path.join(projectRoot, ".factory"),
3534
- codexRoot: path.join(projectRoot, ".codex"),
3535
- projectRoot,
3536
- homeDir
3537
- };
3538
- }
3539
-
3540
- // src/core/mappings.ts
3541
- function getMappings(opts) {
3542
- const roots = resolveRoots(opts);
3543
- const canonical = roots.canonicalRoot;
3544
- return [
3545
- {
3546
- name: "agents-md",
3547
- source: path2.join(canonical, "AGENTS.md"),
3548
- targets: [path2.join(roots.claudeRoot, "CLAUDE.md")],
3549
- 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
3550
3754
  },
3551
- {
3552
- name: "commands",
3553
- source: path2.join(canonical, "commands"),
3554
- targets: [
3555
- path2.join(roots.claudeRoot, "commands"),
3556
- path2.join(roots.factoryRoot, "commands"),
3557
- path2.join(roots.codexRoot, "prompts")
3558
- ],
3559
- 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
3560
3788
  },
3561
- {
3562
- name: "hooks",
3563
- source: path2.join(canonical, "hooks"),
3564
- targets: [
3565
- path2.join(roots.claudeRoot, "hooks"),
3566
- path2.join(roots.factoryRoot, "hooks")
3567
- ],
3568
- kind: "dir"
3789
+ rgbToAnsi: {
3790
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
3791
+ enumerable: false
3569
3792
  },
3570
- {
3571
- name: "skills",
3572
- source: path2.join(canonical, "skills"),
3573
- targets: [
3574
- path2.join(roots.claudeRoot, "skills"),
3575
- path2.join(roots.factoryRoot, "skills"),
3576
- path2.join(roots.codexRoot, "skills")
3577
- ],
3578
- kind: "dir"
3793
+ hexToAnsi: {
3794
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
3795
+ enumerable: false
3579
3796
  }
3580
- ];
3797
+ });
3798
+ return styles;
3581
3799
  }
3800
+ var ansiStyles = assembleStyles();
3801
+ var ansi_styles_default = ansiStyles;
3582
3802
 
3583
- // src/utils/fs.ts
3584
- import fs from "fs";
3585
- import path3 from "path";
3586
- async function pathExists(p) {
3587
- try {
3588
- await fs.promises.lstat(p);
3589
- return true;
3590
- } catch (err) {
3591
- if (err && err.code === "ENOENT")
3592
- return false;
3593
- throw err;
3594
- }
3595
- }
3596
- async function ensureDir(dir) {
3597
- await fs.promises.mkdir(dir, { recursive: true });
3598
- }
3599
- async function ensureFile(filePath, content) {
3600
- await ensureDir(path3.dirname(filePath));
3601
- await fs.promises.writeFile(filePath, content, "utf8");
3602
- }
3603
- async function readText(filePath) {
3604
- return await fs.promises.readFile(filePath, "utf8");
3605
- }
3606
- async function copyFile(src, dest, force = false) {
3607
- if (!force && await pathExists(dest))
3608
- return "skipped";
3609
- await ensureDir(path3.dirname(dest));
3610
- await fs.promises.copyFile(src, dest);
3611
- 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);
3612
3812
  }
3613
- async function copyDir(src, dest, force = false) {
3614
- if (!force && await pathExists(dest))
3615
- return "skipped";
3616
- await ensureDir(path3.dirname(dest));
3617
- await fs.promises.cp(src, dest, { recursive: true, force });
3618
- 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;
3619
3819
  }
3620
- async function removePath(target) {
3621
- if (!await pathExists(target))
3622
- return;
3623
- const stat = await fs.promises.lstat(target);
3624
- if (stat.isDirectory() && !stat.isSymbolicLink()) {
3625
- await fs.promises.rm(target, { recursive: true, force: true });
3626
- } else {
3627
- 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);
3628
3829
  }
3629
3830
  }
3630
- async function listFiles(dir) {
3631
- try {
3632
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
3633
- return entries.filter((e) => e.isFile()).map((e) => path3.join(dir, e.name));
3634
- } catch (err) {
3635
- if (err && err.code === "ENOENT")
3636
- return [];
3637
- throw err;
3831
+ function translateLevel(level) {
3832
+ if (level === 0) {
3833
+ return false;
3638
3834
  }
3835
+ return {
3836
+ level,
3837
+ hasBasic: true,
3838
+ has256: level >= 2,
3839
+ has16m: level >= 3
3840
+ };
3639
3841
  }
3640
- async function listMarkdownFiles(dir) {
3641
- const files = await listFiles(dir);
3642
- return files.filter((f) => f.toLowerCase().endsWith(".md"));
3643
- }
3644
- async function listDirs(dir) {
3645
- try {
3646
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
3647
- return entries.filter((e) => e.isDirectory()).map((e) => path3.join(dir, e.name));
3648
- } catch (err) {
3649
- if (err && err.code === "ENOENT")
3650
- return [];
3651
- throw err;
3842
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
3843
+ const noFlagForceColor = envForceColor();
3844
+ if (noFlagForceColor !== undefined) {
3845
+ flagForceColor = noFlagForceColor;
3652
3846
  }
3653
- }
3654
-
3655
- // src/core/plan.ts
3656
- async function getLinkTargetAbsolute(targetPath) {
3657
- try {
3658
- const link = await fs2.promises.readlink(targetPath);
3659
- if (!path4.isAbsolute(link)) {
3660
- 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;
3661
3857
  }
3662
- return link;
3663
- } catch {
3664
- return null;
3665
3858
  }
3666
- }
3667
- async function ensureSourceTask(source, kind) {
3668
- const exists = await pathExists(source);
3669
- if (!exists)
3670
- return [{ type: "ensure-source", path: source, kind }];
3671
- const stat = await fs2.promises.lstat(source);
3672
- if (kind === "file" && stat.isDirectory()) {
3673
- 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;
3674
3861
  }
3675
- if (kind === "dir" && !stat.isDirectory()) {
3676
- return [{ type: "conflict", source, target: source, reason: "Expected directory but found file", kind }];
3862
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
3863
+ return 0;
3677
3864
  }
3678
- return [];
3679
- }
3680
- async function analyzeTarget(source, target, kind) {
3681
- const exists = await pathExists(target);
3682
- if (!exists)
3683
- return { type: "link", source, target, kind };
3684
- const stat = await fs2.promises.lstat(target);
3685
- if (stat.isSymbolicLink()) {
3686
- const resolved = await getLinkTargetAbsolute(target);
3687
- if (resolved && path4.resolve(resolved) === path4.resolve(source)) {
3688
- 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;
3689
3873
  }
3690
- const detail = resolved ? `Symlink points elsewhere: ${resolved}` : "Symlink points elsewhere";
3691
- return { type: "conflict", source, target, reason: detail, kind };
3874
+ return 1;
3692
3875
  }
3693
- const targetKind = stat.isDirectory() ? "directory" : stat.isFile() ? "file" : "path";
3694
- return { type: "conflict", source, target, reason: `Target exists and is not a symlink (${targetKind})`, kind };
3695
- }
3696
- async function buildLinkPlan(opts) {
3697
- const mappings = getMappings(opts);
3698
- const tasks = [];
3699
- for (const mapping of mappings) {
3700
- tasks.push(...await ensureSourceTask(mapping.source, mapping.kind));
3701
- for (const target of mapping.targets) {
3702
- 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;
3703
3882
  }
3883
+ return min;
3704
3884
  }
3705
- const conflicts = tasks.filter((t) => t.type === "conflict");
3706
- const changes = tasks.filter((t) => t.type === "link" || t.type === "ensure-source");
3707
- 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);
3708
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;
3709
3934
 
3710
- // src/core/apply.ts
3711
- import fs3 from "fs";
3712
- import path5 from "path";
3713
- 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
+ }
3714
3967
 
3715
- Add shared agent instructions here.
3716
- `;
3717
- async function createSource(task) {
3718
- if (task.kind === "dir") {
3719
- await ensureDir(task.path);
3720
- return;
3721
- }
3722
- 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);
3723
3995
  }
3724
- function commonPath(paths) {
3725
- if (paths.length === 0)
3726
- return null;
3727
- const splitPaths = paths.map((p) => path5.resolve(p).split(path5.sep));
3728
- const minLen = Math.min(...splitPaths.map((parts) => parts.length));
3729
- const shared = [];
3730
- for (let i = 0;i < minLen; i += 1) {
3731
- const segment = splitPaths[0]?.[i];
3732
- if (!segment)
3733
- break;
3734
- if (splitPaths.every((parts) => parts[i] === segment)) {
3735
- shared.push(segment);
3736
- } else {
3737
- break;
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;
3738
4003
  }
3739
- }
3740
- if (shared.length === 0)
3741
- return null;
3742
- if (shared[0] === "")
3743
- return path5.sep + shared.slice(1).join(path5.sep);
3744
- return shared.join(path5.sep);
3745
- }
3746
- function inferBackupDir(plan) {
3747
- const sourceDirs = plan.tasks.map((task) => task.type === "ensure-source" ? task.path : task.source).filter(Boolean).map((p) => path5.dirname(p));
3748
- const root = commonPath(sourceDirs);
3749
- if (!root)
3750
- return null;
3751
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
3752
- return path5.join(root, "backup", timestamp);
4004
+ };
3753
4005
  }
3754
- async function backupTarget(target, backupDir) {
3755
- if (!await pathExists(target))
3756
- return false;
3757
- const stat = await fs3.promises.lstat(target);
3758
- if (stat.isSymbolicLink())
3759
- return false;
3760
- const root = path5.parse(target).root || path5.sep;
3761
- const rel = path5.relative(root, target);
3762
- const dest = path5.join(backupDir, rel);
3763
- await ensureDir(path5.dirname(dest));
3764
- try {
3765
- await fs3.promises.rename(target, dest);
3766
- return true;
3767
- } catch (err) {
3768
- if (err?.code !== "EXDEV")
3769
- throw err;
4006
+ styles2.visible = {
4007
+ get() {
4008
+ const builder = createBuilder(this, this[STYLER], true);
4009
+ Object.defineProperty(this, "visible", { value: builder });
4010
+ return builder;
3770
4011
  }
3771
- if (stat.isDirectory()) {
3772
- await copyDir(target, dest, true);
3773
- } else {
3774
- await copyFile(target, dest, true);
4012
+ };
4013
+ var getModelAnsi = (model, level, type, ...arguments_) => {
4014
+ if (model === "rgb") {
4015
+ if (level === "ansi16m") {
4016
+ return ansi_styles_default[type].ansi16m(...arguments_);
4017
+ }
4018
+ if (level === "ansi256") {
4019
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
4020
+ }
4021
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
3775
4022
  }
3776
- await removePath(target);
3777
- return true;
3778
- }
3779
- async function createLink(source, target, kind, force, backupDir) {
3780
- if (await pathExists(target)) {
3781
- if (!force)
3782
- return { created: false, backedUp: false };
3783
- const backedUp = backupDir ? await backupTarget(target, backupDir) : false;
3784
- await removePath(target);
3785
- await ensureDir(path5.dirname(target));
3786
- const type2 = kind === "dir" ? "junction" : "file";
3787
- await fs3.promises.symlink(source, target, type2);
3788
- return { created: true, backedUp };
4023
+ if (model === "hex") {
4024
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
3789
4025
  }
3790
- await ensureDir(path5.dirname(target));
3791
- const type = kind === "dir" ? "junction" : "file";
3792
- await fs3.promises.symlink(source, target, type);
3793
- return { created: true, backedUp: false };
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
+ };
4037
+ }
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
+ };
4047
+ }
4048
+ };
3794
4049
  }
3795
- async function applyLinkPlan(plan, opts) {
3796
- const force = !!opts?.force;
3797
- const backupDir = force ? opts?.backupDir || inferBackupDir(plan) || undefined : undefined;
3798
- let applied = 0;
3799
- let skipped = 0;
3800
- let conflicts = 0;
3801
- let backedUp = 0;
3802
- for (const task of plan.tasks) {
3803
- if (task.type === "conflict") {
3804
- conflicts += 1;
3805
- if (force && task.target !== task.source && task.kind) {
3806
- const result = await createLink(task.source, task.target, task.kind, true, backupDir);
3807
- if (result.backedUp)
3808
- backedUp += 1;
3809
- applied += 1;
3810
- }
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)
3811
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;
3812
4191
  }
3813
- if (task.type === "noop") {
3814
- skipped += 1;
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);
3815
4257
  continue;
3816
4258
  }
3817
- if (task.type === "ensure-source") {
3818
- await createSource(task);
3819
- applied += 1;
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);
3820
4282
  continue;
3821
4283
  }
3822
- if (task.type === "link") {
3823
- const before = await pathExists(task.target);
3824
- const result = await createLink(task.source, task.target, task.kind, force, backupDir);
3825
- if (result.backedUp)
3826
- backedUp += 1;
3827
- if (before && !force)
3828
- skipped += 1;
3829
- else
3830
- applied += 1;
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;
3831
4424
  }
3832
4425
  }
3833
- return { applied, skipped, conflicts, backupDir, backedUp };
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 };
3834
4947
  }
3835
4948
 
3836
4949
  // src/core/status.ts
3837
- import fs4 from "fs";
3838
- import path6 from "path";
4950
+ import fs3 from "fs";
4951
+ import path5 from "path";
3839
4952
  async function resolveLinkTarget(targetPath) {
3840
4953
  try {
3841
- const link = await fs4.promises.readlink(targetPath);
3842
- if (!path6.isAbsolute(link))
3843
- 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);
3844
4957
  return link;
3845
4958
  } catch {
3846
4959
  return null;
3847
4960
  }
3848
4961
  }
3849
4962
  async function getLinkStatus(opts) {
3850
- const mappings = getMappings(opts);
4963
+ const mappings = await getMappings(opts);
3851
4964
  const statuses = [];
3852
4965
  for (const mapping of mappings) {
3853
4966
  const targets = [];
@@ -3857,10 +4970,10 @@ async function getLinkStatus(opts) {
3857
4970
  targets.push({ path: target, status: "missing" });
3858
4971
  continue;
3859
4972
  }
3860
- const stat = await fs4.promises.lstat(target);
4973
+ const stat = await fs3.promises.lstat(target);
3861
4974
  if (stat.isSymbolicLink()) {
3862
4975
  const resolved = await resolveLinkTarget(target);
3863
- if (resolved && path6.resolve(resolved) === path6.resolve(mapping.source)) {
4976
+ if (resolved && path5.resolve(resolved) === path5.resolve(mapping.source)) {
3864
4977
  targets.push({ path: target, status: "linked" });
3865
4978
  } else {
3866
4979
  targets.push({ path: target, status: "conflict" });
@@ -3875,12 +4988,12 @@ async function getLinkStatus(opts) {
3875
4988
  }
3876
4989
 
3877
4990
  // src/core/migrate.ts
3878
- import fs5 from "fs";
3879
- import path8 from "path";
4991
+ import fs6 from "fs";
4992
+ import path9 from "path";
3880
4993
 
3881
4994
  // src/core/skills.ts
3882
4995
  var import_gray_matter = __toESM(require_gray_matter(), 1);
3883
- import path7 from "path";
4996
+ import path6 from "path";
3884
4997
  var NAME_RE = /^[a-z0-9-]{1,64}$/;
3885
4998
  async function parseSkillFile(skillFile) {
3886
4999
  const raw = await readText(skillFile);
@@ -3902,13 +5015,13 @@ async function parseSkillFile(skillFile) {
3902
5015
  };
3903
5016
  }
3904
5017
  async function isSkillDir(dir) {
3905
- return await pathExists(path7.join(dir, "SKILL.md"));
5018
+ return await pathExists(path6.join(dir, "SKILL.md"));
3906
5019
  }
3907
5020
  async function findSkillDirs(root) {
3908
5021
  const direct = await isSkillDir(root);
3909
5022
  if (direct)
3910
5023
  return [root];
3911
- const skillsDir = path7.join(root, "skills");
5024
+ const skillsDir = path6.join(root, "skills");
3912
5025
  const skillsDirExists = await pathExists(skillsDir);
3913
5026
  if (skillsDirExists) {
3914
5027
  const children2 = await listDirs(skillsDir);
@@ -3917,87 +5030,267 @@ async function findSkillDirs(root) {
3917
5030
  if (await isSkillDir(child))
3918
5031
  matches2.push(child);
3919
5032
  }
3920
- if (matches2.length)
3921
- return matches2;
3922
- }
3923
- const children = await listDirs(root);
3924
- const matches = [];
3925
- for (const child of children) {
3926
- if (await isSkillDir(child))
3927
- matches.push(child);
5033
+ if (matches2.length)
5034
+ return matches2;
5035
+ }
5036
+ const children = await listDirs(root);
5037
+ const matches = [];
5038
+ for (const child of children) {
5039
+ if (await isSkillDir(child))
5040
+ matches.push(child);
5041
+ }
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 };
5175
+ }
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
+ }
3928
5227
  }
3929
- return matches;
3930
- }
3931
- function skillDestDir(canonicalSkillsRoot, name) {
3932
- return path7.join(canonicalSkillsRoot, name);
5228
+ return { applied, skipped, conflicts, backupDir: backup.dir, backedUp };
3933
5229
  }
3934
5230
 
3935
5231
  // src/core/migrate.ts
3936
5232
  async function isSymlink(p) {
3937
5233
  try {
3938
- const stat = await fs5.promises.lstat(p);
5234
+ const stat = await fs6.promises.lstat(p);
3939
5235
  return stat.isSymbolicLink();
3940
5236
  } catch {
3941
5237
  return false;
3942
5238
  }
3943
5239
  }
3944
- async function listFiles2(dir) {
5240
+ async function listFiles(dir) {
3945
5241
  try {
3946
- const entries = await fs5.promises.readdir(dir, { withFileTypes: true });
3947
- 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));
3948
5244
  } catch {
3949
5245
  return [];
3950
5246
  }
3951
5247
  }
3952
- async function movePath(src, dest, kind) {
3953
- await ensureDir(path8.dirname(dest));
3954
- try {
3955
- await fs5.promises.rename(src, dest);
3956
- return;
3957
- } catch (err) {
3958
- if (err?.code !== "EXDEV")
3959
- throw err;
3960
- }
3961
- if (kind === "file") {
3962
- await copyFile(src, dest, true);
3963
- } else {
3964
- await copyDir(src, dest, true);
3965
- }
3966
- await removePath(src);
3967
- }
3968
5248
  function conflictLabel(targetPath, canonicalRoot) {
3969
5249
  if (targetPath.startsWith(canonicalRoot)) {
3970
- const rel = path8.relative(canonicalRoot, targetPath);
3971
- return rel || path8.basename(targetPath);
5250
+ const rel = path9.relative(canonicalRoot, targetPath);
5251
+ return rel || path9.basename(targetPath);
3972
5252
  }
3973
- return path8.basename(targetPath);
5253
+ return path9.basename(targetPath);
3974
5254
  }
3975
5255
  async function scanMigration(opts) {
3976
5256
  const roots = resolveRoots(opts);
3977
5257
  const canonicalRoot = roots.canonicalRoot;
3978
5258
  const candidatesByTarget = new Map;
3979
- const canonicalCommands = path8.join(canonicalRoot, "commands");
3980
- const canonicalHooks = path8.join(canonicalRoot, "hooks");
3981
- const canonicalSkills = path8.join(canonicalRoot, "skills");
3982
- 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");
3983
5266
  const sources = {
3984
5267
  commands: [
3985
- { label: "Claude commands", dir: path8.join(roots.claudeRoot, "commands") },
3986
- { label: "Factory commands", dir: path8.join(roots.factoryRoot, "commands") },
3987
- { label: "Codex prompts", dir: path8.join(roots.codexRoot, "prompts") }
3988
- ],
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),
3989
5274
  hooks: [
3990
- { label: "Claude hooks", dir: path8.join(roots.claudeRoot, "hooks") },
3991
- { label: "Factory hooks", dir: path8.join(roots.factoryRoot, "hooks") }
3992
- ],
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),
3993
5278
  skills: [
3994
- { label: "Claude skills", dir: path8.join(roots.claudeRoot, "skills") },
3995
- { label: "Factory skills", dir: path8.join(roots.factoryRoot, "skills") },
3996
- { label: "Codex skills", dir: path8.join(roots.codexRoot, "skills") }
3997
- ],
3998
- agents: [
3999
- { label: "Claude CLAUDE.md", file: path8.join(roots.claudeRoot, "CLAUDE.md") }
4000
- ]
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) : []
4001
5294
  };
4002
5295
  const addCandidate = (candidate) => {
4003
5296
  const list = candidatesByTarget.get(candidate.targetPath) || [];
@@ -4007,18 +5300,18 @@ async function scanMigration(opts) {
4007
5300
  for (const src of sources.commands) {
4008
5301
  if (!await pathExists(src.dir) || await isSymlink(src.dir))
4009
5302
  continue;
4010
- const files = await listFiles2(src.dir);
5303
+ const files = await listFiles(src.dir);
4011
5304
  for (const file of files) {
4012
- const targetPath = path8.join(canonicalCommands, path8.basename(file));
5305
+ const targetPath = path9.join(canonicalCommands, path9.basename(file));
4013
5306
  addCandidate({ label: src.label, targetPath, kind: "file", action: "copy", sourcePath: file });
4014
5307
  }
4015
5308
  }
4016
5309
  for (const src of sources.hooks) {
4017
5310
  if (!await pathExists(src.dir) || await isSymlink(src.dir))
4018
5311
  continue;
4019
- const files = await listFiles2(src.dir);
5312
+ const files = await listFiles(src.dir);
4020
5313
  for (const file of files) {
4021
- const targetPath = path8.join(canonicalHooks, path8.basename(file));
5314
+ const targetPath = path9.join(canonicalHooks, path9.basename(file));
4022
5315
  addCandidate({ label: src.label, targetPath, kind: "file", action: "copy", sourcePath: file });
4023
5316
  }
4024
5317
  }
@@ -4028,8 +5321,8 @@ async function scanMigration(opts) {
4028
5321
  const skillDirs = await findSkillDirs(src.dir);
4029
5322
  for (const dir of skillDirs) {
4030
5323
  try {
4031
- const meta = await parseSkillFile(path8.join(dir, "SKILL.md"));
4032
- 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);
4033
5326
  addCandidate({ label: src.label, targetPath, kind: "dir", action: "copy", sourcePath: dir });
4034
5327
  } catch {}
4035
5328
  }
@@ -4039,6 +5332,11 @@ async function scanMigration(opts) {
4039
5332
  continue;
4040
5333
  addCandidate({ label: src.label, targetPath: canonicalAgents, kind: "file", action: "copy", sourcePath: src.file });
4041
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
+ }
4042
5340
  const auto = [];
4043
5341
  const conflicts = [];
4044
5342
  for (const [targetPath, list] of candidatesByTarget.entries()) {
@@ -4046,7 +5344,7 @@ async function scanMigration(opts) {
4046
5344
  if (canonicalExists) {
4047
5345
  let kind = "file";
4048
5346
  try {
4049
- const stat = await fs5.promises.lstat(targetPath);
5347
+ const stat = await fs6.promises.lstat(targetPath);
4050
5348
  kind = stat.isDirectory() ? "dir" : "file";
4051
5349
  } catch {}
4052
5350
  list.unshift({
@@ -4068,28 +5366,23 @@ async function scanMigration(opts) {
4068
5366
  candidates: list
4069
5367
  });
4070
5368
  }
4071
- const backupPaths = [
4072
- { label: "claude/commands", path: path8.join(roots.claudeRoot, "commands"), kind: "dir" },
4073
- { label: "factory/commands", path: path8.join(roots.factoryRoot, "commands"), kind: "dir" },
4074
- { label: "codex/prompts", path: path8.join(roots.codexRoot, "prompts"), kind: "dir" },
4075
- { label: "claude/hooks", path: path8.join(roots.claudeRoot, "hooks"), kind: "dir" },
4076
- { label: "factory/hooks", path: path8.join(roots.factoryRoot, "hooks"), kind: "dir" },
4077
- { label: "claude/skills", path: path8.join(roots.claudeRoot, "skills"), kind: "dir" },
4078
- { label: "factory/skills", path: path8.join(roots.factoryRoot, "skills"), kind: "dir" },
4079
- { label: "codex/skills", path: path8.join(roots.codexRoot, "skills"), kind: "dir" },
4080
- { label: "claude/CLAUDE.md", path: path8.join(roots.claudeRoot, "CLAUDE.md"), kind: "file" }
4081
- ];
4082
- return { auto, conflicts, backupPaths, canonicalRoot };
5369
+ return { auto, conflicts, canonicalRoot };
4083
5370
  }
4084
5371
  async function applyMigration(plan, selections, opts) {
4085
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
4086
- const backupDir = path8.join(plan.canonicalRoot, "backup", timestamp);
4087
- await ensureDir(backupDir);
5372
+ const backup = opts.backup;
5373
+ if (!backup)
5374
+ throw new Error("Backup session required.");
4088
5375
  let copied = 0;
4089
5376
  let skipped = 0;
4090
5377
  const copyCandidate = async (candidate) => {
4091
5378
  if (candidate.action !== "copy" || !candidate.sourcePath)
4092
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
+ }
4093
5386
  if (candidate.kind === "file") {
4094
5387
  await copyFile(candidate.sourcePath, candidate.targetPath, true);
4095
5388
  } else {
@@ -4114,1316 +5407,467 @@ async function applyMigration(plan, selections, opts) {
4114
5407
  else
4115
5408
  skipped += 1;
4116
5409
  }
4117
- for (const item of plan.backupPaths) {
4118
- if (!await pathExists(item.path))
4119
- continue;
4120
- if (await isSymlink(item.path))
4121
- continue;
4122
- const dest = path8.join(backupDir, item.label);
4123
- await movePath(item.path, dest, item.kind);
4124
- }
4125
5410
  const linkPlan = await buildLinkPlan(opts);
4126
- await applyLinkPlan(linkPlan);
4127
- 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
+ };
4128
5423
  }
4129
5424
 
4130
- // src/installers/skills.ts
4131
- import fs8 from "fs";
4132
- import path13 from "path";
4133
-
4134
- // src/installers/source.ts
5425
+ // src/core/undo.ts
4135
5426
  import fs7 from "fs";
4136
- import os3 from "os";
4137
- import path12 from "path";
4138
-
4139
- // src/utils/paths.ts
4140
- import os2 from "os";
4141
- import path9 from "path";
4142
- function expandHome(p) {
4143
- if (!p)
4144
- return p;
4145
- if (p === "~")
4146
- return os2.homedir();
4147
- if (p.startsWith("~/"))
4148
- return path9.join(os2.homedir(), p.slice(2));
4149
- return p;
4150
- }
4151
- function isUrl(input) {
4152
- return /^https?:\/\//i.test(input);
4153
- }
4154
- function isGitUrl(input) {
4155
- return /^(git@|https?:\/\/).+\.git$/i.test(input) || input.startsWith("git://");
4156
- }
4157
- function isFileUrl(input) {
4158
- return /^file:\/\//i.test(input);
4159
- }
4160
- function normalizeFileUrl(input) {
4161
- if (!isFileUrl(input))
4162
- return input;
4163
- const url = new URL(input);
4164
- return url.pathname;
4165
- }
4166
-
4167
- // src/utils/http.ts
4168
- import fs6 from "fs";
4169
5427
  import path10 from "path";
4170
- async function fetchText(url) {
4171
- const res = await fetch(url, { headers: { "User-Agent": "dotagents" } });
4172
- if (!res.ok)
4173
- throw new Error(`HTTP ${res.status} for ${url}`);
4174
- return await res.text();
4175
- }
4176
- async function fetchJson(url) {
4177
- const text = await fetchText(url);
4178
- 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));
4179
5434
  }
4180
- async function downloadToFile(url, dest) {
4181
- const res = await fetch(url, { headers: { "User-Agent": "dotagents" } });
4182
- if (!res.ok)
4183
- throw new Error(`HTTP ${res.status} for ${url}`);
4184
- const buf = new Uint8Array(await res.arrayBuffer());
4185
- await ensureDir(path10.dirname(dest));
4186
- 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;
4187
5447
  }
4188
-
4189
- // src/utils/archive.ts
4190
- import path11 from "path";
4191
-
4192
- // src/utils/run.ts
4193
- import { spawn } from "child_process";
4194
- async function runCommand(cmd, args, opts) {
4195
- return await new Promise((resolve, reject) => {
4196
- const child = spawn(cmd, args, { cwd: opts?.cwd, stdio: ["ignore", "pipe", "pipe"] });
4197
- let stdout = "";
4198
- let stderr = "";
4199
- child.stdout.on("data", (d) => stdout += d.toString());
4200
- child.stderr.on("data", (d) => stderr += d.toString());
4201
- child.on("error", reject);
4202
- child.on("close", (code) => {
4203
- if (code === 0)
4204
- resolve({ stdout, stderr });
4205
- else
4206
- reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}: ${stderr || stdout}`));
4207
- });
4208
- });
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);
4209
5455
  }
4210
-
4211
- // src/utils/archive.ts
4212
- async function extractArchive(archivePath, destDir) {
4213
- const lower = archivePath.toLowerCase();
4214
- if (lower.endsWith(".zip")) {
4215
- await runCommand("unzip", ["-q", archivePath, "-d", destDir]);
5456
+ async function restorePath(entry) {
5457
+ if (entry.action === "create") {
5458
+ await removePath(entry.originalPath);
4216
5459
  return;
4217
5460
  }
4218
- if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz")) {
4219
- await runCommand("tar", ["-xzf", archivePath, "-C", destDir]);
5461
+ if (!entry.backupPath)
5462
+ return;
5463
+ if (entry.kind === "symlink") {
5464
+ await restoreSymlink(entry);
4220
5465
  return;
4221
5466
  }
4222
- if (lower.endsWith(".tar")) {
4223
- 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);
4224
5470
  return;
5471
+ } catch (err) {
5472
+ if (err?.code !== "EXDEV")
5473
+ throw err;
4225
5474
  }
4226
- throw new Error(`Unsupported archive format: ${path11.basename(archivePath)}`);
4227
- }
4228
-
4229
- // src/installers/source.ts
4230
- async function makeTempDir(prefix) {
4231
- return await fs7.promises.mkdtemp(path12.join(os3.tmpdir(), prefix));
4232
- }
4233
- async function cloneGitRepo(repo, dest, ref) {
4234
- await runCommand("git", ["clone", "--depth", "1", repo, dest]);
4235
- if (ref) {
4236
- 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);
4237
5479
  }
5480
+ await removePath(entry.backupPath);
4238
5481
  }
4239
- function detectSourceType(source) {
4240
- if (isFileUrl(source))
4241
- return "local";
4242
- if (isGitUrl(source))
4243
- return "git";
4244
- if (isUrl(source))
4245
- return "url";
4246
- 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
+ }
4247
5488
  }
4248
- async function resolveSource(source, type = "auto", opts) {
4249
- const inferred = type === "auto" ? detectSourceType(source) : type;
4250
- const input = expandHome(source);
4251
- if (inferred === "local") {
4252
- const p = isFileUrl(input) ? normalizeFileUrl(input) : input;
4253
- if (!fs7.existsSync(p))
4254
- throw new Error(`Source path not found: ${p}`);
4255
- return { dir: p, cleanup: async () => {} };
4256
- }
4257
- const tempDir = await makeTempDir("dotagents-src-");
4258
- if (inferred === "git") {
4259
- await cloneGitRepo(input, tempDir, opts?.ref);
4260
- return { dir: tempDir, cleanup: async () => {
4261
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4262
- } };
4263
- }
4264
- if (inferred === "url") {
4265
- const lower = input.toLowerCase();
4266
- if (lower.endsWith(".zip") || lower.endsWith(".tar.gz") || lower.endsWith(".tgz") || lower.endsWith(".tar")) {
4267
- const archivePath = path12.join(tempDir, path12.basename(lower));
4268
- await downloadToFile(input, archivePath);
4269
- await ensureDir(tempDir);
4270
- await extractArchive(archivePath, tempDir);
4271
- return { dir: tempDir, cleanup: async () => {
4272
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4273
- } };
4274
- }
4275
- if (lower.endsWith("skill.md")) {
4276
- const skillDir = path12.join(tempDir, "skill");
4277
- await ensureDir(skillDir);
4278
- const dest = path12.join(skillDir, "SKILL.md");
4279
- await downloadToFile(input, dest);
4280
- return { dir: skillDir, cleanup: async () => {
4281
- await fs7.promises.rm(tempDir, { recursive: true, force: true });
4282
- } };
4283
- }
4284
- throw new Error("Unsupported URL source. Provide a git URL, archive (.zip/.tar.gz), or direct SKILL.md URL.");
4285
- }
4286
- 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 };
4287
5526
  }
4288
5527
 
4289
- // src/installers/skills.ts
4290
- 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;
4291
5542
  try {
4292
- const url = new URL(input);
4293
- if (url.hostname === "raw.githubusercontent.com") {
4294
- const parts2 = url.pathname.split("/").filter(Boolean);
4295
- if (parts2.length < 4)
4296
- return null;
4297
- const [owner2, repo2, ref2, ...rest2] = parts2;
4298
- const filePath2 = rest2.join("/");
4299
- const subdir2 = filePath2.toLowerCase().endsWith("skill.md") ? filePath2.split("/").slice(0, -1).join("/") : filePath2;
4300
- return { repoUrl: `https://github.com/${owner2}/${repo2}.git`, ref: ref2, subdir: subdir2 };
4301
- }
4302
- if (url.hostname !== "github.com")
4303
- return null;
4304
- const parts = url.pathname.split("/").filter(Boolean);
4305
- if (parts.length < 4)
4306
- return null;
4307
- const [owner, repo, kind, ref, ...rest] = parts;
4308
- if (kind !== "blob" && kind !== "tree")
4309
- return null;
4310
- const filePath = rest.join("/");
4311
- const subdir = filePath.toLowerCase().endsWith("skill.md") ? filePath.split("/").slice(0, -1).join("/") : filePath;
4312
- return { repoUrl: `https://github.com/${owner}/${repo}.git`, ref, subdir };
5543
+ const stat = await fs8.promises.lstat(task.target);
5544
+ return stat.isSymbolicLink();
4313
5545
  } catch {
4314
- return null;
5546
+ return false;
4315
5547
  }
4316
5548
  }
4317
- function parseGitLabUrl(input) {
4318
- try {
4319
- const url = new URL(input);
4320
- if (url.hostname !== "gitlab.com")
4321
- return null;
4322
- const parts = url.pathname.split("/").filter(Boolean);
4323
- const dash = parts.indexOf("-");
4324
- if (dash === -1)
4325
- return null;
4326
- const kind = parts[dash + 1];
4327
- if (kind !== "blob" && kind !== "tree" && kind !== "raw")
4328
- return null;
4329
- const ref = parts[dash + 2];
4330
- const rest = parts.slice(dash + 3).join("/");
4331
- const namespacePath = parts.slice(0, dash).join("/");
4332
- if (!namespacePath)
4333
- return null;
4334
- const subdir = rest.toLowerCase().endsWith("skill.md") ? rest.split("/").slice(0, -1).join("/") : rest;
4335
- return { repoUrl: `https://gitlab.com/${namespacePath}.git`, ref, subdir };
4336
- } catch {
4337
- 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);
4338
5555
  }
5556
+ return candidates;
4339
5557
  }
4340
- function inferRepoFromUrl(input) {
4341
- return parseGitHubUrl(input) || parseGitLabUrl(input);
4342
- }
4343
- async function installSkillsFromSource(opts) {
4344
- const roots = resolveRoots({ scope: opts.scope, projectRoot: opts.projectRoot, homeDir: opts.homeDir });
4345
- const canonicalSkills = path13.join(roots.canonicalRoot, "skills");
4346
- await ensureDir(canonicalSkills);
4347
- const sourceType = opts.sourceType || "auto";
4348
- const isHttp = isUrl(opts.source);
4349
- const inferred = (sourceType === "auto" || sourceType === "url") && isHttp ? inferRepoFromUrl(opts.source) : null;
4350
- const resolved = inferred ? await resolveSource(inferred.repoUrl, "git", { ref: inferred.ref }) : await resolveSource(opts.source, sourceType);
4351
- try {
4352
- let rootDir = inferred?.subdir ? path13.join(resolved.dir, inferred.subdir) : resolved.dir;
4353
- try {
4354
- const stat = await fs8.promises.lstat(rootDir);
4355
- if (stat.isFile()) {
4356
- if (path13.basename(rootDir).toLowerCase() !== "skill.md") {
4357
- throw new Error("Expected a skills folder or SKILL.md file");
4358
- }
4359
- rootDir = path13.dirname(rootDir);
4360
- }
4361
- } catch {}
4362
- const skillDirs = await findSkillDirs(rootDir);
4363
- if (!skillDirs.length)
4364
- throw new Error("No SKILL.md found in source");
4365
- const installed = [];
4366
- const skipped = [];
4367
- const metas = [];
4368
- for (const dir of skillDirs) {
4369
- const skillFile = path13.join(dir, "SKILL.md");
4370
- const meta = await parseSkillFile(skillFile);
4371
- metas.push(meta);
4372
- const dest = skillDestDir(canonicalSkills, meta.name);
4373
- const exists = await pathExists(dest);
4374
- if (exists && !opts.force) {
4375
- skipped.push(meta.name);
4376
- continue;
4377
- }
4378
- await copyDir(dir, dest, true);
4379
- 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));
5571
+ }
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);
4380
5580
  }
4381
- return { installed, skipped, skills: metas };
4382
- } finally {
4383
- await resolved.cleanup();
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);
4384
5584
  }
5585
+ return { targets: targets.size };
4385
5586
  }
4386
5587
 
4387
- // src/installers/marketplace.ts
4388
- import fs9 from "fs";
4389
- import path14 from "path";
4390
- function parseGitHubRawUrl(input) {
4391
- try {
4392
- const url = new URL(input);
4393
- if (url.hostname !== "raw.githubusercontent.com")
4394
- return null;
4395
- const parts = url.pathname.split("/").filter(Boolean);
4396
- if (parts.length < 4)
4397
- return null;
4398
- const [owner, repo, ref, ...rest] = parts;
4399
- const filePath = rest.join("/");
4400
- return { kind: "github", owner, repo, ref, basePath: path14.posix.dirname(filePath) };
4401
- } catch {
4402
- return null;
4403
- }
5588
+ // src/cli.tsx
5589
+ var appTitle = "dotagents";
5590
+ function exitCancelled() {
5591
+ ue("Cancelled");
5592
+ process.exit(0);
4404
5593
  }
4405
- function parseGitHubBlobUrl(input) {
4406
- try {
4407
- const url = new URL(input);
4408
- if (url.hostname !== "github.com")
4409
- return null;
4410
- const parts = url.pathname.split("/").filter(Boolean);
4411
- if (parts.length < 5)
4412
- return null;
4413
- const [owner, repo, blob, ref, ...rest] = parts;
4414
- if (blob !== "blob")
4415
- return null;
4416
- const filePath = rest.join("/");
4417
- return { kind: "github", owner, repo, ref, basePath: path14.posix.dirname(filePath) };
4418
- } catch {
4419
- return null;
4420
- }
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];
4421
5609
  }
4422
- async function loadMarketplace(input) {
4423
- if (isUrl(input)) {
4424
- const json2 = await fetchJson(input);
4425
- const gh = parseGitHubRawUrl(input) || parseGitHubBlobUrl(input);
4426
- return { json: json2, context: gh || {} };
4427
- }
4428
- const resolved = path14.resolve(input);
4429
- let file = resolved;
4430
- if (fs9.existsSync(resolved) && fs9.statSync(resolved).isDirectory()) {
4431
- file = path14.join(resolved, ".claude-plugin", "marketplace.json");
4432
- }
4433
- if (!fs9.existsSync(file))
4434
- throw new Error(`marketplace.json not found: ${file}`);
4435
- const raw = await fs9.promises.readFile(file, "utf8");
4436
- const json = JSON.parse(raw);
4437
- 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;
4438
5618
  }
4439
- function resolvePluginPath(entry, ctx, pluginRoot) {
4440
- const base = ctx.baseDir || process.cwd();
4441
- const root = pluginRoot ? path14.resolve(base, pluginRoot) : base;
4442
- if (typeof entry.source === "string") {
4443
- if (isUrl(entry.source))
4444
- return { source: entry.source, type: "url" };
4445
- if (ctx.kind === "github" && ctx.owner && ctx.repo) {
4446
- const repoRoot = pluginRoot ? pluginRoot : "";
4447
- const primary = path14.posix.normalize(path14.posix.join(repoRoot, entry.source));
4448
- const candidates = [primary];
4449
- if (ctx.basePath) {
4450
- candidates.push(path14.posix.normalize(path14.posix.join(ctx.basePath, entry.source)));
4451
- }
4452
- return { source: `https://github.com/${ctx.owner}/${ctx.repo}.git`, type: "git", subdirCandidates: candidates, ref: ctx.ref };
4453
- }
4454
- const candidate = path14.resolve(root, entry.source);
4455
- return { source: candidate, type: "local" };
4456
- }
4457
- const src = entry.source;
4458
- if (src.source === "github" && src.repo) {
4459
- return { source: `https://github.com/${src.repo}.git`, type: "git", ref: src.ref };
4460
- }
4461
- if (src.source === "git" && src.url) {
4462
- return { source: src.url, type: "git", ref: src.ref };
4463
- }
4464
- if (src.source === "url" && src.url) {
4465
- return { source: src.url, type: "url" };
4466
- }
4467
- 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
+ });
4468
5626
  }
4469
- async function scanPluginDir(dir) {
4470
- const commandsDir = path14.join(dir, "commands");
4471
- const hooksDir = path14.join(dir, "hooks");
4472
- const skillsDir = path14.join(dir, "skills");
4473
- const commands = await listMarkdownFiles(commandsDir);
4474
- const hooks = await listFiles(hooksDir);
4475
- const skillsExists = await pathExists(skillsDir);
4476
- 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;
4477
5641
  }
4478
- async function installMarketplace(opts) {
4479
- const roots = resolveRoots({ scope: opts.scope, projectRoot: opts.projectRoot, homeDir: opts.homeDir });
4480
- const canonicalRoot = roots.canonicalRoot;
4481
- const commandsDest = path14.join(canonicalRoot, "commands");
4482
- const hooksDest = path14.join(canonicalRoot, "hooks");
4483
- await ensureDir(commandsDest);
4484
- await ensureDir(hooksDest);
4485
- const { json, context } = await loadMarketplace(opts.marketplace);
4486
- const selected = opts.plugins === "all" ? json.plugins : json.plugins.filter((p) => opts.plugins.includes(p.name));
4487
- const installedCommands = [];
4488
- const installedHooks = [];
4489
- const installedSkills = [];
4490
- const skippedCommands = [];
4491
- const skippedHooks = [];
4492
- const skippedSkills = [];
4493
- for (const plugin of selected) {
4494
- const { source, type, subdir, subdirCandidates, ref } = resolvePluginPath(plugin, context, json.pluginRoot);
4495
- const resolved = await resolveSource(source, type, { ref });
4496
- try {
4497
- let pluginDir = resolved.dir;
4498
- if (subdirCandidates && subdirCandidates.length) {
4499
- const found = subdirCandidates.map((candidate) => path14.join(resolved.dir, candidate)).find((candidate) => fs9.existsSync(candidate));
4500
- if (!found) {
4501
- throw new Error(`Plugin path not found in repo: ${subdirCandidates.join(", ")}`);
4502
- }
4503
- pluginDir = found;
4504
- } else if (subdir) {
4505
- pluginDir = path14.join(resolved.dir, subdir);
4506
- }
4507
- const scan = await scanPluginDir(pluginDir);
4508
- for (const cmd of scan.commands) {
4509
- const name = path14.basename(cmd);
4510
- const dest = path14.join(commandsDest, name);
4511
- const result = await copyFile(cmd, dest, !!opts.force);
4512
- if (result === "written")
4513
- installedCommands.push(`${plugin.name}:${name}`);
4514
- else
4515
- skippedCommands.push(`${plugin.name}:${name}`);
4516
- }
4517
- for (const hook of scan.hooks) {
4518
- const name = path14.basename(hook);
4519
- const dest = path14.join(hooksDest, name);
4520
- const result = await copyFile(hook, dest, !!opts.force);
4521
- if (result === "written")
4522
- installedHooks.push(`${plugin.name}:${name}`);
4523
- else
4524
- skippedHooks.push(`${plugin.name}:${name}`);
4525
- }
4526
- if (scan.skillsDir) {
4527
- const skillResult = await installSkillsFromSource({
4528
- source: scan.skillsDir,
4529
- sourceType: "local",
4530
- scope: opts.scope,
4531
- projectRoot: opts.projectRoot,
4532
- homeDir: opts.homeDir,
4533
- force: opts.force
4534
- });
4535
- installedSkills.push(...skillResult.installed.map((n) => `${plugin.name}:${n}`));
4536
- skippedSkills.push(...skillResult.skipped.map((n) => `${plugin.name}:${n}`));
4537
- }
4538
- } finally {
4539
- 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}`) : ""}`);
4540
5650
  }
4541
5651
  }
4542
- return {
4543
- installedCommands,
4544
- installedHooks,
4545
- installedSkills,
4546
- skippedCommands,
4547
- skippedHooks,
4548
- skippedSkills
4549
- };
4550
- }
4551
-
4552
- // src/tui/ui/HelpBar.tsx
4553
- import { Box, Text } from "ink";
4554
- import { jsxDEV } from "react/jsx-dev-runtime";
4555
- function HelpBar({ text }) {
4556
- return /* @__PURE__ */ jsxDEV(Box, {
4557
- marginTop: 1,
4558
- children: /* @__PURE__ */ jsxDEV(Text, {
4559
- dimColor: true,
4560
- children: text
4561
- }, undefined, false, undefined, this)
4562
- }, undefined, false, undefined, this);
5652
+ return lines;
4563
5653
  }
4564
-
4565
- // src/tui/ui/ScrollArea.tsx
4566
- import { useEffect, useReducer, useRef } from "react";
4567
- import { Box as Box2, measureElement, useInput, useStdout } from "ink";
4568
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
4569
- var reducer = (s, a) => {
4570
- switch (a.type) {
4571
- case "SET_INNER": {
4572
- const max = Math.max(0, a.h - s.height);
4573
- const nextScrollTop = Math.min(s.scrollTop, max);
4574
- if (s.innerHeight === a.h && nextScrollTop === s.scrollTop)
4575
- return s;
4576
- return { ...s, innerHeight: a.h, scrollTop: nextScrollTop };
4577
- }
4578
- case "SET_HEIGHT": {
4579
- const max = Math.max(0, s.innerHeight - a.h);
4580
- const nextScrollTop = Math.min(s.scrollTop, max);
4581
- if (s.height === a.h && nextScrollTop === s.scrollTop)
4582
- return s;
4583
- return { ...s, height: a.h, scrollTop: nextScrollTop };
4584
- }
4585
- case "SCROLL": {
4586
- const max = Math.max(0, s.innerHeight - s.height);
4587
- const nextScrollTop = Math.max(0, Math.min(max, s.scrollTop + a.delta));
4588
- if (nextScrollTop === s.scrollTop)
4589
- return s;
4590
- return { ...s, scrollTop: nextScrollTop };
4591
- }
4592
- case "TOP": {
4593
- if (s.scrollTop === 0)
4594
- return s;
4595
- return { ...s, scrollTop: 0 };
4596
- }
4597
- case "BOTTOM": {
4598
- const max = Math.max(0, s.innerHeight - s.height);
4599
- if (s.scrollTop === max)
4600
- return s;
4601
- return { ...s, scrollTop: max };
4602
- }
4603
- default:
4604
- return s;
4605
- }
4606
- };
4607
- function ScrollArea({ height, children }) {
4608
- const innerRef = useRef(null);
4609
- const { stdout } = useStdout();
4610
- const [state, dispatch] = useReducer(reducer, { innerHeight: 0, height, scrollTop: 0 });
4611
- useEffect(() => {
4612
- dispatch({ type: "SET_HEIGHT", h: height });
4613
- }, [height]);
4614
- useEffect(() => {
4615
- if (!innerRef.current)
4616
- return;
4617
- const dim = measureElement(innerRef.current);
4618
- dispatch({ type: "SET_INNER", h: dim.height });
4619
- });
4620
- useEffect(() => {
4621
- const onResize = () => dispatch({ type: "SET_HEIGHT", h: stdout.rows });
4622
- return () => void onResize();
4623
- }, [stdout]);
4624
- useInput((input, key) => {
4625
- if (key.pageDown || key.downArrow && key.meta)
4626
- dispatch({ type: "SCROLL", delta: Math.max(1, Math.floor(state.height * 0.8)) });
4627
- if (key.pageUp || key.upArrow && key.meta)
4628
- dispatch({ type: "SCROLL", delta: -Math.max(1, Math.floor(state.height * 0.8)) });
4629
- if (input === "g")
4630
- dispatch({ type: "TOP" });
4631
- if (input === "G")
4632
- 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
+ ]
4633
5662
  });
4634
- return /* @__PURE__ */ jsxDEV2(Box2, {
4635
- height,
4636
- flexDirection: "column",
4637
- overflow: "hidden",
4638
- children: /* @__PURE__ */ jsxDEV2(Box2, {
4639
- ref: innerRef,
4640
- flexShrink: 0,
4641
- flexDirection: "column",
4642
- marginTop: -state.scrollTop,
4643
- children
4644
- }, undefined, false, undefined, this)
4645
- }, 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;
4646
5670
  }
4647
-
4648
- // src/tui/ui/Screen.tsx
4649
- import { Box as Box3, useStdout as useStdout2 } from "ink";
4650
- import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
4651
- function Screen({ children }) {
4652
- const { stdout } = useStdout2();
4653
- const height = stdout?.rows;
4654
- return /* @__PURE__ */ jsxDEV3(Box3, {
4655
- flexDirection: "column",
4656
- height,
4657
- children
4658
- }, undefined, false, undefined, this);
5671
+ function scopeLabel(scope) {
5672
+ return scope === "global" ? "Global (~/.agents)" : "Project (.agents)";
4659
5673
  }
4660
-
4661
- // src/tui/App.tsx
4662
- import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
4663
- var appTitle = "dotagents";
4664
- var App = () => {
4665
- const { exit } = useApp();
4666
- const [step, setStep] = useState("scope");
4667
- const [scope, setScope] = useState(null);
4668
- const [plan, setPlan] = useState(null);
4669
- const [status, setStatus] = useState([]);
4670
- const [message, setMessage] = useState("");
4671
- const [busy, setBusy] = useState(null);
4672
- const [migratePlan, setMigratePlan] = useState(null);
4673
- const [migrateIndex, setMigrateIndex] = useState(0);
4674
- const [migrateSelections, setMigrateSelections] = useState(new Map);
4675
- const [skillType, setSkillType] = useState("local");
4676
- const [skillInput, setSkillInput] = useState("");
4677
- const [marketplaceInput, setMarketplaceInput] = useState("");
4678
- const [marketplacePlugins, setMarketplacePlugins] = useState([]);
4679
- const [forceBackupDir, setForceBackupDir] = useState(null);
4680
- const [showDetails, setShowDetails] = useState(false);
4681
- const [conflictsOnly, setConflictsOnly] = useState(false);
4682
- const { stdout } = useStdout3();
4683
- useInput2((input, key) => {
4684
- if (input === "q")
4685
- exit();
4686
- if (step === "status" && input === "d")
4687
- setShowDetails((prev) => !prev);
4688
- if (step === "status" && input === "c")
4689
- setConflictsOnly(true);
4690
- if (step === "status" && input === "a")
4691
- setConflictsOnly(false);
4692
- if (key.escape) {
4693
- if (step === "action")
4694
- return setStep("scope");
4695
- if (step === "status")
4696
- return setStep("action");
4697
- if (step === "force-confirm")
4698
- return setStep("action");
4699
- if (step === "migrate-choice") {
4700
- setMigratePlan(null);
4701
- setMigrateSelections(new Map);
4702
- return setStep("action");
4703
- }
4704
- if (step === "skill-source-type")
4705
- return setStep("action");
4706
- if (step === "skill-input")
4707
- return setStep("skill-source-type");
4708
- if (step === "plugin-marketplace-input")
4709
- return setStep("action");
4710
- if (step === "plugin-select")
4711
- return setStep("plugin-marketplace-input");
4712
- if (step === "done")
4713
- return setStep("action");
4714
- }
4715
- if (step === "done" && key.return)
4716
- 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
4717
5693
  });
4718
- const scopeLabel = scope === "global" ? "Global (~/.agents)" : scope === "project" ? "Project (.agents)" : "";
4719
- const refreshStatus = async (nextScope) => {
4720
- const s = await getLinkStatus({ scope: nextScope });
4721
- setStatus(s);
4722
- const p = await buildLinkPlan({ scope: nextScope });
4723
- setPlan(p);
4724
- };
4725
- useEffect2(() => {
4726
- if (scope)
4727
- refreshStatus(scope);
4728
- }, [scope]);
4729
- const conflicts = plan?.conflicts.length || 0;
4730
- const changes = plan?.changes.length || 0;
4731
- const actionItems = useMemo(() => {
4732
- const items = [
4733
- { label: "Apply/repair links", value: "apply" }
4734
- ];
4735
- if (conflicts > 0)
4736
- items.push({ label: "Force apply (backup + overwrite conflicts)", value: "force-apply" });
4737
- items.push({ label: "View status", value: "view-status" });
4738
- items.push({ label: "Migrate existing content", value: "migrate" });
4739
- items.push({ label: "Add skill", value: "add-skill" });
4740
- items.push({ label: "Install plugin", value: "install-plugin" });
4741
- items.push({ label: "Exit", value: "exit" });
4742
- return items;
4743
- }, [conflicts]);
4744
- const displayName = (name) => {
4745
- if (name === "agents-md")
4746
- return "AGENTS.md";
4747
- 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"
4748
5705
  };
4749
- const statusSummary = useMemo(() => {
4750
- return status.map((s) => {
4751
- const linked = s.targets.filter((t) => t.status === "linked").length;
4752
- const missing = s.targets.filter((t) => t.status === "missing").length;
4753
- const conflict = s.targets.filter((t) => t.status === "conflict").length;
4754
- 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 }))
4755
5721
  });
4756
- }, [status]);
4757
- const summaryTable = useMemo(() => {
4758
- const rows = statusSummary.map((s) => ({
4759
- name: s.name,
4760
- conflict: String(s.conflict),
4761
- missing: String(s.missing),
4762
- linked: String(s.linked)
4763
- }));
4764
- const header = { name: "Section", conflict: "Conflicts", missing: "Need link", linked: "Linked" };
4765
- const width = {
4766
- name: Math.max(header.name.length, ...rows.map((r) => r.name.length)),
4767
- conflict: Math.max(header.conflict.length, ...rows.map((r) => r.conflict.length)),
4768
- missing: Math.max(header.missing.length, ...rows.map((r) => r.missing.length)),
4769
- linked: Math.max(header.linked.length, ...rows.map((r) => r.linked.length))
4770
- };
4771
- const pad = (value, len) => value.padEnd(len, " ");
4772
- const lines = [
4773
- `${pad(header.name, width.name)} ${pad(header.conflict, width.conflict)} ${pad(header.missing, width.missing)} ${pad(header.linked, width.linked)}`,
4774
- ...rows.map((r) => `${pad(r.name, width.name)} ${pad(r.conflict, width.conflict)} ${pad(r.missing, width.missing)} ${pad(r.linked, width.linked)}`)
4775
- ];
4776
- return lines;
4777
- }, [statusSummary]);
4778
- const [conflictDetails, setConflictDetails] = useState(new Map);
4779
- useEffect2(() => {
4780
- let cancelled = false;
4781
- const load = async () => {
4782
- if (!plan)
4783
- return;
4784
- const map = new Map;
4785
- for (const task of plan.conflicts) {
4786
- map.set(task.target, { reason: task.reason });
4787
- try {
4788
- const stat = await fs10.promises.lstat(task.target);
4789
- if (stat.isDirectory() && !stat.isSymbolicLink()) {
4790
- const entries = await fs10.promises.readdir(task.target);
4791
- const shown = entries.slice(0, 6);
4792
- const more = entries.length > 6 ? `… +${entries.length - 6} more` : "";
4793
- const contents = entries.length === 0 ? "(empty)" : `${shown.join(", ")}${more ? `, ${more}` : ""}`;
4794
- map.set(task.target, { reason: task.reason, contents: `Contains: ${contents}` });
4795
- }
4796
- } catch {}
4797
- }
4798
- if (!cancelled)
4799
- setConflictDetails(map);
4800
- };
4801
- load();
4802
- return () => {
4803
- cancelled = true;
4804
- };
4805
- }, [plan]);
4806
- const renderStatusList = () => {
4807
- const sections = status.map((s) => {
4808
- const targets = conflictsOnly ? s.targets.filter((t) => t.status === "conflict") : s.targets;
4809
- if (conflictsOnly && targets.length === 0)
4810
- return null;
4811
- return /* @__PURE__ */ jsxDEV4(Box4, {
4812
- flexDirection: "column",
4813
- marginTop: 1,
4814
- children: [
4815
- /* @__PURE__ */ jsxDEV4(Text2, {
4816
- color: "cyan",
4817
- children: displayName(s.name)
4818
- }, undefined, false, undefined, this),
4819
- targets.map((t) => /* @__PURE__ */ jsxDEV4(Box4, {
4820
- flexDirection: "column",
4821
- children: [
4822
- /* @__PURE__ */ jsxDEV4(Text2, {
4823
- children: [
4824
- t.status === "linked" ? "✓" : t.status === "missing" ? "•" : "⚠",
4825
- " ",
4826
- t.path
4827
- ]
4828
- }, undefined, true, undefined, this),
4829
- showDetails && t.status === "conflict" && conflictDetails.has(t.path) ? /* @__PURE__ */ jsxDEV4(Fragment, {
4830
- children: [
4831
- /* @__PURE__ */ jsxDEV4(Text2, {
4832
- color: "red",
4833
- children: [
4834
- " ",
4835
- conflictDetails.get(t.path)?.reason
4836
- ]
4837
- }, undefined, true, undefined, this),
4838
- conflictDetails.get(t.path)?.contents ? /* @__PURE__ */ jsxDEV4(Text2, {
4839
- dimColor: true,
4840
- children: [
4841
- " ",
4842
- conflictDetails.get(t.path)?.contents
4843
- ]
4844
- }, undefined, true, undefined, this) : null
4845
- ]
4846
- }, undefined, true, undefined, this) : null
4847
- ]
4848
- }, t.path, true, undefined, this))
4849
- ]
4850
- }, s.name, true, undefined, this);
4851
- }).filter(Boolean);
4852
- if (!sections.length) {
4853
- return /* @__PURE__ */ jsxDEV4(Box4, {
4854
- marginTop: 1,
4855
- children: /* @__PURE__ */ jsxDEV4(Text2, {
4856
- dimColor: true,
4857
- children: "No conflicts found."
4858
- }, undefined, false, undefined, this)
4859
- }, undefined, false, undefined, this);
4860
- }
4861
- return /* @__PURE__ */ jsxDEV4(Box4, {
4862
- flexDirection: "column",
4863
- children: sections
4864
- }, undefined, false, undefined, this);
4865
- };
4866
- if (step === "scope") {
4867
- return /* @__PURE__ */ jsxDEV4(Screen, {
4868
- children: [
4869
- /* @__PURE__ */ jsxDEV4(Text2, {
4870
- color: "green",
4871
- children: appTitle
4872
- }, undefined, false, undefined, this),
4873
- /* @__PURE__ */ jsxDEV4(Text2, {
4874
- children: "Choose a workspace:"
4875
- }, undefined, false, undefined, this),
4876
- /* @__PURE__ */ jsxDEV4(SelectInput, {
4877
- items: [
4878
- { label: "Global home", value: "global" },
4879
- { label: "Project folder", value: "project" },
4880
- { label: "Exit", value: "exit" }
4881
- ],
4882
- onSelect: (item) => {
4883
- if (item.value === "exit")
4884
- return exit();
4885
- setScope(item.value);
4886
- setStep("action");
4887
- }
4888
- }, undefined, false, undefined, this)
4889
- ]
4890
- }, undefined, true, undefined, this);
4891
- }
4892
- if (step === "action") {
4893
- return /* @__PURE__ */ jsxDEV4(Screen, {
4894
- children: [
4895
- /* @__PURE__ */ jsxDEV4(Text2, {
4896
- color: "green",
4897
- children: appTitle
4898
- }, undefined, false, undefined, this),
4899
- /* @__PURE__ */ jsxDEV4(Box4, {
4900
- flexDirection: "column",
4901
- marginTop: 1,
4902
- children: [
4903
- /* @__PURE__ */ jsxDEV4(Text2, {
4904
- children: [
4905
- "Scope: ",
4906
- scopeLabel
4907
- ]
4908
- }, undefined, true, undefined, this),
4909
- /* @__PURE__ */ jsxDEV4(Text2, {
4910
- children: [
4911
- "Pending changes: ",
4912
- changes,
4913
- " · Conflicts: ",
4914
- conflicts
4915
- ]
4916
- }, undefined, true, undefined, this),
4917
- summaryTable.map((line) => /* @__PURE__ */ jsxDEV4(Text2, {
4918
- children: line
4919
- }, line, false, undefined, this))
4920
- ]
4921
- }, undefined, true, undefined, this),
4922
- /* @__PURE__ */ jsxDEV4(Box4, {
4923
- marginTop: 1,
4924
- flexDirection: "column",
4925
- children: [
4926
- /* @__PURE__ */ jsxDEV4(Text2, {
4927
- children: "Choose an action:"
4928
- }, undefined, false, undefined, this),
4929
- /* @__PURE__ */ jsxDEV4(SelectInput, {
4930
- items: actionItems,
4931
- onSelect: (item) => {
4932
- if (item.value === "exit")
4933
- return exit();
4934
- if (item.value === "view-status") {
4935
- setStep("status");
4936
- return;
4937
- }
4938
- if (item.value === "migrate") {
4939
- if (!scope)
4940
- return;
4941
- setBusy("Scanning existing content...");
4942
- setStep("applying");
4943
- (async () => {
4944
- try {
4945
- const plan2 = await scanMigration({ scope });
4946
- setMigratePlan(plan2);
4947
- setMigrateIndex(0);
4948
- setMigrateSelections(new Map);
4949
- if (plan2.conflicts.length > 0) {
4950
- setBusy(null);
4951
- setStep("migrate-choice");
4952
- return;
4953
- }
4954
- setBusy("Migrating...");
4955
- const result = await applyMigration(plan2, new Map, { scope });
4956
- setMessage(`Migrated ${result.copied} items. Backup: ${result.backupDir}`);
4957
- await refreshStatus(scope);
4958
- setStep("done");
4959
- } catch (err) {
4960
- setMessage(err?.message || String(err));
4961
- setStep("done");
4962
- } finally {
4963
- setBusy(null);
4964
- }
4965
- })();
4966
- return;
4967
- }
4968
- if (item.value === "apply" || item.value === "force-apply") {
4969
- if (item.value === "force-apply") {
4970
- setBusy("Preparing force apply...");
4971
- setStep("applying");
4972
- (async () => {
4973
- try {
4974
- if (!scope)
4975
- return;
4976
- const roots = resolveRoots({ scope });
4977
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
4978
- setForceBackupDir(path15.join(roots.canonicalRoot, "backup", timestamp));
4979
- setStep("force-confirm");
4980
- } catch (err) {
4981
- setMessage(err?.message || String(err));
4982
- setStep("done");
4983
- } finally {
4984
- setBusy(null);
4985
- }
4986
- })();
4987
- return;
4988
- }
4989
- setBusy("Applying...");
4990
- setStep("applying");
4991
- (async () => {
4992
- try {
4993
- if (!plan || !scope)
4994
- return;
4995
- const result = await applyLinkPlan(plan);
4996
- setMessage(`Applied: ${result.applied}, Skipped: ${result.skipped}, Conflicts: ${result.conflicts}`);
4997
- await refreshStatus(scope);
4998
- } catch (err) {
4999
- setMessage(err?.message || String(err));
5000
- } finally {
5001
- setBusy(null);
5002
- setStep("done");
5003
- }
5004
- })();
5005
- return;
5006
- }
5007
- if (item.value === "add-skill") {
5008
- setSkillInput("");
5009
- setStep("skill-source-type");
5010
- return;
5011
- }
5012
- if (item.value === "install-plugin") {
5013
- setMarketplaceInput("");
5014
- setStep("plugin-marketplace-input");
5015
- return;
5016
- }
5017
- }
5018
- }, undefined, false, undefined, this),
5019
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5020
- text: "Use ↑↓ to navigate, Enter to select, Esc to go back, q to quit"
5021
- }, undefined, false, undefined, this)
5022
- ]
5023
- }, undefined, true, undefined, this)
5024
- ]
5025
- }, undefined, true, undefined, this);
5026
- }
5027
- if (step === "status") {
5028
- const listHeight = Math.max(6, (stdout?.rows ?? 24) - 8);
5029
- return /* @__PURE__ */ jsxDEV4(Screen, {
5030
- children: [
5031
- /* @__PURE__ */ jsxDEV4(Text2, {
5032
- color: "green",
5033
- children: appTitle
5034
- }, undefined, false, undefined, this),
5035
- /* @__PURE__ */ jsxDEV4(Box4, {
5036
- flexDirection: "column",
5037
- marginTop: 1,
5038
- children: [
5039
- /* @__PURE__ */ jsxDEV4(Text2, {
5040
- children: [
5041
- "Scope: ",
5042
- scopeLabel
5043
- ]
5044
- }, undefined, true, undefined, this),
5045
- /* @__PURE__ */ jsxDEV4(Text2, {
5046
- children: [
5047
- "Pending changes: ",
5048
- changes,
5049
- " · Conflicts: ",
5050
- conflicts
5051
- ]
5052
- }, undefined, true, undefined, this),
5053
- /* @__PURE__ */ jsxDEV4(Text2, {
5054
- dimColor: true,
5055
- children: "Legend: ✓ linked • need link ⚠ conflict"
5056
- }, undefined, false, undefined, this),
5057
- /* @__PURE__ */ jsxDEV4(Text2, {
5058
- dimColor: true,
5059
- children: [
5060
- "Mode: ",
5061
- conflictsOnly ? "Conflicts only" : "All",
5062
- " · Details: ",
5063
- showDetails ? "On" : "Off"
5064
- ]
5065
- }, undefined, true, undefined, this)
5066
- ]
5067
- }, undefined, true, undefined, this),
5068
- /* @__PURE__ */ jsxDEV4(ScrollArea, {
5069
- height: listHeight,
5070
- children: renderStatusList()
5071
- }, undefined, false, undefined, this),
5072
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5073
- text: "d: details · c: conflicts only · a: show all · Esc: back · q: quit"
5074
- }, undefined, false, undefined, this)
5075
- ]
5076
- }, undefined, true, undefined, this);
5077
- }
5078
- if (step === "force-confirm") {
5079
- return /* @__PURE__ */ jsxDEV4(Screen, {
5080
- children: [
5081
- /* @__PURE__ */ jsxDEV4(Text2, {
5082
- color: "yellow",
5083
- children: "Force apply will overwrite existing real files/directories."
5084
- }, undefined, false, undefined, this),
5085
- /* @__PURE__ */ jsxDEV4(Box4, {
5086
- flexDirection: "column",
5087
- marginTop: 1,
5088
- children: [
5089
- /* @__PURE__ */ jsxDEV4(Text2, {
5090
- children: "Backup will be created at:"
5091
- }, undefined, false, undefined, this),
5092
- /* @__PURE__ */ jsxDEV4(Text2, {
5093
- dimColor: true,
5094
- children: forceBackupDir || "(pending)"
5095
- }, undefined, false, undefined, this)
5096
- ]
5097
- }, undefined, true, undefined, this),
5098
- /* @__PURE__ */ jsxDEV4(Box4, {
5099
- marginTop: 1,
5100
- flexDirection: "column",
5101
- children: [
5102
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5103
- items: [
5104
- { label: "Proceed (create backup + overwrite)", value: "proceed" },
5105
- { label: "Cancel", value: "cancel" }
5106
- ],
5107
- onSelect: (item) => {
5108
- if (item.value === "cancel") {
5109
- setForceBackupDir(null);
5110
- setStep("action");
5111
- return;
5112
- }
5113
- setBusy("Applying (force)...");
5114
- setStep("applying");
5115
- (async () => {
5116
- try {
5117
- if (!plan || !scope)
5118
- return;
5119
- const backupDir = forceBackupDir || undefined;
5120
- const result = await applyLinkPlan(plan, { force: true, backupDir });
5121
- const backupNote = result.backedUp > 0 && result.backupDir ? `, Backed up: ${result.backedUp} (${result.backupDir})` : "";
5122
- setMessage(`Applied: ${result.applied}, Skipped: ${result.skipped}, Conflicts: ${result.conflicts}${backupNote}`);
5123
- await refreshStatus(scope);
5124
- } catch (err) {
5125
- setMessage(err?.message || String(err));
5126
- } finally {
5127
- setForceBackupDir(null);
5128
- setBusy(null);
5129
- setStep("done");
5130
- }
5131
- })();
5132
- }
5133
- }, undefined, false, undefined, this),
5134
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5135
- text: "Enter to confirm · Esc to cancel · q to quit"
5136
- }, undefined, false, undefined, this)
5137
- ]
5138
- }, undefined, true, undefined, this)
5139
- ]
5140
- }, undefined, true, undefined, this);
5141
- }
5142
- if (step === "migrate-choice" && migratePlan) {
5143
- const conflict = migratePlan.conflicts[migrateIndex];
5144
- if (!conflict) {
5145
- return /* @__PURE__ */ jsxDEV4(Screen, {
5146
- children: [
5147
- /* @__PURE__ */ jsxDEV4(Text2, {
5148
- color: "green",
5149
- children: appTitle
5150
- }, undefined, false, undefined, this),
5151
- /* @__PURE__ */ jsxDEV4(Text2, {
5152
- dimColor: true,
5153
- children: "No conflicts to resolve."
5154
- }, undefined, false, undefined, this),
5155
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5156
- text: "Esc: back · q: quit"
5157
- }, undefined, false, undefined, this)
5158
- ]
5159
- }, undefined, true, undefined, this);
5160
- }
5161
- const items = conflict.candidates.map((c) => ({
5162
- label: c.label,
5163
- value: c
5164
- }));
5165
- return /* @__PURE__ */ jsxDEV4(Screen, {
5166
- children: [
5167
- /* @__PURE__ */ jsxDEV4(Text2, {
5168
- color: "green",
5169
- children: appTitle
5170
- }, undefined, false, undefined, this),
5171
- /* @__PURE__ */ jsxDEV4(Box4, {
5172
- flexDirection: "column",
5173
- marginTop: 1,
5174
- children: [
5175
- /* @__PURE__ */ jsxDEV4(Text2, {
5176
- children: [
5177
- "Resolve conflict ",
5178
- migrateIndex + 1,
5179
- " of ",
5180
- migratePlan.conflicts.length
5181
- ]
5182
- }, undefined, true, undefined, this),
5183
- /* @__PURE__ */ jsxDEV4(Text2, {
5184
- dimColor: true,
5185
- children: conflict.label
5186
- }, undefined, false, undefined, this)
5187
- ]
5188
- }, undefined, true, undefined, this),
5189
- /* @__PURE__ */ jsxDEV4(Box4, {
5190
- marginTop: 1,
5191
- flexDirection: "column",
5192
- children: [
5193
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5194
- items,
5195
- onSelect: (item) => {
5196
- if (!scope)
5197
- return;
5198
- const next = new Map(migrateSelections);
5199
- next.set(conflict.targetPath, item.value);
5200
- setMigrateSelections(next);
5201
- if (migrateIndex + 1 < migratePlan.conflicts.length) {
5202
- setMigrateIndex(migrateIndex + 1);
5203
- return;
5204
- }
5205
- setBusy("Migrating...");
5206
- setStep("applying");
5207
- (async () => {
5208
- try {
5209
- const result = await applyMigration(migratePlan, next, { scope });
5210
- setMessage(`Migrated ${result.copied} items. Backup: ${result.backupDir}`);
5211
- await refreshStatus(scope);
5212
- } catch (err) {
5213
- setMessage(err?.message || String(err));
5214
- } finally {
5215
- setBusy(null);
5216
- setMigratePlan(null);
5217
- setMigrateIndex(0);
5218
- setMigrateSelections(new Map);
5219
- setStep("done");
5220
- }
5221
- })();
5222
- }
5223
- }, undefined, false, undefined, this),
5224
- /* @__PURE__ */ jsxDEV4(HelpBar, {
5225
- text: "Use ↑↓ to choose, Enter to select, Esc to cancel"
5226
- }, undefined, false, undefined, this)
5227
- ]
5228
- }, undefined, true, undefined, this)
5229
- ]
5230
- }, undefined, true, undefined, this);
5231
- }
5232
- if (step === "applying") {
5233
- return /* @__PURE__ */ jsxDEV4(Screen, {
5234
- children: /* @__PURE__ */ jsxDEV4(Text2, {
5235
- color: "yellow",
5236
- children: [
5237
- /* @__PURE__ */ jsxDEV4(Spinner, {
5238
- type: "dots"
5239
- }, undefined, false, undefined, this),
5240
- " ",
5241
- busy || "Working..."
5242
- ]
5243
- }, undefined, true, undefined, this)
5244
- }, undefined, false, undefined, this);
5245
- }
5246
- if (step === "skill-source-type") {
5247
- return /* @__PURE__ */ jsxDEV4(Screen, {
5248
- children: [
5249
- /* @__PURE__ */ jsxDEV4(Text2, {
5250
- children: "Select skill source type:"
5251
- }, undefined, false, undefined, this),
5252
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5253
- items: [
5254
- { label: "Local path", value: "local" },
5255
- { label: "URL", value: "url" },
5256
- { label: "Back", value: "back" }
5257
- ],
5258
- onSelect: (item) => {
5259
- if (item.value === "back") {
5260
- setStep("action");
5261
- return;
5262
- }
5263
- setSkillType(item.value);
5264
- setStep("skill-input");
5265
- }
5266
- }, undefined, false, undefined, this),
5267
- /* @__PURE__ */ jsxDEV4(Text2, {
5268
- dimColor: true,
5269
- children: "Press Esc to go back, or q to quit."
5270
- }, undefined, false, undefined, this)
5271
- ]
5272
- }, undefined, true, undefined, this);
5273
- }
5274
- if (step === "skill-input") {
5275
- return /* @__PURE__ */ jsxDEV4(Screen, {
5276
- children: [
5277
- skillType === "local" ? /* @__PURE__ */ jsxDEV4(Fragment, {
5278
- children: [
5279
- /* @__PURE__ */ jsxDEV4(Text2, {
5280
- children: "Paste a skills folder path and we’ll install all skills inside."
5281
- }, undefined, false, undefined, this),
5282
- /* @__PURE__ */ jsxDEV4(Text2, {
5283
- children: "Or paste a SKILL.md file and we’ll install the full skill."
5284
- }, undefined, false, undefined, this)
5285
- ]
5286
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV4(Fragment, {
5287
- children: [
5288
- /* @__PURE__ */ jsxDEV4(Text2, {
5289
- children: "Paste a skills folder URL and we’ll fetch all skills inside."
5290
- }, undefined, false, undefined, this),
5291
- /* @__PURE__ */ jsxDEV4(Text2, {
5292
- children: "Or paste a SKILL.md URL and we’ll install the full skill."
5293
- }, undefined, false, undefined, this)
5294
- ]
5295
- }, undefined, true, undefined, this),
5296
- /* @__PURE__ */ jsxDEV4(TextInput, {
5297
- value: skillInput,
5298
- onChange: setSkillInput,
5299
- onSubmit: () => {
5300
- if (!scope)
5301
- return;
5302
- setBusy("Installing skill(s)...");
5303
- setStep("applying");
5304
- (async () => {
5305
- try {
5306
- const result = await installSkillsFromSource({
5307
- source: skillInput,
5308
- sourceType: skillType,
5309
- scope
5310
- });
5311
- setMessage(`Installed: ${result.installed.join(", ") || "none"} · Skipped: ${result.skipped.join(", ") || "none"}`);
5312
- await refreshStatus(scope);
5313
- } catch (err) {
5314
- setMessage(err?.message || String(err));
5315
- } finally {
5316
- setBusy(null);
5317
- setStep("done");
5318
- }
5319
- })();
5320
- }
5321
- }, undefined, false, undefined, this),
5322
- /* @__PURE__ */ jsxDEV4(Text2, {
5323
- dimColor: true,
5324
- children: "Press Enter to continue, Esc to go back, or q to quit."
5325
- }, undefined, false, undefined, this)
5326
- ]
5327
- }, undefined, true, undefined, this);
5328
- }
5329
- if (step === "plugin-marketplace-input") {
5330
- return /* @__PURE__ */ jsxDEV4(Screen, {
5331
- children: [
5332
- /* @__PURE__ */ jsxDEV4(Text2, {
5333
- children: "Enter marketplace path or URL:"
5334
- }, undefined, false, undefined, this),
5335
- /* @__PURE__ */ jsxDEV4(TextInput, {
5336
- value: marketplaceInput,
5337
- onChange: setMarketplaceInput,
5338
- onSubmit: () => {
5339
- if (!scope)
5340
- return;
5341
- setBusy("Loading marketplace...");
5342
- setStep("applying");
5343
- (async () => {
5344
- try {
5345
- const loaded = await loadMarketplace(marketplaceInput);
5346
- const plugins = loaded.json.plugins.map((p) => p.name);
5347
- setMarketplacePlugins(plugins);
5348
- setBusy(null);
5349
- setStep("plugin-select");
5350
- } catch (err) {
5351
- setMessage(err?.message || String(err));
5352
- setBusy(null);
5353
- setStep("done");
5354
- }
5355
- })();
5356
- }
5357
- }, undefined, false, undefined, this),
5358
- /* @__PURE__ */ jsxDEV4(Text2, {
5359
- dimColor: true,
5360
- children: "Press Enter to continue, Esc to go back, or q to quit."
5361
- }, undefined, false, undefined, this)
5362
- ]
5363
- }, undefined, true, undefined, this);
5364
- }
5365
- if (step === "plugin-select") {
5366
- return /* @__PURE__ */ jsxDEV4(Screen, {
5367
- children: [
5368
- /* @__PURE__ */ jsxDEV4(Text2, {
5369
- children: "Select plugin to install:"
5370
- }, undefined, false, undefined, this),
5371
- /* @__PURE__ */ jsxDEV4(SelectInput, {
5372
- items: [
5373
- { label: "All plugins", value: "all" },
5374
- ...marketplacePlugins.map((p) => ({ label: p, value: p })),
5375
- { label: "Back", value: "back" }
5376
- ],
5377
- onSelect: (item) => {
5378
- if (!scope)
5379
- return;
5380
- if (item.value === "back") {
5381
- setStep("action");
5382
- return;
5383
- }
5384
- setBusy("Installing plugin(s)...");
5385
- setStep("applying");
5386
- (async () => {
5387
- try {
5388
- const result = await installMarketplace({
5389
- marketplace: marketplaceInput,
5390
- plugins: item.value === "all" ? "all" : [String(item.value)],
5391
- scope
5392
- });
5393
- setMessage(`Installed commands: ${result.installedCommands.length}, hooks: ${result.installedHooks.length}, skills: ${result.installedSkills.length}`);
5394
- await refreshStatus(scope);
5395
- } catch (err) {
5396
- setMessage(err?.message || String(err));
5397
- } finally {
5398
- setBusy(null);
5399
- setStep("done");
5400
- }
5401
- })();
5402
- }
5403
- }, undefined, false, undefined, this),
5404
- /* @__PURE__ */ jsxDEV4(Text2, {
5405
- dimColor: true,
5406
- children: "Press Esc to go back, or q to quit."
5407
- }, undefined, false, undefined, this)
5408
- ]
5409
- }, undefined, true, undefined, this);
5410
- }
5411
- if (step === "done") {
5412
- return /* @__PURE__ */ jsxDEV4(Screen, {
5413
- children: [
5414
- /* @__PURE__ */ jsxDEV4(Text2, {
5415
- children: message || "Done."
5416
- }, undefined, false, undefined, this),
5417
- /* @__PURE__ */ jsxDEV4(Text2, {
5418
- dimColor: true,
5419
- children: "Press Enter to continue, Esc to go back, or q to quit."
5420
- }, 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" }
5421
5753
  ]
5422
- }, 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;
5423
5764
  }
5424
- return null;
5425
- };
5426
-
5427
- // src/cli.tsx
5428
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
5429
- 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
+ });