dsh-client-auto-continue 0.3.2 → 0.4.1

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.
@@ -2,20 +2,25 @@
2
2
  /**
3
3
  * Vendor patch for a known DSH limitation (0.1.0-rc.6):
4
4
  *
5
- * The web plugin-configuration section only exposes settings namespaces listed
6
- * in `WEB_SETTINGS_NAMESPACES`, hardcoded in the installed
7
- * `@deepseek-ai/dsh-host-apiproxy` bundle ("adding a section to that page is a
8
- * decision made here rather than by the registering plugin. Moving that
9
- * declaration to `settings.register()` ... is deferred work"). Without this
10
- * patch the browser half of a third-party plugin's settings card reads
11
- * `settings-not-exposed` and renders nothing.
5
+ * The web settings surface only exposes namespaces listed in the hardcoded
6
+ * `WEB_SETTINGS_NAMESPACES` / `PRODUCT_SETTINGS_NAMESPACES` allowlists inside
7
+ * the installed `@deepseek-ai/dsh-host-apiproxy` bundle. Any other registered
8
+ * namespace answers `settings-not-exposed`, so a third-party plugin's settings
9
+ * section renders nothing even though its namespace registered fine (the
10
+ * proxy's own comment calls moving exposure into `settings.register()` "deferred
11
+ * work").
12
12
  *
13
- * This script adds the `auto-continue` namespace to that allowlist in EVERY
14
- * reachable dsh installation: the profile-linked copy (pnpm store / npx cache)
15
- * and a global `npm i -g @deepseek-ai/dsh` install under the active Node
16
- * version, plus the invoking directory's own install. It is idempotent:
17
- * re-running it after any dsh reinstall reapplies the patch to the copies
18
- * that lack it.
13
+ * This script makes the exposure REGISTRY-DRIVEN instead of hardcoded: it
14
+ * patches `exposedNamespaces()` to also expose every namespace currently
15
+ * registered with the settings provider. The patch contains NO plugin-specific
16
+ * string, so the settings of ANY plugin that registers a namespace (and mounts
17
+ * its own settings section) appear automatically this plugin included.
18
+ *
19
+ * It is applied to every reachable dsh installation: the profile-linked copy
20
+ * (pnpm store / npx cache), a global `npm i -g @deepseek-ai/dsh` install under
21
+ * the active Node version, and the invoking directory's own install. Re-run it
22
+ * after any dsh reinstall; it is idempotent and also removes the previous
23
+ * per-plugin allowlist entry (pre-0.4.0 installs).
19
24
  *
20
25
  * Usage: node scripts/patch-expose.mjs
21
26
  */
@@ -24,13 +29,22 @@ import { readFileSync, writeFileSync, realpathSync } from 'node:fs';
24
29
  import { dirname, join } from 'node:path';
25
30
  import { homedir } from 'node:os';
26
31
 
27
- /** The namespace this plugin's settings card edits. */
28
- const NS = 'auto-continue';
32
+ /** The registry-driven patch: expose every namespace the provider knows. */
33
+ const GENERIC_ADD = `\t\tconst settings = ctx.get("settings");
34
+ \t\tif (settings !== void 0) for (const descriptor of settings.describe()) exposed.add(String(descriptor.ns));`;
35
+
36
+ /** Marker proving the generic patch is already applied. */
37
+ const GENERIC_MARKER = 'for (const descriptor of settings.describe()) exposed.add(String(descriptor.ns))';
38
+
39
+ /** The hardcoded allowlist tail, as shipped (and as the old patch rewrote it). */
40
+ const ARRAY_TAIL_PLAIN = `\t"web-search-deepseek"\n];`;
41
+ const ARRAY_TAIL_OLD_PATCH = `\t"web-search-deepseek",\n\t"auto-continue"\n];`;
29
42
 
30
43
  /**
31
44
  * Collect candidate dsh-host-apiproxy package.json paths: the profile-linked
32
- * copy, a global install under the active Node version (nvm layout), and the
33
- * invoking directory's own install. Deduplicated by real path.
45
+ * copy, a global install under the active Node version's nvm layout
46
+ * (`<nvm>/<version>/lib/node_modules/@deepseek-ai/dsh`), and the invoking
47
+ * directory's own install. Deduplicated by real path.
34
48
  */
35
49
  function candidatePackageJsons() {
36
50
  const found = new Set();
@@ -51,8 +65,7 @@ function candidatePackageJsons() {
51
65
 
52
66
  // 1. The copy the profile's node_modules links to.
53
67
  tryResolve(createRequire(join(homedir(), '.dsh', 'profiles', 'web', 'package.json')));
54
- // 2. A global install under the active Node version's nvm layout
55
- // (`<nvm>/<version>/lib/node_modules/@deepseek-ai/dsh`).
68
+ // 2. A global install under the active Node version's nvm layout.
56
69
  try {
57
70
  const globalRoot = realpathSync(join(process.execPath, '..', '..', 'lib', 'node_modules'));
58
71
  tryResolve(createRequire(join(globalRoot, '@deepseek-ai', 'dsh', 'package.json')));
@@ -70,23 +83,46 @@ if (candidates.length === 0) {
70
83
  process.exit(1);
71
84
  }
72
85
 
73
- let patchedAny = false;
86
+ let changedAny = false;
74
87
  for (const packageJson of candidates) {
75
88
  const bundlePath = join(dirname(packageJson), 'lib', 'index.js');
76
- const source = readFileSync(bundlePath, 'utf8');
77
- if (source.includes(`"${NS}"`)) {
78
- console.log(`[patch-expose] ${NS} already present in ${bundlePath} — skipped.`);
79
- continue;
89
+ let source = readFileSync(bundlePath, 'utf8');
90
+ let changed = false;
91
+
92
+ // 1. Remove the previous per-plugin allowlist entry (pre-0.4.0 installs).
93
+ if (source.includes(ARRAY_TAIL_OLD_PATCH)) {
94
+ source = source.replace(ARRAY_TAIL_OLD_PATCH, ARRAY_TAIL_PLAIN);
95
+ changed = true;
96
+ console.log(`[patch-expose] removed per-plugin allowlist entry in ${bundlePath}`);
80
97
  }
81
- const marker = `\t"web-search-deepseek"\n];`;
82
- if (!source.includes(marker)) {
83
- console.error(`[patch-expose] could not locate the WEB_SETTINGS_NAMESPACES tail in ${bundlePath}`);
84
- continue;
98
+
99
+ // 2. Make exposure registry-driven (idempotent).
100
+ if (!source.includes(GENERIC_MARKER)) {
101
+ const fnStart = source.indexOf('\tfunction exposedNamespaces() {');
102
+ if (fnStart === -1) {
103
+ console.error(`[patch-expose] could not locate exposedNamespaces() in ${bundlePath}`);
104
+ continue;
105
+ }
106
+ const fnEnd = source.indexOf('\t}', fnStart);
107
+ if (fnEnd === -1) {
108
+ console.error(`[patch-expose] could not locate the end of exposedNamespaces() in ${bundlePath}`);
109
+ continue;
110
+ }
111
+ const body = source.slice(fnStart, fnEnd);
112
+ if (!body.includes('return exposed;')) {
113
+ console.error(`[patch-expose] unexpected exposedNamespaces() body in ${bundlePath}`);
114
+ continue;
115
+ }
116
+ const patchedBody = body.replace('\t\treturn exposed;', `${GENERIC_ADD}\n\t\treturn exposed;`);
117
+ source = source.slice(0, fnStart) + patchedBody + source.slice(fnEnd);
118
+ changed = true;
119
+ console.log(`[patch-expose] made exposure registry-driven in ${bundlePath}`);
120
+ } else {
121
+ console.log(`[patch-expose] registry-driven exposure already present in ${bundlePath} — skipped.`);
85
122
  }
86
- const patched = source.replace(marker, `\t"web-search-deepseek",\n\t"${NS}"\n];`);
87
- writeFileSync(bundlePath, patched);
88
- patchedAny = true;
89
- console.log(`[patch-expose] added "${NS}" to WEB_SETTINGS_NAMESPACES in ${bundlePath}`);
123
+
124
+ if (changed) writeFileSync(bundlePath, source);
125
+ changedAny = changedAny || changed;
90
126
  }
91
127
 
92
- if (patchedAny) console.log('[patch-expose] restart `dsh web` for the change to take effect.');
128
+ if (changedAny) console.log('[patch-expose] restart `dsh web` for the change to take effect.');