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,170 @@
1
+ /**
2
+ * CLI-2 bootstrap: everything a CLI session needs BEFORE any subcommand
3
+ * logic runs — interactive prompting, candidate-profile scanning with the
4
+ * multi-select plugin install, and bringing a DSH instance up.
5
+ *
6
+ * Three injectable seams keep this testable without a real terminal or a
7
+ * real daemon (SPEC's test seam three): a `CliPrompter` the tests replace
8
+ * with fakes, a `spawnCommand` the tests record instead of running
9
+ * `dsh plugin add`, and an `execProbe` the tests substitute for systemctl /
10
+ * launchctl / open. The real implementations sit next to them in this file
11
+ * and exercise the very same code paths.
12
+ *
13
+ * The non-interactive iron rule lives here: with `!isTTY` or `--yes`, a
14
+ * question with no command-line answer throws `MissingRequiredOptionError`
15
+ * IMMEDIATELY — a headless run must fail fast and legibly, never hang on a
16
+ * stdin read nothing will ever answer.
17
+ */
18
+ import type { Readable, Writable } from 'node:stream';
19
+ import { discoverCliSockets } from './ipc-client.js';
20
+ import type { CliIpcClient, CliPingResponse } from './ipc-client.js';
21
+ import type { CliTranslator } from './i18n.js';
22
+ export interface CliMultiSelection {
23
+ /** Indices into the `choices` array, in the order the user entered them. */
24
+ indices: number[];
25
+ /** Names typed via the manual-input entry (`a`). */
26
+ customNames: string[];
27
+ }
28
+ export interface CliPrompter {
29
+ selectOne(question: string, choices: readonly string[], defaultIndex: number): Promise<number>;
30
+ selectMulti(question: string, choices: readonly string[], defaultIndices: readonly number[], allowCustomInput?: boolean): Promise<CliMultiSelection>;
31
+ inputText(question: string, defaultValue?: string, validate?: (value: string) => string | undefined): Promise<string>;
32
+ confirm(question: string, defaultYes?: boolean): Promise<boolean>;
33
+ close(): void;
34
+ }
35
+ /** Raised when a required value is missing in a run that must not prompt
36
+ * (`!isTTY` or `--yes`). Carries the option name so the top level can render
37
+ * one precise bilingual line instead of a stack trace. */
38
+ export declare class MissingRequiredOptionError extends Error {
39
+ readonly optionName: string;
40
+ constructor(optionName: string);
41
+ }
42
+ /** The interactivity verdict every prompt flows through: a TTY and no
43
+ * `--yes`. One function so the rule has exactly one home. */
44
+ export declare function isInteractiveSession(args: {
45
+ options: {
46
+ yes: boolean;
47
+ };
48
+ }, isTty: boolean): boolean;
49
+ /**
50
+ * One ask-everything funnel: a command-line-provided (or caller-default)
51
+ * value answers directly; otherwise interactive runs prompt, and
52
+ * non-interactive runs throw {@link MissingRequiredOptionError} naming the
53
+ * option — before any await that could hang.
54
+ */
55
+ export declare function promptOrFail<T>(params: {
56
+ optionName: string;
57
+ interactive: boolean;
58
+ provided: T | undefined;
59
+ ask: () => Promise<T>;
60
+ }): Promise<T>;
61
+ /**
62
+ * The default `CliPrompter` over `node:readline/promises`. Scaffold strings
63
+ * (the "pick a number" hints) go through the translator like everything
64
+ * else; questions and choices arrive pre-translated from the callers.
65
+ */
66
+ export declare function createReadlinePrompter(input?: Readable, output?: Writable, t?: CliTranslator): CliPrompter;
67
+ export interface CandidateProfile {
68
+ name: string;
69
+ installed: boolean;
70
+ }
71
+ /**
72
+ * The installable profiles under `<dshHome>/profiles/`: real directories,
73
+ * excluding `desktop` (the DSH app manages it and `dsh plugin` must not
74
+ * touch it), `node_modules`, and dot-hidden entries. `web` is ALWAYS at
75
+ * index 0 — synthesized when the directory does not exist yet — so both the
76
+ * prompt's default check and the preferred-profile rule can rely on it.
77
+ */
78
+ export declare function scanCandidateProfiles(dshHome: string): CandidateProfile[];
79
+ export interface EnsurePluginInstalledOptions {
80
+ dshHome: string;
81
+ /** Explicit `--profile p1,p2` targets; skips the scan-and-ask flow and
82
+ * installs even over already-installed profiles (idempotent add). */
83
+ profileFlag?: readonly string[];
84
+ /** TTY && !`--yes`, decided by the caller (see isInteractiveSession). */
85
+ interactive?: boolean;
86
+ prompter?: CliPrompter;
87
+ /** Injectable runner for `dsh plugin … add` — tests record instead of run. */
88
+ spawnCommand?: (command: string, args: readonly string[]) => Promise<number>;
89
+ stdout?: {
90
+ write(text: string): void;
91
+ };
92
+ t?: CliTranslator;
93
+ }
94
+ export interface EnsurePluginInstalledResult {
95
+ ok: boolean;
96
+ code: 'ok' | 'desktop-refused' | 'install-failed' | 'no-profiles';
97
+ /** Every profile this step decided is (or should now be) installed. */
98
+ targets: string[];
99
+ /** `web` when the targets include it, else the first target. */
100
+ preferredProfile: string | undefined;
101
+ /** Profiles the install actually ran for, in order. */
102
+ installedNow: string[];
103
+ selectedBy: 'flag' | 'prompt' | 'default' | 'already-installed';
104
+ failedProfile?: string;
105
+ manualCommand?: string;
106
+ }
107
+ /**
108
+ * Make sure `dsh-zen-remote` is installed into at least one usable profile:
109
+ * explicit `--profile` wins; otherwise an already-installed profile ends the
110
+ * flow; otherwise an interactive TTY multi-selects from the candidate scan
111
+ * (default-checked `web`, manual names welcome) and a non-interactive run
112
+ * defaults to `web`. Each selected profile gets
113
+ * `dsh plugin --profile <name> add dsh-zen-remote`; a failure prints the
114
+ * verbatim manual command and reports `install-failed`. `desktop` is
115
+ * refused everywhere — the DeepSeek Harness app owns that profile.
116
+ */
117
+ export declare function ensurePluginInstalled(options: EnsurePluginInstalledOptions): Promise<EnsurePluginInstalledResult>;
118
+ export interface ExecProbeResult {
119
+ code: number;
120
+ stdout: string;
121
+ }
122
+ export type ExecProbe = (command: string, args: readonly string[]) => Promise<ExecProbeResult>;
123
+ export interface EnsureDshRunningOptions {
124
+ dshHome: string;
125
+ /** Among several live instances prefer the one serving this role. */
126
+ targetRole?: 'host' | 'client';
127
+ /** Feeds the manual-start guidance and (nothing spawns daemons per-profile
128
+ * today) future per-profile daemons. */
129
+ preferredProfile?: string;
130
+ /** Poll budget after a daemon trigger; default 20s. */
131
+ waitSeconds?: number;
132
+ /** Probe only this socket instead of the candidate walk. */
133
+ explicitSocket?: string;
134
+ /** Platform override (tests pin every branch on one machine). */
135
+ platform?: NodeJS.Platform;
136
+ /** uid for the launchd `gui/<uid>/…` target; default process.getuid(). */
137
+ uid?: number;
138
+ /** Injectable command runner for the daemon probes/triggers. */
139
+ execProbe?: ExecProbe;
140
+ /** Injectable discovery (tests can stage socket states per call). */
141
+ discover?: typeof discoverCliSockets;
142
+ /** macOS app bundle path; tests relocate it off the real /Applications. */
143
+ macosAppPath?: string;
144
+ /** System systemd unit dir; tests relocate it off the real /etc. */
145
+ systemUnitDir?: string;
146
+ stdout?: {
147
+ write(text: string): void;
148
+ };
149
+ t?: CliTranslator;
150
+ }
151
+ export type EnsureDshRunningResult = {
152
+ started: true;
153
+ client: CliIpcClient;
154
+ socketPath: string;
155
+ ping: CliPingResponse;
156
+ } | {
157
+ started: false;
158
+ outcome: 'permission-denied' | 'no-daemon' | 'timeout';
159
+ message: string;
160
+ };
161
+ /**
162
+ * Find (or launch) a DSH this CLI can drive: discovery first — a live
163
+ * version-matching socket answers immediately (preferring the target role
164
+ * among multiple instances); EACCES / EPERM reports the cross-user hint and
165
+ * stops; otherwise the platform's daemon triggers fire and discovery polls
166
+ * until a socket appears or `waitSeconds` run out. Windows and daemon-less
167
+ * machines get the manual-start guidance and a structured `no-daemon` result.
168
+ */
169
+ export declare function ensureDshRunning(options: EnsureDshRunningOptions): Promise<EnsureDshRunningResult>;
170
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/cli/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * CLI-5: the `setup` end-to-end wizard — the web three-step wizard
3
+ * (`GatewayWizard.tsx`) rendered onto a terminal, in one interactive /
4
+ * parametric state machine: command-line-provided answers are taken as-is,
5
+ * missing ones are asked in a TTY run and raise MissingRequiredOptionError
6
+ * in a `--yes` / headless run.
7
+ *
8
+ * Preflight (SPEC §4) runs FIRST and always: discover the plugin's IPC
9
+ * socket — when nothing live answers (or `--profile` was given explicitly)
10
+ * the multi-select profile install runs, then `ensureDshRunning` brings a
11
+ * DSH up (daemon trigger + bounded poll). Everything after that goes through
12
+ * THAT live IPC client.
13
+ *
14
+ * Step 1 is the role. Switching mirrors GatewayWizard.tsx's discipline
15
+ * exactly: host → client stops the managed Caddy / Cloudflare tunnel through
16
+ * their IPC stop routes BEFORE writing `role: 'client'`, then polls ping
17
+ * until `connects`; client → host writes `role: 'host'` and polls until
18
+ * `serves` (the row reloads under the CLI — the hot-swap socket never
19
+ * drops).
20
+ *
21
+ * Steps 2 & 3 are NOT reimplementations: the host branch drives
22
+ * `runHostIngressStartCommand` / `runHostIngressVerifyCommand` (mode
23
+ * switch cleanup, snippets, three lights, QR) and the client branch drives
24
+ * `runClientPairCommand` / `runClientUnpairCommand` (claim, handshake lights,
25
+ * removal) — the same code `host *` / `client *` use, over a synthesized
26
+ * argv. `setup`'s own additions are only the flow around them: the
27
+ * keep-current-config choice, the two-question recommendation funnel, the
28
+ * retry menu after a failed verification, the desktop-client pairing
29
+ * follow-up, and the paired-host management menu.
30
+ */
31
+ import type { ParsedCliArgs } from './args.js';
32
+ import type { CliPrompter, ExecProbe } from './bootstrap.js';
33
+ import { discoverCliSockets } from './ipc-client.js';
34
+ import type { CliTranslator } from './i18n.js';
35
+ /** Everything `runSetupCommand` needs beyond a plain command context: the
36
+ * preflight owns discovery and launch, so it takes the same injectable
37
+ * seams `main.ts` collected (SPEC's test seam three). */
38
+ export interface SetupCommandContext {
39
+ args: ParsedCliArgs;
40
+ dshHome: string;
41
+ /** TTY && !`--yes`, decided once by the entry point. */
42
+ interactive: boolean;
43
+ t: CliTranslator;
44
+ stdout: {
45
+ write(text: string): void;
46
+ };
47
+ /** Present whenever the run may prompt. */
48
+ prompter?: CliPrompter;
49
+ /** Poll-interval seam (role-switch wait, shared with the driven commands). */
50
+ pollIntervalMs?: number;
51
+ /** Ctrl-C seam — forwarded into the verify wait. */
52
+ abortSignal?: AbortSignal;
53
+ now?: () => Date;
54
+ cwd?: string;
55
+ /** Discover seam (tests stage socket states per call). */
56
+ discover?: typeof discoverCliSockets;
57
+ /** `dsh plugin add` runner seam. */
58
+ spawnCommand?: (command: string, args: readonly string[]) => Promise<number>;
59
+ /** Daemon probe/trigger seam. */
60
+ execProbe?: ExecProbe;
61
+ platform?: NodeJS.Platform;
62
+ uid?: number;
63
+ macosAppPath?: string;
64
+ systemUnitDir?: string;
65
+ }
66
+ /**
67
+ * `dsh-zen-remote setup` — preflight, step 1 (role + switch sync), then the
68
+ * role's steps 2 & 3. Missing required answers in a headless run throw
69
+ * MissingRequiredOptionError for the entry point to render.
70
+ */
71
+ export declare function runSetupCommand(ctx: SetupCommandContext): Promise<number>;
72
+ //# sourceMappingURL=command-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/command-setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,WAAW,CAAA;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAIpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAa9C;;yDAEyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAA;IACpB,CAAC,EAAE,aAAa,CAAA;IAChB,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IACrC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oDAAoD;IACpD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,kBAAkB,CAAA;IACpC,oCAAoC;IACpC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5E,iCAAiC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AA2YD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2D/E"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CLI-3: the `client` subcommand family — `pair`, `unpair`, `list`. Every
3
+ * entry point passes the connectsRole gate FIRST (the task discipline: a
4
+ * host never dials a remote host; the message names the `setup --role
5
+ * client` switch), then drives the plugin's own pairing routes over IPC —
6
+ * the CLI never touches the relay pool or the state file directly, the
7
+ * plugin process stays the single owner.
8
+ *
9
+ * Interactivity follows the bootstrap iron rule: a missing value prompts in
10
+ * a TTY run, and a non-interactive run throws MissingRequiredOptionError
11
+ * immediately — except the one retry the SPEC pins: a WRONG pairing code in
12
+ * an interactive run falls back to re-asking ONLY the code, the already
13
+ * entered address stays put.
14
+ */
15
+ import type { CliExecutionContext } from './context.js';
16
+ /**
17
+ * `client list [--json]` — the paired-host table. `--json` echoes the pool
18
+ * status's own servers array verbatim (the machine-readable truth), the
19
+ * terminal mode prints the header count and one line per host.
20
+ */
21
+ export declare function runClientListCommand(ctx: CliExecutionContext): Promise<number>;
22
+ /**
23
+ * `client pair [hostUrl] [--code <8位码>] [--name <本机名>] [--json]` — the
24
+ * full pairing flow: local address validation, name sync through the
25
+ * anti-shadowing config writer, the claim round-trip (with the SPEC's
26
+ * code-only retry in interactive runs), and the bounded wait for `online`.
27
+ */
28
+ export declare function runClientPairCommand(ctx: CliExecutionContext): Promise<number>;
29
+ /**
30
+ * `client unpair [<hostUrl|entryId>|--all] [--yes] [--json]` — a target is
31
+ * matched against the pool's own status rows (entry id first, then the
32
+ * normalized address); `--all` needs `--yes` outside a TTY confirm; no
33
+ * target at all in an interactive run picks from the current list.
34
+ */
35
+ export declare function runClientUnpairCommand(ctx: CliExecutionContext): Promise<number>;
36
+ //# sourceMappingURL=commands-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-client.d.ts","sourceRoot":"","sources":["../../../src/cli/commands-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AA+DvD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BpF;AAqFD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDpF;AA6CD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgEtF"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * CLI-4: the `host` subcommand family — `device pair|list|revoke` and
3
+ * `ingress start|stop|verify|snippet`. Every entry point passes the
4
+ * servesRole gate FIRST (the task discipline: a client never drives the
5
+ * server-owner surfaces; the message names the `setup` switch), then drives
6
+ * the plugin's own admin/wizard routes over IPC.
7
+ *
8
+ * The iron rule for ingress: the CLI NEVER spawns `caddy` or `cloudflared`
9
+ * itself — download, start, stop, status and the three-light verification
10
+ * all happen inside the plugin process through the
11
+ * `/_dsh/zen-remote/admin/wizard/*` routes (SPEC §1). Mode switches mirror
12
+ * `GatewayWizard.tsx`'s discipline: any managed ingress process that does
13
+ * not belong to the new mode is stopped through its stop route before the
14
+ * new mode's flow runs, managed caddy/cloudflared reset `host` back to
15
+ * `127.0.0.1`, and lan rebinds it to `0.0.0.0`.
16
+ *
17
+ * Interactivity follows the bootstrap iron rule: a missing value prompts in
18
+ * a TTY run and throws MissingRequiredOptionError otherwise — except the
19
+ * values with a SAVED fallback (domain, public URL), which the saved wizard
20
+ * status answers before any prompt.
21
+ */
22
+ import type { CliExecutionContext } from './context.js';
23
+ /** The anti-shadowing config write, reporting `env-shadowed` and generic
24
+ * failures through the translator. Shared with `command-setup.ts`'s role
25
+ * switch, which writes the same way. */
26
+ export declare function writeConfigOrReport(ctx: CliExecutionContext, set: Record<string, unknown>): Promise<boolean>;
27
+ /**
28
+ * `host device pair [--device-role web|desktop-client] [--json]` — mint one
29
+ * pairing code through the admin pair route and print it with everything
30
+ * the receiving side needs: the reachable URL (public URL, or the LAN
31
+ * address assembled with the gateway's actual port), a terminal QR for web
32
+ * devices, the copy-paste `client pair` command for desktop clients, and
33
+ * the code with its validity window (the gateway mints 10-minute codes).
34
+ */
35
+ export declare function runHostDevicePairCommand(ctx: CliExecutionContext): Promise<number>;
36
+ /**
37
+ * `host device list [--json]` — the gateway's device table. `--json` echoes
38
+ * the gateway's own devices array verbatim (the machine-readable truth);
39
+ * the terminal mode prints one line per device with its id, name, role,
40
+ * kind and the created / last-seen stamps.
41
+ */
42
+ export declare function runHostDeviceListCommand(ctx: CliExecutionContext): Promise<number>;
43
+ /**
44
+ * `host device revoke [<id>|--all] [--yes] [--json]` — one revoke POST per
45
+ * invocation. `--all` needs `--yes` outside a TTY confirm (the missing
46
+ * confirmation IS the missing required option); a missing target in an
47
+ * interactive run picks from the current list.
48
+ */
49
+ export declare function runHostDeviceRevokeCommand(ctx: CliExecutionContext): Promise<number>;
50
+ /**
51
+ * `host ingress snippet [--proxy nginx|caddy|lucky]` — the copy-paste
52
+ * reverse-proxy material for the external ingress mode. The upstream port
53
+ * is the gateway's ACTUAL port (a gateway that retried past its configured
54
+ * port must not hand out snippets pointing at the wrong place); the domain
55
+ * falls back to the example placeholder.
56
+ */
57
+ export declare function runHostIngressSnippetCommand(ctx: CliExecutionContext): Promise<number>;
58
+ /**
59
+ * `host ingress start [--mode …] …` — the four ingress modes, all driven
60
+ * through the plugin's wizard routes. The mode comes from the flags, then
61
+ * the saved config, then the interactive question; before the new mode's
62
+ * flow runs, every managed process that does not belong to it is stopped
63
+ * through its own stop route (GatewayWizard.tsx's discipline).
64
+ */
65
+ export declare function runHostIngressStartCommand(ctx: CliExecutionContext): Promise<number>;
66
+ /**
67
+ * `host ingress stop [--yes] [--json]` — stop both managed ingress
68
+ * processes through their stop routes (the CLI owns no process handles to
69
+ * reach for). `--yes` outside a TTY confirm, same discipline as revoke.
70
+ */
71
+ export declare function runHostIngressStopCommand(ctx: CliExecutionContext): Promise<number>;
72
+ /**
73
+ * `host ingress verify [--public-url <origin>] [--no-wait] [--json]` — the
74
+ * three-light check, driven entirely by the plugin's verify orchestration:
75
+ * POST mints the code and walks the public URL (lights 1 + 2), GET polls
76
+ * for the real phone pairing (light 3). `--no-wait` / `--json` stop after
77
+ * the first two lights; an aborted signal (the entry point's Ctrl-C seam)
78
+ * skips the wait gracefully with exit code 0 — the first two lights'
79
+ * verdict is already on the record.
80
+ */
81
+ export declare function runHostIngressVerifyCommand(ctx: CliExecutionContext): Promise<number>;
82
+ //# sourceMappingURL=commands-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-host.d.ts","sourceRoot":"","sources":["../../../src/cli/commands-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAqBH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAgDvD;;wCAEwC;AACxC,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAclH;AAsED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2FxF;AAMD;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BxF;AAMD;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkE1F;AAmED;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAe5F;AAkWD;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkD1F;AAMD;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BzF;AAwCD;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgJ3F"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * CLI-3: the `status` command — one identity read (ping) plus whatever the
3
+ * role actually answers, rendered either as pretty JSON (`--json`) or as
4
+ * bilingual terminal lines. `--debug` is its own branch: fetch the plugin
5
+ * process's redacted diagnostic report over IPC and write it to a file
6
+ * (explicit path or a `zen-remote-debug-<role>-<yyyymmdd-hhmm>.json` in the
7
+ * working directory).
8
+ *
9
+ * Per SPEC the IPC channel only carries structured data — every terminal
10
+ * string is rendered here through the translator. The per-server line
11
+ * renderer is shared with `commands-client.ts` (`client list` prints the
12
+ * same rows), so the two surfaces cannot drift.
13
+ */
14
+ import type { CliIpcRequestResult } from './ipc-client.js';
15
+ import type { CliTranslator } from './i18n.js';
16
+ import type { CliExecutionContext } from './context.js';
17
+ /** One pool `servers` row (client/status), defensively typed — the command
18
+ * layer renders whatever shape arrived, it never trusts it. */
19
+ export type ServerRow = Record<string, unknown>;
20
+ /**
21
+ * Fetch one JSON object over IPC; every failure mode (transport error,
22
+ * error status, non-object body) is `null` — a broken surface means "no
23
+ * information" for a status view, never a failed command.
24
+ */
25
+ export declare function fetchBody(run: () => Promise<CliIpcRequestResult>): Promise<ServerRow | null>;
26
+ /** One plain JSON object, or null. */
27
+ export declare function plainOf(value: unknown): ServerRow | null;
28
+ /** The connection-state label: the three common states translated, the rest
29
+ * (revoked / incompatible / unpaired) each with their own word. */
30
+ export declare function stateLabelOf(t: CliTranslator, value: unknown): string;
31
+ /** The fingerprint-compat half of the compat/bridge column. */
32
+ export declare function compatLabelOf(t: CliTranslator, value: unknown): string;
33
+ /** The bridged-plugin half: how many of the row's plugins are bridged. */
34
+ export declare function bridgeLabelOf(t: CliTranslator, value: unknown): string;
35
+ /** One paired-host row, the exact shape both surfaces print:
36
+ * `[entryId] displayName serverUrl state compat/bridge`. */
37
+ export declare function serverLineText(t: CliTranslator, row: ServerRow): string;
38
+ /**
39
+ * `dsh-zen-remote status [--json] [--debug [outPath]]`. Identity from one
40
+ * ping; the host surfaces (admin status, wizard status, share list) and the
41
+ * client pool status each fetched only when the role answers them. Exit
42
+ * codes: 0 on any answered status, 1 when the ping itself or the debug
43
+ * round-trip failed.
44
+ */
45
+ export declare function runStatusCommand(ctx: CliExecutionContext): Promise<number>;
46
+ //# sourceMappingURL=commands-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEvD;+DAC+D;AAC/D,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE/C;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAQlG;AAED,sCAAsC;AACtC,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAIxD;AAcD;mEACmE;AACnE,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAUrE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAOtE;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAItE;AAED;+DAC+D;AAC/D,wBAAgB,cAAc,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAGvE;AAuJD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuChF"}
@@ -0,0 +1,92 @@
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 type { ZenRemoteConfig } from '../config.js';
30
+ /**
31
+ * The env variable each config field answers to, for fields that HAVE one.
32
+ * Fields without an entry (role, serverName, idleHours, the wizard's ingress
33
+ * fields, pluginBridgeConsent — src/config.ts explains each absence) can
34
+ * never be env-shadowed, so they are deliberately missing: `writeCliConfig`
35
+ * falls back to the field name itself when asked for one.
36
+ */
37
+ export declare const ENV_VAR_BY_FIELD: Readonly<Partial<Record<keyof ZenRemoteConfig, string>>>;
38
+ export interface WriteCliConfigOptions {
39
+ /** The DSH home the config files live under (`lan-gate.config.json`,
40
+ * `profiles/<name>/cordis.patch.yml`). Authoritative — env.DSH_HOME is
41
+ * not consulted. */
42
+ dshHome: string;
43
+ /** The profile whose `cordis.patch.yml` is scanned FIRST; the fallback
44
+ * scan over every `<dshHome>/profiles/<name>/cordis.patch.yml` runs
45
+ * besides it, so an un-named profile carrying a stale key is un-shadowed
46
+ * too. */
47
+ profileName?: string | undefined;
48
+ /** The plugin row as `apply()` received it (volatile `{ get() }` wrappers
49
+ * included). Shadowing keys on it are DELETED so the file layer shows
50
+ * through; omit on a composition without a row. */
51
+ row?: Record<string, unknown> | undefined;
52
+ /** The environment carrying `LAN_GATE_*` / `DSH_PUSH_*`; defaults to
53
+ * `process.env`. */
54
+ env?: NodeJS.ProcessEnv | undefined;
55
+ /** Keys to merge into `lan-gate.config.json` (and un-shadow everywhere). */
56
+ set?: Record<string, unknown> | undefined;
57
+ /** Keys to delete from `lan-gate.config.json` (and un-shadow everywhere). */
58
+ unset?: readonly string[] | undefined;
59
+ /** Called AFTER every successful write (never on a refusal and never for
60
+ * an empty write) — the IPC delegate passes the restart watcher's
61
+ * `checkNow`, which reloads the row at once when a restart-required field
62
+ * moved. */
63
+ onAfterWrite?: (() => void) | undefined;
64
+ }
65
+ export type WriteCliConfigResult = {
66
+ ok: true;
67
+ values: ZenRemoteConfig;
68
+ } | {
69
+ ok: false;
70
+ code: 'env-shadowed';
71
+ field: string;
72
+ envVar: string;
73
+ };
74
+ export declare function applyUnshadowedRowKeys(dshHome: string, row: Record<string, unknown> | undefined): void;
75
+ export declare function clearUnshadowedRowKeys(dshHome: string, keys: readonly string[]): void;
76
+ /**
77
+ * Remove `keys` from EVERY `- id: dsh-zen-remote` (or bare `id:`) entry's
78
+ * `config:` block, purely textually: a key line and its deeper-indented
79
+ * children disappear, every other line — comments, other plugins' blocks,
80
+ * formatting — survives byte for byte. A block emptied by the removal keeps
81
+ * a `config: {}` line (an entry with no config key at all changes loader
82
+ * semantics). No match, no change: the same string comes back.
83
+ */
84
+ export declare function unshadowPatchYml(text: string, keys: readonly string[]): string;
85
+ /**
86
+ * Write CLI config changes through the anti-shadowing pipeline. Returns the
87
+ * refused `env-shadowed` verdict (with the exact field and its variable
88
+ * name) WITHOUT touching any file, or the freshly resolved effective values
89
+ * after the write, the row-key deletions and the patch-file un-shadowing.
90
+ */
91
+ export declare function writeCliConfig(options: WriteCliConfigOptions): WriteCliConfigResult;
92
+ //# sourceMappingURL=config-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-writer.d.ts","sourceRoot":"","sources":["../../../src/cli/config-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,KAAK,EAAgB,eAAe,EAAE,MAAM,cAAc,CAAA;AAEjE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,eAAe,EAAE,MAAM,CAAC,CAAC,CAerF,CAAA;AAED,MAAM,WAAW,qBAAqB;IACpC;;wBAEoB;IACpB,OAAO,EAAE,MAAM,CAAA;IACf;;;cAGU;IACV,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC;;uDAEmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACzC;wBACoB;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAA;IACnC,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACzC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IACrC;;;gBAGY;IACZ,YAAY,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACxC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAetE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAUtG;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAIrF;AAoED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAsF9E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAgEnF"}
@@ -0,0 +1,39 @@
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
+ import type { ParsedCliArgs } from './args.js';
10
+ import type { CliIpcClient } from './ipc-client.js';
11
+ import type { CliTranslator } from './i18n.js';
12
+ import type { CliPrompter } from './bootstrap.js';
13
+ export interface CliExecutionContext {
14
+ /** The command and options this run parsed. */
15
+ args: ParsedCliArgs;
16
+ /** A client bound to the discovered live IPC socket. */
17
+ ipc: CliIpcClient;
18
+ /** The translator for this run's language. */
19
+ t: CliTranslator;
20
+ /** TTY && !`--yes`, decided once by the entry point (isInteractiveSession). */
21
+ interactive: boolean;
22
+ /** The ask-everything funnel; present whenever the run may prompt. */
23
+ prompter?: CliPrompter;
24
+ stdout: {
25
+ write(text: string): void;
26
+ };
27
+ /** Clock for the `status --debug` default filename; default `new Date()`. */
28
+ now?: () => Date;
29
+ /** Working directory for that default path; default `process.cwd()`. */
30
+ cwd?: string;
31
+ /** `client pair`'s online-wait poll interval (default 250ms; tests shrink
32
+ * it — the 10s budget itself stays fixed). */
33
+ pollIntervalMs?: number;
34
+ /** `host ingress verify`'s Ctrl-C seam: the entry point (CLI-5's main)
35
+ * aborts it on SIGINT so the phone-pairing wait can be skipped gracefully;
36
+ * tests abort it directly. */
37
+ abortSignal?: AbortSignal;
38
+ }
39
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/cli/context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,IAAI,EAAE,aAAa,CAAA;IACnB,wDAAwD;IACxD,GAAG,EAAE,YAAY,CAAA;IACjB,8CAA8C;IAC9C,CAAC,EAAE,aAAa,CAAA;IAChB,+EAA+E;IAC/E,WAAW,EAAE,OAAO,CAAA;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IACrC,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;kDAC8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;kCAE8B;IAC9B,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * CLI-2 bilingual dictionary and language resolution. Per SPEC the IPC
3
+ * channel only ever carries machine-readable codes and structured data —
4
+ * every terminal string the user sees is rendered HERE, on the CLI side, in
5
+ * the selected language. Placeholder syntax is `{name}`, filled from the
6
+ * `params` argument.
7
+ *
8
+ * Vocabulary discipline (SPEC): the copy speaks ONLY of `host` / `client` /
9
+ * `peer` — `server` / `both` and similar aliases must not leak into any
10
+ * string, in either language. The test file scans both tables for the banned
11
+ * English words to keep it that way.
12
+ */
13
+ export type CliLang = 'zh' | 'en';
14
+ export type CliTranslator = ((key: string, params?: Record<string, string | number>) => string) & {
15
+ /** The language's raw table, for tests and for key inventory checks. */
16
+ readonly keys: Readonly<Record<string, string>>;
17
+ };
18
+ /**
19
+ * Resolve the CLI language: `--lang` wins (`zh` / `en`; `auto` and unknown
20
+ * values fall through), then `ZEN_REMOTE_LANG`, then the locale variables in
21
+ * the standard `LC_ALL` > `LC_MESSAGES` > `LANG` order — anything matching
22
+ * `/^zh/i` is Chinese, everything else (including `C`, `POSIX`, empty) is
23
+ * English.
24
+ */
25
+ export declare function resolveCliLang(flagLang: string | undefined, env?: NodeJS.ProcessEnv): CliLang;
26
+ /**
27
+ * Build a translator for `lang`. Missing keys fall back to the English table
28
+ * and then to the key itself — a forgotten key must be VISIBLE in the output,
29
+ * never silently empty.
30
+ */
31
+ export declare function createTranslator(lang: CliLang): CliTranslator;
32
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/cli/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAA;AAEjC,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG;IAChG,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAChD,CAAA;AA8kBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAU7F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAY7D"}