@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.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/README.zh.md +143 -0
- package/UPDATE-API-V1.md +132 -0
- package/client/client.js +11534 -0
- package/cordis.patch.yml +5 -0
- package/lib/accelerate.js +184 -0
- package/lib/agents.js +36 -0
- package/lib/backup.js +572 -0
- package/lib/catalog-local-match.js +126 -0
- package/lib/catalog-npm.js +111 -0
- package/lib/changelog.js +242 -0
- package/lib/channels.js +64 -0
- package/lib/check.js +1067 -0
- package/lib/compatibility.js +198 -0
- package/lib/diagnostics.js +49 -0
- package/lib/discovery-compatibility.js +260 -0
- package/lib/dsh-cli.js +949 -0
- package/lib/dsh-install.js +108 -0
- package/lib/gist.js +352 -0
- package/lib/groups.js +97 -0
- package/lib/home-paths.js +42 -0
- package/lib/hot.js +519 -0
- package/lib/http.js +39 -0
- package/lib/index.js +97 -0
- package/lib/install.js +387 -0
- package/lib/log.js +197 -0
- package/lib/ndjson.js +154 -0
- package/lib/net.js +98 -0
- package/lib/order.js +284 -0
- package/lib/patch.js +521 -0
- package/lib/pnpm-compat.js +490 -0
- package/lib/presets.js +278 -0
- package/lib/profile.js +911 -0
- package/lib/region-probe.js +93 -0
- package/lib/regions.js +253 -0
- package/lib/registry.js +204 -0
- package/lib/restart.js +373 -0
- package/lib/routes.js +4372 -0
- package/lib/settings.js +109 -0
- package/lib/skill-market/api.js +119 -0
- package/lib/skill-market/config.js +29 -0
- package/lib/skill-market/installer.js +352 -0
- package/lib/skill-market/runtime.js +13 -0
- package/lib/skill-market/tui.js +119 -0
- package/lib/skill-market/types.js +1 -0
- package/lib/skill-market/web-routes.js +123 -0
- package/lib/snapshot.js +500 -0
- package/lib/source-migration.js +54 -0
- package/lib/sources.js +596 -0
- package/lib/store.js +91 -0
- package/lib/themes.js +102 -0
- package/lib/trial.js +116 -0
- package/lib/types/accelerate.d.ts +85 -0
- package/lib/types/agents.d.ts +22 -0
- package/lib/types/backup.d.ts +131 -0
- package/lib/types/catalog-local-match.d.ts +50 -0
- package/lib/types/catalog-npm.d.ts +47 -0
- package/lib/types/changelog.d.ts +102 -0
- package/lib/types/channels.d.ts +56 -0
- package/lib/types/check.d.ts +266 -0
- package/lib/types/compatibility.d.ts +64 -0
- package/lib/types/diagnostics.d.ts +29 -0
- package/lib/types/discovery-compatibility.d.ts +80 -0
- package/lib/types/dsh-cli.d.ts +324 -0
- package/lib/types/dsh-install.d.ts +46 -0
- package/lib/types/gist.d.ts +53 -0
- package/lib/types/groups.d.ts +34 -0
- package/lib/types/home-paths.d.ts +16 -0
- package/lib/types/hot.d.ts +221 -0
- package/lib/types/http.d.ts +12 -0
- package/lib/types/index.d.ts +14 -0
- package/lib/types/install.d.ts +172 -0
- package/lib/types/log.d.ts +43 -0
- package/lib/types/ndjson.d.ts +52 -0
- package/lib/types/net.d.ts +58 -0
- package/lib/types/order.d.ts +100 -0
- package/lib/types/patch.d.ts +129 -0
- package/lib/types/pnpm-compat.d.ts +93 -0
- package/lib/types/presets.d.ts +90 -0
- package/lib/types/profile.d.ts +253 -0
- package/lib/types/region-probe.d.ts +50 -0
- package/lib/types/regions.d.ts +122 -0
- package/lib/types/registry.d.ts +86 -0
- package/lib/types/restart.d.ts +194 -0
- package/lib/types/routes.d.ts +67 -0
- package/lib/types/settings.d.ts +78 -0
- package/lib/types/skill-market/api.d.ts +10 -0
- package/lib/types/skill-market/config.d.ts +3 -0
- package/lib/types/skill-market/installer.d.ts +23 -0
- package/lib/types/skill-market/runtime.d.ts +10 -0
- package/lib/types/skill-market/tui.d.ts +4 -0
- package/lib/types/skill-market/types.d.ts +71 -0
- package/lib/types/skill-market/web-routes.d.ts +19 -0
- package/lib/types/snapshot.d.ts +93 -0
- package/lib/types/source-migration.d.ts +11 -0
- package/lib/types/sources.d.ts +216 -0
- package/lib/types/store.d.ts +30 -0
- package/lib/types/themes.d.ts +40 -0
- package/lib/types/trial.d.ts +61 -0
- package/lib/types/update-api-v1.d.ts +66 -0
- package/lib/types/updates.d.ts +123 -0
- package/lib/types/verify.d.ts +139 -0
- package/lib/update-api-v1.js +215 -0
- package/lib/updates.js +361 -0
- package/lib/verify.js +453 -0
- package/package.json +121 -0
- package/src/accelerate.ts +213 -0
- package/src/agents.ts +43 -0
- package/src/backup.ts +583 -0
- package/src/catalog-local-match.ts +144 -0
- package/src/catalog-npm.ts +120 -0
- package/src/changelog.ts +282 -0
- package/src/channels.ts +70 -0
- package/src/check.ts +1239 -0
- package/src/client/CommentsModal.tsx +119 -0
- package/src/client/Diagnostics.tsx +907 -0
- package/src/client/ErrorBoundary.tsx +111 -0
- package/src/client/InstallToast.tsx +31 -0
- package/src/client/Market.module.css +830 -0
- package/src/client/MarketSection.tsx +5301 -0
- package/src/client/OperationsPanel.tsx +365 -0
- package/src/client/SettingsCard.tsx +621 -0
- package/src/client/SkillMarket.module.css +21 -0
- package/src/client/SkillMarketSection.tsx +162 -0
- package/src/client/comments.ts +54 -0
- package/src/client/globals.d.ts +13 -0
- package/src/client/index.ts +180 -0
- package/src/client/locales.ts +1112 -0
- package/src/client/market-data.ts +1321 -0
- package/src/client/operations.ts +201 -0
- package/src/client/preset-panel.tsx +263 -0
- package/src/client/primitives.d.ts +140 -0
- package/src/client/self-check.ts +147 -0
- package/src/client/snapshot-panel.tsx +244 -0
- package/src/compatibility.ts +237 -0
- package/src/diagnostics.ts +84 -0
- package/src/discovery-compatibility.ts +315 -0
- package/src/dsh-cli.ts +1126 -0
- package/src/dsh-install.ts +118 -0
- package/src/gist.ts +362 -0
- package/src/groups.ts +111 -0
- package/src/home-paths.ts +53 -0
- package/src/hot.ts +628 -0
- package/src/http.ts +41 -0
- package/src/index.ts +128 -0
- package/src/install.ts +420 -0
- package/src/log.ts +206 -0
- package/src/ndjson.ts +185 -0
- package/src/net.ts +106 -0
- package/src/order.ts +303 -0
- package/src/patch.ts +522 -0
- package/src/pnpm-compat.ts +527 -0
- package/src/presets.ts +344 -0
- package/src/profile.ts +940 -0
- package/src/region-probe.ts +97 -0
- package/src/regions.ts +310 -0
- package/src/registry.ts +250 -0
- package/src/restart.ts +396 -0
- package/src/routes.ts +4506 -0
- package/src/settings.ts +141 -0
- package/src/skill-market/api.ts +130 -0
- package/src/skill-market/config.ts +32 -0
- package/src/skill-market/installer.ts +337 -0
- package/src/skill-market/runtime.ts +14 -0
- package/src/skill-market/tui.ts +157 -0
- package/src/skill-market/types.ts +80 -0
- package/src/skill-market/web-routes.ts +132 -0
- package/src/snapshot.ts +532 -0
- package/src/source-migration.ts +61 -0
- package/src/sources.ts +565 -0
- package/src/store.ts +89 -0
- package/src/themes.ts +125 -0
- package/src/trial.ts +156 -0
- package/src/update-api-v1.ts +277 -0
- package/src/updates.ts +400 -0
- 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;
|