@chatcode/cco-market 1.45.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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/README.zh.md +143 -0
  4. package/UPDATE-API-V1.md +132 -0
  5. package/client/client.js +11534 -0
  6. package/cordis.patch.yml +5 -0
  7. package/lib/accelerate.js +184 -0
  8. package/lib/agents.js +36 -0
  9. package/lib/backup.js +572 -0
  10. package/lib/catalog-local-match.js +126 -0
  11. package/lib/catalog-npm.js +111 -0
  12. package/lib/changelog.js +242 -0
  13. package/lib/channels.js +64 -0
  14. package/lib/check.js +1067 -0
  15. package/lib/compatibility.js +198 -0
  16. package/lib/diagnostics.js +49 -0
  17. package/lib/discovery-compatibility.js +260 -0
  18. package/lib/dsh-cli.js +949 -0
  19. package/lib/dsh-install.js +108 -0
  20. package/lib/gist.js +352 -0
  21. package/lib/groups.js +97 -0
  22. package/lib/home-paths.js +42 -0
  23. package/lib/hot.js +519 -0
  24. package/lib/http.js +39 -0
  25. package/lib/index.js +97 -0
  26. package/lib/install.js +387 -0
  27. package/lib/log.js +197 -0
  28. package/lib/ndjson.js +154 -0
  29. package/lib/net.js +98 -0
  30. package/lib/order.js +284 -0
  31. package/lib/patch.js +521 -0
  32. package/lib/pnpm-compat.js +490 -0
  33. package/lib/presets.js +278 -0
  34. package/lib/profile.js +911 -0
  35. package/lib/region-probe.js +93 -0
  36. package/lib/regions.js +253 -0
  37. package/lib/registry.js +204 -0
  38. package/lib/restart.js +373 -0
  39. package/lib/routes.js +4372 -0
  40. package/lib/settings.js +109 -0
  41. package/lib/skill-market/api.js +119 -0
  42. package/lib/skill-market/config.js +29 -0
  43. package/lib/skill-market/installer.js +352 -0
  44. package/lib/skill-market/runtime.js +13 -0
  45. package/lib/skill-market/tui.js +119 -0
  46. package/lib/skill-market/types.js +1 -0
  47. package/lib/skill-market/web-routes.js +123 -0
  48. package/lib/snapshot.js +500 -0
  49. package/lib/source-migration.js +54 -0
  50. package/lib/sources.js +596 -0
  51. package/lib/store.js +91 -0
  52. package/lib/themes.js +102 -0
  53. package/lib/trial.js +116 -0
  54. package/lib/types/accelerate.d.ts +85 -0
  55. package/lib/types/agents.d.ts +22 -0
  56. package/lib/types/backup.d.ts +131 -0
  57. package/lib/types/catalog-local-match.d.ts +50 -0
  58. package/lib/types/catalog-npm.d.ts +47 -0
  59. package/lib/types/changelog.d.ts +102 -0
  60. package/lib/types/channels.d.ts +56 -0
  61. package/lib/types/check.d.ts +266 -0
  62. package/lib/types/compatibility.d.ts +64 -0
  63. package/lib/types/diagnostics.d.ts +29 -0
  64. package/lib/types/discovery-compatibility.d.ts +80 -0
  65. package/lib/types/dsh-cli.d.ts +324 -0
  66. package/lib/types/dsh-install.d.ts +46 -0
  67. package/lib/types/gist.d.ts +53 -0
  68. package/lib/types/groups.d.ts +34 -0
  69. package/lib/types/home-paths.d.ts +16 -0
  70. package/lib/types/hot.d.ts +221 -0
  71. package/lib/types/http.d.ts +12 -0
  72. package/lib/types/index.d.ts +14 -0
  73. package/lib/types/install.d.ts +172 -0
  74. package/lib/types/log.d.ts +43 -0
  75. package/lib/types/ndjson.d.ts +52 -0
  76. package/lib/types/net.d.ts +58 -0
  77. package/lib/types/order.d.ts +100 -0
  78. package/lib/types/patch.d.ts +129 -0
  79. package/lib/types/pnpm-compat.d.ts +93 -0
  80. package/lib/types/presets.d.ts +90 -0
  81. package/lib/types/profile.d.ts +253 -0
  82. package/lib/types/region-probe.d.ts +50 -0
  83. package/lib/types/regions.d.ts +122 -0
  84. package/lib/types/registry.d.ts +86 -0
  85. package/lib/types/restart.d.ts +194 -0
  86. package/lib/types/routes.d.ts +67 -0
  87. package/lib/types/settings.d.ts +78 -0
  88. package/lib/types/skill-market/api.d.ts +10 -0
  89. package/lib/types/skill-market/config.d.ts +3 -0
  90. package/lib/types/skill-market/installer.d.ts +23 -0
  91. package/lib/types/skill-market/runtime.d.ts +10 -0
  92. package/lib/types/skill-market/tui.d.ts +4 -0
  93. package/lib/types/skill-market/types.d.ts +71 -0
  94. package/lib/types/skill-market/web-routes.d.ts +19 -0
  95. package/lib/types/snapshot.d.ts +93 -0
  96. package/lib/types/source-migration.d.ts +11 -0
  97. package/lib/types/sources.d.ts +216 -0
  98. package/lib/types/store.d.ts +30 -0
  99. package/lib/types/themes.d.ts +40 -0
  100. package/lib/types/trial.d.ts +61 -0
  101. package/lib/types/update-api-v1.d.ts +66 -0
  102. package/lib/types/updates.d.ts +123 -0
  103. package/lib/types/verify.d.ts +139 -0
  104. package/lib/update-api-v1.js +215 -0
  105. package/lib/updates.js +361 -0
  106. package/lib/verify.js +453 -0
  107. package/package.json +121 -0
  108. package/src/accelerate.ts +213 -0
  109. package/src/agents.ts +43 -0
  110. package/src/backup.ts +583 -0
  111. package/src/catalog-local-match.ts +144 -0
  112. package/src/catalog-npm.ts +120 -0
  113. package/src/changelog.ts +282 -0
  114. package/src/channels.ts +70 -0
  115. package/src/check.ts +1239 -0
  116. package/src/client/CommentsModal.tsx +119 -0
  117. package/src/client/Diagnostics.tsx +907 -0
  118. package/src/client/ErrorBoundary.tsx +111 -0
  119. package/src/client/InstallToast.tsx +31 -0
  120. package/src/client/Market.module.css +830 -0
  121. package/src/client/MarketSection.tsx +5301 -0
  122. package/src/client/OperationsPanel.tsx +365 -0
  123. package/src/client/SettingsCard.tsx +621 -0
  124. package/src/client/SkillMarket.module.css +21 -0
  125. package/src/client/SkillMarketSection.tsx +162 -0
  126. package/src/client/comments.ts +54 -0
  127. package/src/client/globals.d.ts +13 -0
  128. package/src/client/index.ts +180 -0
  129. package/src/client/locales.ts +1112 -0
  130. package/src/client/market-data.ts +1321 -0
  131. package/src/client/operations.ts +201 -0
  132. package/src/client/preset-panel.tsx +263 -0
  133. package/src/client/primitives.d.ts +140 -0
  134. package/src/client/self-check.ts +147 -0
  135. package/src/client/snapshot-panel.tsx +244 -0
  136. package/src/compatibility.ts +237 -0
  137. package/src/diagnostics.ts +84 -0
  138. package/src/discovery-compatibility.ts +315 -0
  139. package/src/dsh-cli.ts +1126 -0
  140. package/src/dsh-install.ts +118 -0
  141. package/src/gist.ts +362 -0
  142. package/src/groups.ts +111 -0
  143. package/src/home-paths.ts +53 -0
  144. package/src/hot.ts +628 -0
  145. package/src/http.ts +41 -0
  146. package/src/index.ts +128 -0
  147. package/src/install.ts +420 -0
  148. package/src/log.ts +206 -0
  149. package/src/ndjson.ts +185 -0
  150. package/src/net.ts +106 -0
  151. package/src/order.ts +303 -0
  152. package/src/patch.ts +522 -0
  153. package/src/pnpm-compat.ts +527 -0
  154. package/src/presets.ts +344 -0
  155. package/src/profile.ts +940 -0
  156. package/src/region-probe.ts +97 -0
  157. package/src/regions.ts +310 -0
  158. package/src/registry.ts +250 -0
  159. package/src/restart.ts +396 -0
  160. package/src/routes.ts +4506 -0
  161. package/src/settings.ts +141 -0
  162. package/src/skill-market/api.ts +130 -0
  163. package/src/skill-market/config.ts +32 -0
  164. package/src/skill-market/installer.ts +337 -0
  165. package/src/skill-market/runtime.ts +14 -0
  166. package/src/skill-market/tui.ts +157 -0
  167. package/src/skill-market/types.ts +80 -0
  168. package/src/skill-market/web-routes.ts +132 -0
  169. package/src/snapshot.ts +532 -0
  170. package/src/source-migration.ts +61 -0
  171. package/src/sources.ts +565 -0
  172. package/src/store.ts +89 -0
  173. package/src/themes.ts +125 -0
  174. package/src/trial.ts +156 -0
  175. package/src/update-api-v1.ts +277 -0
  176. package/src/updates.ts +400 -0
  177. package/src/verify.ts +492 -0
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Process layer: re-invoking the ChatCode CLI launcher that started this host,
3
+ * spawning plugin commands with timeouts and live progress, and provisioning
4
+ * pnpm. This is the only module that starts child processes.
5
+ *
6
+ * Installs run through node:child_process, not ctx.shell: the shell service is
7
+ * the agent's sandboxed executor and denies writes to the profile directory.
8
+ */
9
+ import type { ChildProcess } from 'node:child_process';
10
+ import { type ProgressPhase } from './ndjson.ts';
11
+ import { type Region } from './regions.ts';
12
+ /**
13
+ * The real Node executable for spawning children. On Android the kernel runs
14
+ * node through the dynamic linker, so `process.execPath` is
15
+ * `/apex/.../linker64` — spawning IT with `--expose-internals` makes the
16
+ * linker treat the flag as the program path and die with
17
+ * `error: expected absolute path: "--expose-internals"`. `process.argv0`
18
+ * carries the real node binary; prefer it whenever it is an existing
19
+ * absolute path, and fall back to execPath everywhere else.
20
+ * @param argv0 - `process.argv0`, injectable for tests.
21
+ * @param execPath - `process.execPath`, injectable for tests.
22
+ */
23
+ export declare function nodeExecutable(argv0?: string | undefined, execPath?: string): string;
24
+ /**
25
+ * The directory holding the Node binary running this process. `npm`,
26
+ * `npm.cmd` and `corepack` are installed alongside it by every official Node
27
+ * distribution, so it is the one place the toolchain can be looked for
28
+ * without guessing — and unlike a PATH entry it cannot be absent, because
29
+ * this process is executing out of it.
30
+ *
31
+ * #167: a Windows desktop host spawned dsh without the Node install
32
+ * directory on PATH. Node itself was running (v24.18.1 in the log) while
33
+ * both `corepack` and `npm` came back "not recognized as an internal or
34
+ * external command", so the one-click setup had no way to succeed.
35
+ */
36
+ export declare const nodeBinDir: string;
37
+ /**
38
+ * Translate the machine's proxy environment into the ONE form pnpm reads.
39
+ *
40
+ * `HTTPS_PROXY` / `http_proxy` are what every other tool honours, and what
41
+ * `net.ts` already routes the market's own catalog fetches through — but
42
+ * pnpm ignores them completely. It reads npm config, so a proxy reaches it
43
+ * only as `npm_config_https_proxy` / `npm_config_proxy` (or an .npmrc entry,
44
+ * which is the user's file and not ours to rewrite).
45
+ *
46
+ * That gap is why the market could load its catalog through a proxy and
47
+ * then hang installing anything at all — reported four separate times
48
+ * (#148, #161, #188, #232), always from a network that needs one.
49
+ *
50
+ * An `npm_config_*` value the caller already set always wins: it is the more
51
+ * specific statement of intent, and on Windows env keys are case-insensitive
52
+ * so the check has to be too. NO_PROXY is forwarded verbatim because pnpm
53
+ * reads `npm_config_noproxy` and a host excluding its own registry mirror
54
+ * must keep excluding it.
55
+ */
56
+ export declare function proxyEnvForPnpm(env?: NodeJS.ProcessEnv, region?: Region): NodeJS.ProcessEnv;
57
+ /**
58
+ * Directories to append to PATH so a spawned pnpm can be found (#32, #38,
59
+ * #167, #292).
60
+ *
61
+ * A GUI or desktop launch inherits none of the shell profile, so PATH holds
62
+ * whatever the launcher had — usually not the directory the user's package
63
+ * manager lives in. The market appends the places it is actually installed
64
+ * to rather than telling the user to fix their environment.
65
+ *
66
+ * Windows used to get only the Node directory, which made the market's own
67
+ * advice unfollowable: the error it prints recommends installing pnpm with
68
+ * `iwr https://get.pnpm.io/install.ps1`, and then it did not look where that
69
+ * installer puts it (#292). Both Windows layouts are covered now — the
70
+ * standalone installer's `%LOCALAPPDATA%\pnpm`, and `%APPDATA%\npm` where
71
+ * `npm i -g pnpm` writes `pnpm.cmd`.
72
+ *
73
+ * `PNPM_HOME` comes first on every platform: the installer sets it, so it is
74
+ * the one answer that is right even when the layout is not the default one.
75
+ *
76
+ * @param platform - `process.platform`, injectable for tests.
77
+ * @param env - environment, for PNPM_HOME and the Windows app-data roots.
78
+ * @param home - home directory, injectable for tests.
79
+ */
80
+ export declare function toolSearchDirs(platform?: string, env?: NodeJS.ProcessEnv, home?: string): string[];
81
+ /**
82
+ * Windows npm/corepack/pnpm are `.cmd` shims. Node's `spawn` without a shell
83
+ * cannot start them (ENOENT / EINVAL). Same pattern as dsh's `plugin` forwarder.
84
+ */
85
+ export declare const winCmdShim: boolean;
86
+ /**
87
+ * Quote one argv token for a cmd.exe `/c` command line. cmd only groups with
88
+ * double quotes, so a token that needs quoting gets wrapped and embedded
89
+ * quotes are doubled.
90
+ */
91
+ export declare function quoteCmdArg(arg: string): string;
92
+ /**
93
+ * Build a cmd.exe command line from argv. Only the Windows shim path uses
94
+ * this: cmd re-parses the joined string, so every token is quoted before
95
+ * joining.
96
+ */
97
+ export declare function cmdCommandLine(argv: readonly string[]): string;
98
+ /**
99
+ * Whether a profile name can cross the rare Windows `dsh.cmd` fallback.
100
+ *
101
+ * cmd.exe expands percent-delimited environment variables even inside a
102
+ * quoted argument. Keep that fallback to names made only of letters, marks,
103
+ * numbers, spaces, dots, underscores, and hyphens. The normal direct-Node
104
+ * launcher remains argv-safe and accepts every DSH-valid profile name.
105
+ */
106
+ export declare function isCmdSafeProfileName(profile: string): boolean;
107
+ /**
108
+ * Argv re-invoking the CLI that launched this host process, so installs work
109
+ * whether ChatCode CLI runs from a global bin, a local install, or repo source
110
+ * (`node --import tsx/esm .../bin.ts`). Falls back to PATH `chatcode-cli`.
111
+ */
112
+ export declare function dshArgv(): {
113
+ file: string;
114
+ args: string[];
115
+ cwd: string | undefined;
116
+ viaShell: boolean;
117
+ };
118
+ /** Outcome of one spawned plugin command. */
119
+ export interface InstallResult {
120
+ exitCode: number | null;
121
+ timedOut: boolean;
122
+ stdout: string;
123
+ stderr: string;
124
+ /** True when the run ended because the user cancelled it. */
125
+ cancelled: boolean;
126
+ /** Desktop's generation-wide package-operation gate rejected the start. */
127
+ busy?: boolean;
128
+ /** Package names pnpm reported as having ignored build scripts (ndjson). */
129
+ ignoredBuilds?: string[];
130
+ /**
131
+ * pnpm's OWN error message and code, from its structured ndjson stream
132
+ * (#244).
133
+ *
134
+ * Without this the only thing a failure could report was the tail of
135
+ * stderr — which for a market install is dsh's wrapper line, "pnpm failed
136
+ * in profile directory …", identical for every possible cause. pnpm's
137
+ * real error never went to stderr at all; it goes to the ndjson stdout
138
+ * this already parses for progress, and was being thrown away on the way
139
+ * out. Three separate reports (#244, #192, #138) are all "the UI shows a
140
+ * stack tail and nothing else".
141
+ */
142
+ pnpmError?: string;
143
+ pnpmErrorCode?: string;
144
+ /**
145
+ * Exact npm version this Desktop run actually handed to the host (#496).
146
+ *
147
+ * Anywhere Labs' install boundary rewrites a floating dist-tag (or bare
148
+ * name) to `name@x.y.z` with its own registry fetch. The update route
149
+ * normally pins that version itself before `add`, so this field matches
150
+ * the request and is unused for verification. It matters when registry
151
+ * metadata was unavailable and the add still carried `@latest`/`@beta`:
152
+ * verification then adopts this pin instead of leaving the expected
153
+ * version unset. When the route already sent an exact pin, callers must
154
+ * keep that pin authoritative and must not let this field lower it.
155
+ */
156
+ resolvedNpmVersion?: string;
157
+ }
158
+ /** The shape every orchestration function takes to run plugin commands (injectable in tests). */
159
+ export type PluginRunner = (profile: string, pluginArgs: string[]) => Promise<InstallResult>;
160
+ /** Package-operation boundary consumed by the HTTP route layer. */
161
+ export interface PluginCommandRuntime {
162
+ runPlugin: PluginRunner;
163
+ probePnpm(): Promise<boolean>;
164
+ provisionPnpm(): Promise<{
165
+ ok: boolean;
166
+ hint?: string;
167
+ }>;
168
+ cancelActive(): boolean;
169
+ /** Whether this host can execute an immutable rollback add target. */
170
+ supportsExactRollbackTarget?(target: string): boolean;
171
+ }
172
+ /** One running package operation, however it was started. */
173
+ export interface DesktopPnpmHandleLike {
174
+ readonly stdout: NodeJS.ReadableStream;
175
+ readonly stderr: NodeJS.ReadableStream;
176
+ readonly done: Promise<{
177
+ readonly exitCode: number | null;
178
+ readonly signal: NodeJS.Signals | null;
179
+ }>;
180
+ cancel(): void;
181
+ }
182
+ /**
183
+ * Structural subset of DSH Desktop's public `desktopPnpm` contract.
184
+ *
185
+ * Anywhere Labs' DSH Desktop is ONE third-party client among several, and
186
+ * this interface exists only for it. Nothing here is part of the official
187
+ * DSH protocol — `desktopPnpm`, `installPlugin` and the install boundary
188
+ * below appear nowhere in `@deepseek-ai/*`. Every other client the market
189
+ * runs under, including other desktop apps, installs through the ordinary
190
+ * `dsh plugin --profile <p> add` CLI, and so does the market itself when
191
+ * none of these services are present.
192
+ *
193
+ * That is why every member past `runPlugin` is optional and reached by
194
+ * feature detection. A host that does not publish one simply never enters
195
+ * the branch, and the ordinary path it already used stays untouched — the
196
+ * cost of accommodating one vendor must not be paid by the others, or by
197
+ * the far larger number of people on plain `dsh web`.
198
+ */
199
+ export interface DesktopPnpmLike {
200
+ runPlugin(args: readonly string[], invokingDir: string, signal?: AbortSignal): DesktopPnpmHandleLike;
201
+ /**
202
+ * Desktop 2.x refuses `add` through `runPlugin` — "plugin add must use the
203
+ * recoverable install boundary" (#215, #219, #272) — and offers this
204
+ * instead, which their launcher enables only for the selected market
205
+ * provider. Same arguments, same handle, no recovery receipt and no
206
+ * write-ahead log for the caller to reconcile.
207
+ *
208
+ * Optional because it is theirs: absent on every other host, including
209
+ * the other third-party desktop client in #292, which installs perfectly
210
+ * well through the ordinary CLI.
211
+ *
212
+ * Read from their published source rather than assumed: it accepts ONLY
213
+ * `add` with exactly one target of the form `name@exact.version`
214
+ * (`validateExternalMarketInstallArgs` in dsh-plugin-desktop/src/pnpm.ts).
215
+ * A `github:owner/repo` target is rejected before any process starts, so
216
+ * the 1085 catalog entries with no npm package — 57% of it — cannot be
217
+ * installed on that host by any spelling this market could send. That is
218
+ * a gap in their contract, not something to work around here.
219
+ */
220
+ runExternalMarketPluginInstall?(args: readonly string[], invokingDir: string, signal?: AbortSignal): DesktopPnpmHandleLike;
221
+ }
222
+ /** Desktop runtime also owns cleanup of any operation started by this fiber. */
223
+ export interface DesktopPluginRuntime extends PluginCommandRuntime {
224
+ dispose(): Promise<void>;
225
+ }
226
+ /**
227
+ * Kill a spawned child and, on Windows, its whole process tree — `kill()`
228
+ * there only terminates the wrapper, leaving pnpm children running.
229
+ * (Contributed in #7 by @mraing.)
230
+ */
231
+ export declare function killChild(child: ChildProcess): void;
232
+ /**
233
+ * Cancel the plugin command currently running.
234
+ * @returns true when there was one to cancel.
235
+ */
236
+ export declare function cancelActive(): boolean;
237
+ /** Why `pnpm --version` last failed, or null when it has not failed. */
238
+ export declare function lastPnpmProbeFailure(): {
239
+ kind: 'missing' | 'failed';
240
+ output: string;
241
+ } | null;
242
+ /** Probe `pnpm --version` on PATH. */
243
+ export declare function probePnpm(): Promise<boolean>;
244
+ /**
245
+ * Provision pnpm without user involvement: corepack (ships with Node) first,
246
+ * a global npm install as fallback.
247
+ * @returns true when `pnpm --version` succeeds afterwards.
248
+ */
249
+ export declare function provisionPnpm(): Promise<{
250
+ ok: boolean;
251
+ hint?: string;
252
+ }>;
253
+ /**
254
+ * Whether a bare command name resolves to a file on the PATH the market
255
+ * hands its children.
256
+ *
257
+ * The market cannot read the reason a spawn failed out of the child's
258
+ * message: cmd.exe reports a missing command in the console's ANSI codepage
259
+ * ("'npm' 不是内部或外部命令" on a Chinese Windows), which is neither the
260
+ * string `ENOENT` nor even valid UTF-8 — so the #32 hint, written against
261
+ * Node's own ENOENT wording, could never fire on Windows and the user was
262
+ * left with no guidance at all (#167). Looking on disk answers the same
263
+ * question in every locale.
264
+ */
265
+ export declare function toolOnPath(name: string): boolean;
266
+ /**
267
+ * Why the one-click pnpm setup failed, in terms the user can act on.
268
+ *
269
+ * Every one of these was a real report where the market said only "自动准备
270
+ * 没成功" while the log held the actual cause: EEXIST (#142 — corepack had
271
+ * already placed a pnpm shim, so `npm -g` refused to overwrite it), EPERM
272
+ * (#108 — Node installed somewhere the user cannot write), ENOENT (#32 —
273
+ * a GUI launch with no Node on PATH at all).
274
+ * @returns a bilingual, actionable hint, or undefined when unrecognized.
275
+ */
276
+ export declare function provisionHint(corepackOutput: string, npmOutput: string, npmFound?: boolean, probeFailure?: {
277
+ kind: 'missing' | 'failed';
278
+ output: string;
279
+ } | null): string | undefined;
280
+ /** Live progress of the running plugin command, for the status route. */
281
+ export interface InstallProgress {
282
+ active: boolean;
283
+ target: string;
284
+ startedAt: number;
285
+ lastLine: string;
286
+ /** Parsed from pnpm's ndjson stage events; null when none arrived. */
287
+ phase: ProgressPhase;
288
+ /** Distinct packages resolved/fetched so far. */
289
+ done: number;
290
+ total: number | null;
291
+ currentPackage: string | null;
292
+ downloaded: number | null;
293
+ size: number | null;
294
+ /** True when structured ndjson progress has been observed. */
295
+ ndjson: boolean;
296
+ /** Last fatal error from the stream (only meaningful after a failure). */
297
+ error: string | null;
298
+ /** True from the moment the user asks to cancel until the run ends. */
299
+ cancelling: boolean;
300
+ }
301
+ /** Singleton progress state; the status route reads it, runDshPlugin writes it. */
302
+ export declare const progress: InstallProgress;
303
+ /** Identifies this host process; the client scopes its pending-restart flags to it. */
304
+ export declare const BOOT_ID: string;
305
+ /**
306
+ * Central allowlist for every spawn target, regardless of which route built
307
+ * it (defense in depth on top of per-route validation — the win32 bare-dsh
308
+ * fallback runs through a shell). Suggested in #16 by @anupamme.
309
+ *
310
+ * `^`, `~` and `=` are intentionally allowed: restore/install flows turn
311
+ * manifest specs such as "dsh-better-sidebar": "^0.14.0" into targets like
312
+ * `dsh-better-sidebar@^0.14.0`, and regex-valid semver ranges must not be
313
+ * mistaken for shell injection (whitespace and shell metacharacters remain
314
+ * rejected — the win32 bare-dsh fallback is the reason to keep them out).
315
+ */
316
+ export declare const TARGET_RE: RegExp;
317
+ /** Run one `chatcode-cli plugin --profile <p> …` command with timeout and progress tracking. */
318
+ export declare function runDshPlugin(profile: string, pluginArgs: string[]): Promise<InstallResult>;
319
+ /**
320
+ * Adapt DSH Desktop's generation-scoped package manager to the existing
321
+ * market runner. There is no runtime import or dependency on Desktop: the
322
+ * Host supplies this public service only when the package is mounted there.
323
+ */
324
+ export declare function createDesktopPluginRuntime(service: DesktopPnpmLike, activeProfileDir: string, invokingDir?: string, timeoutMs?: number): DesktopPluginRuntime;
@@ -0,0 +1,46 @@
1
+ /** Locate the DSH host package in CLI and packaged Desktop runtimes. */
2
+ /**
3
+ * The version of the DSH host this market is running inside.
4
+ *
5
+ * Read from the same manifest `findDshInstallDir` already parses to identify
6
+ * the package — the version was sitting in that object and being discarded.
7
+ *
8
+ * Worth reporting because the host version has repeatedly been the thing
9
+ * neither side could see. #293 turned on it (the reporter was on
10
+ * 0.1.1-rc.2 while every attempt to reproduce had been on 0.1.0-rc.8, which
11
+ * nobody knew until three rounds in), and #404 is entirely about a plugin
12
+ * that requires a host newer than the Desktop build it was installed on.
13
+ *
14
+ * The directory comes back too, because WHERE it was found is the other half
15
+ * of the answer: a path under Electron's resources is a Desktop-bundled host,
16
+ * which #139 established can be older than whatever `npm ls` would report.
17
+ * Asking the user is not a substitute — that is the number they do not have.
18
+ * @returns the host version and the directory it was read from, or null when
19
+ * no host package is locatable (a plain `dsh web` from a global install can
20
+ * legitimately land here).
21
+ */
22
+ export declare function dshHostInfo(entry?: string): {
23
+ version: string;
24
+ directory: string;
25
+ } | null;
26
+ /**
27
+ * Walk up from the CLI entry first, then inspect Electron's authoritative
28
+ * resources directory. Desktop distributions may keep node_modules outside
29
+ * the ASAR, expose them through ASAR's virtual filesystem, or disable ASAR.
30
+ *
31
+ * The entry is resolved through symlinks before the walk, because for a
32
+ * globally installed dsh it IS one. `npm i -g` and Homebrew both put a link
33
+ * in a `bin/` directory pointing at the real package, so `process.argv[1]`
34
+ * is `/opt/homebrew/bin/dsh` and walking up from there reaches `/` without
35
+ * ever passing the package. Measured: the same call answers `null` for the
36
+ * link and the correct directory for its target.
37
+ *
38
+ * That was not a cosmetic gap. Everything downstream reads the host version
39
+ * from here — the exported log's `dsh host:` line (#426), Discover's
40
+ * host-requirement column and filter (#473), and the pre-update check
41
+ * (#404) — and a null version makes every one of them answer "unknown",
42
+ * silently, on exactly the ordinary global install. A bundled Desktop host
43
+ * is reached by the resources branch below and was never affected, which is
44
+ * why this survived: the case that worked is the one that gets tested.
45
+ */
46
+ export declare function findDshInstallDir(entry?: string): string | null;
@@ -0,0 +1,53 @@
1
+ import { type ProfileBackup } from './backup.ts';
2
+ /** The single file every dshmarket backup Gist carries. */
3
+ export declare const GIST_FILENAME = "dsh-profile-backup.json";
4
+ /** GitHub hard limit for one Gist file (1 MB); enforced before upload. */
5
+ export declare const GIST_MAX_BYTES: number;
6
+ /** Environment variable for a host-configured token (never read from disk). */
7
+ export declare const GIST_TOKEN_ENV = "CHATCODE_CLI_MARKET_GITHUB_TOKEN";
8
+ export declare const LEGACY_GIST_TOKEN_ENV = "DSH_GITHUB_TOKEN";
9
+ /** Machine-readable error codes the client maps to localized messages. */
10
+ export type GistErrorCode = 'auth' | 'notfound' | 'rate-limit' | 'invalid' | 'timeout' | 'network' | 'other';
11
+ /** Error with a code for the UI; the message stays human-readable. */
12
+ export declare class GistError extends Error {
13
+ readonly code: GistErrorCode;
14
+ constructor(message: string, code?: GistErrorCode);
15
+ }
16
+ /** Classify any thrown value into a stable GistErrorCode. */
17
+ export declare function gistErrorCode(error: unknown): GistErrorCode;
18
+ export interface GistRef {
19
+ id: string;
20
+ htmlUrl: string;
21
+ }
22
+ /** Where the token used for a request came from (shown in the UI). */
23
+ export type GistTokenSource = 'token' | 'env' | 'gh';
24
+ /**
25
+ * Normalize a Gist id or a gist.github.com URL to a bare id.
26
+ * Anything else (paths, embedded slashes, oversize input) is rejected.
27
+ */
28
+ export declare function parseGistId(input: string): string;
29
+ /**
30
+ * Resolve the token for one request, in order of preference:
31
+ * 1. an explicitly supplied token (session memory only);
32
+ * 2. the host-configured CHATCODE_CLI_MARKET_GITHUB_TOKEN environment variable;
33
+ * 3. an already-logged-in GitHub CLI (`gh auth token`) — the token is used
34
+ * for this request only and never written to disk.
35
+ */
36
+ export declare function resolveGistTokenSource(bodyToken: unknown): Promise<{
37
+ token: string;
38
+ source: GistTokenSource;
39
+ }>;
40
+ /** Resolve just the token (kept for callers that do not need the source). */
41
+ export declare function resolveGistToken(bodyToken: unknown): Promise<string>;
42
+ /** Test hook: drop the gh token cache between tests. */
43
+ export declare function resetGhTokenCache(): void;
44
+ /** Create a new private Gist carrying one backup file. */
45
+ export declare function createGist(token: string, content: string, signal?: AbortSignal): Promise<GistRef>;
46
+ /** Overwrite the backup file inside an existing Gist (other files kept). */
47
+ export declare function updateGist(token: string, gistId: string, content: string, signal?: AbortSignal): Promise<GistRef>;
48
+ /** Download and strictly validate the backup file inside a Gist. */
49
+ export declare function readGist(token: string, gistId: string, signal?: AbortSignal): Promise<ProfileBackup>;
50
+ /** Confirm the token is usable (GET /user). */
51
+ export declare function verifyGistToken(token: string, signal?: AbortSignal): Promise<void>;
52
+ /** True when the serialized backup fits inside a Gist file. */
53
+ export declare function fitsGistLimit(content: string): boolean;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Custom plugin groups (Roadmap #60): user-defined named collections of
3
+ * installed plugins whose enable/disable state can be switched as a unit —
4
+ * borrowing the "group by capability, toggle as one" idea from Claude
5
+ * Desktop's skill management. Membership lives in state.json and is the
6
+ * only durable truth: a group's switch state is always derived from its
7
+ * members and never persisted itself.
8
+ *
9
+ * Pure CRUD over the caller-owned state objects; routes.ts persists after
10
+ * each mutation and applies the live toggles for the batch action.
11
+ */
12
+ export type GroupAction = 'create' | 'rename' | 'delete' | 'set-members' | 'toggle';
13
+ /** The slices of market state group CRUD touches (routes.ts owns the rest). */
14
+ export interface GroupState {
15
+ groups: Record<string, string[]>;
16
+ groupOrder: string[];
17
+ }
18
+ export interface GroupMutationResult {
19
+ ok: boolean;
20
+ error?: string;
21
+ }
22
+ export declare function createGroup(state: GroupState, name: unknown): GroupMutationResult;
23
+ export declare function renameGroup(state: GroupState, name: unknown, newName: unknown): GroupMutationResult;
24
+ export declare function deleteGroup(state: GroupState, name: unknown): GroupMutationResult;
25
+ /**
26
+ * Replace a group's membership. Only currently installed plugins can be
27
+ * members — ghost names (uninstalled meanwhile) are dropped and duplicates
28
+ * collapse, so the persisted list stays clean. Themes are exclusive: a group
29
+ * may hold at most one theme plugin, mirroring the global one-active-theme
30
+ * rule (only one theme can be enabled at a time).
31
+ */
32
+ export declare function setGroupMembers(state: GroupState, name: unknown, members: unknown, installed: ReadonlySet<string>, themes: ReadonlySet<string>): GroupMutationResult;
33
+ /** Drop `name` from every group (called after a successful uninstall). */
34
+ export declare function removeFromGroups(state: GroupState, name: string): void;
@@ -0,0 +1,16 @@
1
+ /** ChatCode CLI Home resolution with legacy Harness input compatibility. */
2
+ /** Default single-root ChatCode CLI home. */
3
+ export declare function defaultChatCodeHome(): string;
4
+ /** @deprecated Compatibility alias for downstream code. */
5
+ export declare const defaultDshHome: typeof defaultChatCodeHome;
6
+ /** Expand the tilde forms supported by ChatCode CLI configuration. */
7
+ export declare function expandHomePath(path: string): string;
8
+ /**
9
+ * Resolve an explicit home, `CHATCODE_CLI_HOME`, legacy `DSH_HOME`, or the
10
+ * default to one normalized absolute path. Blank environment values are unset.
11
+ */
12
+ export declare function resolveChatCodeHome(configured?: string, env?: Record<string, string | undefined>): string;
13
+ /** @deprecated Compatibility alias for callers that still import the old API. */
14
+ export declare const resolveDshHome: typeof resolveChatCodeHome;
15
+ /** Read a non-empty ChatCode variable before its legacy compatibility input. */
16
+ export declare function compatibilityEnv(env: Record<string, string | undefined>, currentName: string, legacyName: string): string | undefined;