aicodeman 1.24.4 → 1.24.6

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 (174) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config/cli-registry/argv.d.ts +44 -0
  5. package/dist/config/cli-registry/argv.d.ts.map +1 -0
  6. package/dist/config/cli-registry/argv.js +157 -0
  7. package/dist/config/cli-registry/argv.js.map +1 -0
  8. package/dist/config/cli-registry/index.d.ts +17 -0
  9. package/dist/config/cli-registry/index.d.ts.map +1 -0
  10. package/dist/config/cli-registry/index.js +11 -0
  11. package/dist/config/cli-registry/index.js.map +1 -0
  12. package/dist/config/cli-registry/patterns.d.ts +42 -0
  13. package/dist/config/cli-registry/patterns.d.ts.map +1 -0
  14. package/dist/config/cli-registry/patterns.js +104 -0
  15. package/dist/config/cli-registry/patterns.js.map +1 -0
  16. package/dist/config/cli-registry/profiles.d.ts +74 -0
  17. package/dist/config/cli-registry/profiles.d.ts.map +1 -0
  18. package/dist/config/cli-registry/profiles.js +90 -0
  19. package/dist/config/cli-registry/profiles.js.map +1 -0
  20. package/dist/config/cli-registry/registry.d.ts +63 -0
  21. package/dist/config/cli-registry/registry.d.ts.map +1 -0
  22. package/dist/config/cli-registry/registry.js +216 -0
  23. package/dist/config/cli-registry/registry.js.map +1 -0
  24. package/dist/config/cli-registry/schema.d.ts +259 -0
  25. package/dist/config/cli-registry/schema.d.ts.map +1 -0
  26. package/dist/config/cli-registry/schema.js +398 -0
  27. package/dist/config/cli-registry/schema.js.map +1 -0
  28. package/dist/config/cli-registry/stock.d.ts +15 -0
  29. package/dist/config/cli-registry/stock.d.ts.map +1 -0
  30. package/dist/config/cli-registry/stock.js +996 -0
  31. package/dist/config/cli-registry/stock.js.map +1 -0
  32. package/dist/config/cli-registry/types.d.ts +565 -0
  33. package/dist/config/cli-registry/types.d.ts.map +1 -0
  34. package/dist/config/cli-registry/types.js +13 -0
  35. package/dist/config/cli-registry/types.js.map +1 -0
  36. package/dist/config/dependency-registry.d.ts +12 -1
  37. package/dist/config/dependency-registry.d.ts.map +1 -1
  38. package/dist/config/dependency-registry.js +155 -203
  39. package/dist/config/dependency-registry.js.map +1 -1
  40. package/dist/cron/cron-service.d.ts.map +1 -1
  41. package/dist/cron/cron-service.js +51 -17
  42. package/dist/cron/cron-service.js.map +1 -1
  43. package/dist/docker-hosts.d.ts +9 -1
  44. package/dist/docker-hosts.d.ts.map +1 -1
  45. package/dist/docker-hosts.js +25 -17
  46. package/dist/docker-hosts.js.map +1 -1
  47. package/dist/remote-hosts.d.ts +73 -0
  48. package/dist/remote-hosts.d.ts.map +1 -1
  49. package/dist/remote-hosts.js +139 -45
  50. package/dist/remote-hosts.js.map +1 -1
  51. package/dist/remote-reconnect.d.ts +10 -1
  52. package/dist/remote-reconnect.d.ts.map +1 -1
  53. package/dist/remote-reconnect.js +9 -0
  54. package/dist/remote-reconnect.js.map +1 -1
  55. package/dist/session-cli-registry-bridge.d.ts +66 -0
  56. package/dist/session-cli-registry-bridge.d.ts.map +1 -0
  57. package/dist/session-cli-registry-bridge.js +165 -0
  58. package/dist/session-cli-registry-bridge.js.map +1 -0
  59. package/dist/session.d.ts +13 -1
  60. package/dist/session.d.ts.map +1 -1
  61. package/dist/session.js +69 -76
  62. package/dist/session.js.map +1 -1
  63. package/dist/tmux-manager.d.ts +50 -35
  64. package/dist/tmux-manager.d.ts.map +1 -1
  65. package/dist/tmux-manager.js +258 -623
  66. package/dist/tmux-manager.js.map +1 -1
  67. package/dist/utils/antigravity-cli-resolver.d.ts.map +1 -1
  68. package/dist/utils/antigravity-cli-resolver.js +8 -10
  69. package/dist/utils/antigravity-cli-resolver.js.map +1 -1
  70. package/dist/utils/cli-executable-resolver.d.ts +9 -1
  71. package/dist/utils/cli-executable-resolver.d.ts.map +1 -1
  72. package/dist/utils/cli-executable-resolver.js +3 -2
  73. package/dist/utils/cli-executable-resolver.js.map +1 -1
  74. package/dist/utils/cli-launcher.d.ts +46 -0
  75. package/dist/utils/cli-launcher.d.ts.map +1 -0
  76. package/dist/utils/cli-launcher.js +101 -0
  77. package/dist/utils/cli-launcher.js.map +1 -0
  78. package/dist/utils/cli-resolver.d.ts +101 -0
  79. package/dist/utils/cli-resolver.d.ts.map +1 -0
  80. package/dist/utils/cli-resolver.js +220 -0
  81. package/dist/utils/cli-resolver.js.map +1 -0
  82. package/dist/utils/codex-cli-resolver.d.ts.map +1 -1
  83. package/dist/utils/codex-cli-resolver.js +8 -11
  84. package/dist/utils/codex-cli-resolver.js.map +1 -1
  85. package/dist/utils/deepseek-cli-resolver.d.ts.map +1 -1
  86. package/dist/utils/deepseek-cli-resolver.js +8 -6
  87. package/dist/utils/deepseek-cli-resolver.js.map +1 -1
  88. package/dist/utils/gemini-cli-resolver.d.ts.map +1 -1
  89. package/dist/utils/gemini-cli-resolver.js +8 -10
  90. package/dist/utils/gemini-cli-resolver.js.map +1 -1
  91. package/dist/utils/grok-cli-resolver.js +8 -8
  92. package/dist/utils/grok-cli-resolver.js.map +1 -1
  93. package/dist/utils/omp-cli-resolver.d.ts.map +1 -1
  94. package/dist/utils/omp-cli-resolver.js +10 -15
  95. package/dist/utils/omp-cli-resolver.js.map +1 -1
  96. package/dist/utils/opencode-cli-resolver.d.ts.map +1 -1
  97. package/dist/utils/opencode-cli-resolver.js +8 -11
  98. package/dist/utils/opencode-cli-resolver.js.map +1 -1
  99. package/dist/utils/pi-cli-resolver.d.ts.map +1 -1
  100. package/dist/utils/pi-cli-resolver.js +8 -9
  101. package/dist/utils/pi-cli-resolver.js.map +1 -1
  102. package/dist/web/public/admin-ui.js.gz +0 -0
  103. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  104. package/dist/web/public/app.a5d2fc08.js.gz +0 -0
  105. package/dist/web/public/approvals-ui.js.gz +0 -0
  106. package/dist/web/public/constants.7bd482dc.js.gz +0 -0
  107. package/dist/web/public/cron-ui.js.gz +0 -0
  108. package/dist/web/public/entrance-animations.js.gz +0 -0
  109. package/dist/web/public/home-sessions.js.gz +0 -0
  110. package/dist/web/public/i18n.9ae15b51.js.gz +0 -0
  111. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  112. package/dist/web/public/index.html +9 -2
  113. package/dist/web/public/index.html.br +0 -0
  114. package/dist/web/public/index.html.gz +0 -0
  115. package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
  116. package/dist/web/public/keyboard-accessory.0454a3e9.js.gz +0 -0
  117. package/dist/web/public/mobile-handlers.0f83a608.js.gz +0 -0
  118. package/dist/web/public/mobile-overview.js.gz +0 -0
  119. package/dist/web/public/mobile.87674154.css.gz +0 -0
  120. package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
  121. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  122. package/dist/web/public/panels-ui.e6e06034.js.gz +0 -0
  123. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  124. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  125. package/dist/web/public/readmymind-ui.js.gz +0 -0
  126. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  127. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  128. package/dist/web/public/session-lineage.js.gz +0 -0
  129. package/dist/web/public/session-ui.c558f981.js.gz +0 -0
  130. package/dist/web/public/{settings-ui.2a814a17.js → settings-ui.95b333c6.js} +1 -1
  131. package/dist/web/public/settings-ui.95b333c6.js.br +0 -0
  132. package/dist/web/public/settings-ui.95b333c6.js.gz +0 -0
  133. package/dist/web/public/styles.421b36d4.css.gz +0 -0
  134. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  135. package/dist/web/public/sw.js.gz +0 -0
  136. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  137. package/dist/web/public/terminal-ui.70445f81.js.gz +0 -0
  138. package/dist/web/public/ultracode-panel.js.gz +0 -0
  139. package/dist/web/public/ultracode-windows.js.gz +0 -0
  140. package/dist/web/public/upload.html.gz +0 -0
  141. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  142. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  143. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  144. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  145. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  146. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  147. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  148. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  149. package/dist/web/public/vendor/xterm.css.gz +0 -0
  150. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  151. package/dist/web/public/voice-input.4ec670b0.js.gz +0 -0
  152. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  153. package/dist/web/public/webview-tabs.js.gz +0 -0
  154. package/dist/web/routes/cron-routes.d.ts.map +1 -1
  155. package/dist/web/routes/cron-routes.js +3 -2
  156. package/dist/web/routes/cron-routes.js.map +1 -1
  157. package/dist/web/routes/session-routes.d.ts +8 -34
  158. package/dist/web/routes/session-routes.d.ts.map +1 -1
  159. package/dist/web/routes/session-routes.js +164 -251
  160. package/dist/web/routes/session-routes.js.map +1 -1
  161. package/dist/web/routes/system-routes.d.ts.map +1 -1
  162. package/dist/web/routes/system-routes.js +2 -1
  163. package/dist/web/routes/system-routes.js.map +1 -1
  164. package/dist/web/schemas.d.ts +12 -48
  165. package/dist/web/schemas.d.ts.map +1 -1
  166. package/dist/web/schemas.js +82 -37
  167. package/dist/web/schemas.js.map +1 -1
  168. package/dist/web/session-wait-registry.d.ts +1 -1
  169. package/dist/web/session-wait-registry.d.ts.map +1 -1
  170. package/dist/web/session-wait-registry.js +20 -12
  171. package/dist/web/session-wait-registry.js.map +1 -1
  172. package/package.json +1 -1
  173. package/dist/web/public/settings-ui.2a814a17.js.br +0 -0
  174. package/dist/web/public/settings-ui.2a814a17.js.gz +0 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @fileoverview Named value patterns for the CLI registry's argv engine.
3
+ *
4
+ * Config entries select a pattern BY NAME; the regexes themselves live here, in code.
5
+ * That is deliberate and is the reason a user-editable `clis.json` cannot widen its own
6
+ * validation: there is no field anywhere in the schema that accepts a raw regex for a
7
+ * shell token, so no entry can supply `.*` (nor a catastrophically backtracking one).
8
+ *
9
+ * The sole user-supplied regex in the whole registry is `discovery.version.regex`, which
10
+ * is applied to `--version` OUTPUT rather than to a shell token, and goes through
11
+ * `compileVersionRegex()` below.
12
+ *
13
+ * Every pattern here is transcribed from the builder it replaces in tmux-manager.ts, so
14
+ * the argv engine accepts and rejects exactly the values the hand-written builders did.
15
+ *
16
+ * @module config/cli-registry/patterns
17
+ */
18
+ /**
19
+ * The patterns, each traced to the builder it came from.
20
+ *
21
+ * ⚠️ These are ALLOWLISTS (`^...$` over a safe character class), never blocklists — with
22
+ * one deliberate exception, `tool-list`, which mirrors the existing `--allowedTools`
23
+ * sanitizer. That one is a metacharacter REJECTION because tool specs legitimately contain
24
+ * `(`, `)`, `*`, `:` and spaces (`Bash(git:*), Read`), so an allowlist of safe words cannot
25
+ * express it. Keeping it byte-identical to the original matters more than making it uniform.
26
+ */
27
+ const PATTERNS = {
28
+ // buildOpenCodeCommand / buildCodexCommand / buildGeminiCommand / buildAntigravityCommand
29
+ model: /^[a-zA-Z0-9._\-/]+$/,
30
+ // buildSpawnCommand's claude branch — `[` and `]` for bracketed model aliases
31
+ 'model-claude': /^[a-zA-Z0-9._\-[\]]+$/,
32
+ // buildPiCommand — `:` for a thinking suffix (`sonnet:high`), `/` for `provider/id`
33
+ 'model-pi': /^[a-zA-Z0-9._\-/:]+$/,
34
+ // opencode --session, codex resume
35
+ id: /^[a-zA-Z0-9_-]+$/,
36
+ // gemini --resume, antigravity --conversation, pi --session
37
+ 'id-dotted': /^[a-zA-Z0-9._-]+$/,
38
+ // claude --resume / --session-id
39
+ uuid: /^[a-f0-9-]+$/,
40
+ // pi --provider
41
+ slug: /^[a-z0-9-]+$/,
42
+ // dsh --profile. Deliberately STRICTER than `id-dotted`: a profile name is both
43
+ // interpolated into the shell line AND joined into a filesystem path, so it must be a
44
+ // single path segment. Requiring a leading alphanumeric is what rules out `.`, `..` and
45
+ // dotfile names, which `id-dotted` would happily accept.
46
+ 'path-segment': /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/,
47
+ // codex --config tui.animations=false
48
+ 'config-kv': /^[A-Za-z0-9._-]+=[A-Za-z0-9._-]+$/,
49
+ // Placeholder; `tool-list` is handled by isSafeToolList() below, not by a match.
50
+ 'tool-list': /^$/,
51
+ };
52
+ /**
53
+ * Shell metacharacters rejected in an `--allowedTools` value. Transcribed verbatim from
54
+ * buildClaudePermissionFlags so the accepted set does not move.
55
+ */
56
+ const TOOL_LIST_DANGEROUS = /[;&|$`\\{}<>'"[\]\n\r]/;
57
+ /** Does `value` satisfy the named pattern? */
58
+ export function matchesPattern(pattern, value) {
59
+ if (pattern === 'tool-list')
60
+ return value.length > 0 && !TOOL_LIST_DANGEROUS.test(value);
61
+ return PATTERNS[pattern].test(value);
62
+ }
63
+ /** Every pattern name, for schema validation and error messages. */
64
+ export const TOKEN_PATTERNS = Object.keys(PATTERNS);
65
+ /**
66
+ * Characters a token may contain and still be emitted UNQUOTED into the `bash -c "..."`
67
+ * command string. Intentionally narrower than "what bash tolerates": anything outside it
68
+ * gets single-quoted, so the classification can only ever err toward more quoting.
69
+ */
70
+ export const SAFE_BARE_TOKEN = /^[A-Za-z0-9._:@=+/,-]+$/;
71
+ /**
72
+ * Longest `--version` output we will run a user-supplied regex over. A version banner is a
73
+ * line or two; anything larger is a misconfiguration, and capping the input is what keeps a
74
+ * sloppy (not necessarily malicious) regex from becoming a stall.
75
+ */
76
+ export const MAX_VERSION_OUTPUT = 200;
77
+ /** Longest permitted `discovery.version.regex` source. */
78
+ const MAX_VERSION_REGEX_SOURCE = 200;
79
+ /**
80
+ * Nested quantifiers — `(a+)+`, `(a*)*`, `(a+)*` and friends — the classic catastrophic
81
+ * backtracking shape. Rejected outright rather than analysed: this field exists to pull a
82
+ * semver out of a banner, and nothing legitimate for that job needs a nested quantifier.
83
+ */
84
+ const NESTED_QUANTIFIER = /\([^)]*[+*][^)]*\)\s*[+*{]/;
85
+ /**
86
+ * Compile a user-supplied version regex, or return null if it is not one we are willing to
87
+ * run. Returning null (rather than throwing) lets the caller degrade to "version unknown",
88
+ * which every consumer already handles.
89
+ */
90
+ export function compileVersionRegex(source) {
91
+ if (source.length > MAX_VERSION_REGEX_SOURCE)
92
+ return null;
93
+ if (NESTED_QUANTIFIER.test(source))
94
+ return null;
95
+ try {
96
+ // No `g`: a global regex carries lastIndex state across calls, which is a documented
97
+ // footgun in this codebase (see utils/regex-patterns.ts).
98
+ return new RegExp(source);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/config/cli-registry/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAeH;;;;;;;;GAQG;AACH,MAAM,QAAQ,GAAiC;IAC7C,0FAA0F;IAC1F,KAAK,EAAE,qBAAqB;IAC5B,8EAA8E;IAC9E,cAAc,EAAE,uBAAuB;IACvC,oFAAoF;IACpF,UAAU,EAAE,sBAAsB;IAClC,mCAAmC;IACnC,EAAE,EAAE,kBAAkB;IACtB,4DAA4D;IAC5D,WAAW,EAAE,mBAAmB;IAChC,iCAAiC;IACjC,IAAI,EAAE,cAAc;IACpB,gBAAgB;IAChB,IAAI,EAAE,cAAc;IACpB,gFAAgF;IAChF,sFAAsF;IACtF,wFAAwF;IACxF,yDAAyD;IACzD,cAAc,EAAE,8BAA8B;IAC9C,sCAAsC;IACtC,WAAW,EAAE,mCAAmC;IAChD,iFAAiF;IACjF,WAAW,EAAE,IAAI;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAErD,8CAA8C;AAC9C,MAAM,UAAU,cAAc,CAAC,OAAqB,EAAE,KAAa;IACjE,IAAI,OAAO,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAmB,CAAC;AAEtE;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC,0DAA0D;AAC1D,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAErC;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,IAAI,MAAM,CAAC,MAAM,GAAG,wBAAwB;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,CAAC;QACH,qFAAqF;QACrF,0DAA0D;QAC1D,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @fileoverview The NAMES of code profiles a `CliEntry` field may select, and the helpers
3
+ * that validate them.
4
+ *
5
+ * A profile is the escape hatch for behaviour that is genuinely code-shaped and cannot be
6
+ * expressed as data — codex's predictive write-through echo, deepseek's profile-launcher
7
+ * runnability check, deepseek's status bridge — without letting any of that code branch on
8
+ * a CLI's id. A registry field names a profile; the implementation lives beside whatever it
9
+ * needs, and looks its name up here.
10
+ *
11
+ * ⚠️ This module is PURE and must stay that way: names, types and predicates only, no
12
+ * imports outside this directory. The implementations pull in resolvers and the status
13
+ * shim, which in turn reach back into the registry, so holding them here would close an
14
+ * import cycle (profiles → deepseek-cli-resolver → cli-resolver → registry → schema →
15
+ * profiles). Keeping the names here and the implementations at their call sites is what
16
+ * lets `schema.ts` validate a profile name at LOAD time — a custom entry naming a profile
17
+ * this build does not implement fails loudly instead of silently failing closed later.
18
+ *
19
+ * The rule all of this enforces: `test/cli-registry-no-id-branching.test.ts` fails on any
20
+ * `mode === '<stock id>'` comparison outside `stock.ts`, so a NEW behavioural special case
21
+ * must be added here, named, and referenced from a registry field — never inlined as an id
22
+ * check at the call site.
23
+ *
24
+ * ⚠️ A profile is a LAST resort, not a convenience. Reach for one only when the behaviour
25
+ * needs to run code (a side effect, a computed value, a probe); anything that is a list, a
26
+ * flag, or a string belongs in the entry as data, where a custom CLI can also use it.
27
+ *
28
+ * @module config/cli-registry/profiles
29
+ */
30
+ /**
31
+ * Predictive local-echo profiles, selected via `capabilities.echo.predictProfile`.
32
+ *
33
+ * Implementation: packages/xterm-zerolag-input/src/predictive-echo-addon.ts.
34
+ *
35
+ * ⚠️ Unlike the other two registries, an unknown name here degrades to the 'buffer' policy
36
+ * rather than failing. Echo is a comfort feature — a worse-but-working overlay beats a
37
+ * refused session — which is why `predictProfile` alone is not schema-validated below.
38
+ */
39
+ export declare const PREDICT_PROFILES: Record<string, true>;
40
+ /**
41
+ * Launcher profiles, selected via `discovery.launcherProfile`.
42
+ *
43
+ * For a CLI whose binary launches some further target, and so cannot answer two questions
44
+ * from the binary alone: is it RUNNABLE (stricter than "is the binary on disk?"), and what
45
+ * is the DEFAULT target when the caller names none? A CLI naming no profile is runnable
46
+ * exactly when its binary resolves, and has no default target.
47
+ *
48
+ * Implementation: `src/utils/cli-launcher.ts`.
49
+ */
50
+ export declare const LAUNCHER_PROFILE_NAMES: readonly ["deepseek-profile"];
51
+ /**
52
+ * Extra `tmux setenv` work, selected via `env.setenvProfile`.
53
+ *
54
+ * Implementation: `src/tmux-manager.ts`, which already owns every setenv call.
55
+ *
56
+ * ⚠️ Anything that is merely "forward this name from the server's own env" belongs in
57
+ * `env.tmuxSetenvKeys` as data and must NOT be given a profile.
58
+ */
59
+ export declare const SETENV_PROFILE_NAMES: readonly ["deepseek-status-bridge"];
60
+ export type LauncherProfileName = (typeof LAUNCHER_PROFILE_NAMES)[number];
61
+ export type SetenvProfileName = (typeof SETENV_PROFILE_NAMES)[number];
62
+ /**
63
+ * Transcript readers, selected via `capabilities.transcript`. Unlike the profile registries
64
+ * above this one is closed over the schema enum itself rather than an open string, since
65
+ * transcript format is a small, genuinely fixed set — see CliCapabilities['transcript'].
66
+ */
67
+ export declare const TRANSCRIPT_READER_NAMES: readonly ["claude-jsonl", "codex-rollout", "deepseek-zstd", "none"];
68
+ /** Composer-row finders, selected via `capabilities.echo.anchor.kind`. Also schema-closed. */
69
+ export declare const COMPOSER_ANCHOR_KINDS: readonly ["glyph", "cursor", "none"];
70
+ /** True when `name` is a predictive-echo profile this build actually implements. */
71
+ export declare function isKnownPredictProfile(name: string | undefined): boolean;
72
+ export declare function isKnownLauncherProfile(name: string): name is LauncherProfileName;
73
+ export declare function isKnownSetenvProfile(name: string): name is SetenvProfileName;
74
+ //# sourceMappingURL=profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../../src/config/cli-registry/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAEjD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,+BAIzB,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,qCAMvB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,qEAAsE,CAAC;AAE3G,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,sCAAuC,CAAC;AAE1E,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,mBAAmB,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,iBAAiB,CAE5E"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @fileoverview The NAMES of code profiles a `CliEntry` field may select, and the helpers
3
+ * that validate them.
4
+ *
5
+ * A profile is the escape hatch for behaviour that is genuinely code-shaped and cannot be
6
+ * expressed as data — codex's predictive write-through echo, deepseek's profile-launcher
7
+ * runnability check, deepseek's status bridge — without letting any of that code branch on
8
+ * a CLI's id. A registry field names a profile; the implementation lives beside whatever it
9
+ * needs, and looks its name up here.
10
+ *
11
+ * ⚠️ This module is PURE and must stay that way: names, types and predicates only, no
12
+ * imports outside this directory. The implementations pull in resolvers and the status
13
+ * shim, which in turn reach back into the registry, so holding them here would close an
14
+ * import cycle (profiles → deepseek-cli-resolver → cli-resolver → registry → schema →
15
+ * profiles). Keeping the names here and the implementations at their call sites is what
16
+ * lets `schema.ts` validate a profile name at LOAD time — a custom entry naming a profile
17
+ * this build does not implement fails loudly instead of silently failing closed later.
18
+ *
19
+ * The rule all of this enforces: `test/cli-registry-no-id-branching.test.ts` fails on any
20
+ * `mode === '<stock id>'` comparison outside `stock.ts`, so a NEW behavioural special case
21
+ * must be added here, named, and referenced from a registry field — never inlined as an id
22
+ * check at the call site.
23
+ *
24
+ * ⚠️ A profile is a LAST resort, not a convenience. Reach for one only when the behaviour
25
+ * needs to run code (a side effect, a computed value, a probe); anything that is a list, a
26
+ * flag, or a string belongs in the entry as data, where a custom CLI can also use it.
27
+ *
28
+ * @module config/cli-registry/profiles
29
+ */
30
+ /**
31
+ * Predictive local-echo profiles, selected via `capabilities.echo.predictProfile`.
32
+ *
33
+ * Implementation: packages/xterm-zerolag-input/src/predictive-echo-addon.ts.
34
+ *
35
+ * ⚠️ Unlike the other two registries, an unknown name here degrades to the 'buffer' policy
36
+ * rather than failing. Echo is a comfort feature — a worse-but-working overlay beats a
37
+ * refused session — which is why `predictProfile` alone is not schema-validated below.
38
+ */
39
+ export const PREDICT_PROFILES = {
40
+ codex: true,
41
+ };
42
+ /**
43
+ * Launcher profiles, selected via `discovery.launcherProfile`.
44
+ *
45
+ * For a CLI whose binary launches some further target, and so cannot answer two questions
46
+ * from the binary alone: is it RUNNABLE (stricter than "is the binary on disk?"), and what
47
+ * is the DEFAULT target when the caller names none? A CLI naming no profile is runnable
48
+ * exactly when its binary resolves, and has no default target.
49
+ *
50
+ * Implementation: `src/utils/cli-launcher.ts`.
51
+ */
52
+ export const LAUNCHER_PROFILE_NAMES = [
53
+ // `dsh` is a launcher over $DSH_HOME/profiles/<name>, and the profiles DeepSeek itself
54
+ // ships (web, headless) cannot drive a terminal pane. Binary AND a pane-capable profile.
55
+ 'deepseek-profile',
56
+ ];
57
+ /**
58
+ * Extra `tmux setenv` work, selected via `env.setenvProfile`.
59
+ *
60
+ * Implementation: `src/tmux-manager.ts`, which already owns every setenv call.
61
+ *
62
+ * ⚠️ Anything that is merely "forward this name from the server's own env" belongs in
63
+ * `env.tmuxSetenvKeys` as data and must NOT be given a profile.
64
+ */
65
+ export const SETENV_PROFILE_NAMES = [
66
+ // DeepSeek's terminal front door reports idle/working/blocked to a supervisor over the
67
+ // generic env-gated Herdr contract; this makes Codeman that supervisor. It needs a
68
+ // profile rather than key names because it writes an executable shim to disk and then
69
+ // exports that shim's path along with the session's own pane id.
70
+ 'deepseek-status-bridge',
71
+ ];
72
+ /**
73
+ * Transcript readers, selected via `capabilities.transcript`. Unlike the profile registries
74
+ * above this one is closed over the schema enum itself rather than an open string, since
75
+ * transcript format is a small, genuinely fixed set — see CliCapabilities['transcript'].
76
+ */
77
+ export const TRANSCRIPT_READER_NAMES = ['claude-jsonl', 'codex-rollout', 'deepseek-zstd', 'none'];
78
+ /** Composer-row finders, selected via `capabilities.echo.anchor.kind`. Also schema-closed. */
79
+ export const COMPOSER_ANCHOR_KINDS = ['glyph', 'cursor', 'none'];
80
+ /** True when `name` is a predictive-echo profile this build actually implements. */
81
+ export function isKnownPredictProfile(name) {
82
+ return name !== undefined && Object.prototype.hasOwnProperty.call(PREDICT_PROFILES, name);
83
+ }
84
+ export function isKnownLauncherProfile(name) {
85
+ return LAUNCHER_PROFILE_NAMES.includes(name);
86
+ }
87
+ export function isKnownSetenvProfile(name) {
88
+ return SETENV_PROFILE_NAMES.includes(name);
89
+ }
90
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../../src/config/cli-registry/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAyB;IACpD,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,uFAAuF;IACvF,yFAAyF;IACzF,kBAAkB;CACV,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,uFAAuF;IACvF,mFAAmF;IACnF,sFAAsF;IACtF,iEAAiE;IACjE,wBAAwB;CAChB,CAAC;AAKX;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,CAAU,CAAC;AAE3G,8FAA8F;AAC9F,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAE1E,oFAAoF;AACpF,MAAM,UAAU,qBAAqB,CAAC,IAAwB;IAC5D,OAAO,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAQ,sBAA4C,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAQ,oBAA0C,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACpE,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @fileoverview Loads, merges and re-validates the CLI registry.
3
+ *
4
+ * `~/.codeman/clis.json` holds OVERRIDES and CUSTOM entries only — never a full copy of the
5
+ * stock catalog — so a shipped fix to a stock definition actually reaches an existing
6
+ * install, and the file stays small enough to hand-edit.
7
+ *
8
+ * Resolution: start from `STOCK_CLIS` → deep-merge each override by id (objects merge
9
+ * key-wise, arrays replace wholesale) → validate every resulting entry. A stock entry that
10
+ * fails validation after merge falls back to its pristine stock definition (a fat-fingered
11
+ * override cannot brick a shipped CLI); a custom entry that fails is dropped with a warning
12
+ * rather than failing the whole load. Stock entries are always emitted, so `shell` and
13
+ * `claude` can be disabled but can never go missing — large parts of the app assume at
14
+ * minimum that a shell fallback exists.
15
+ *
16
+ * ⚠️ READ-ONLY. Nothing in this module writes, creates or migrates the file. That is a
17
+ * deliberate property, not a missing feature: there is no settings UI and no write API yet,
18
+ * so there is nothing to persist, and it means importing the registry — which
19
+ * `src/web/schemas.ts` does, transitively, just to validate a request — performs no
20
+ * filesystem writes. A `seededStockIds` ratchet belongs with the write API that needs it.
21
+ * The one exception is the quarantine RENAME of a file that fails to parse (see
22
+ * `readRegistryFile`), which happens on first use rather than at import.
23
+ *
24
+ * ⚠️ The file must be mode 0600. `isUnsafePermissions` refuses ANY group/world bit, read
25
+ * bits included, so a file created with a normal umask (0644) is ignored. Every reason the
26
+ * file was ignored, or an entry in it dropped, is logged ONCE on first load: the warnings
27
+ * used to be returned to a caller that nobody wired up, so a normally-created file was
28
+ * ignored with no feedback anywhere (found reviewing #347).
29
+ *
30
+ * @module config/cli-registry/registry
31
+ */
32
+ import type { CliEntry, CliId, CliRegistryFile } from './types.js';
33
+ /** Construct a validated CliId. Throws if `raw` is not a well-formed id — call at API boundaries. */
34
+ export declare function asCliId(raw: string): CliId;
35
+ export interface LoadResult {
36
+ entries: CliEntry[];
37
+ warnings: string[];
38
+ }
39
+ /**
40
+ * Merge the stock catalog with a (possibly absent) registry file. PURE — no IO, which is
41
+ * what lets the load tests drive every merge case directly.
42
+ */
43
+ export declare function resolveRegistry(stock: CliEntry[], file: CliRegistryFile | null, warnings: string[]): LoadResult;
44
+ /**
45
+ * Load the effective registry (stock + user overrides). Memoized for the process lifetime;
46
+ * `reloadCliRegistry()` invalidates.
47
+ */
48
+ export declare function loadCliRegistry(): LoadResult;
49
+ /** Drop the memoized registry so the next `loadCliRegistry()` re-reads the file. */
50
+ export declare function reloadCliRegistry(): void;
51
+ export declare function listClis(): CliEntry[];
52
+ export declare function enabledClis(): CliEntry[];
53
+ export declare function getCli(id: string): CliEntry | undefined;
54
+ export declare function cliIds(): string[];
55
+ /** Every enabled entry's id, in registry order. */
56
+ export declare function enabledCliIds(): string[];
57
+ /**
58
+ * Resolve the install command for the current platform, falling back to the linux one (the
59
+ * common case for a `curl | bash` or `npm install -g` line) and then to whatever is
60
+ * declared. Display text only — never executed. See CliDiscovery.install.command.
61
+ */
62
+ export declare function resolveInstallCommandForPlatform(entry: CliEntry): string | undefined;
63
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/config/cli-registry/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAInE,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAK1C;AAkCD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA2DD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,CAoC/G;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAS5C;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,wBAAgB,QAAQ,IAAI,QAAQ,EAAE,CAErC;AAED,wBAAgB,WAAW,IAAI,QAAQ,EAAE,CAExC;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAEvD;AAED,wBAAgB,MAAM,IAAI,MAAM,EAAE,CAEjC;AAED,mDAAmD;AACnD,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAExC;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAIpF"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @fileoverview Loads, merges and re-validates the CLI registry.
3
+ *
4
+ * `~/.codeman/clis.json` holds OVERRIDES and CUSTOM entries only — never a full copy of the
5
+ * stock catalog — so a shipped fix to a stock definition actually reaches an existing
6
+ * install, and the file stays small enough to hand-edit.
7
+ *
8
+ * Resolution: start from `STOCK_CLIS` → deep-merge each override by id (objects merge
9
+ * key-wise, arrays replace wholesale) → validate every resulting entry. A stock entry that
10
+ * fails validation after merge falls back to its pristine stock definition (a fat-fingered
11
+ * override cannot brick a shipped CLI); a custom entry that fails is dropped with a warning
12
+ * rather than failing the whole load. Stock entries are always emitted, so `shell` and
13
+ * `claude` can be disabled but can never go missing — large parts of the app assume at
14
+ * minimum that a shell fallback exists.
15
+ *
16
+ * ⚠️ READ-ONLY. Nothing in this module writes, creates or migrates the file. That is a
17
+ * deliberate property, not a missing feature: there is no settings UI and no write API yet,
18
+ * so there is nothing to persist, and it means importing the registry — which
19
+ * `src/web/schemas.ts` does, transitively, just to validate a request — performs no
20
+ * filesystem writes. A `seededStockIds` ratchet belongs with the write API that needs it.
21
+ * The one exception is the quarantine RENAME of a file that fails to parse (see
22
+ * `readRegistryFile`), which happens on first use rather than at import.
23
+ *
24
+ * ⚠️ The file must be mode 0600. `isUnsafePermissions` refuses ANY group/world bit, read
25
+ * bits included, so a file created with a normal umask (0644) is ignored. Every reason the
26
+ * file was ignored, or an entry in it dropped, is logged ONCE on first load: the warnings
27
+ * used to be returned to a caller that nobody wired up, so a normally-created file was
28
+ * ignored with no feedback anywhere (found reviewing #347).
29
+ *
30
+ * @module config/cli-registry/registry
31
+ */
32
+ import { existsSync, readFileSync, renameSync, statSync } from 'node:fs';
33
+ import { dataPath } from '../instance.js';
34
+ import { CliEntrySchema } from './schema.js';
35
+ import { STOCK_CLIS } from './stock.js';
36
+ /** Construct a validated CliId. Throws if `raw` is not a well-formed id — call at API boundaries. */
37
+ export function asCliId(raw) {
38
+ if (!/^[a-z][a-z0-9-]{0,23}$/.test(raw)) {
39
+ throw new Error(`invalid CLI id: ${JSON.stringify(raw)}`);
40
+ }
41
+ return raw;
42
+ }
43
+ function filePath() {
44
+ return dataPath('clis.json');
45
+ }
46
+ /**
47
+ * Keys that must never be merged out of a hand-editable JSON file.
48
+ *
49
+ * `JSON.parse` produces `__proto__` as an ORDINARY own property, but `result[key] = …` on a
50
+ * plain object walks the setter chain and would set the merged object's PROTOTYPE instead.
51
+ * Not exploitable today — every merged entry is spread into `{ ...merged, id, stock }` and
52
+ * then Zod-parsed before anything reads it, which drops the effect — but "not exploitable
53
+ * because of what a caller happens to do afterwards" is a property that quietly stops
54
+ * holding. A `continue` in the loop that reads the file is the cheap end of that trade.
55
+ */
56
+ const UNMERGEABLE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
57
+ /** Plain-object deep merge: nested objects merge key-wise, arrays and primitives replace. */
58
+ function deepMerge(base, override) {
59
+ if (override === null || typeof override !== 'object' || Array.isArray(override)) {
60
+ return (override === undefined ? base : override) ?? base;
61
+ }
62
+ if (base === null || typeof base !== 'object' || Array.isArray(base)) {
63
+ return override;
64
+ }
65
+ const result = { ...base };
66
+ for (const [key, value] of Object.entries(override)) {
67
+ if (UNMERGEABLE_KEYS.has(key))
68
+ continue;
69
+ result[key] = deepMerge(base[key], value);
70
+ }
71
+ return result;
72
+ }
73
+ /**
74
+ * Refuse a registry file with any group/world permission bit — same posture as the ssh-key
75
+ * discipline, so 0600 is the only accepted mode. This file selects the binaries Codeman
76
+ * spawns, so a writable one is a way to redirect every session.
77
+ *
78
+ * POSIX only: Windows has no meaningful group/world bits on NTFS (Node reports every file
79
+ * as mode 0o666 there regardless of its actual ACL), so this check would flag every file on
80
+ * Windows and silently ignore all user config. `win32` relies on NTFS ACLs instead, which
81
+ * this check cannot see and does not attempt to.
82
+ */
83
+ function isUnsafePermissions(path) {
84
+ if (process.platform === 'win32')
85
+ return false;
86
+ try {
87
+ const mode = statSync(path).mode & 0o777;
88
+ return (mode & 0o077) !== 0;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ function readRegistryFile(path, warnings) {
95
+ if (!existsSync(path))
96
+ return null;
97
+ if (isUnsafePermissions(path)) {
98
+ warnings.push(`${path} must be mode 0600 (no group/world permission bits; run \`chmod 600 ${path}\`); ignoring it and falling back to stock CLIs.`);
99
+ return null;
100
+ }
101
+ let raw;
102
+ try {
103
+ raw = readFileSync(path, 'utf-8');
104
+ }
105
+ catch (err) {
106
+ warnings.push(`Failed to read ${path}: ${err.message}. Falling back to stock CLIs.`);
107
+ return null;
108
+ }
109
+ try {
110
+ const parsed = JSON.parse(raw);
111
+ if (typeof parsed !== 'object' || parsed === null || typeof parsed.clis !== 'object') {
112
+ throw new Error('missing "clis" object');
113
+ }
114
+ return parsed;
115
+ }
116
+ catch (err) {
117
+ // QUARANTINE, never overwrite: the file is hand-editable, so a syntax error is far more
118
+ // likely to be a half-finished edit than junk. Renaming keeps the user's work.
119
+ const quarantined = `${path}.invalid-${Date.now()}`;
120
+ try {
121
+ renameSync(path, quarantined);
122
+ warnings.push(`${path} was not valid JSON (${err.message}); moved to ${quarantined}.`);
123
+ }
124
+ catch {
125
+ warnings.push(`${path} was not valid JSON (${err.message}); left in place, falling back to stock CLIs.`);
126
+ }
127
+ return null;
128
+ }
129
+ }
130
+ /**
131
+ * Merge the stock catalog with a (possibly absent) registry file. PURE — no IO, which is
132
+ * what lets the load tests drive every merge case directly.
133
+ */
134
+ export function resolveRegistry(stock, file, warnings) {
135
+ const stockById = new Map(stock.map((e) => [e.id, e]));
136
+ const overrides = file?.clis ?? {};
137
+ const entries = [];
138
+ for (const stockEntry of stock) {
139
+ const id = stockEntry.id;
140
+ const override = overrides[id];
141
+ const merged = override ? deepMerge(stockEntry, override) : stockEntry;
142
+ // `stock: true` is forced here rather than read from the merged object, so an override
143
+ // can never flip a custom entry's provenance or vice versa.
144
+ const parsed = CliEntrySchema.safeParse({ ...merged, id, stock: true });
145
+ if (parsed.success) {
146
+ entries.push(parsed.data);
147
+ }
148
+ else {
149
+ warnings.push(`Override for stock CLI "${id}" failed validation; using the shipped definition. ${parsed.error.message}`);
150
+ entries.push(stockEntry);
151
+ }
152
+ }
153
+ for (const [id, raw] of Object.entries(overrides)) {
154
+ if (stockById.has(id))
155
+ continue; // already merged above
156
+ // Same forcing in the other direction: a custom entry claiming `stock: true` cannot
157
+ // shadow or impersonate a shipped one.
158
+ const parsed = CliEntrySchema.safeParse({ ...raw, id, stock: false });
159
+ if (parsed.success) {
160
+ entries.push(parsed.data);
161
+ }
162
+ else {
163
+ warnings.push(`Custom CLI "${id}" failed validation and was dropped. ${parsed.error.message}`);
164
+ }
165
+ }
166
+ entries.sort((a, b) => a.order - b.order);
167
+ return { entries, warnings };
168
+ }
169
+ let cache = null;
170
+ /**
171
+ * Load the effective registry (stock + user overrides). Memoized for the process lifetime;
172
+ * `reloadCliRegistry()` invalidates.
173
+ */
174
+ export function loadCliRegistry() {
175
+ if (cache)
176
+ return cache;
177
+ const warnings = [];
178
+ const existing = readRegistryFile(filePath(), warnings);
179
+ cache = resolveRegistry(STOCK_CLIS, existing, warnings);
180
+ // Once per process (the result is memoized): silence here is what made a 0644 file look
181
+ // like "the override feature does nothing".
182
+ for (const warning of warnings)
183
+ console.warn(`[cli-registry] ${warning}`);
184
+ return cache;
185
+ }
186
+ /** Drop the memoized registry so the next `loadCliRegistry()` re-reads the file. */
187
+ export function reloadCliRegistry() {
188
+ cache = null;
189
+ }
190
+ export function listClis() {
191
+ return loadCliRegistry().entries;
192
+ }
193
+ export function enabledClis() {
194
+ return listClis().filter((e) => e.enabled);
195
+ }
196
+ export function getCli(id) {
197
+ return listClis().find((e) => e.id === id);
198
+ }
199
+ export function cliIds() {
200
+ return listClis().map((e) => e.id);
201
+ }
202
+ /** Every enabled entry's id, in registry order. */
203
+ export function enabledCliIds() {
204
+ return enabledClis().map((e) => e.id);
205
+ }
206
+ /**
207
+ * Resolve the install command for the current platform, falling back to the linux one (the
208
+ * common case for a `curl | bash` or `npm install -g` line) and then to whatever is
209
+ * declared. Display text only — never executed. See CliDiscovery.install.command.
210
+ */
211
+ export function resolveInstallCommandForPlatform(entry) {
212
+ const { command } = entry.discovery.install;
213
+ const platform = process.platform;
214
+ return command[platform] ?? command.linux ?? Object.values(command)[0];
215
+ }
216
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/config/cli-registry/registry.ts"],"names":[],"mappings":"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"}