@indy2kro/agentenv 1.0.1 → 1.0.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 (130) hide show
  1. package/dist/adapters/agent-dirs.d.ts +29 -0
  2. package/dist/adapters/agent-dirs.d.ts.map +1 -0
  3. package/dist/adapters/agent-dirs.js +46 -0
  4. package/dist/adapters/agent-dirs.js.map +1 -0
  5. package/dist/adapters/base.d.ts +7 -1
  6. package/dist/adapters/base.d.ts.map +1 -1
  7. package/dist/adapters/base.js.map +1 -1
  8. package/dist/adapters/claude.d.ts.map +1 -1
  9. package/dist/adapters/claude.js +18 -10
  10. package/dist/adapters/claude.js.map +1 -1
  11. package/dist/adapters/cline.d.ts.map +1 -1
  12. package/dist/adapters/cline.js +2 -2
  13. package/dist/adapters/cline.js.map +1 -1
  14. package/dist/adapters/codex.d.ts.map +1 -1
  15. package/dist/adapters/codex.js +3 -2
  16. package/dist/adapters/codex.js.map +1 -1
  17. package/dist/adapters/copilot.d.ts.map +1 -1
  18. package/dist/adapters/copilot.js +3 -4
  19. package/dist/adapters/copilot.js.map +1 -1
  20. package/dist/adapters/cursor.d.ts.map +1 -1
  21. package/dist/adapters/cursor.js +7 -6
  22. package/dist/adapters/cursor.js.map +1 -1
  23. package/dist/adapters/detect.d.ts.map +1 -1
  24. package/dist/adapters/detect.js +1 -0
  25. package/dist/adapters/detect.js.map +1 -1
  26. package/dist/adapters/gemini.d.ts.map +1 -1
  27. package/dist/adapters/gemini.js +2 -2
  28. package/dist/adapters/gemini.js.map +1 -1
  29. package/dist/adapters/index.d.ts +4 -0
  30. package/dist/adapters/index.d.ts.map +1 -1
  31. package/dist/adapters/index.js +21 -0
  32. package/dist/adapters/index.js.map +1 -1
  33. package/dist/adapters/opencode.d.ts.map +1 -1
  34. package/dist/adapters/opencode.js +2 -2
  35. package/dist/adapters/opencode.js.map +1 -1
  36. package/dist/adapters/rtk-delegation.d.ts.map +1 -1
  37. package/dist/adapters/rtk-delegation.js +16 -1
  38. package/dist/adapters/rtk-delegation.js.map +1 -1
  39. package/dist/adapters/vibe.d.ts.map +1 -1
  40. package/dist/adapters/vibe.js +2 -2
  41. package/dist/adapters/vibe.js.map +1 -1
  42. package/dist/adapters/windsurf.d.ts.map +1 -1
  43. package/dist/adapters/windsurf.js +2 -2
  44. package/dist/adapters/windsurf.js.map +1 -1
  45. package/dist/cli/exit.d.ts +17 -6
  46. package/dist/cli/exit.d.ts.map +1 -1
  47. package/dist/cli/exit.js +17 -7
  48. package/dist/cli/exit.js.map +1 -1
  49. package/dist/commands/apply.d.ts +77 -0
  50. package/dist/commands/apply.d.ts.map +1 -1
  51. package/dist/commands/apply.js +202 -27
  52. package/dist/commands/apply.js.map +1 -1
  53. package/dist/commands/config-edit.d.ts +33 -0
  54. package/dist/commands/config-edit.d.ts.map +1 -0
  55. package/dist/commands/config-edit.js +216 -0
  56. package/dist/commands/config-edit.js.map +1 -0
  57. package/dist/commands/doctor.d.ts +41 -0
  58. package/dist/commands/doctor.d.ts.map +1 -1
  59. package/dist/commands/doctor.js +135 -52
  60. package/dist/commands/doctor.js.map +1 -1
  61. package/dist/commands/setup.d.ts +4 -0
  62. package/dist/commands/setup.d.ts.map +1 -1
  63. package/dist/commands/setup.js +58 -5
  64. package/dist/commands/setup.js.map +1 -1
  65. package/dist/commands/status.d.ts.map +1 -1
  66. package/dist/commands/status.js +40 -16
  67. package/dist/commands/status.js.map +1 -1
  68. package/dist/commands/uninstall.d.ts +78 -1
  69. package/dist/commands/uninstall.d.ts.map +1 -1
  70. package/dist/commands/uninstall.js +329 -31
  71. package/dist/commands/uninstall.js.map +1 -1
  72. package/dist/commands/update.d.ts +51 -0
  73. package/dist/commands/update.d.ts.map +1 -1
  74. package/dist/commands/update.js +172 -71
  75. package/dist/commands/update.js.map +1 -1
  76. package/dist/commands/wizard.d.ts +27 -1
  77. package/dist/commands/wizard.d.ts.map +1 -1
  78. package/dist/commands/wizard.js +48 -31
  79. package/dist/commands/wizard.js.map +1 -1
  80. package/dist/config/schema.d.ts +28 -3
  81. package/dist/config/schema.d.ts.map +1 -1
  82. package/dist/config/schema.js +206 -54
  83. package/dist/config/schema.js.map +1 -1
  84. package/dist/config/scopes.d.ts +4 -2
  85. package/dist/config/scopes.d.ts.map +1 -1
  86. package/dist/config/scopes.js +23 -4
  87. package/dist/config/scopes.js.map +1 -1
  88. package/dist/generate/agentsmd.d.ts +54 -0
  89. package/dist/generate/agentsmd.d.ts.map +1 -1
  90. package/dist/generate/agentsmd.js +222 -143
  91. package/dist/generate/agentsmd.js.map +1 -1
  92. package/dist/index.js +9 -2
  93. package/dist/index.js.map +1 -1
  94. package/dist/integrations/render.d.ts.map +1 -1
  95. package/dist/integrations/render.js +25 -10
  96. package/dist/integrations/render.js.map +1 -1
  97. package/dist/integrations/superpowers.d.ts.map +1 -1
  98. package/dist/integrations/superpowers.js +2 -0
  99. package/dist/integrations/superpowers.js.map +1 -1
  100. package/dist/shell/detector.d.ts +22 -2
  101. package/dist/shell/detector.d.ts.map +1 -1
  102. package/dist/shell/detector.js +122 -34
  103. package/dist/shell/detector.js.map +1 -1
  104. package/dist/toolchain/gh.d.ts.map +1 -1
  105. package/dist/toolchain/gh.js +1 -0
  106. package/dist/toolchain/gh.js.map +1 -1
  107. package/dist/toolchain/mise.d.ts +7 -0
  108. package/dist/toolchain/mise.d.ts.map +1 -1
  109. package/dist/toolchain/mise.js +20 -3
  110. package/dist/toolchain/mise.js.map +1 -1
  111. package/dist/toolchain/rtk.d.ts +71 -3
  112. package/dist/toolchain/rtk.d.ts.map +1 -1
  113. package/dist/toolchain/rtk.js +115 -7
  114. package/dist/toolchain/rtk.js.map +1 -1
  115. package/dist/ui/output.d.ts.map +1 -1
  116. package/dist/ui/output.js +10 -2
  117. package/dist/ui/output.js.map +1 -1
  118. package/dist/ui/spinner.d.ts +15 -3
  119. package/dist/ui/spinner.d.ts.map +1 -1
  120. package/dist/ui/spinner.js +52 -4
  121. package/dist/ui/spinner.js.map +1 -1
  122. package/dist/ui/theme.d.ts +27 -1
  123. package/dist/ui/theme.d.ts.map +1 -1
  124. package/dist/ui/theme.js +73 -8
  125. package/dist/ui/theme.js.map +1 -1
  126. package/dist/utils/fs-retry.d.ts +16 -0
  127. package/dist/utils/fs-retry.d.ts.map +1 -1
  128. package/dist/utils/fs-retry.js +28 -0
  129. package/dist/utils/fs-retry.js.map +1 -1
  130. package/package.json +2 -1
@@ -14,12 +14,24 @@ export interface Spinner {
14
14
  stop(): Spinner;
15
15
  }
16
16
  export type SpinnerFactory = (text: string) => Spinner;
17
+ /** Force the animated spinner on/off; pass undefined to restore auto-detection. Wired to --no-spinner. */
18
+ export declare function setSpinnerEnabled(enabled: boolean | undefined): void;
19
+ /**
20
+ * Whether to animate: off under TERM=dumb or CI (most CI systems set
21
+ * CI=true; the animation floods a non-interactive log with redraw frames),
22
+ * unless --no-spinner/setSpinnerEnabled() overrides either way.
23
+ */
24
+ export declare function isSpinnerEnabled(): boolean;
17
25
  /**
18
26
  * Run fn() under a spinner labeled `label`, resolving succeed/fail from the
19
27
  * result's `success` field. `-q/--quiet` swaps in a no-op spinner so quiet
20
- * output is actually silent even on a TTY. `fn` receives the spinner itself
21
- * so a long inner step can `stop()` it before printing raw output and
22
- * `start()` it again afterwards.
28
+ * output is actually silent even on a TTY; `--no-spinner`/TERM=dumb/CI swap
29
+ * the *real* (ora) spinner for a static, non-animated one that still prints
30
+ * the label and succeed/fail lines — an explicitly injected `spinnerFactory`
31
+ * (as every test passes) is never second-guessed by that auto-detection,
32
+ * since a test double has no animation to disable in the first place. `fn`
33
+ * receives the spinner itself so a long inner step can `stop()` it before
34
+ * printing raw output and `start()` it again afterwards.
23
35
  */
24
36
  export declare function withSpinner<T extends {
25
37
  success: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,OAAO;IACtB,KAAK,IAAI,OAAO,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,kNAAkN;IAClN,IAAI,IAAI,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;AAWvD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,EAC9D,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EACpC,cAAc,GAAE,cAAsC,GACrD,OAAO,CAAC,CAAC,CAAC,CAYZ"}
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,OAAO;IACtB,KAAK,IAAI,OAAO,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,kNAAkN;IAClN,IAAI,IAAI,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;AAiCvD,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAG1C;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,EAC9D,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EACpC,cAAc,GAAE,cAAsC,GACrD,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import ora from 'ora';
10
10
  import { isQuiet } from './output.js';
11
+ import { colorizeLine, failGlyph, successGlyph } from './theme.js';
11
12
  const defaultSpinnerFactory = (text) => ora(text);
12
13
  const quietSpinner = {
13
14
  start: () => quietSpinner,
@@ -15,15 +16,62 @@ const quietSpinner = {
15
16
  fail: () => quietSpinner,
16
17
  stop: () => quietSpinner,
17
18
  };
19
+ /** A non-animated stand-in: prints the label once, then a plain succeed/fail line — no redrawing. */
20
+ function staticSpinner(label) {
21
+ const spinner = {
22
+ start: () => {
23
+ console.log(label);
24
+ return spinner;
25
+ },
26
+ succeed: (text) => {
27
+ console.log(colorizeLine(`${successGlyph()} ${text ?? label}`));
28
+ return spinner;
29
+ },
30
+ fail: (text) => {
31
+ console.log(colorizeLine(`${failGlyph()} ${text ?? label}`));
32
+ return spinner;
33
+ },
34
+ stop: () => spinner,
35
+ };
36
+ return spinner;
37
+ }
38
+ let spinnerOverride;
39
+ /** Force the animated spinner on/off; pass undefined to restore auto-detection. Wired to --no-spinner. */
40
+ export function setSpinnerEnabled(enabled) {
41
+ spinnerOverride = enabled;
42
+ }
43
+ /**
44
+ * Whether to animate: off under TERM=dumb or CI (most CI systems set
45
+ * CI=true; the animation floods a non-interactive log with redraw frames),
46
+ * unless --no-spinner/setSpinnerEnabled() overrides either way.
47
+ */
48
+ export function isSpinnerEnabled() {
49
+ if (spinnerOverride !== undefined)
50
+ return spinnerOverride;
51
+ return process.env.TERM !== 'dumb' && !process.env.CI;
52
+ }
18
53
  /**
19
54
  * Run fn() under a spinner labeled `label`, resolving succeed/fail from the
20
55
  * result's `success` field. `-q/--quiet` swaps in a no-op spinner so quiet
21
- * output is actually silent even on a TTY. `fn` receives the spinner itself
22
- * so a long inner step can `stop()` it before printing raw output and
23
- * `start()` it again afterwards.
56
+ * output is actually silent even on a TTY; `--no-spinner`/TERM=dumb/CI swap
57
+ * the *real* (ora) spinner for a static, non-animated one that still prints
58
+ * the label and succeed/fail lines — an explicitly injected `spinnerFactory`
59
+ * (as every test passes) is never second-guessed by that auto-detection,
60
+ * since a test double has no animation to disable in the first place. `fn`
61
+ * receives the spinner itself so a long inner step can `stop()` it before
62
+ * printing raw output and `start()` it again afterwards.
24
63
  */
25
64
  export async function withSpinner(label, fn, spinnerFactory = defaultSpinnerFactory) {
26
- const factory = isQuiet() ? () => quietSpinner : spinnerFactory;
65
+ let factory;
66
+ if (isQuiet()) {
67
+ factory = () => quietSpinner;
68
+ }
69
+ else if (spinnerFactory === defaultSpinnerFactory && !isSpinnerEnabled()) {
70
+ factory = staticSpinner;
71
+ }
72
+ else {
73
+ factory = spinnerFactory;
74
+ }
27
75
  const spinner = factory(label).start();
28
76
  try {
29
77
  const result = await fn(spinner);
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAYtC,MAAM,qBAAqB,GAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAuB,CAAC;AAExF,MAAM,YAAY,GAAY;IAC5B,KAAK,EAAE,GAAG,EAAE,CAAC,YAAY;IACzB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY;IAC3B,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY;IACxB,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,EAAoC,EACpC,iBAAiC,qBAAqB;IAEtD,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,GAAY,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;IACzE,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;;YACtC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAYnE,MAAM,qBAAqB,GAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAuB,CAAC;AAExF,MAAM,YAAY,GAAY;IAC5B,KAAK,EAAE,GAAG,EAAE,CAAC,YAAY;IACzB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY;IAC3B,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY;IACxB,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY;CACzB,CAAC;AAEF,qGAAqG;AACrG,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,GAAG,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAChB,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,YAAY,EAAE,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAChE,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;YACb,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,SAAS,EAAE,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO;KACpB,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,IAAI,eAAoC,CAAC;AAEzC,0GAA0G;AAC1G,MAAM,UAAU,iBAAiB,CAAC,OAA4B;IAC5D,eAAe,GAAG,OAAO,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,eAAe,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC;IAC1D,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,EAAoC,EACpC,iBAAiC,qBAAqB;IAEtD,IAAI,OAAuB,CAAC;IAC5B,IAAI,OAAO,EAAE,EAAE,CAAC;QACd,OAAO,GAAG,GAAY,EAAE,CAAC,YAAY,CAAC;IACxC,CAAC;SAAM,IAAI,cAAc,KAAK,qBAAqB,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC3E,OAAO,GAAG,aAAa,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,cAAc,CAAC;IAC3B,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;;YACtC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -12,11 +12,37 @@ export declare const theme: {
12
12
  fail: (text: string) => string;
13
13
  warn: (text: string) => string;
14
14
  };
15
+ export interface AsciiDetectionEnv {
16
+ /** Overrides process.env.AGENTENV_ASCII ("1"/"true" forces ASCII, "0"/"false" forces Unicode). */
17
+ forceAscii?: string;
18
+ term?: string;
19
+ platform?: NodeJS.Platform;
20
+ getWindowsCodePage?: () => number | undefined;
21
+ }
22
+ /**
23
+ * True when the console likely can't render ✓/✗/✅/⚠️/❌ reliably: an explicit
24
+ * AGENTENV_ASCII override, TERM=dumb, or (on Windows) an active code page
25
+ * other than 65001 (UTF-8) — legacy `conhost` defaults to the OS locale's
26
+ * code page (437 on a US system), which renders these as mojibake.
27
+ */
28
+ export declare function useAsciiGlyphs(env?: AsciiDetectionEnv): boolean;
29
+ /** useAsciiGlyphs() for the real process environment, probed once per process and cached. */
30
+ export declare function asciiGlyphsEnabled(): boolean;
31
+ /** Test-only: clear the cached ascii-mode detection so a new environment can be probed. */
32
+ export declare function resetAsciiGlyphsCache(): void;
33
+ /** The glyph agentenv prints for a passing/configured check. */
34
+ export declare function successGlyph(): string;
35
+ /** The glyph agentenv prints for a failing/missing check. */
36
+ export declare function failGlyph(): string;
37
+ /** The glyph agentenv prints for a tool/agent this platform doesn't support. */
38
+ export declare function unsupportedGlyph(): string;
39
+ export declare const DRIFT_GLYPH = "!";
15
40
  /**
16
41
  * Colorize a pre-formatted message line by its leading status glyph (or a
17
42
  * "warning:" substring), so command output built elsewhere in the pipeline
18
43
  * (mise, adapters, integrations) gets consistent coloring without every
19
- * producer needing to know about chalk.
44
+ * producer needing to know about chalk. Recognizes both the Unicode and
45
+ * ASCII-fallback glyph forms, regardless of which mode produced the line.
20
46
  */
21
47
  export declare function colorizeLine(line: string): string;
22
48
  //# sourceMappingURL=theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEtD;AAED,eAAO,MAAM,KAAK;oBACA,MAAM;iBACT,MAAM;gBACP,MAAM;eACP,MAAM;iBACJ,MAAM;iBACN,MAAM;CACpB,CAAC;AAOF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEtD;AAED,eAAO,MAAM,KAAK;oBACA,MAAM;iBACT,MAAM;gBACP,MAAM;eACP,MAAM;iBACJ,MAAM;iBACN,MAAM;CACpB,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;CAC/C;AAiBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,iBAAsB,GAAG,OAAO,CAanE;AAID,6FAA6F;AAC7F,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED,2FAA2F;AAC3F,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,gEAAgE;AAChE,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAGD,eAAO,MAAM,WAAW,MAAM,CAAC;AAK/B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBjD"}
package/dist/ui/theme.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * is the only override this CLI needs (wired to --no-color in index.ts).
5
5
  */
6
6
  import chalk from 'chalk';
7
+ import { execFileSync } from 'child_process';
7
8
  export function setColorEnabled(enabled) {
8
9
  if (!enabled)
9
10
  chalk.level = 0;
@@ -16,27 +17,91 @@ export const theme = {
16
17
  fail: (text) => chalk.red(text),
17
18
  warn: (text) => chalk.yellow(text),
18
19
  };
19
- const SUCCESS_GLYPH = '✓';
20
- const FAIL_GLYPH = '✗';
21
- const DRIFT_GLYPH = '!';
22
- const UNSUPPORTED_GLYPH = '·';
20
+ /** The active Windows console code page (e.g. 437, 65001), or undefined if `chcp` can't be read. */
21
+ function detectWindowsCodePage() {
22
+ try {
23
+ const output = execFileSync('chcp.com', [], {
24
+ encoding: 'utf8',
25
+ timeout: 1000,
26
+ windowsHide: true,
27
+ });
28
+ const match = /(\d+)/.exec(output);
29
+ return match ? Number(match[1]) : undefined;
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ }
35
+ /**
36
+ * True when the console likely can't render ✓/✗/✅/⚠️/❌ reliably: an explicit
37
+ * AGENTENV_ASCII override, TERM=dumb, or (on Windows) an active code page
38
+ * other than 65001 (UTF-8) — legacy `conhost` defaults to the OS locale's
39
+ * code page (437 on a US system), which renders these as mojibake.
40
+ */
41
+ export function useAsciiGlyphs(env = {}) {
42
+ const forceAscii = env.forceAscii ?? process.env.AGENTENV_ASCII;
43
+ if (forceAscii === '1' || forceAscii === 'true')
44
+ return true;
45
+ if (forceAscii === '0' || forceAscii === 'false')
46
+ return false;
47
+ if ((env.term ?? process.env.TERM) === 'dumb')
48
+ return true;
49
+ if ((env.platform ?? process.platform) === 'win32') {
50
+ const codePage = (env.getWindowsCodePage ?? detectWindowsCodePage)();
51
+ if (codePage !== undefined && codePage !== 65001)
52
+ return true;
53
+ }
54
+ return false;
55
+ }
56
+ let cachedAsciiGlyphs;
57
+ /** useAsciiGlyphs() for the real process environment, probed once per process and cached. */
58
+ export function asciiGlyphsEnabled() {
59
+ if (cachedAsciiGlyphs === undefined)
60
+ cachedAsciiGlyphs = useAsciiGlyphs();
61
+ return cachedAsciiGlyphs;
62
+ }
63
+ /** Test-only: clear the cached ascii-mode detection so a new environment can be probed. */
64
+ export function resetAsciiGlyphsCache() {
65
+ cachedAsciiGlyphs = undefined;
66
+ }
67
+ /** The glyph agentenv prints for a passing/configured check. */
68
+ export function successGlyph() {
69
+ return asciiGlyphsEnabled() ? '[ok]' : '✓';
70
+ }
71
+ /** The glyph agentenv prints for a failing/missing check. */
72
+ export function failGlyph() {
73
+ return asciiGlyphsEnabled() ? '[FAIL]' : '✗';
74
+ }
75
+ /** The glyph agentenv prints for a tool/agent this platform doesn't support. */
76
+ export function unsupportedGlyph() {
77
+ return asciiGlyphsEnabled() ? '[-]' : '·';
78
+ }
79
+ // Already ASCII-safe; kept as a named export so callers don't hardcode '!'.
80
+ export const DRIFT_GLYPH = '!';
81
+ const UNICODE_GLYPHS = { success: '✓', fail: '✗', unsupported: '·' };
82
+ const ASCII_GLYPHS = { success: '[ok]', fail: '[FAIL]', unsupported: '[-]' };
23
83
  /**
24
84
  * Colorize a pre-formatted message line by its leading status glyph (or a
25
85
  * "warning:" substring), so command output built elsewhere in the pipeline
26
86
  * (mise, adapters, integrations) gets consistent coloring without every
27
- * producer needing to know about chalk.
87
+ * producer needing to know about chalk. Recognizes both the Unicode and
88
+ * ASCII-fallback glyph forms, regardless of which mode produced the line.
28
89
  */
29
90
  export function colorizeLine(line) {
30
91
  const trimmed = line.trimStart();
31
- if (trimmed.startsWith(SUCCESS_GLYPH))
92
+ if (trimmed.startsWith(UNICODE_GLYPHS.success) || trimmed.startsWith(ASCII_GLYPHS.success)) {
32
93
  return theme.ok(line);
33
- if (trimmed.startsWith(FAIL_GLYPH))
94
+ }
95
+ if (trimmed.startsWith(UNICODE_GLYPHS.fail) || trimmed.startsWith(ASCII_GLYPHS.fail)) {
34
96
  return theme.fail(line);
97
+ }
35
98
  if (trimmed.startsWith(DRIFT_GLYPH) || line.toLowerCase().includes('warning:')) {
36
99
  return theme.warn(line);
37
100
  }
38
- if (trimmed.startsWith(UNSUPPORTED_GLYPH))
101
+ if (trimmed.startsWith(UNICODE_GLYPHS.unsupported) ||
102
+ trimmed.startsWith(ASCII_GLYPHS.unsupported)) {
39
103
  return theme.dim(line);
104
+ }
40
105
  return line;
41
106
  }
42
107
  //# sourceMappingURL=theme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,IAAI,CAAC,OAAO;QAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACtC,EAAE,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;IACvC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACvC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IACjC,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7D,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,IAAI,CAAC,OAAO;QAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACtC,EAAE,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;IACvC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACvC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;CAC3C,CAAC;AAUF,oGAAoG;AACpG,SAAS,qBAAqB;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,EAAE,EAAE,EAAE;YAC1C,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,EAAE;IACxD,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAChE,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAE/D,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAE3D,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,kBAAkB,IAAI,qBAAqB,CAAC,EAAE,CAAC;QACrE,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;IAChE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,IAAI,iBAAsC,CAAC;AAE3C,6FAA6F;AAC7F,MAAM,UAAU,kBAAkB;IAChC,IAAI,iBAAiB,KAAK,SAAS;QAAE,iBAAiB,GAAG,cAAc,EAAE,CAAC;IAC1E,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB;IACnC,iBAAiB,GAAG,SAAS,CAAC;AAChC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY;IAC1B,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,SAAS;IACvB,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;AAC/C,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB;IAC9B,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAE/B,MAAM,cAAc,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC;AACrE,MAAM,YAAY,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAE7E;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IACjC,IAAI,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3F,OAAO,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACrF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,IACE,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC;QAC9C,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,EAC5C,CAAC;QACD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -33,6 +33,22 @@ export declare function isRetryableWriteError(err: unknown): boolean;
33
33
  * (EBUSY/EPERM). Throws when the write ultimately cannot succeed.
34
34
  */
35
35
  export declare function writeFileWithRetry(filePath: string, content: string, opts?: WriteRetryOptions, fsImpl?: RetryFs): void;
36
+ /**
37
+ * Back up `filePath`'s current content to `<filePath>.agentenv-backup` the
38
+ * first time agentenv is about to modify a file it did not create — a
39
+ * user-global file like ~/.claude/settings.json or a pre-existing user-scope
40
+ * CLAUDE.md/AGENTS.md. Tier 0's shell-fix writes to these same kinds of
41
+ * files already have an undo path (shell-fix-state.json); the adapters'
42
+ * writes did not.
43
+ *
44
+ * Never overwrites an existing backup — once one exists it holds the user's
45
+ * true pre-agentenv content, and a later call (a second `apply`) must not
46
+ * clobber it with agentenv's own already-modified content. A no-op when
47
+ * `filePath` doesn't exist yet (nothing to back up: this is a fresh file
48
+ * agentenv is creating, not modifying). Backing up is advisory: a failure
49
+ * here (e.g. a locked filesystem) must never block the real write.
50
+ */
51
+ export declare function backupBeforeFirstEdit(filePath: string): void;
36
52
  export interface WriteVerifyResult {
37
53
  success: boolean;
38
54
  message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"fs-retry.d.ts","sourceRoot":"","sources":["../../src/utils/fs-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC/C;AAED,eAAO,MAAM,cAAc,EAAE,OAS5B,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAKD,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAK3D;AAOD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,EAC5B,MAAM,GAAE,OAAwB,GAC/B,IAAI,CAcN;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,EAC5B,MAAM,GAAE,OAAwB,GAC/B,iBAAiB,CAwBnB"}
1
+ {"version":3,"file":"fs-retry.d.ts","sourceRoot":"","sources":["../../src/utils/fs-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC/C;AAED,eAAO,MAAM,cAAc,EAAE,OAS5B,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAKD,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAK3D;AAOD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,EAC5B,MAAM,GAAE,OAAwB,GAC/B,IAAI,CAcN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAS5D;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAsB,EAC5B,MAAM,GAAE,OAAwB,GAC/B,iBAAiB,CAwBnB"}
@@ -61,6 +61,34 @@ export function writeFileWithRetry(filePath, content, opts = {}, fsImpl = defaul
61
61
  }
62
62
  }
63
63
  }
64
+ /**
65
+ * Back up `filePath`'s current content to `<filePath>.agentenv-backup` the
66
+ * first time agentenv is about to modify a file it did not create — a
67
+ * user-global file like ~/.claude/settings.json or a pre-existing user-scope
68
+ * CLAUDE.md/AGENTS.md. Tier 0's shell-fix writes to these same kinds of
69
+ * files already have an undo path (shell-fix-state.json); the adapters'
70
+ * writes did not.
71
+ *
72
+ * Never overwrites an existing backup — once one exists it holds the user's
73
+ * true pre-agentenv content, and a later call (a second `apply`) must not
74
+ * clobber it with agentenv's own already-modified content. A no-op when
75
+ * `filePath` doesn't exist yet (nothing to back up: this is a fresh file
76
+ * agentenv is creating, not modifying). Backing up is advisory: a failure
77
+ * here (e.g. a locked filesystem) must never block the real write.
78
+ */
79
+ export function backupBeforeFirstEdit(filePath) {
80
+ try {
81
+ if (!fs.existsSync(filePath))
82
+ return;
83
+ const backupPath = `${filePath}.agentenv-backup`;
84
+ if (fs.existsSync(backupPath))
85
+ return;
86
+ fs.copyFileSync(filePath, backupPath);
87
+ }
88
+ catch {
89
+ // Advisory only — never block the real write on a failed backup.
90
+ }
91
+ }
64
92
  /**
65
93
  * Write `content` and confirm it persisted: the file must exist after the
66
94
  * write, and, for non-empty content, be non-empty. Any mismatch is reported as
@@ -1 +1 @@
1
- {"version":3,"file":"fs-retry.js","sourceRoot":"","sources":["../../src/utils/fs-retry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fs-retry.js","sourceRoot":"","sources":["../../src/utils/fs-retry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indy2kro/agentenv",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI for configuring a consistent, capable shell environment for AI coding agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,6 +27,7 @@
27
27
  "start": "ts-node src/index.ts",
28
28
  "dev": "ts-node-dev src/index.ts",
29
29
  "test": "npm run build && cd dist && node --test",
30
+ "test:coverage": "npm run build && cd dist && node --experimental-test-coverage --test-coverage-lines=80 --test-coverage-branches=75 --test-coverage-functions=80 --test",
30
31
  "smoke": "npm run build && node scripts/smoke.mjs",
31
32
  "smoke:real": "npm run build && node scripts/smoke.mjs --real",
32
33
  "lint": "eslint src --max-warnings 0",