dsh-zen-remote 2.3.11 → 2.4.0

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 (244) hide show
  1. package/CHANGELOG.md +39 -78
  2. package/README.md +94 -84
  3. package/README.zh-CN.md +90 -81
  4. package/bin/zen-remote.mjs +5 -0
  5. package/docs/interface.md +6 -6
  6. package/docs/remote-access.en.md +6 -4
  7. package/docs/remote-access.md +6 -4
  8. package/dsh-push.mjs +96 -10
  9. package/lib/adapters/dsh-better-sidebar/index.js +7 -3
  10. package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
  11. package/lib/admin-routes.js +10 -2
  12. package/lib/admin-routes.js.map +1 -1
  13. package/lib/cli/args.js +251 -0
  14. package/lib/cli/args.js.map +1 -0
  15. package/lib/cli/bootstrap.js +449 -0
  16. package/lib/cli/bootstrap.js.map +1 -0
  17. package/lib/cli/command-setup.js +484 -0
  18. package/lib/cli/command-setup.js.map +1 -0
  19. package/lib/cli/commands-client.js +359 -0
  20. package/lib/cli/commands-client.js.map +1 -0
  21. package/lib/cli/commands-host.js +1108 -0
  22. package/lib/cli/commands-host.js.map +1 -0
  23. package/lib/cli/commands-status.js +279 -0
  24. package/lib/cli/commands-status.js.map +1 -0
  25. package/lib/cli/config-writer.js +334 -0
  26. package/lib/cli/config-writer.js.map +1 -0
  27. package/lib/cli/context.js +10 -0
  28. package/lib/cli/context.js.map +1 -0
  29. package/lib/cli/i18n.js +620 -0
  30. package/lib/cli/i18n.js.map +1 -0
  31. package/lib/cli/ipc-client.js +160 -0
  32. package/lib/cli/ipc-client.js.map +1 -0
  33. package/lib/cli/ipc-server.js +464 -0
  34. package/lib/cli/ipc-server.js.map +1 -0
  35. package/lib/cli/main.js +245 -0
  36. package/lib/cli/main.js.map +1 -0
  37. package/lib/cli/qr-terminal.js +48 -0
  38. package/lib/cli/qr-terminal.js.map +1 -0
  39. package/lib/client-data/qr.js +286 -0
  40. package/lib/client-data/qr.js.map +1 -0
  41. package/lib/client-routes.js +308 -25
  42. package/lib/client-routes.js.map +1 -1
  43. package/lib/client.js +1013 -229
  44. package/lib/config.js +50 -12
  45. package/lib/config.js.map +1 -1
  46. package/lib/debug-report.js +28 -1
  47. package/lib/debug-report.js.map +1 -1
  48. package/lib/fetch-route-intercept.js +334 -26
  49. package/lib/fetch-route-intercept.js.map +1 -1
  50. package/lib/index.js +564 -363
  51. package/lib/index.js.map +1 -1
  52. package/lib/intercept.js +1833 -280
  53. package/lib/intercept.js.map +1 -1
  54. package/lib/lan-gate-server.cjs +36 -10
  55. package/lib/merge-streams.js +103 -11
  56. package/lib/merge-streams.js.map +1 -1
  57. package/lib/plugin-route-intercept.js +93 -63
  58. package/lib/plugin-route-intercept.js.map +1 -1
  59. package/lib/relay-access.js +8 -1
  60. package/lib/relay-access.js.map +1 -1
  61. package/lib/relay-client.js +133 -4
  62. package/lib/relay-client.js.map +1 -1
  63. package/lib/relay-pool.js +275 -0
  64. package/lib/relay-pool.js.map +1 -0
  65. package/lib/relay-server.js +269 -17
  66. package/lib/relay-server.js.map +1 -1
  67. package/lib/restart-fields.js +6 -4
  68. package/lib/restart-fields.js.map +1 -1
  69. package/lib/share-store.js +65 -27
  70. package/lib/share-store.js.map +1 -1
  71. package/lib/state-store.js +400 -0
  72. package/lib/state-store.js.map +1 -0
  73. package/lib/types/adapters/dsh-better-sidebar/index.d.ts +3 -2
  74. package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
  75. package/lib/types/admin-routes.d.ts.map +1 -1
  76. package/lib/types/cli/args.d.ts +78 -0
  77. package/lib/types/cli/args.d.ts.map +1 -0
  78. package/lib/types/cli/bootstrap.d.ts +170 -0
  79. package/lib/types/cli/bootstrap.d.ts.map +1 -0
  80. package/lib/types/cli/command-setup.d.ts +72 -0
  81. package/lib/types/cli/command-setup.d.ts.map +1 -0
  82. package/lib/types/cli/commands-client.d.ts +36 -0
  83. package/lib/types/cli/commands-client.d.ts.map +1 -0
  84. package/lib/types/cli/commands-host.d.ts +82 -0
  85. package/lib/types/cli/commands-host.d.ts.map +1 -0
  86. package/lib/types/cli/commands-status.d.ts +46 -0
  87. package/lib/types/cli/commands-status.d.ts.map +1 -0
  88. package/lib/types/cli/config-writer.d.ts +92 -0
  89. package/lib/types/cli/config-writer.d.ts.map +1 -0
  90. package/lib/types/cli/context.d.ts +39 -0
  91. package/lib/types/cli/context.d.ts.map +1 -0
  92. package/lib/types/cli/i18n.d.ts +32 -0
  93. package/lib/types/cli/i18n.d.ts.map +1 -0
  94. package/lib/types/cli/ipc-client.d.ts +83 -0
  95. package/lib/types/cli/ipc-client.d.ts.map +1 -0
  96. package/lib/types/cli/ipc-server.d.ts +113 -0
  97. package/lib/types/cli/ipc-server.d.ts.map +1 -0
  98. package/lib/types/cli/main.d.ts +57 -0
  99. package/lib/types/cli/main.d.ts.map +1 -0
  100. package/lib/types/cli/qr-terminal.d.ts +17 -0
  101. package/lib/types/cli/qr-terminal.d.ts.map +1 -0
  102. package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -1
  103. package/lib/types/client/current-session-report.d.ts +4 -0
  104. package/lib/types/client/current-session-report.d.ts.map +1 -1
  105. package/lib/types/client/effects/model-group-side.d.ts.map +1 -1
  106. package/lib/types/client/effects/remote-session.d.ts.map +1 -1
  107. package/lib/types/client/locales.d.ts +47 -3
  108. package/lib/types/client/locales.d.ts.map +1 -1
  109. package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
  110. package/lib/types/client/settings/settings-css.d.ts +1 -1
  111. package/lib/types/client/settings/settings-css.d.ts.map +1 -1
  112. package/lib/types/client/styles/remote-session.css.d.ts +1 -1
  113. package/lib/types/client/styles/remote-session.css.d.ts.map +1 -1
  114. package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -1
  115. package/lib/types/client/wizard/cards/ProxyCard.d.ts.map +1 -1
  116. package/lib/types/client/wizard/wizard-css.d.ts +1 -1
  117. package/lib/types/client/wizard/wizard-css.d.ts.map +1 -1
  118. package/lib/types/client-data/model-group-side.d.ts +23 -2
  119. package/lib/types/client-data/model-group-side.d.ts.map +1 -1
  120. package/lib/types/client-data/remote-status.d.ts +47 -1
  121. package/lib/types/client-data/remote-status.d.ts.map +1 -1
  122. package/lib/types/client-data/settings-form.d.ts +85 -1
  123. package/lib/types/client-data/settings-form.d.ts.map +1 -1
  124. package/lib/types/client-data/wizard.d.ts +56 -1
  125. package/lib/types/client-data/wizard.d.ts.map +1 -1
  126. package/lib/types/client-routes.d.ts +25 -1
  127. package/lib/types/client-routes.d.ts.map +1 -1
  128. package/lib/types/config.d.ts +40 -14
  129. package/lib/types/config.d.ts.map +1 -1
  130. package/lib/types/debug-report.d.ts.map +1 -1
  131. package/lib/types/fetch-route-intercept.d.ts +66 -8
  132. package/lib/types/fetch-route-intercept.d.ts.map +1 -1
  133. package/lib/types/index.d.ts +9 -2
  134. package/lib/types/index.d.ts.map +1 -1
  135. package/lib/types/intercept.d.ts +72 -10
  136. package/lib/types/intercept.d.ts.map +1 -1
  137. package/lib/types/merge-streams.d.ts +79 -1
  138. package/lib/types/merge-streams.d.ts.map +1 -1
  139. package/lib/types/plugin-route-intercept.d.ts +25 -9
  140. package/lib/types/plugin-route-intercept.d.ts.map +1 -1
  141. package/lib/types/relay-access.d.ts +3 -1
  142. package/lib/types/relay-access.d.ts.map +1 -1
  143. package/lib/types/relay-client.d.ts +23 -2
  144. package/lib/types/relay-client.d.ts.map +1 -1
  145. package/lib/types/relay-pool.d.ts +148 -0
  146. package/lib/types/relay-pool.d.ts.map +1 -0
  147. package/lib/types/relay-server.d.ts +30 -3
  148. package/lib/types/relay-server.d.ts.map +1 -1
  149. package/lib/types/restart-fields.d.ts +5 -5
  150. package/lib/types/restart-fields.d.ts.map +1 -1
  151. package/lib/types/share-store.d.ts.map +1 -1
  152. package/lib/types/state-store.d.ts +179 -0
  153. package/lib/types/state-store.d.ts.map +1 -0
  154. package/lib/types/upload-limits.d.ts +15 -0
  155. package/lib/types/upload-limits.d.ts.map +1 -1
  156. package/lib/types/virtual-id.d.ts +21 -0
  157. package/lib/types/virtual-id.d.ts.map +1 -1
  158. package/lib/types/wizard/probe.d.ts.map +1 -1
  159. package/lib/types/wizard/proxy-snippets.d.ts +3 -0
  160. package/lib/types/wizard/proxy-snippets.d.ts.map +1 -1
  161. package/lib/types/wizard/routes.d.ts +1 -0
  162. package/lib/types/wizard/routes.d.ts.map +1 -1
  163. package/lib/types/wizard/status.d.ts +9 -0
  164. package/lib/types/wizard/status.d.ts.map +1 -1
  165. package/lib/types/wizard/verify.d.ts +3 -0
  166. package/lib/types/wizard/verify.d.ts.map +1 -1
  167. package/lib/upload-limits.js +15 -0
  168. package/lib/upload-limits.js.map +1 -1
  169. package/lib/virtual-id.js +60 -0
  170. package/lib/virtual-id.js.map +1 -1
  171. package/lib/wizard/probe.js +46 -1
  172. package/lib/wizard/probe.js.map +1 -1
  173. package/lib/wizard/proxy-snippets.js +14 -1
  174. package/lib/wizard/proxy-snippets.js.map +1 -1
  175. package/lib/wizard/routes.js +23 -4
  176. package/lib/wizard/routes.js.map +1 -1
  177. package/lib/wizard/status.js +21 -0
  178. package/lib/wizard/status.js.map +1 -1
  179. package/lib/wizard/verify.js +31 -8
  180. package/lib/wizard/verify.js.map +1 -1
  181. package/package.json +8 -4
  182. package/pwa/icons/badge-96.png +0 -0
  183. package/pwa/icons/badge.svg +1 -0
  184. package/pwa/manifest.json +2 -1
  185. package/pwa/sw.js +3 -1
  186. package/scripts/check-debug-report.mjs +41 -1
  187. package/scripts/check-settings-form.mjs +14 -3
  188. package/scripts/check-settings-view.mjs +247 -0
  189. package/scripts/check-wizard-ui.mjs +37 -0
  190. package/src/adapters/dsh-better-sidebar/index.ts +7 -3
  191. package/src/admin-routes.ts +10 -2
  192. package/src/cli/args.ts +289 -0
  193. package/src/cli/bootstrap.ts +569 -0
  194. package/src/cli/command-setup.ts +540 -0
  195. package/src/cli/commands-client.ts +369 -0
  196. package/src/cli/commands-host.ts +1127 -0
  197. package/src/cli/commands-status.ts +296 -0
  198. package/src/cli/config-writer.ts +354 -0
  199. package/src/cli/context.ts +38 -0
  200. package/src/cli/i18n.ts +645 -0
  201. package/src/cli/ipc-client.ts +216 -0
  202. package/src/cli/ipc-server.ts +531 -0
  203. package/src/cli/main.ts +285 -0
  204. package/src/cli/qr-terminal.ts +49 -0
  205. package/src/client/RemoteStatusIcon.tsx +4 -1
  206. package/src/client/current-session-report.ts +28 -4
  207. package/src/client/effects/model-group-side.ts +19 -5
  208. package/src/client/effects/remote-session.ts +26 -6
  209. package/src/client/locales.ts +96 -6
  210. package/src/client/settings/SettingsSection.tsx +287 -92
  211. package/src/client/settings/settings-css.ts +18 -0
  212. package/src/client/styles/remote-session.css.ts +15 -1
  213. package/src/client/wizard/GatewayWizard.tsx +470 -109
  214. package/src/client/wizard/cards/ProxyCard.tsx +2 -1
  215. package/src/client/wizard/wizard-css.ts +23 -0
  216. package/src/client-data/model-group-side.ts +37 -10
  217. package/src/client-data/remote-status.ts +112 -17
  218. package/src/client-data/settings-form.ts +164 -8
  219. package/src/client-data/wizard.ts +112 -2
  220. package/src/client-routes.ts +334 -26
  221. package/src/config.ts +62 -16
  222. package/src/debug-report.ts +27 -1
  223. package/src/fetch-route-intercept.ts +381 -32
  224. package/src/index.ts +566 -367
  225. package/src/intercept.ts +1866 -286
  226. package/src/merge-streams.ts +155 -10
  227. package/src/plugin-route-intercept.ts +120 -71
  228. package/src/relay-access.ts +14 -3
  229. package/src/relay-client.ts +163 -5
  230. package/src/relay-pool.ts +387 -0
  231. package/src/relay-server.ts +312 -16
  232. package/src/restart-fields.ts +6 -4
  233. package/src/share-store.ts +59 -26
  234. package/src/state-store.ts +428 -0
  235. package/src/upload-limits.ts +16 -0
  236. package/src/virtual-id.ts +57 -0
  237. package/src/wizard/probe.ts +54 -2
  238. package/src/wizard/proxy-snippets.ts +17 -2
  239. package/src/wizard/routes.ts +24 -5
  240. package/src/wizard/status.ts +28 -0
  241. package/src/wizard/verify.ts +33 -11
  242. package/AGENTS.md +0 -185
  243. package/docs/adr/0001-plugin-bridge-forwards-plugin-routes.md +0 -15
  244. package/docs/adr/0002-relay-emulates-websocket.md +0 -8
@@ -0,0 +1,334 @@
1
+ /**
2
+ * The CLI's anti-shadowing config writer (CLI-1).
3
+ *
4
+ * `resolveConfig` reads four layers in the order env > row > file > default
5
+ * (src/config.ts). A CLI write lands in the FILE layer
6
+ * (`<dshHome>/lan-gate.config.json`), so two layers can silently swallow it:
7
+ * an environment variable set at the top, and a value the loader put on the
8
+ * plugin row (persisted in the current profile's `cordis.patch.yml`). The
9
+ * writer refuses the first case with the exact variable name, and REMOVES the
10
+ * shadowing keys in the other two — the in-memory row object `apply()` still
11
+ * holds, and the `dsh-zen-remote` `config:` block of every profile patch file
12
+ * it can find — so the just-written file value is what the next
13
+ * `resolveConfig` answers. `onAfterWrite` then lets the caller (the IPC
14
+ * delegate in src/index.ts) trigger the restart watcher immediately, so a
15
+ * restart-required field reloads the row without waiting out the 2s poll.
16
+ *
17
+ * The file is read from `dshHome` DIRECTLY, not through `readFileConfig(env)`:
18
+ * the latter resolves `<env.DSH_HOME ?? ~/.dsh>` and would silently read the
19
+ * developer's real file when a test passes an explicit dshHome with an empty
20
+ * env — resolution and the write must never disagree about which file is the
21
+ * truth.
22
+ *
23
+ * The `cordis.patch.yml` edit is line-based on purpose: the files are
24
+ * user-owned YAML full of comments and hand-tuned formatting that a
25
+ * parse-serialize round trip would destroy, and the edit itself (delete a
26
+ * key line and its indented children from one plugin's config block) is a
27
+ * purely textual operation.
28
+ */
29
+ import { chmodSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';
30
+ import { join } from 'node:path';
31
+ import { resolveConfig } from '../config.js';
32
+ /**
33
+ * The env variable each config field answers to, for fields that HAVE one.
34
+ * Fields without an entry (role, serverName, idleHours, the wizard's ingress
35
+ * fields, pluginBridgeConsent — src/config.ts explains each absence) can
36
+ * never be env-shadowed, so they are deliberately missing: `writeCliConfig`
37
+ * falls back to the field name itself when asked for one.
38
+ */
39
+ export const ENV_VAR_BY_FIELD = {
40
+ port: 'LAN_GATE_PORT',
41
+ host: 'LAN_GATE_HOST',
42
+ targetPort: 'LAN_GATE_TARGET_PORT',
43
+ rateLimit: 'LAN_GATE_RATE_LIMIT',
44
+ trustedProxies: 'LAN_GATE_TRUSTED_PROXIES',
45
+ vapidSubject: 'LAN_GATE_VAPID_SUBJECT',
46
+ lang: 'LAN_GATE_LANG',
47
+ pushEvents: 'DSH_PUSH_EVENTS',
48
+ pushDebounceMs: 'DSH_PUSH_DEBOUNCE_MS',
49
+ pushSummary: 'DSH_PUSH_SUMMARY',
50
+ pushTurnEnd: 'DSH_PUSH_TURN_END',
51
+ pushTool: 'DSH_PUSH_TOOL',
52
+ pushEnabled: 'DSH_PUSH_ENABLED',
53
+ pushSessionName: 'DSH_PUSH_SESSION_NAME',
54
+ };
55
+ /**
56
+ * Keys that CLI explicitly wrote to `lan-gate.config.json` and unshadowed in
57
+ * `cordis.patch.yml` during this process lifetime, keyed by `dshHome`. When
58
+ * `fiber.restart()` reloads the plugin row, `cordis-plugin-loader` re-hydrates
59
+ * the new `config` object from its in-memory patch snapshot (without
60
+ * re-reading `cordis.patch.yml` from disk), which would otherwise re-shadow
61
+ * the file layer with stale `{ get() }` wrappers. `applyUnshadowedRowKeys`
62
+ * strips those stale wrappers on the reloaded `apply()`, and a subsequent
63
+ * Web UI save (`loader/volatile-update`) clears them via
64
+ * `clearUnshadowedRowKeys`.
65
+ */
66
+ const unshadowedByHome = new Map();
67
+ export function applyUnshadowedRowKeys(dshHome, row) {
68
+ if (row === undefined || row === null || typeof row !== 'object')
69
+ return;
70
+ const keys = unshadowedByHome.get(dshHome);
71
+ if (keys === undefined)
72
+ return;
73
+ for (const key of keys) {
74
+ const val = row[key];
75
+ if (val !== null && typeof val === 'object' && typeof val.get === 'function') {
76
+ delete row[key];
77
+ }
78
+ }
79
+ }
80
+ export function clearUnshadowedRowKeys(dshHome, keys) {
81
+ const set = unshadowedByHome.get(dshHome);
82
+ if (set === undefined)
83
+ return;
84
+ for (const key of keys)
85
+ set.delete(key);
86
+ }
87
+ /** Read `<dshHome>/lan-gate.config.json` — `{}` when absent or unparsable,
88
+ * the same degrade-not-throw contract as src/config.ts's readFileConfig. */
89
+ function readFileAt(dshHome) {
90
+ try {
91
+ const parsed = JSON.parse(readFileSync(join(dshHome, 'lan-gate.config.json'), 'utf8'));
92
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
93
+ return {};
94
+ return parsed;
95
+ }
96
+ catch {
97
+ return {};
98
+ }
99
+ }
100
+ /** Atomic 0600 rewrite: tmp + explicit chmod + rename, so a crash mid-write
101
+ * can never leave a half file behind (the discipline of the wizard's
102
+ * trust-proxy persister). */
103
+ function writeJsonAtomic(dshHome, body) {
104
+ const file = join(dshHome, 'lan-gate.config.json');
105
+ try {
106
+ mkdirSync(dshHome, { recursive: true });
107
+ }
108
+ catch { /* an existing directory or an unwritable one — the write below reports it */ }
109
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
110
+ writeFileSync(tmp, `${JSON.stringify(body, null, 2)}\n`, { mode: 0o600 });
111
+ chmodSync(tmp, 0o600);
112
+ renameSync(tmp, file);
113
+ }
114
+ /** The candidate `cordis.patch.yml` paths: the named profile first (when
115
+ * given), then every profile's patch file found on disk — deduplicated, and
116
+ * only files that actually exist (the editor never CREATES one). */
117
+ function patchFileCandidates(dshHome, profileName) {
118
+ const out = [];
119
+ const push = (candidate) => {
120
+ if (!out.includes(candidate) && existsQuiet(candidate))
121
+ out.push(candidate);
122
+ };
123
+ if (profileName !== undefined && profileName !== '') {
124
+ push(join(dshHome, 'profiles', profileName, 'cordis.patch.yml'));
125
+ }
126
+ const profilesDir = join(dshHome, 'profiles');
127
+ try {
128
+ for (const entry of readdirSync(profilesDir, { withFileTypes: true })) {
129
+ if (!entry.isDirectory())
130
+ continue;
131
+ if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name === 'desktop')
132
+ continue;
133
+ push(join(profilesDir, entry.name, 'cordis.patch.yml'));
134
+ }
135
+ }
136
+ catch { /* no profiles directory — nothing to scan */ }
137
+ return out;
138
+ }
139
+ function existsQuiet(path) {
140
+ try {
141
+ statSync(path);
142
+ return true;
143
+ }
144
+ catch {
145
+ return false;
146
+ }
147
+ }
148
+ function leadingSpaces(line) {
149
+ const match = /^[ \t]*/u.exec(line);
150
+ return match === null ? 0 : match[0].length;
151
+ }
152
+ function escapeRegExp(text) {
153
+ return text.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
154
+ }
155
+ /**
156
+ * Remove `keys` from EVERY `- id: dsh-zen-remote` (or bare `id:`) entry's
157
+ * `config:` block, purely textually: a key line and its deeper-indented
158
+ * children disappear, every other line — comments, other plugins' blocks,
159
+ * formatting — survives byte for byte. A block emptied by the removal keeps
160
+ * a `config: {}` line (an entry with no config key at all changes loader
161
+ * semantics). No match, no change: the same string comes back.
162
+ */
163
+ export function unshadowPatchYml(text, keys) {
164
+ if (keys.length === 0)
165
+ return text;
166
+ const lines = text.split('\n');
167
+ const toDelete = new Set();
168
+ const toReplace = new Map();
169
+ for (let i = 0; i < lines.length; i += 1) {
170
+ // The id line: an optional dash + `id: dsh-zen-remote`, trailing comment
171
+ // allowed (`- id: agent-default-model # magpie` shows the shape). The
172
+ // id KEY's column is the prefix length — `config:` sits at that column.
173
+ const idMatch = /^([ \t]*(?:-[ \t]+)?)(id):[ \t]*dsh-zen-remote[ \t]*(?:#.*)?$/u.exec(lines[i]);
174
+ if (idMatch === null)
175
+ continue;
176
+ const keyIndent = idMatch[1].length;
177
+ // The entry's `config:` line: the first `config:` at the id column
178
+ // before the entry ends (a shallower line starts the next entry).
179
+ let configLine = -1;
180
+ let configIndent = -1;
181
+ for (let j = i + 1; j < lines.length; j += 1) {
182
+ const line = lines[j];
183
+ if (line.trim() === '')
184
+ continue;
185
+ const indent = leadingSpaces(line);
186
+ if (indent < keyIndent)
187
+ break;
188
+ if (indent === keyIndent && /^[ \t]*config[ \t]*:(\s|$|#)/u.test(line)) {
189
+ configLine = j;
190
+ configIndent = indent;
191
+ break;
192
+ }
193
+ }
194
+ if (configLine === -1)
195
+ continue;
196
+ // The config block: every following line deeper than the config column
197
+ // (blank lines skipped — they belong to no key). The shallowest indent
198
+ // inside the block is where its top-level keys sit.
199
+ let blockEnd = configLine + 1;
200
+ let minIndent = Number.POSITIVE_INFINITY;
201
+ while (blockEnd < lines.length) {
202
+ const line = lines[blockEnd];
203
+ if (line.trim() === '') {
204
+ blockEnd += 1;
205
+ continue;
206
+ }
207
+ const indent = leadingSpaces(line);
208
+ if (indent <= configIndent)
209
+ break;
210
+ if (indent < minIndent)
211
+ minIndent = indent;
212
+ blockEnd += 1;
213
+ }
214
+ if (!Number.isFinite(minIndent))
215
+ continue;
216
+ for (const key of keys) {
217
+ const keyLine = new RegExp(`^([ \\t]*)${escapeRegExp(key)}[ \\t]*:(\\s|$|#)`, 'u');
218
+ for (let j = configLine + 1; j < blockEnd; j += 1) {
219
+ if (toDelete.has(j))
220
+ continue;
221
+ const line = lines[j];
222
+ if (line.trim() === '')
223
+ continue;
224
+ const indent = leadingSpaces(line);
225
+ if (indent !== minIndent || !keyLine.test(line))
226
+ continue;
227
+ toDelete.add(j);
228
+ // The key's children (deeper-indented lists/maps) go with it.
229
+ for (let q = j + 1; q < blockEnd; q += 1) {
230
+ const child = lines[q];
231
+ if (child.trim() === '')
232
+ continue;
233
+ if (leadingSpaces(child) <= indent)
234
+ break;
235
+ toDelete.add(q);
236
+ }
237
+ }
238
+ }
239
+ // Emptied block → keep a `config: {}` line so the entry's shape survives.
240
+ let remains = false;
241
+ for (let j = configLine + 1; j < blockEnd; j += 1) {
242
+ if (!toDelete.has(j) && lines[j].trim() !== '') {
243
+ remains = true;
244
+ break;
245
+ }
246
+ }
247
+ if (!remains)
248
+ toReplace.set(configLine, `${' '.repeat(configIndent)}config: {}`);
249
+ }
250
+ if (toDelete.size === 0 && toReplace.size === 0)
251
+ return text;
252
+ const out = [];
253
+ for (let i = 0; i < lines.length; i += 1) {
254
+ const replacement = toReplace.get(i);
255
+ if (replacement !== undefined)
256
+ out.push(replacement);
257
+ else if (!toDelete.has(i))
258
+ out.push(lines[i]);
259
+ }
260
+ return out.join('\n');
261
+ }
262
+ /**
263
+ * Write CLI config changes through the anti-shadowing pipeline. Returns the
264
+ * refused `env-shadowed` verdict (with the exact field and its variable
265
+ * name) WITHOUT touching any file, or the freshly resolved effective values
266
+ * after the write, the row-key deletions and the patch-file un-shadowing.
267
+ */
268
+ export function writeCliConfig(options) {
269
+ const env = options.env ?? process.env;
270
+ const row = options.row ?? {};
271
+ const set = options.set ?? {};
272
+ const unset = options.unset ?? [];
273
+ const setKeys = Object.keys(set);
274
+ const targetKeys = [...setKeys, ...unset];
275
+ if (targetKeys.length > 0) {
276
+ // Step 1 — the env layer is untouchable from here: a field whose CURRENT
277
+ // effective source is `env` (a legal value lives in a LAN_GATE_* /
278
+ // DSH_PUSH_* variable) refuses the write outright, naming the variable.
279
+ const snapshot = resolveConfig(row, readFileAt(options.dshHome), env);
280
+ const sources = snapshot.sources;
281
+ for (const key of targetKeys) {
282
+ if (sources[key] !== 'env')
283
+ continue;
284
+ return { ok: false, code: 'env-shadowed', field: key, envVar: ENV_VAR_BY_FIELD[key] ?? key };
285
+ }
286
+ // Step 2 — the file layer: merge / delete the keys atomically (0600).
287
+ const merged = { ...readFileAt(options.dshHome) };
288
+ for (const key of setKeys)
289
+ merged[key] = set[key];
290
+ for (const key of unset)
291
+ delete merged[key];
292
+ writeJsonAtomic(options.dshHome, merged);
293
+ // Step 3a — the row layer: the loader wrapped the row's volatile fields
294
+ // in `{ get() }` references, but they are still plain own properties of
295
+ // the same object apply() holds — a delete makes the NEXT resolveConfig
296
+ // fall through this layer to the freshly written file. Record the keys
297
+ // for this `dshHome` so a subsequent `fiber.restart()` also strips the
298
+ // loader's re-hydrated in-memory `{ get() }` wrappers.
299
+ let remembered = unshadowedByHome.get(options.dshHome);
300
+ if (remembered === undefined) {
301
+ remembered = new Set();
302
+ unshadowedByHome.set(options.dshHome, remembered);
303
+ }
304
+ for (const key of targetKeys) {
305
+ remembered.add(key);
306
+ if (key in row)
307
+ delete row[key];
308
+ }
309
+ // Step 3b — the persisted row layer: the profile patch files the loader
310
+ // itself writes when a settings save pins a key on the plugin row.
311
+ for (const file of patchFileCandidates(options.dshHome, options.profileName)) {
312
+ try {
313
+ const before = readFileSync(file, 'utf8');
314
+ const after = unshadowPatchYml(before, targetKeys);
315
+ if (after === before)
316
+ continue;
317
+ let mode = 0o644;
318
+ try {
319
+ mode = statSync(file).mode & 0o777;
320
+ }
321
+ catch { /* keep the default */ }
322
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
323
+ writeFileSync(tmp, after, { mode });
324
+ renameSync(tmp, file);
325
+ }
326
+ catch { /* one unreadable profile never blocks the others */ }
327
+ }
328
+ options.onAfterWrite?.();
329
+ }
330
+ // Step 4 — the caller's reload hook fired; answer the values the layers
331
+ // resolve to NOW (the file layer just moved; the row keys just left).
332
+ return { ok: true, values: resolveConfig(row, readFileAt(options.dshHome), env).values };
333
+ }
334
+ //# sourceMappingURL=config-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-writer.js","sourceRoot":"","sources":["../../src/cli/config-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC9G,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAG5C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA6D;IACxF,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,eAAe;IACrB,UAAU,EAAE,sBAAsB;IAClC,SAAS,EAAE,qBAAqB;IAChC,cAAc,EAAE,0BAA0B;IAC1C,YAAY,EAAE,wBAAwB;IACtC,IAAI,EAAE,eAAe;IACrB,UAAU,EAAE,iBAAiB;IAC7B,cAAc,EAAE,sBAAsB;IACtC,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EAAE,mBAAmB;IAChC,QAAQ,EAAE,eAAe;IACzB,WAAW,EAAE,kBAAkB;IAC/B,eAAe,EAAE,uBAAuB;CACzC,CAAA;AAkCD;;;;;;;;;;GAUG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAuB,CAAA;AAEvD,MAAM,UAAU,sBAAsB,CAAC,OAAe,EAAE,GAAwC;IAC9F,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAM;IACxE,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,IAAI,KAAK,SAAS;QAAE,OAAM;IAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;QACpB,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAQ,GAAyB,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;YACpG,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAe,EAAE,IAAuB;IAC7E,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACzC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAM;IAC7B,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACzC,CAAC;AAED;4EAC4E;AAC5E,SAAS,UAAU,CAAC,OAAe;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;QAC/F,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAA;QACrF,OAAO,MAAiC,CAAA;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;6BAE6B;AAC7B,SAAS,eAAe,CAAC,OAAe,EAAE,IAA6B;IACrE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAA;IAClD,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC,CAAC,6EAA6E,CAAC,CAAC;IACzF,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;IACtD,aAAa,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACzE,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACrB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;oEAEoE;AACpE,SAAS,mBAAmB,CAAC,OAAe,EAAE,WAA+B;IAC3E,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,CAAC,SAAiB,EAAQ,EAAE;QACvC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,SAAS,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC7E,CAAC,CAAA;IACD,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC7C,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAQ;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;gBAAE,SAAQ;YACrG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,6CAA6C,CAAC,CAAC;IACzD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;AAC7C,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAuB;IACpE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,yEAAyE;QACzE,sEAAsE;QACtE,wEAAwE;QACxE,MAAM,OAAO,GAAG,gEAAgE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/F,IAAI,OAAO,KAAK,IAAI;YAAE,SAAQ;QAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;QAEnC,mEAAmE;QACnE,kEAAkE;QAClE,IAAI,UAAU,GAAG,CAAC,CAAC,CAAA;QACnB,IAAI,YAAY,GAAG,CAAC,CAAC,CAAA;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAQ;YAChC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;YAClC,IAAI,MAAM,GAAG,SAAS;gBAAE,MAAK;YAC7B,IAAI,MAAM,KAAK,SAAS,IAAI,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvE,UAAU,GAAG,CAAC,CAAA;gBACd,YAAY,GAAG,MAAM,CAAA;gBACrB,MAAK;YACP,CAAC;QACH,CAAC;QACD,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,SAAQ;QAE/B,uEAAuE;QACvE,uEAAuE;QACvE,oDAAoD;QACpD,IAAI,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAA;QAC7B,IAAI,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAA;QACxC,OAAO,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;YAC5B,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBACvB,QAAQ,IAAI,CAAC,CAAA;gBACb,SAAQ;YACV,CAAC;YACD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;YAClC,IAAI,MAAM,IAAI,YAAY;gBAAE,MAAK;YACjC,IAAI,MAAM,GAAG,SAAS;gBAAE,SAAS,GAAG,MAAM,CAAA;YAC1C,QAAQ,IAAI,CAAC,CAAA;QACf,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAQ;QAEzC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,aAAa,YAAY,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAA;YAClF,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClD,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,SAAQ;gBAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;gBACrB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;oBAAE,SAAQ;gBAChC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;gBAClC,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,SAAQ;gBACzD,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gBACf,8DAA8D;gBAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;oBACtB,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;wBAAE,SAAQ;oBACjC,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,MAAM;wBAAE,MAAK;oBACzC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;QACD,0EAA0E;QAC1E,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC/C,OAAO,GAAG,IAAI,CAAA;gBACd,MAAK;YACP,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;IAClF,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5D,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACpC,IAAI,WAAW,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;aAC/C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAA;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAA;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAA;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChC,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC,CAAA;IAEzC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,yEAAyE;QACzE,mEAAmE;QACnE,wEAAwE;QACxE,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAA;QACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAuC,CAAA;QAChE,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK;gBAAE,SAAQ;YACpC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAA4B,CAAC,IAAI,GAAG,EAAE,CAAA;QACvH,CAAC;QAED,sEAAsE;QACtE,MAAM,MAAM,GAA4B,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAA;QAC1E,KAAK,MAAM,GAAG,IAAI,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;QACjD,KAAK,MAAM,GAAG,IAAI,KAAK;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;QAC3C,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAExC,wEAAwE;QACxE,wEAAwE;QACxE,wEAAwE;QACxE,uEAAuE;QACvE,uEAAuE;QACvE,uDAAuD;QACvD,IAAI,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACtD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;YAC9B,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QACnD,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACnB,IAAI,GAAG,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;QACjC,CAAC;QAED,wEAAwE;QACxE,mEAAmE;QACnE,KAAK,MAAM,IAAI,IAAI,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7E,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBACzC,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;gBAClD,IAAI,KAAK,KAAK,MAAM;oBAAE,SAAQ;gBAC9B,IAAI,IAAI,GAAG,KAAK,CAAA;gBAChB,IAAI,CAAC;oBACH,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,CAAA;gBACpC,CAAC;gBAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;gBAClC,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;gBACtD,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;gBACnC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YACvB,CAAC;YAAC,MAAM,CAAC,CAAC,oDAAoD,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,CAAC,YAAY,EAAE,EAAE,CAAA;IAC1B,CAAC;IAED,wEAAwE;IACxE,sEAAsE;IACtE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;AAC1F,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CLI-3: the execution context every command function receives. One bag with
3
+ * everything a command needs but never constructs itself — the parsed
4
+ * grammar, the live IPC client, the translator, and the interactivity
5
+ * verdict — plus the seams tests inject (a clock, a poll interval, an
6
+ * alternate working directory). Pure types: the real builder is CLI-5's
7
+ * main.ts; the tests assemble the object literal directly.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/cli/context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}