dsh-zen-remote 2.3.10 → 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.
- package/CHANGELOG.md +44 -72
- package/README.md +94 -84
- package/README.zh-CN.md +90 -81
- package/bin/zen-remote.mjs +5 -0
- package/docs/interface.md +6 -6
- package/docs/remote-access.en.md +6 -4
- package/docs/remote-access.md +6 -4
- package/dsh-push.mjs +96 -10
- package/lib/adapters/dsh-better-sidebar/index.js +7 -3
- package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
- package/lib/admin-routes.js +10 -2
- package/lib/admin-routes.js.map +1 -1
- package/lib/cli/args.js +251 -0
- package/lib/cli/args.js.map +1 -0
- package/lib/cli/bootstrap.js +449 -0
- package/lib/cli/bootstrap.js.map +1 -0
- package/lib/cli/command-setup.js +484 -0
- package/lib/cli/command-setup.js.map +1 -0
- package/lib/cli/commands-client.js +359 -0
- package/lib/cli/commands-client.js.map +1 -0
- package/lib/cli/commands-host.js +1108 -0
- package/lib/cli/commands-host.js.map +1 -0
- package/lib/cli/commands-status.js +279 -0
- package/lib/cli/commands-status.js.map +1 -0
- package/lib/cli/config-writer.js +334 -0
- package/lib/cli/config-writer.js.map +1 -0
- package/lib/cli/context.js +10 -0
- package/lib/cli/context.js.map +1 -0
- package/lib/cli/i18n.js +620 -0
- package/lib/cli/i18n.js.map +1 -0
- package/lib/cli/ipc-client.js +160 -0
- package/lib/cli/ipc-client.js.map +1 -0
- package/lib/cli/ipc-server.js +464 -0
- package/lib/cli/ipc-server.js.map +1 -0
- package/lib/cli/main.js +245 -0
- package/lib/cli/main.js.map +1 -0
- package/lib/cli/qr-terminal.js +48 -0
- package/lib/cli/qr-terminal.js.map +1 -0
- package/lib/client-data/qr.js +286 -0
- package/lib/client-data/qr.js.map +1 -0
- package/lib/client-routes.js +308 -25
- package/lib/client-routes.js.map +1 -1
- package/lib/client.js +1013 -229
- package/lib/config.js +50 -12
- package/lib/config.js.map +1 -1
- package/lib/debug-report.js +28 -1
- package/lib/debug-report.js.map +1 -1
- package/lib/fetch-route-intercept.js +334 -26
- package/lib/fetch-route-intercept.js.map +1 -1
- package/lib/index.js +573 -366
- package/lib/index.js.map +1 -1
- package/lib/intercept.js +1833 -280
- package/lib/intercept.js.map +1 -1
- package/lib/lan-gate-server.cjs +36 -10
- package/lib/merge-streams.js +103 -11
- package/lib/merge-streams.js.map +1 -1
- package/lib/plugin-route-intercept.js +93 -63
- package/lib/plugin-route-intercept.js.map +1 -1
- package/lib/relay-access.js +8 -1
- package/lib/relay-access.js.map +1 -1
- package/lib/relay-client.js +133 -4
- package/lib/relay-client.js.map +1 -1
- package/lib/relay-pool.js +275 -0
- package/lib/relay-pool.js.map +1 -0
- package/lib/relay-server.js +269 -17
- package/lib/relay-server.js.map +1 -1
- package/lib/restart-fields.js +6 -4
- package/lib/restart-fields.js.map +1 -1
- package/lib/share-store.js +65 -27
- package/lib/share-store.js.map +1 -1
- package/lib/state-store.js +400 -0
- package/lib/state-store.js.map +1 -0
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts +3 -2
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
- package/lib/types/admin-routes.d.ts.map +1 -1
- package/lib/types/cli/args.d.ts +78 -0
- package/lib/types/cli/args.d.ts.map +1 -0
- package/lib/types/cli/bootstrap.d.ts +170 -0
- package/lib/types/cli/bootstrap.d.ts.map +1 -0
- package/lib/types/cli/command-setup.d.ts +72 -0
- package/lib/types/cli/command-setup.d.ts.map +1 -0
- package/lib/types/cli/commands-client.d.ts +36 -0
- package/lib/types/cli/commands-client.d.ts.map +1 -0
- package/lib/types/cli/commands-host.d.ts +82 -0
- package/lib/types/cli/commands-host.d.ts.map +1 -0
- package/lib/types/cli/commands-status.d.ts +46 -0
- package/lib/types/cli/commands-status.d.ts.map +1 -0
- package/lib/types/cli/config-writer.d.ts +92 -0
- package/lib/types/cli/config-writer.d.ts.map +1 -0
- package/lib/types/cli/context.d.ts +39 -0
- package/lib/types/cli/context.d.ts.map +1 -0
- package/lib/types/cli/i18n.d.ts +32 -0
- package/lib/types/cli/i18n.d.ts.map +1 -0
- package/lib/types/cli/ipc-client.d.ts +83 -0
- package/lib/types/cli/ipc-client.d.ts.map +1 -0
- package/lib/types/cli/ipc-server.d.ts +113 -0
- package/lib/types/cli/ipc-server.d.ts.map +1 -0
- package/lib/types/cli/main.d.ts +57 -0
- package/lib/types/cli/main.d.ts.map +1 -0
- package/lib/types/cli/qr-terminal.d.ts +17 -0
- package/lib/types/cli/qr-terminal.d.ts.map +1 -0
- package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -1
- package/lib/types/client/current-session-report.d.ts +4 -0
- package/lib/types/client/current-session-report.d.ts.map +1 -1
- package/lib/types/client/effects/model-group-side.d.ts.map +1 -1
- package/lib/types/client/effects/remote-session.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +47 -3
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
- package/lib/types/client/settings/settings-css.d.ts +1 -1
- package/lib/types/client/settings/settings-css.d.ts.map +1 -1
- package/lib/types/client/styles/remote-session.css.d.ts +1 -1
- package/lib/types/client/styles/remote-session.css.d.ts.map +1 -1
- package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -1
- package/lib/types/client/wizard/cards/ProxyCard.d.ts.map +1 -1
- package/lib/types/client/wizard/wizard-css.d.ts +1 -1
- package/lib/types/client/wizard/wizard-css.d.ts.map +1 -1
- package/lib/types/client-data/model-group-side.d.ts +23 -2
- package/lib/types/client-data/model-group-side.d.ts.map +1 -1
- package/lib/types/client-data/remote-status.d.ts +47 -1
- package/lib/types/client-data/remote-status.d.ts.map +1 -1
- package/lib/types/client-data/settings-form.d.ts +85 -1
- package/lib/types/client-data/settings-form.d.ts.map +1 -1
- package/lib/types/client-data/wizard.d.ts +56 -1
- package/lib/types/client-data/wizard.d.ts.map +1 -1
- package/lib/types/client-routes.d.ts +25 -1
- package/lib/types/client-routes.d.ts.map +1 -1
- package/lib/types/config.d.ts +40 -14
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/debug-report.d.ts.map +1 -1
- package/lib/types/fetch-route-intercept.d.ts +66 -8
- package/lib/types/fetch-route-intercept.d.ts.map +1 -1
- package/lib/types/index.d.ts +9 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/intercept.d.ts +72 -10
- package/lib/types/intercept.d.ts.map +1 -1
- package/lib/types/merge-streams.d.ts +79 -1
- package/lib/types/merge-streams.d.ts.map +1 -1
- package/lib/types/plugin-route-intercept.d.ts +25 -9
- package/lib/types/plugin-route-intercept.d.ts.map +1 -1
- package/lib/types/relay-access.d.ts +3 -1
- package/lib/types/relay-access.d.ts.map +1 -1
- package/lib/types/relay-client.d.ts +23 -2
- package/lib/types/relay-client.d.ts.map +1 -1
- package/lib/types/relay-pool.d.ts +148 -0
- package/lib/types/relay-pool.d.ts.map +1 -0
- package/lib/types/relay-server.d.ts +30 -3
- package/lib/types/relay-server.d.ts.map +1 -1
- package/lib/types/restart-fields.d.ts +5 -5
- package/lib/types/restart-fields.d.ts.map +1 -1
- package/lib/types/share-store.d.ts.map +1 -1
- package/lib/types/state-store.d.ts +179 -0
- package/lib/types/state-store.d.ts.map +1 -0
- package/lib/types/upload-limits.d.ts +15 -0
- package/lib/types/upload-limits.d.ts.map +1 -1
- package/lib/types/virtual-id.d.ts +21 -0
- package/lib/types/virtual-id.d.ts.map +1 -1
- package/lib/types/wizard/probe.d.ts.map +1 -1
- package/lib/types/wizard/proxy-snippets.d.ts +3 -0
- package/lib/types/wizard/proxy-snippets.d.ts.map +1 -1
- package/lib/types/wizard/routes.d.ts +1 -0
- package/lib/types/wizard/routes.d.ts.map +1 -1
- package/lib/types/wizard/status.d.ts +9 -0
- package/lib/types/wizard/status.d.ts.map +1 -1
- package/lib/types/wizard/verify.d.ts +3 -0
- package/lib/types/wizard/verify.d.ts.map +1 -1
- package/lib/upload-limits.js +15 -0
- package/lib/upload-limits.js.map +1 -1
- package/lib/virtual-id.js +60 -0
- package/lib/virtual-id.js.map +1 -1
- package/lib/wizard/probe.js +46 -1
- package/lib/wizard/probe.js.map +1 -1
- package/lib/wizard/proxy-snippets.js +14 -1
- package/lib/wizard/proxy-snippets.js.map +1 -1
- package/lib/wizard/routes.js +23 -4
- package/lib/wizard/routes.js.map +1 -1
- package/lib/wizard/status.js +21 -0
- package/lib/wizard/status.js.map +1 -1
- package/lib/wizard/verify.js +31 -8
- package/lib/wizard/verify.js.map +1 -1
- package/package.json +8 -4
- package/pwa/icons/badge-96.png +0 -0
- package/pwa/icons/badge.svg +1 -0
- package/pwa/manifest.json +2 -1
- package/pwa/sw.js +3 -1
- package/scripts/check-debug-report.mjs +41 -1
- package/scripts/check-settings-form.mjs +14 -3
- package/scripts/check-settings-view.mjs +247 -0
- package/scripts/check-wizard-ui.mjs +37 -0
- package/src/adapters/dsh-better-sidebar/index.ts +7 -3
- package/src/admin-routes.ts +10 -2
- package/src/cli/args.ts +289 -0
- package/src/cli/bootstrap.ts +569 -0
- package/src/cli/command-setup.ts +540 -0
- package/src/cli/commands-client.ts +369 -0
- package/src/cli/commands-host.ts +1127 -0
- package/src/cli/commands-status.ts +296 -0
- package/src/cli/config-writer.ts +354 -0
- package/src/cli/context.ts +38 -0
- package/src/cli/i18n.ts +645 -0
- package/src/cli/ipc-client.ts +216 -0
- package/src/cli/ipc-server.ts +531 -0
- package/src/cli/main.ts +285 -0
- package/src/cli/qr-terminal.ts +49 -0
- package/src/client/RemoteStatusIcon.tsx +4 -1
- package/src/client/current-session-report.ts +28 -4
- package/src/client/effects/model-group-side.ts +19 -5
- package/src/client/effects/remote-session.ts +26 -6
- package/src/client/locales.ts +96 -6
- package/src/client/settings/SettingsSection.tsx +287 -92
- package/src/client/settings/settings-css.ts +18 -0
- package/src/client/styles/remote-session.css.ts +15 -1
- package/src/client/wizard/GatewayWizard.tsx +470 -109
- package/src/client/wizard/cards/ProxyCard.tsx +2 -1
- package/src/client/wizard/wizard-css.ts +23 -0
- package/src/client-data/model-group-side.ts +37 -10
- package/src/client-data/remote-status.ts +112 -17
- package/src/client-data/settings-form.ts +164 -8
- package/src/client-data/wizard.ts +112 -2
- package/src/client-routes.ts +334 -26
- package/src/config.ts +62 -16
- package/src/debug-report.ts +27 -1
- package/src/fetch-route-intercept.ts +381 -32
- package/src/index.ts +575 -370
- package/src/intercept.ts +1866 -286
- package/src/merge-streams.ts +155 -10
- package/src/plugin-route-intercept.ts +120 -71
- package/src/relay-access.ts +14 -3
- package/src/relay-client.ts +163 -5
- package/src/relay-pool.ts +387 -0
- package/src/relay-server.ts +312 -16
- package/src/restart-fields.ts +6 -4
- package/src/share-store.ts +59 -26
- package/src/state-store.ts +428 -0
- package/src/upload-limits.ts +16 -0
- package/src/virtual-id.ts +57 -0
- package/src/wizard/probe.ts +54 -2
- package/src/wizard/proxy-snippets.ts +17 -2
- package/src/wizard/routes.ts +24 -5
- package/src/wizard/status.ts +28 -0
- package/src/wizard/verify.ts +33 -11
- package/AGENTS.md +0 -185
- package/docs/adr/0001-plugin-bridge-forwards-plugin-routes.md +0 -15
- 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"}
|