@anweat/dsh-browser 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +274 -70
  2. package/assets/skills/dsh-browser/SKILL.md +13 -11
  3. package/assets/skills/dsh-browser/references/develop.md +8 -0
  4. package/assets/skills/dsh-browser/references/files.md +36 -0
  5. package/assets/skills/dsh-browser/references/observe.md +2 -2
  6. package/assets/skills/dsh-browser/references/policy.md +32 -0
  7. package/cordis.patch.yml +10 -3
  8. package/lib/actions/automation.js +1 -1
  9. package/lib/actions/automation.js.map +1 -1
  10. package/lib/actions/errors.js +7 -2
  11. package/lib/actions/errors.js.map +1 -1
  12. package/lib/actions/index-view.d.ts +4 -1
  13. package/lib/actions/index-view.js +16 -3
  14. package/lib/actions/index-view.js.map +1 -1
  15. package/lib/actions/inspect.js +15 -0
  16. package/lib/actions/inspect.js.map +1 -1
  17. package/lib/actions/observe.js +1 -1
  18. package/lib/actions/observe.js.map +1 -1
  19. package/lib/actions/opencli.d.ts +1 -1
  20. package/lib/actions/opencli.js +4 -4
  21. package/lib/actions/opencli.js.map +1 -1
  22. package/lib/actions/policy.d.ts +15 -0
  23. package/lib/actions/policy.js +131 -0
  24. package/lib/actions/policy.js.map +1 -0
  25. package/lib/actions/registry.d.ts +8 -0
  26. package/lib/actions/registry.js +16 -5
  27. package/lib/actions/registry.js.map +1 -1
  28. package/lib/actions/run.js +3 -3
  29. package/lib/actions/run.js.map +1 -1
  30. package/lib/actions/runtime.js +2 -2
  31. package/lib/actions/runtime.js.map +1 -1
  32. package/lib/actions/surface.d.ts +7 -0
  33. package/lib/actions/surface.js +11 -1
  34. package/lib/actions/surface.js.map +1 -1
  35. package/lib/actions/target.js +35 -3
  36. package/lib/actions/target.js.map +1 -1
  37. package/lib/actions/types.d.ts +1 -1
  38. package/lib/actions/types.js.map +1 -1
  39. package/lib/approval-policy.d.ts +20 -1
  40. package/lib/approval-policy.js +58 -1
  41. package/lib/approval-policy.js.map +1 -1
  42. package/lib/auth-profiles.d.ts +4 -1
  43. package/lib/auth-profiles.js +3 -0
  44. package/lib/auth-profiles.js.map +1 -1
  45. package/lib/automation-assets-rpc.js +26 -0
  46. package/lib/automation-assets-rpc.js.map +1 -1
  47. package/lib/browser-service.d.ts +165 -4
  48. package/lib/browser-service.js +505 -55
  49. package/lib/browser-service.js.map +1 -1
  50. package/lib/client/SettingsCard.d.ts +10 -8
  51. package/lib/client/SettingsCard.js +12 -137
  52. package/lib/client/SettingsCard.js.map +1 -1
  53. package/lib/client/auth-profiles-form.d.ts +23 -0
  54. package/lib/client/auth-profiles-form.js +64 -0
  55. package/lib/client/auth-profiles-form.js.map +1 -0
  56. package/lib/client/card-frame.d.ts +22 -0
  57. package/lib/client/card-frame.js +61 -0
  58. package/lib/client/card-frame.js.map +1 -0
  59. package/lib/client/field-rows.d.ts +59 -0
  60. package/lib/client/field-rows.js +63 -0
  61. package/lib/client/field-rows.js.map +1 -0
  62. package/lib/client/field-rules.d.ts +17 -0
  63. package/lib/client/field-rules.js +68 -0
  64. package/lib/client/field-rules.js.map +1 -0
  65. package/lib/client/form.d.ts +108 -7
  66. package/lib/client/form.js +255 -11
  67. package/lib/client/form.js.map +1 -1
  68. package/lib/client/group-access.d.ts +14 -0
  69. package/lib/client/group-access.js +97 -0
  70. package/lib/client/group-access.js.map +1 -0
  71. package/lib/client/group-advanced.d.ts +11 -0
  72. package/lib/client/group-advanced.js +32 -0
  73. package/lib/client/group-advanced.js.map +1 -0
  74. package/lib/client/group-assets.d.ts +13 -0
  75. package/lib/client/group-assets.js +50 -0
  76. package/lib/client/group-assets.js.map +1 -0
  77. package/lib/client/group-browser.d.ts +9 -0
  78. package/lib/client/group-browser.js +27 -0
  79. package/lib/client/group-browser.js.map +1 -0
  80. package/lib/client/group-common.d.ts +10 -0
  81. package/lib/client/group-common.js +21 -0
  82. package/lib/client/group-common.js.map +1 -0
  83. package/lib/client/group-context.d.ts +20 -0
  84. package/lib/client/group-context.js +76 -0
  85. package/lib/client/group-context.js.map +1 -0
  86. package/lib/client/group-downloads.d.ts +10 -0
  87. package/lib/client/group-downloads.js +33 -0
  88. package/lib/client/group-downloads.js.map +1 -0
  89. package/lib/client/group-limits.d.ts +9 -0
  90. package/lib/client/group-limits.js +57 -0
  91. package/lib/client/group-limits.js.map +1 -0
  92. package/lib/client/group-prompts.d.ts +13 -0
  93. package/lib/client/group-prompts.js +136 -0
  94. package/lib/client/group-prompts.js.map +1 -0
  95. package/lib/client/index.d.ts +21 -1
  96. package/lib/client/index.js +10 -4
  97. package/lib/client/index.js.map +1 -1
  98. package/lib/client/locales-policy.d.ts +83 -0
  99. package/lib/client/locales-policy.js +46 -0
  100. package/lib/client/locales-policy.js.map +1 -0
  101. package/lib/client/locales-prompts.d.ts +57 -0
  102. package/lib/client/locales-prompts.js +41 -0
  103. package/lib/client/locales-prompts.js.map +1 -0
  104. package/lib/client/locales-ui.d.ts +223 -0
  105. package/lib/client/locales-ui.js +157 -0
  106. package/lib/client/locales-ui.js.map +1 -0
  107. package/lib/client/locales.d.ts +359 -67
  108. package/lib/client/locales.js +68 -22
  109. package/lib/client/locales.js.map +1 -1
  110. package/lib/client/policy-fields.d.ts +31 -0
  111. package/lib/client/policy-fields.js +66 -0
  112. package/lib/client/policy-fields.js.map +1 -0
  113. package/lib/client/policy-status-client.d.ts +91 -0
  114. package/lib/client/policy-status-client.js +64 -0
  115. package/lib/client/policy-status-client.js.map +1 -0
  116. package/lib/client/prompts-form.d.ts +33 -0
  117. package/lib/client/prompts-form.js +87 -0
  118. package/lib/client/prompts-form.js.map +1 -1
  119. package/lib/client/prompts-status-client.d.ts +21 -1
  120. package/lib/client/prompts-status-client.js +36 -4
  121. package/lib/client/prompts-status-client.js.map +1 -1
  122. package/lib/client/properties-form.d.ts +90 -0
  123. package/lib/client/properties-form.js +187 -0
  124. package/lib/client/properties-form.js.map +1 -0
  125. package/lib/client/property-docs.d.ts +18 -0
  126. package/lib/client/property-docs.js +78 -0
  127. package/lib/client/property-docs.js.map +1 -0
  128. package/lib/client/size-units.d.ts +12 -0
  129. package/lib/client/size-units.js +29 -0
  130. package/lib/client/size-units.js.map +1 -0
  131. package/lib/client/styles.d.ts +47 -31
  132. package/lib/client/styles.js +59 -20
  133. package/lib/client/styles.js.map +1 -1
  134. package/lib/client/ui-kit.d.ts +173 -0
  135. package/lib/client/ui-kit.js +112 -0
  136. package/lib/client/ui-kit.js.map +1 -0
  137. package/lib/client.js +5291 -834
  138. package/lib/client.js.map +1 -1
  139. package/lib/config-rules.d.ts +40 -0
  140. package/lib/config-rules.js +103 -0
  141. package/lib/config-rules.js.map +1 -0
  142. package/lib/config.d.ts +64 -2
  143. package/lib/config.js +106 -0
  144. package/lib/config.js.map +1 -1
  145. package/lib/context-options.d.ts +85 -0
  146. package/lib/context-options.js +206 -0
  147. package/lib/context-options.js.map +1 -0
  148. package/lib/deps.d.ts +42 -5
  149. package/lib/deps.js +219 -9
  150. package/lib/deps.js.map +1 -1
  151. package/lib/downloads.d.ts +79 -0
  152. package/lib/downloads.js +189 -0
  153. package/lib/downloads.js.map +1 -0
  154. package/lib/index.d.ts +3 -2
  155. package/lib/index.js +11 -5
  156. package/lib/index.js.map +1 -1
  157. package/lib/policy-keys.d.ts +39 -0
  158. package/lib/policy-keys.js +21 -0
  159. package/lib/policy-keys.js.map +1 -1
  160. package/lib/policy-overlay.d.ts +189 -0
  161. package/lib/policy-overlay.js +649 -0
  162. package/lib/policy-overlay.js.map +1 -0
  163. package/lib/prompts-yaml.d.ts +11 -0
  164. package/lib/prompts-yaml.js +121 -0
  165. package/lib/prompts-yaml.js.map +1 -0
  166. package/lib/prompts.d.ts +2 -0
  167. package/lib/prompts.js +7 -3
  168. package/lib/prompts.js.map +1 -1
  169. package/lib/system-browser.d.ts +61 -0
  170. package/lib/system-browser.js +109 -0
  171. package/lib/system-browser.js.map +1 -0
  172. package/lib/tools.js +9 -1
  173. package/lib/tools.js.map +1 -1
  174. package/lib/usage-policy.d.ts +3 -1
  175. package/lib/usage-policy.js +2 -0
  176. package/lib/usage-policy.js.map +1 -1
  177. package/package.json +42 -38
  178. package/scripts/dump-prompts.mjs +12 -2
package/lib/deps.d.ts CHANGED
@@ -2,11 +2,13 @@
2
2
  * Dependency resolution for dsh-browser, with reuse fallback.
3
3
  *
4
4
  * Resolution order (per dependency):
5
- * 1. THIS plugin's own node_modules — self-contained when distributed
6
- * (playwright / @jackwener/opencli are declared in package.json).
5
+ * 1. THIS plugin's own node_modules — playwright / patchright are declared in package.json.
7
6
  * 2. The global npm root — reuse what's already installed on the machine,
8
7
  * so a dev box needs zero extra install.
9
8
  *
9
+ * `@jackwener/opencli` is NOT declared: its install script makes pnpm 11 fail `dsh plugin add`. It is found
10
+ * wherever it is installed (see `locateOpencli`) and is only needed by the `opencli.*` actions.
11
+ *
10
12
  * The Playwright BROWSER BINARY (chromium) is NOT bundled here and NOT
11
13
  * re-downloaded: playwright loads it from its shared cache (Windows:
12
14
  * %LOCALAPPDATA%\ms-playwright), which this machine already has. So
@@ -31,10 +33,45 @@ export declare function loadPlaywright(): any;
31
33
  export declare function playwrightCliPath(): string;
32
34
  /** CLI entry for the selected Playwright-compatible runtime. */
33
35
  export declare function browserRuntimeCliPath(runtime: BrowserRuntimeName): string;
34
- /** Entry JS for the bundled/reused @jackwener/opencli (its bin/main). */
36
+ /** Where `@jackwener/opencli` was found. */
37
+ export type OpencliSource = 'env' | 'plugin' | 'path' | 'global-npm' | 'common-prefix';
38
+ export interface OpencliLocation {
39
+ /** The JavaScript entry (`bin.opencli` of its package.json). Run with Node. */
40
+ entry: string;
41
+ /** The package directory. */
42
+ packageDir: string;
43
+ source: OpencliSource;
44
+ }
45
+ /**
46
+ * What to tell a user whose machine has no OpenCLI. OpenCLI is optional: the browser tools never need it, only the
47
+ * `opencli.*` actions do. It is NOT a dependency of this package, because its install scripts make pnpm 11 fail
48
+ * `dsh plugin add` (ERR_PNPM_IGNORED_BUILDS) on a profile that has not approved them.
49
+ */
50
+ export declare const OPENCLI_INSTALL_HINT: string;
51
+ /** Everything `locateOpencli` reads from the machine, so a test can describe a machine instead of owning one. */
52
+ export interface OpencliSearchEnv {
53
+ platform: NodeJS.Platform;
54
+ env: NodeJS.ProcessEnv;
55
+ home: string;
56
+ /** package.json files of the dependency, in the order the plugin's own resolution finds them. */
57
+ pluginPackageJsons: () => string[];
58
+ /** `npm root -g`, or undefined when npm cannot be run. */
59
+ npmGlobalRoot: () => string | undefined;
60
+ }
61
+ /**
62
+ * Find OpenCLI without requiring it to be a dependency of the plugin. Order: `DSH_BROWSER_OPENCLI`, the plugin's own
63
+ * resolution (pnpm store, plugin-local, an `@jackwener/opencli` the user added to the profile), an `opencli` launcher on PATH,
64
+ * `npm root -g`, and the usual global locations. The first hit wins. Pure apart from reading the file system.
65
+ */
66
+ export declare function locateOpencli(search: OpencliSearchEnv): OpencliLocation | undefined;
67
+ /** Find OpenCLI on this machine. A hit is remembered while its files exist; a miss is looked up again (the user may install it while DSH runs). */
68
+ export declare function opencliLocation(): OpencliLocation | undefined;
69
+ /** What to tell the user when OpenCLI was not found: names a wrong `DSH_BROWSER_OPENCLI` first, since that one is theirs to fix. */
70
+ export declare function opencliMissingMessage(): string;
71
+ /** Entry JS of OpenCLI (its bin/main). Throws the install hint when OpenCLI is not installed. */
35
72
  export declare function opencliEntryPath(): string;
36
73
  /**
37
- * Run a Node.js script with piped stdio capture (bundled opencli / playwright
74
+ * Run a Node.js script with piped stdio capture (opencli / playwright
38
75
  * CLI). Mirrors web-search-pro's runCli contract.
39
76
  */
40
77
  export declare function runNode(script: string, args: string[], opts?: {
@@ -44,7 +81,7 @@ export declare function runNode(script: string, args: string[], opts?: {
44
81
  cwd?: string;
45
82
  env?: Record<string, string>;
46
83
  }): Promise<CliResult>;
47
- /** Run opencli (bundled or global-reuse). */
84
+ /** Run opencli (found by `opencliLocation`). */
48
85
  export declare function runOpencli(args: string[], opts?: {
49
86
  timeoutMs?: number;
50
87
  signal: AbortSignal | undefined;
package/lib/deps.js CHANGED
@@ -2,11 +2,13 @@
2
2
  * Dependency resolution for dsh-browser, with reuse fallback.
3
3
  *
4
4
  * Resolution order (per dependency):
5
- * 1. THIS plugin's own node_modules — self-contained when distributed
6
- * (playwright / @jackwener/opencli are declared in package.json).
5
+ * 1. THIS plugin's own node_modules — playwright / patchright are declared in package.json.
7
6
  * 2. The global npm root — reuse what's already installed on the machine,
8
7
  * so a dev box needs zero extra install.
9
8
  *
9
+ * `@jackwener/opencli` is NOT declared: its install script makes pnpm 11 fail `dsh plugin add`. It is found
10
+ * wherever it is installed (see `locateOpencli`) and is only needed by the `opencli.*` actions.
11
+ *
10
12
  * The Playwright BROWSER BINARY (chromium) is NOT bundled here and NOT
11
13
  * re-downloaded: playwright loads it from its shared cache (Windows:
12
14
  * %LOCALAPPDATA%\ms-playwright), which this machine already has. So
@@ -122,12 +124,220 @@ export function playwrightCliPath() {
122
124
  export function browserRuntimeCliPath(runtime) {
123
125
  return path.join(pkgDir(browserRuntimePackage(runtime)), 'cli.js');
124
126
  }
125
- /** Entry JS for the bundled/reused @jackwener/opencli (its bin/main). */
127
+ /**
128
+ * What to tell a user whose machine has no OpenCLI. OpenCLI is optional: the browser tools never need it, only the
129
+ * `opencli.*` actions do. It is NOT a dependency of this package, because its install scripts make pnpm 11 fail
130
+ * `dsh plugin add` (ERR_PNPM_IGNORED_BUILDS) on a profile that has not approved them.
131
+ */
132
+ export const OPENCLI_INSTALL_HINT = 'OpenCLI is not installed (it is optional: only the opencli.* actions need it). Install it with `npm i -g @jackwener/opencli` and restart DSH. '
133
+ + 'If DSH cannot see your PATH (desktop app), set DSH_BROWSER_OPENCLI to the path of its main.js.';
134
+ const OPENCLI_PACKAGE = '@jackwener/opencli';
135
+ /** Read `bin.opencli` (or `main`) of an opencli package directory and return its existing entry file. */
136
+ function opencliEntryOf(packageDir) {
137
+ try {
138
+ const pkg = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8'));
139
+ if (pkg?.name !== OPENCLI_PACKAGE)
140
+ return undefined;
141
+ const bin = typeof pkg.bin === 'string' ? pkg.bin : (pkg.bin?.opencli ?? pkg.main ?? 'dist/src/main.js');
142
+ const entry = path.join(packageDir, bin);
143
+ return fs.existsSync(entry) ? entry : undefined;
144
+ }
145
+ catch {
146
+ return undefined;
147
+ }
148
+ }
149
+ /** The opencli package directory a `main.js` / launcher path belongs to: walk up to the nearest package.json named for it. */
150
+ function opencliPackageDirOf(file) {
151
+ let dir = path.dirname(file);
152
+ for (let i = 0; i < 8; i++) {
153
+ if (opencliEntryOf(dir))
154
+ return dir;
155
+ const parent = path.dirname(dir);
156
+ if (parent === dir)
157
+ return undefined;
158
+ dir = parent;
159
+ }
160
+ return undefined;
161
+ }
162
+ /** `DSH_BROWSER_OPENCLI` may name the package directory, its main.js, or the `opencli` launcher. */
163
+ function opencliFromPath(target) {
164
+ let resolved;
165
+ try {
166
+ resolved = fs.realpathSync(target);
167
+ }
168
+ catch {
169
+ return undefined;
170
+ }
171
+ let stat;
172
+ try {
173
+ stat = fs.statSync(resolved);
174
+ }
175
+ catch {
176
+ return undefined;
177
+ }
178
+ const packageDir = stat.isDirectory() ? (opencliEntryOf(resolved) ? resolved : undefined) : opencliPackageDirOf(resolved);
179
+ const entry = packageDir ? opencliEntryOf(packageDir) : undefined;
180
+ return packageDir && entry ? { entry, packageDir, source: 'env' } : undefined;
181
+ }
182
+ /** Launchers named `opencli` on PATH: a symlink into the package on Unix, a `.cmd` shim next to `node_modules` on Windows. */
183
+ function opencliFromPathVariable(env, platform) {
184
+ const delimiter = platform === 'win32' ? ';' : ':';
185
+ const names = platform === 'win32' ? ['opencli.cmd', 'opencli.exe', 'opencli'] : ['opencli'];
186
+ for (const raw of (env.PATH ?? env.Path ?? env.path ?? '').split(delimiter)) {
187
+ const dir = raw.trim().replace(/^"|"$/g, '');
188
+ if (!dir)
189
+ continue;
190
+ for (const name of names) {
191
+ const launcher = path.join(dir, name);
192
+ if (!fs.existsSync(launcher))
193
+ continue;
194
+ // Unix: the launcher is a symlink to <package>/dist/src/main.js. Windows: the npm shim sits beside node_modules.
195
+ const viaLink = opencliPackageDirOf(safeRealpath(launcher) ?? launcher);
196
+ const packageDir = viaLink ?? (opencliEntryOf(path.join(dir, 'node_modules', OPENCLI_PACKAGE)) ? path.join(dir, 'node_modules', OPENCLI_PACKAGE) : undefined);
197
+ const entry = packageDir ? opencliEntryOf(packageDir) : undefined;
198
+ if (packageDir && entry)
199
+ return { entry, packageDir, source: 'path' };
200
+ }
201
+ }
202
+ return undefined;
203
+ }
204
+ function safeRealpath(file) {
205
+ try {
206
+ return fs.realpathSync(file);
207
+ }
208
+ catch {
209
+ return undefined;
210
+ }
211
+ }
212
+ /** Global `node_modules` directories a desktop app (which does not inherit the shell's PATH) is likely to need. */
213
+ function commonGlobalRoots(env, platform, home) {
214
+ const roots = [];
215
+ const prefix = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
216
+ if (prefix)
217
+ roots.push(platform === 'win32' ? path.join(prefix, 'node_modules') : path.join(prefix, 'lib', 'node_modules'));
218
+ if (platform === 'win32') {
219
+ if (env.APPDATA)
220
+ roots.push(path.join(env.APPDATA, 'npm', 'node_modules'));
221
+ return roots;
222
+ }
223
+ roots.push('/opt/homebrew/lib/node_modules', '/usr/local/lib/node_modules', '/usr/lib/node_modules', path.join(home, '.npm-global', 'lib', 'node_modules'), path.join(home, '.local', 'lib', 'node_modules'), path.join(home, '.bun', 'install', 'global', 'node_modules'), path.join(home, '.volta', 'tools', 'image', 'packages', 'opencli', 'lib', 'node_modules'));
224
+ // Version managers keep one global root per Node version: take them all, newest directory name first.
225
+ const managed = [path.join(home, '.nvm', 'versions', 'node'), path.join(home, '.local', 'share', 'fnm', 'node-versions'), path.join(home, 'Library', 'Application Support', 'fnm', 'node-versions'), path.join(home, '.fnm', 'node-versions')];
226
+ for (const base of managed) {
227
+ let versions;
228
+ try {
229
+ versions = fs.readdirSync(base).sort().reverse();
230
+ }
231
+ catch {
232
+ continue;
233
+ }
234
+ for (const version of versions) {
235
+ roots.push(path.join(base, version, 'lib', 'node_modules'), path.join(base, version, 'installation', 'lib', 'node_modules'));
236
+ }
237
+ }
238
+ return roots;
239
+ }
240
+ /**
241
+ * Find OpenCLI without requiring it to be a dependency of the plugin. Order: `DSH_BROWSER_OPENCLI`, the plugin's own
242
+ * resolution (pnpm store, plugin-local, an `@jackwener/opencli` the user added to the profile), an `opencli` launcher on PATH,
243
+ * `npm root -g`, and the usual global locations. The first hit wins. Pure apart from reading the file system.
244
+ */
245
+ export function locateOpencli(search) {
246
+ const override = search.env.DSH_BROWSER_OPENCLI?.trim();
247
+ if (override) {
248
+ const found = opencliFromPath(override);
249
+ if (found)
250
+ return found;
251
+ // An explicit override that does not resolve is reported by the caller; do not silently use another copy.
252
+ return undefined;
253
+ }
254
+ for (const pkgJson of search.pluginPackageJsons()) {
255
+ const packageDir = path.dirname(pkgJson);
256
+ const entry = opencliEntryOf(packageDir);
257
+ if (entry)
258
+ return { entry, packageDir, source: 'plugin' };
259
+ }
260
+ const viaPath = opencliFromPathVariable(search.env, search.platform);
261
+ if (viaPath)
262
+ return viaPath;
263
+ const globalRoot = search.npmGlobalRoot();
264
+ if (globalRoot) {
265
+ const packageDir = path.join(globalRoot, OPENCLI_PACKAGE);
266
+ const entry = opencliEntryOf(packageDir);
267
+ if (entry)
268
+ return { entry, packageDir, source: 'global-npm' };
269
+ }
270
+ for (const root of commonGlobalRoots(search.env, search.platform, search.home)) {
271
+ const packageDir = path.join(root, OPENCLI_PACKAGE);
272
+ const entry = opencliEntryOf(packageDir);
273
+ if (entry)
274
+ return { entry, packageDir, source: 'common-prefix' };
275
+ }
276
+ return undefined;
277
+ }
278
+ /** The plugin's own copies of opencli: pnpm's virtual store, then module resolution from the plugin root (the profile's hoisted node_modules). */
279
+ function pluginOpencliPackageJsons() {
280
+ const found = [];
281
+ const store = pnpmStorePackageJson(OPENCLI_PACKAGE);
282
+ if (store)
283
+ found.push(store);
284
+ const req = createRequire(path.join(PLUGIN_ROOT, 'package.json'));
285
+ try {
286
+ found.push(req.resolve(OPENCLI_PACKAGE + '/package.json'));
287
+ }
288
+ catch { /* exports-restricted or absent */ }
289
+ try {
290
+ const root = findPackageRoot(req.resolve(OPENCLI_PACKAGE));
291
+ if (root)
292
+ found.push(root);
293
+ }
294
+ catch { /* absent */ }
295
+ return found;
296
+ }
297
+ let npmRootAsked = false;
298
+ let npmRootValue;
299
+ /** `npm root -g`, asked once per process (a spawn per status call would be slow), without the bogus Windows fallback when APPDATA is not set. */
300
+ function npmGlobalRootOrUndefined() {
301
+ if (npmRootAsked)
302
+ return npmRootValue;
303
+ npmRootAsked = true;
304
+ try {
305
+ const root = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', windowsHide: true, timeout: 15000 }).trim();
306
+ if (root)
307
+ npmRootValue = root;
308
+ }
309
+ catch { /* npm is not on PATH (a desktop app launched from the Dock has a minimal one) */ }
310
+ if (!npmRootValue && process.platform === 'win32' && process.env.APPDATA)
311
+ npmRootValue = path.join(process.env.APPDATA, 'npm', 'node_modules');
312
+ return npmRootValue;
313
+ }
314
+ let cachedOpencli;
315
+ /** Find OpenCLI on this machine. A hit is remembered while its files exist; a miss is looked up again (the user may install it while DSH runs). */
316
+ export function opencliLocation() {
317
+ const key = process.env.DSH_BROWSER_OPENCLI?.trim() ?? '';
318
+ if (cachedOpencli && cachedOpencli.key === key && fs.existsSync(cachedOpencli.location.entry))
319
+ return cachedOpencli.location;
320
+ const location = locateOpencli({
321
+ platform: process.platform,
322
+ env: process.env,
323
+ home: process.env.HOME ?? process.env.USERPROFILE ?? '',
324
+ pluginPackageJsons: pluginOpencliPackageJsons,
325
+ npmGlobalRoot: npmGlobalRootOrUndefined,
326
+ });
327
+ cachedOpencli = location ? { key, location } : undefined;
328
+ return location;
329
+ }
330
+ /** What to tell the user when OpenCLI was not found: names a wrong `DSH_BROWSER_OPENCLI` first, since that one is theirs to fix. */
331
+ export function opencliMissingMessage() {
332
+ const override = process.env.DSH_BROWSER_OPENCLI?.trim();
333
+ return override ? `DSH_BROWSER_OPENCLI=${override} is not an OpenCLI package directory, its main.js or the opencli launcher: fix or unset it. ${OPENCLI_INSTALL_HINT}` : OPENCLI_INSTALL_HINT;
334
+ }
335
+ /** Entry JS of OpenCLI (its bin/main). Throws the install hint when OpenCLI is not installed. */
126
336
  export function opencliEntryPath() {
127
- const dir = pkgDir('@jackwener/opencli');
128
- const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
129
- const bin = typeof pkg.bin === 'string' ? pkg.bin : (pkg.bin?.opencli ?? pkg.main ?? 'dist/src/main.js');
130
- return path.join(dir, bin);
337
+ const location = opencliLocation();
338
+ if (!location)
339
+ throw new Error(opencliMissingMessage());
340
+ return location.entry;
131
341
  }
132
342
  /** Electron's process.execPath points to the desktop app, not a Node CLI. */
133
343
  function nodeExecutable(env) {
@@ -153,7 +363,7 @@ function nodeExecutable(env) {
153
363
  return undefined;
154
364
  }
155
365
  /**
156
- * Run a Node.js script with piped stdio capture (bundled opencli / playwright
366
+ * Run a Node.js script with piped stdio capture (opencli / playwright
157
367
  * CLI). Mirrors web-search-pro's runCli contract.
158
368
  */
159
369
  export function runNode(script, args, opts = { signal: undefined }) {
@@ -213,7 +423,7 @@ export function runNode(script, args, opts = { signal: undefined }) {
213
423
  opts.signal?.addEventListener('abort', onAbort);
214
424
  });
215
425
  }
216
- /** Run opencli (bundled or global-reuse). */
426
+ /** Run opencli (found by `opencliLocation`). */
217
427
  export function runOpencli(args, opts = { signal: undefined }) {
218
428
  return runNode(opencliEntryPath(), args, opts);
219
429
  }
package/lib/deps.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deps.js","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Download saving: file-name rules, collision-free placement inside `downloadDir`, and size-capped streaming.
3
+ *
4
+ * Everything that decides where a byte lands lives here, apart from the browser, so the rules are testable
5
+ * on their own: a name is reduced to a plain file name, a file never overwrites another, and the only
6
+ * directory a file can end up in is the configured one.
7
+ * @module dsh-browser/downloads
8
+ */
9
+ /** How many download records a session keeps in memory (oldest dropped first). */
10
+ export declare const DOWNLOAD_HISTORY_LIMIT = 50;
11
+ /** What `inspect.downloads` reports for one download. The file itself is on disk; this record only lives in memory. */
12
+ export interface DownloadRecord {
13
+ /** `d1`, `d2`, ... within the session. */
14
+ id: string;
15
+ /** The URL the download came from, with credential-looking query parameters masked. */
16
+ url: string;
17
+ /** `saved`, or `failed` (nothing is left on disk for a failed one). */
18
+ status: 'saved' | 'failed';
19
+ /** `request`: fetched by `target.download` with the session's cookies. `browser`: a download event of a page (navigation or click). */
20
+ source: 'request' | 'browser';
21
+ /** The name the server or page suggested. */
22
+ suggestedFilename: string;
23
+ /** Absolute path of the saved file (saved only). */
24
+ path?: string;
25
+ bytes?: number;
26
+ sha256?: string;
27
+ /** Why it failed (failed only). */
28
+ error?: string;
29
+ timestamp: string;
30
+ }
31
+ /** A download was cut because it passed `downloadMaxBytes`. */
32
+ export declare class DownloadLimitError extends Error {
33
+ readonly maxBytes: number;
34
+ constructor(maxBytes: number);
35
+ }
36
+ /**
37
+ * Reduce a file name to a plain, portable one.
38
+ *
39
+ * `strict` is for a name the caller chose (`target.download` `filename`): anything that is not already a plain
40
+ * name is refused with INVALID_ARGS, so a path or a traversal never turns into a different file silently.
41
+ * Lenient is for a name a server or page suggested: only the last path segment is kept and unusable characters
42
+ * are replaced. Control characters are stripped in both. Returns '' when nothing usable is left (lenient only).
43
+ */
44
+ export declare function sanitizeDownloadName(raw: string, strict: boolean): string;
45
+ /** The name a download is saved under: the caller's (strict), else what the server suggested, else the URL's last segment. */
46
+ export declare function resolveDownloadFilename(input: {
47
+ requested?: string;
48
+ suggested?: string;
49
+ url?: string;
50
+ }): string;
51
+ /** The last path segment of a URL, percent-decoded; '' when there is none. */
52
+ export declare function downloadNameFromUrl(url: string): string;
53
+ /** The file name of a Content-Disposition header (`filename*=UTF-8''...` first, then `filename=`); '' when absent. */
54
+ export declare function contentDispositionFilename(header: string | undefined): string;
55
+ /**
56
+ * Move a finished temporary file to its final name inside `dir`, never overwriting: a taken name gets
57
+ * `-1`, `-2`, ... before the extension. `name` must already be a plain file name (see {@link sanitizeDownloadName});
58
+ * this checks it again, because it is the last line before bytes become a path. Returns the absolute path.
59
+ */
60
+ export declare function claimDownloadPath(dir: string, name: string, temporary: string): string;
61
+ /** A fresh temporary file path inside `dir` (dot-prefixed, so a half-written file is not mistaken for a result). */
62
+ export declare function temporaryDownloadPath(dir: string): string;
63
+ /**
64
+ * Write a stream to `file`, counting bytes and hashing as they pass. Past `maxBytes` the source is destroyed
65
+ * and {@link DownloadLimitError} is thrown, so the caller deletes the partial file.
66
+ */
67
+ export declare function streamToFile(source: NodeJS.ReadableStream & {
68
+ destroy?: (error?: Error) => void;
69
+ }, file: string, maxBytes: number): Promise<{
70
+ bytes: number;
71
+ sha256: string;
72
+ }>;
73
+ /** Write an in-memory body to `file` with the same result shape as {@link streamToFile}. */
74
+ export declare function writeBufferToFile(body: Buffer, file: string, maxBytes: number): {
75
+ bytes: number;
76
+ sha256: string;
77
+ };
78
+ /** Remove a file that may not exist; never throws. */
79
+ export declare function removeQuietly(file: string | undefined): void;
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Download saving: file-name rules, collision-free placement inside `downloadDir`, and size-capped streaming.
3
+ *
4
+ * Everything that decides where a byte lands lives here, apart from the browser, so the rules are testable
5
+ * on their own: a name is reduced to a plain file name, a file never overwrites another, and the only
6
+ * directory a file can end up in is the configured one.
7
+ * @module dsh-browser/downloads
8
+ */
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+ import crypto from 'node:crypto';
12
+ import { ActionArgError } from "./actions/types.js";
13
+ /** How many download records a session keeps in memory (oldest dropped first). */
14
+ export const DOWNLOAD_HISTORY_LIMIT = 50;
15
+ /** A download was cut because it passed `downloadMaxBytes`. */
16
+ export class DownloadLimitError extends Error {
17
+ maxBytes;
18
+ constructor(maxBytes) {
19
+ super(`the download is larger than downloadMaxBytes (${maxBytes} bytes) ; the transfer was stopped and nothing was saved`);
20
+ this.maxBytes = maxBytes;
21
+ this.name = 'DownloadLimitError';
22
+ }
23
+ }
24
+ // Control characters, the bidirectional overrides that make "txt.exe" read as "exe.txt", and line separators.
25
+ const INVISIBLE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g;
26
+ // What Windows refuses in a name; refused everywhere so a file is portable.
27
+ const WINDOWS_INVALID = /[<>:"|?*]/;
28
+ const WINDOWS_INVALID_ALL = /[<>:"|?*]/g;
29
+ const WINDOWS_RESERVED = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;
30
+ const MAX_NAME_CHARS = 180;
31
+ function limitLength(name) {
32
+ if (name.length <= MAX_NAME_CHARS)
33
+ return name;
34
+ const extension = path.extname(name);
35
+ const keep = extension.length > 0 && extension.length <= 20 ? extension : '';
36
+ return name.slice(0, MAX_NAME_CHARS - keep.length) + keep;
37
+ }
38
+ /**
39
+ * Reduce a file name to a plain, portable one.
40
+ *
41
+ * `strict` is for a name the caller chose (`target.download` `filename`): anything that is not already a plain
42
+ * name is refused with INVALID_ARGS, so a path or a traversal never turns into a different file silently.
43
+ * Lenient is for a name a server or page suggested: only the last path segment is kept and unusable characters
44
+ * are replaced. Control characters are stripped in both. Returns '' when nothing usable is left (lenient only).
45
+ */
46
+ export function sanitizeDownloadName(raw, strict) {
47
+ const fail = (message) => { throw new ActionArgError(`filename ${message}`, 'Pass a plain file name such as report.pdf; the directory is the downloadDir configuration.'); };
48
+ let name = String(raw).replace(INVISIBLE, '');
49
+ if (strict && /[\\/]/.test(name))
50
+ fail('must be a plain file name, not a path (no / or \\)');
51
+ if (!strict)
52
+ name = name.split(/[\\/]/).pop() ?? '';
53
+ if (strict && WINDOWS_INVALID.test(name))
54
+ fail('must not contain any of < > : " | ? *');
55
+ name = name.replace(WINDOWS_INVALID_ALL, '_');
56
+ // Trailing dots and spaces are dropped by Windows, so "a.pdf." and "a.pdf" would otherwise be two names for one file.
57
+ name = name.trim().replace(/[. ]+$/, '');
58
+ if (!name || name === '.' || name === '..' || /^\.+$/.test(name)) {
59
+ if (strict)
60
+ fail('must not be empty, "." or ".."');
61
+ return '';
62
+ }
63
+ if (WINDOWS_RESERVED.test(name.split('.')[0])) {
64
+ if (strict)
65
+ fail(`"${name}" is a reserved device name`);
66
+ name = '_' + name;
67
+ }
68
+ return limitLength(name);
69
+ }
70
+ /** The name a download is saved under: the caller's (strict), else what the server suggested, else the URL's last segment. */
71
+ export function resolveDownloadFilename(input) {
72
+ if (input.requested !== undefined)
73
+ return sanitizeDownloadName(input.requested, true);
74
+ return sanitizeDownloadName(input.suggested ?? '', false)
75
+ || sanitizeDownloadName(downloadNameFromUrl(input.url ?? ''), false)
76
+ || 'download';
77
+ }
78
+ /** The last path segment of a URL, percent-decoded; '' when there is none. */
79
+ export function downloadNameFromUrl(url) {
80
+ try {
81
+ const last = new URL(url).pathname.split('/').filter(Boolean).pop() ?? '';
82
+ return decodeURIComponent(last);
83
+ }
84
+ catch {
85
+ return '';
86
+ }
87
+ }
88
+ /** The file name of a Content-Disposition header (`filename*=UTF-8''...` first, then `filename=`); '' when absent. */
89
+ export function contentDispositionFilename(header) {
90
+ if (!header)
91
+ return '';
92
+ const extended = /filename\*\s*=\s*([^']*)'[^']*'([^;]+)/i.exec(header);
93
+ if (extended) {
94
+ try {
95
+ return decodeURIComponent(extended[2].trim().replace(/^"|"$/g, ''));
96
+ }
97
+ catch { /* fall through to the plain form */ }
98
+ }
99
+ const quoted = /filename\s*=\s*"((?:[^"\\]|\\.)*)"/i.exec(header);
100
+ if (quoted)
101
+ return quoted[1].replace(/\\(.)/g, '$1');
102
+ const bare = /filename\s*=\s*([^;]+)/i.exec(header);
103
+ return bare ? bare[1].trim() : '';
104
+ }
105
+ /**
106
+ * Move a finished temporary file to its final name inside `dir`, never overwriting: a taken name gets
107
+ * `-1`, `-2`, ... before the extension. `name` must already be a plain file name (see {@link sanitizeDownloadName});
108
+ * this checks it again, because it is the last line before bytes become a path. Returns the absolute path.
109
+ */
110
+ export function claimDownloadPath(dir, name, temporary) {
111
+ const root = path.resolve(dir);
112
+ if (name !== path.basename(name) || name === '' || name === '.' || name === '..' || /[\\/]/.test(name)) {
113
+ throw new Error(`refusing to save outside the download directory: ${JSON.stringify(name)}`);
114
+ }
115
+ const extension = path.extname(name);
116
+ const stem = extension ? name.slice(0, -extension.length) : name;
117
+ for (let attempt = 0; attempt < 10_000; attempt++) {
118
+ const candidate = path.join(root, attempt === 0 ? name : `${stem}-${attempt}${extension}`);
119
+ if (path.dirname(candidate) !== root)
120
+ throw new Error(`refusing to save outside the download directory: ${JSON.stringify(name)}`);
121
+ try {
122
+ // A hard link either takes the name or fails: it is the one atomic "create unless it exists".
123
+ fs.linkSync(temporary, candidate);
124
+ }
125
+ catch (error) {
126
+ const code = error.code;
127
+ if (code === 'EEXIST')
128
+ continue;
129
+ // File systems without hard links: an exclusive copy gives the same guarantee.
130
+ try {
131
+ fs.copyFileSync(temporary, candidate, fs.constants.COPYFILE_EXCL);
132
+ }
133
+ catch (copyError) {
134
+ if (copyError.code === 'EEXIST')
135
+ continue;
136
+ throw copyError;
137
+ }
138
+ }
139
+ fs.unlinkSync(temporary);
140
+ return candidate;
141
+ }
142
+ throw new Error(`could not find a free file name for ${JSON.stringify(name)} in the download directory`);
143
+ }
144
+ /** A fresh temporary file path inside `dir` (dot-prefixed, so a half-written file is not mistaken for a result). */
145
+ export function temporaryDownloadPath(dir) {
146
+ return path.join(path.resolve(dir), `.part-${crypto.randomUUID().slice(0, 12)}`);
147
+ }
148
+ /**
149
+ * Write a stream to `file`, counting bytes and hashing as they pass. Past `maxBytes` the source is destroyed
150
+ * and {@link DownloadLimitError} is thrown, so the caller deletes the partial file.
151
+ */
152
+ export async function streamToFile(source, file, maxBytes) {
153
+ const hash = crypto.createHash('sha256');
154
+ const handle = await fs.promises.open(file, 'wx');
155
+ let bytes = 0;
156
+ try {
157
+ for await (const chunk of source) {
158
+ const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
159
+ bytes += buffer.length;
160
+ if (bytes > maxBytes) {
161
+ source.destroy?.();
162
+ throw new DownloadLimitError(maxBytes);
163
+ }
164
+ hash.update(buffer);
165
+ await handle.write(buffer);
166
+ }
167
+ }
168
+ finally {
169
+ await handle.close();
170
+ }
171
+ return { bytes, sha256: hash.digest('hex') };
172
+ }
173
+ /** Write an in-memory body to `file` with the same result shape as {@link streamToFile}. */
174
+ export function writeBufferToFile(body, file, maxBytes) {
175
+ if (body.length > maxBytes)
176
+ throw new DownloadLimitError(maxBytes);
177
+ fs.writeFileSync(file, body, { flag: 'wx' });
178
+ return { bytes: body.length, sha256: crypto.createHash('sha256').update(body).digest('hex') };
179
+ }
180
+ /** Remove a file that may not exist; never throws. */
181
+ export function removeQuietly(file) {
182
+ if (!file)
183
+ return;
184
+ try {
185
+ fs.unlinkSync(file);
186
+ }
187
+ catch { /* already gone */ }
188
+ }
189
+ //# sourceMappingURL=downloads.js.map