@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,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deciding a download region by asking the network, once.
|
|
3
|
+
*
|
|
4
|
+
* The alternative was reading the system time zone, and it is wrong for
|
|
5
|
+
* exactly the people who most need this to work: someone in Shanghai behind
|
|
6
|
+
* a corporate proxy or a VPN reaches the official registry perfectly well
|
|
7
|
+
* and would be routed onto mirrors they do not need, while a Chinese-locale
|
|
8
|
+
* machine sitting in Singapore would be routed onto mirrors that are further
|
|
9
|
+
* away than the origin. A time zone says where a clock is. It does not say
|
|
10
|
+
* what the network can reach, which is the only question here.
|
|
11
|
+
*
|
|
12
|
+
* So the probe measures the thing itself: it asks both registries for the
|
|
13
|
+
* same small document and takes whichever answers first. That is
|
|
14
|
+
* self-correcting in a way a lookup table cannot be — the machine behind the
|
|
15
|
+
* proxy measures fast official access and stays global, without anyone
|
|
16
|
+
* having to enumerate the exceptions.
|
|
17
|
+
*
|
|
18
|
+
* It runs ONCE, when no region has ever been decided, and its answer is
|
|
19
|
+
* persisted as the decision. Re-probing every boot would let a market
|
|
20
|
+
* silently change routes between runs, which is the kind of behaviour that
|
|
21
|
+
* makes "it was fast yesterday" impossible to debug.
|
|
22
|
+
*/
|
|
23
|
+
import { type Region } from './regions.ts';
|
|
24
|
+
/**
|
|
25
|
+
* Ask every region's registry the same question; return whichever answers
|
|
26
|
+
* first.
|
|
27
|
+
*
|
|
28
|
+
* First-past-the-post rather than a latency comparison, deliberately. From
|
|
29
|
+
* inside China the official registry usually does answer eventually, so
|
|
30
|
+
* "did it fail" is the wrong test and "which came back first" is the right
|
|
31
|
+
* one. From outside, the mainland mirror is reachable but further, and the
|
|
32
|
+
* same rule picks global. One rule, both directions, no thresholds to tune.
|
|
33
|
+
*
|
|
34
|
+
* @param timeoutMs - how long to wait before giving up on all of them.
|
|
35
|
+
* @param env - environment, for the registry overrides.
|
|
36
|
+
* @returns the winning region, or `global` when nothing answered — an
|
|
37
|
+
* unreachable network is not evidence for switching routes.
|
|
38
|
+
*/
|
|
39
|
+
export declare function probeRegion(timeoutMs?: number, env?: NodeJS.ProcessEnv): Promise<Region>;
|
|
40
|
+
/**
|
|
41
|
+
* The region to run under, probing only if nothing has ever decided one.
|
|
42
|
+
*
|
|
43
|
+
* @param stored - the region already on record, or undefined.
|
|
44
|
+
* @returns the region, and whether this call decided it (which is what earns
|
|
45
|
+
* the user a one-time notice explaining the choice).
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveRegion(stored: Region | undefined, timeoutMs?: number, env?: NodeJS.ProcessEnv): Promise<{
|
|
48
|
+
region: Region;
|
|
49
|
+
probed: boolean;
|
|
50
|
+
}>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Download regions: which route the market's own network requests take.
|
|
3
|
+
*
|
|
4
|
+
* Almost every external request the market makes lands on npm's registry or
|
|
5
|
+
* on GitHub — the plugin catalog, update checks, package downloads, author
|
|
6
|
+
* avatars, README screenshots. From mainland China several of those can be
|
|
7
|
+
* slow, which is why this is ONE setting rather than a
|
|
8
|
+
* row of them: "npm mirror", "GitHub proxy" and "image proxy" are three
|
|
9
|
+
* spellings of a single question the user is actually being asked, which is
|
|
10
|
+
* where they are.
|
|
11
|
+
*
|
|
12
|
+
* The routing table is the single source of truth. Every consumer asks it
|
|
13
|
+
* rather than reaching for a hardcoded host, so adding a region is a table
|
|
14
|
+
* entry instead of a search across six modules.
|
|
15
|
+
*
|
|
16
|
+
* Each route has a ChatCode-first environment escape hatch, with the former
|
|
17
|
+
* `DSHM_*` spelling retained only as a compatibility input.
|
|
18
|
+
* (src/registry.ts). The China route has service-specific public-proxy
|
|
19
|
+
* fallbacks; those come and go, and a user whose routes have died needs a way
|
|
20
|
+
* out that is not "wait for the next release".
|
|
21
|
+
*/
|
|
22
|
+
/** A region the market can download from. */
|
|
23
|
+
export type Region = 'global' | 'china';
|
|
24
|
+
/** Every region a user may pick. */
|
|
25
|
+
export declare const REGIONS: readonly Region[];
|
|
26
|
+
/** Narrow an untrusted value to a Region, or null. */
|
|
27
|
+
export declare function asRegion(value: unknown): Region | null;
|
|
28
|
+
/**
|
|
29
|
+
* The npm registry the market and pnpm read, no trailing slash.
|
|
30
|
+
*
|
|
31
|
+
* Exported because callers need to tell "this region uses the default" from
|
|
32
|
+
* "this region names a mirror" — the difference between leaving a spawned
|
|
33
|
+
* pnpm's registry alone and setting it.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
36
|
+
/** GitHub transports that fail independently on filtered networks. */
|
|
37
|
+
export type GithubService = 'git' | 'raw' | 'avatar';
|
|
38
|
+
/** A prefix proxy, or null for the canonical GitHub address. */
|
|
39
|
+
export type GithubRoute = string | null;
|
|
40
|
+
/** Ordered candidates per GitHub service. */
|
|
41
|
+
export type GithubRoutes = Record<GithubService, GithubRoute[]>;
|
|
42
|
+
/**
|
|
43
|
+
* One place the catalog can be read from.
|
|
44
|
+
*
|
|
45
|
+
* Two kinds because the two routes are genuinely different transports, not
|
|
46
|
+
* two URLs. The npm route reads a published package — which is what lets the
|
|
47
|
+
* catalog ride the same mirror as everything else, and gives it a version
|
|
48
|
+
* number that can be rolled back when a bad build ships.
|
|
49
|
+
*/
|
|
50
|
+
export type CatalogSource = {
|
|
51
|
+
kind: 'url';
|
|
52
|
+
url: string;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'npm';
|
|
55
|
+
registry: string;
|
|
56
|
+
pkg: string;
|
|
57
|
+
};
|
|
58
|
+
/** Where one region sends each kind of request. `null` means "go direct". */
|
|
59
|
+
export interface RegionRoutes {
|
|
60
|
+
/** npm registry base, no trailing slash. */
|
|
61
|
+
npmRegistry: string;
|
|
62
|
+
/** Prefix proxy for github.com-family URLs, or null to go direct. */
|
|
63
|
+
githubProxy: string | null;
|
|
64
|
+
/** Ordered routes per service; every list ends in a direct escape path. */
|
|
65
|
+
githubRoutes: GithubRoutes;
|
|
66
|
+
/**
|
|
67
|
+
* Where to look for the catalog, in order. Later entries are fallbacks.
|
|
68
|
+
*
|
|
69
|
+
* The catalog is the FIRST request the market makes, so a mirror that has
|
|
70
|
+
* gone down must mean a slow market rather than an empty one — every
|
|
71
|
+
* region ends its list at an address that has always worked.
|
|
72
|
+
*/
|
|
73
|
+
catalog: CatalogSource[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Normalize a user-maintained prefix, or reject it.
|
|
77
|
+
*
|
|
78
|
+
* Public mirrors receive the complete destination URL in their path. Only
|
|
79
|
+
* HTTPS prefixes without embedded credentials or query fragments are safe to
|
|
80
|
+
* persist and show again in the settings UI.
|
|
81
|
+
*/
|
|
82
|
+
export declare function normalizeGithubProxy(value: unknown): string | null;
|
|
83
|
+
/** Apply (or clear) the persisted UI escape route. */
|
|
84
|
+
export declare function setCustomGithubProxy(proxy: string | null): void;
|
|
85
|
+
/** Whether the operator-owned environment variable disables UI changes. */
|
|
86
|
+
export declare function githubProxyManaged(env?: NodeJS.ProcessEnv): boolean;
|
|
87
|
+
/** Remember one verified route without changing other GitHub services. */
|
|
88
|
+
export declare function rememberGithubRoute(service: GithubService, route: GithubRoute): void;
|
|
89
|
+
/** Forget learned winners after the configured candidates change. */
|
|
90
|
+
export declare function resetGithubRoutePreferences(): void;
|
|
91
|
+
/**
|
|
92
|
+
* The routes for a region, with environment overrides applied.
|
|
93
|
+
*
|
|
94
|
+
* Overrides win over the table because they are the user's statement about
|
|
95
|
+
* their own network, and they are the way out when a public proxy dies.
|
|
96
|
+
*
|
|
97
|
+
* `CHATCODE_CLI_MARKET_REGISTRY_URL` names the catalog URL. The former
|
|
98
|
+
* `DSHM_REGISTRY_URL` spelling keeps the same meaning as a compatibility
|
|
99
|
+
* input. When set, either form
|
|
100
|
+
* when set it REPLACES the source list rather than heading it: someone
|
|
101
|
+
* pointing the market at their own catalog does not want it quietly
|
|
102
|
+
* reverting to ours.
|
|
103
|
+
*/
|
|
104
|
+
export declare function routesFor(region: Region, env?: NodeJS.ProcessEnv): RegionRoutes;
|
|
105
|
+
/** Ordered candidates with this process's last verified winner first. */
|
|
106
|
+
export declare function githubRoutesFor(service: GithubService, region?: Region, env?: NodeJS.ProcessEnv): GithubRoute[];
|
|
107
|
+
/** The region in force. */
|
|
108
|
+
export declare function activeRegion(): Region;
|
|
109
|
+
/** Set the region in force. Callers are responsible for their own caches. */
|
|
110
|
+
export declare function setActiveRegion(region: Region): void;
|
|
111
|
+
/**
|
|
112
|
+
* Wrap a github.com-family URL in a prefix proxy.
|
|
113
|
+
*
|
|
114
|
+
* The proxy takes the full absolute URL as its path (`{proxy}/{url}`) rather
|
|
115
|
+
* than a rewritten hostname, so the same joining rule works for every
|
|
116
|
+
* GitHub service a caller has explicitly allowed through public routes.
|
|
117
|
+
*
|
|
118
|
+
* @param proxy - the prefix, or null to go direct.
|
|
119
|
+
* @param url - an absolute https URL on a github.com-family host.
|
|
120
|
+
* @returns the proxied URL, or `url` unchanged when there is no proxy.
|
|
121
|
+
*/
|
|
122
|
+
export declare function throughProxy(proxy: string | null, url: string): string;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry access: the curated list from awesome-dsh-plugin.com, fetched
|
|
3
|
+
* fresh on every request. See `loadRegistry` for why there is nothing
|
|
4
|
+
* behind it any more.
|
|
5
|
+
*/
|
|
6
|
+
import { type Region } from './regions.ts';
|
|
7
|
+
export interface RegistryPlugin {
|
|
8
|
+
name: string;
|
|
9
|
+
owner: string;
|
|
10
|
+
url: string;
|
|
11
|
+
/** One legacy category id or several category ids. */
|
|
12
|
+
category: string | string[];
|
|
13
|
+
description: Record<string, string>;
|
|
14
|
+
npm?: string | null;
|
|
15
|
+
tarball?: string | null;
|
|
16
|
+
stars?: number | null;
|
|
17
|
+
/**
|
|
18
|
+
* npm downloads in the last 30 days, when the entry has a published
|
|
19
|
+
* package. `null`/absent means "no npm package" — a coverage gap, not a
|
|
20
|
+
* zero — so sorting must not read it as "less popular than 0".
|
|
21
|
+
*/
|
|
22
|
+
downloads?: number | null;
|
|
23
|
+
install: string;
|
|
24
|
+
added: string;
|
|
25
|
+
/**
|
|
26
|
+
* Catalog-side deprecation flags (#60): supplied by awesome-dsh-plugin,
|
|
27
|
+
* absent for every normal entry — the market only consumes them, so a
|
|
28
|
+
* catalog without the fields behaves exactly as before.
|
|
29
|
+
*/
|
|
30
|
+
deprecated?: boolean;
|
|
31
|
+
/** Catalog name of the suggested replacement plugin, when deprecated. */
|
|
32
|
+
replacement?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Category ids for one catalog entry, de-duplicated in declaration order.
|
|
36
|
+
*
|
|
37
|
+
* Catalog JSON is an external input, so malformed array members are omitted
|
|
38
|
+
* here and an entry with no usable category is rejected by `asRegistry`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function pluginCategories(plugin: Pick<RegistryPlugin, 'category'>): string[];
|
|
41
|
+
export interface Registry {
|
|
42
|
+
updated: string;
|
|
43
|
+
count: number;
|
|
44
|
+
categories: Record<string, Record<string, string>>;
|
|
45
|
+
plugins: RegistryPlugin[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Drop what we remember, so the next call is unconditional.
|
|
49
|
+
*
|
|
50
|
+
* Exists for tests: the memo is module state, and a spec that asserted a
|
|
51
|
+
* 304 would otherwise leak a validator into the next one.
|
|
52
|
+
*/
|
|
53
|
+
export declare function forgetCatalog(): void;
|
|
54
|
+
/**
|
|
55
|
+
* The catalog, revalidated every time it is asked for.
|
|
56
|
+
*
|
|
57
|
+
* There used to be three answers here — live, a one-hour in-memory cache,
|
|
58
|
+
* and a snapshot bundled into the npm package — and only the first was
|
|
59
|
+
* correct. The other two were indistinguishable from it on screen, so a
|
|
60
|
+
* machine that could not reach the registry browsed the publish-time file
|
|
61
|
+
* (839 entries against 1367 live, and frozen forever for anyone on an older
|
|
62
|
+
* release), while a machine that COULD reach it still saw an hour-old
|
|
63
|
+
* listing of a catalog that grows by ~250 entries a day.
|
|
64
|
+
*
|
|
65
|
+
* For a catalog, stale is not a degraded answer, it is a wrong one: a plugin
|
|
66
|
+
* published this morning reads as "does not exist". So there is one source
|
|
67
|
+
* now, and a failure is a failure — the caller reports it and offers a
|
|
68
|
+
* retry, which is a state the user can act on. In particular a network
|
|
69
|
+
* failure is NEVER answered from `served`: an origin that cannot be reached
|
|
70
|
+
* has not confirmed anything, and quietly handing back the last catalog
|
|
71
|
+
* would rebuild exactly the fallback this replaced.
|
|
72
|
+
* @throws when the catalog cannot be fetched or does not look like one.
|
|
73
|
+
*/
|
|
74
|
+
export declare function loadRegistry(region?: Region): Promise<Registry>;
|
|
75
|
+
/**
|
|
76
|
+
* A catalog failure with the facts needed to classify it, in the message
|
|
77
|
+
* itself.
|
|
78
|
+
*
|
|
79
|
+
* The market shows this string and the log export carries it, so it is the
|
|
80
|
+
* whole of what a bug report will contain. "The operation was aborted due to
|
|
81
|
+
* timeout" alone cannot distinguish a slow link from a blocked one from a
|
|
82
|
+
* proxy this process cannot use — and Node's `fetch` ignores HTTP_PROXY
|
|
83
|
+
* entirely (measured on Node 25), so a machine whose only route out is a
|
|
84
|
+
* proxy fails here every time while every other tool on it works.
|
|
85
|
+
*/
|
|
86
|
+
export declare function describeFetchFailure(error: unknown, elapsedMs: number, attempts?: number): string;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-restart: relaunch the exact ChatCode CLI invocation that booted this host so
|
|
3
|
+
* pending (non-hot) plugin changes take effect without the user leaving the
|
|
4
|
+
* UI. Contributed in #14 by @ysyyhhh; ported onto the layered architecture.
|
|
5
|
+
*
|
|
6
|
+
* Safety model: the endpoint accepts only direct same-origin loopback
|
|
7
|
+
* requests (no forwarding headers), refuses while a plugin operation runs,
|
|
8
|
+
* and deployments under a supervisor (systemd/launchd/pm2) can disable the
|
|
9
|
+
* whole feature with `allowRestart: false` — the supervisor owns restarts.
|
|
10
|
+
*/
|
|
11
|
+
import type { IncomingMessage } from 'node:http';
|
|
12
|
+
/** @internal test hook — production callers use detectedDebugger() only. */
|
|
13
|
+
export declare function setDetectedDebuggerOverride(value: 'inspector' | null | undefined): void;
|
|
14
|
+
/**
|
|
15
|
+
* The process supervisor running this host, when one can be identified —
|
|
16
|
+
* `null` when nothing says so.
|
|
17
|
+
*
|
|
18
|
+
* This exists because the failure it prevents is the worst one the market
|
|
19
|
+
* can cause. Under systemd's default `KillMode=control-group`, everything in
|
|
20
|
+
* the unit's cgroup dies with the main process — including the detached
|
|
21
|
+
* helper that was supposed to bring the replacement up. So "restart" killed
|
|
22
|
+
* a production service and nothing came back (#229 by @SkillBase-Al: "杀死了
|
|
23
|
+
* 服务但是无法重复启动服务"). `allowRestart: false` was always the documented
|
|
24
|
+
* answer, but it is opt-in, and nothing told the operator to opt in until
|
|
25
|
+
* after they had already lost the service.
|
|
26
|
+
*
|
|
27
|
+
* TWO signals are required, and the second is the whole reason this function
|
|
28
|
+
* is not a one-line env check. `INVOCATION_ID` is INHERITED: every
|
|
29
|
+
* descendant of a systemd unit carries it, which on Linux includes an
|
|
30
|
+
* ordinary desktop terminal (its shell descends from a user-session unit)
|
|
31
|
+
* and a CI runner (the agent is a unit — this repo's own smoke test caught
|
|
32
|
+
* that). Treating inheritance as ownership would disable the button for a
|
|
33
|
+
* large population of hosts where it works fine, which is a worse bug than
|
|
34
|
+
* the one being fixed.
|
|
35
|
+
*
|
|
36
|
+
* The parent test is what distinguishes being the unit's own main process
|
|
37
|
+
* from merely descending from one: a terminal's node has the shell as its
|
|
38
|
+
* parent and a runner's has the agent. It used to be `ppid === 1`, which is
|
|
39
|
+
* only true for SYSTEM units. A per-user unit's service is forked by that
|
|
40
|
+
* user's manager instance — `systemd --user`, an ordinary PID — so user-unit
|
|
41
|
+
* hosts read as unsupervised, and one-click restart killed them for good
|
|
42
|
+
* (#471 by @automagik-genie, with the journal to prove the whole chain:
|
|
43
|
+
* clean SIGTERM exit → `Restart=on-failure` does not fire → `KillMode=mixed`
|
|
44
|
+
* SIGKILLs the detached helper before it can spawn the replacement). So the
|
|
45
|
+
* parent counts as a manager when it is PID 1 or its comm is `systemd` —
|
|
46
|
+
* the one name both manager instances share and the false-positive parents
|
|
47
|
+
* (shells, CI agents) never carry. `/proc` is Linux-only, which is exactly
|
|
48
|
+
* as wide as systemd itself; anywhere it cannot be read the answer stays
|
|
49
|
+
* "not a manager".
|
|
50
|
+
*
|
|
51
|
+
* Scoped to systemd on purpose. pm2 sets `pm_id`, but it is inherited the
|
|
52
|
+
* same way and pm2's God daemon — not PID 1 — is the parent, so there is no
|
|
53
|
+
* equivalent second signal; a guess there would reintroduce exactly the
|
|
54
|
+
* false positive this pair exists to avoid. launchd has no marker at all.
|
|
55
|
+
* Both still need the explicit setting: detection is a safety net over the
|
|
56
|
+
* documented option, never a replacement for it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function detectedSupervisor(env?: NodeJS.ProcessEnv, ppid?: number, parentComm?: (pid: number) => string | null): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Whether this host process is under a debugger, when one can be identified —
|
|
61
|
+
* `'inspector'` or `null`.
|
|
62
|
+
*
|
|
63
|
+
* Parallel to `detectedSupervisor()` (#229): a runtime latch for the restart
|
|
64
|
+
* route and status poll, NOT an entry in `restartAllowed()`. Folding it into
|
|
65
|
+
* `restartAllowed()` would write `allowRestart: false` through the settings
|
|
66
|
+
* page while a debug session is open, and the switch would stay off after
|
|
67
|
+
* the debugger detaches (#447).
|
|
68
|
+
*
|
|
69
|
+
* An explicit `allowRestart: true` does NOT override this latch either —
|
|
70
|
+
* unlike systemd, there is no documented deployment shape where killing a
|
|
71
|
+
* debug-attached host from the market UI is the right answer.
|
|
72
|
+
*
|
|
73
|
+
* Primary signal: `inspector.url()` is set (covers `--inspect` at boot,
|
|
74
|
+
* `inspector.open()`, and SIGUSR1 attach). Secondary: inspect-family flags
|
|
75
|
+
* in `execArgv` and `NODE_OPTIONS`, matched by token prefix — not a
|
|
76
|
+
* `/inspect/` substring, so script paths like `.../inspect-tool.js` do not
|
|
77
|
+
* false-positive. Includes `--inspect-wait` for Node versions that expose it
|
|
78
|
+
* as a distinct flag before `inspector.url()` is populated.
|
|
79
|
+
*
|
|
80
|
+
* Accepted false positive (same trade as #229 not guessing pm2): a host left
|
|
81
|
+
* listening on an inspector port — including `NODE_OPTIONS=--inspect` with
|
|
82
|
+
* nobody attached — is treated as debug-owned and gets no one-click restart.
|
|
83
|
+
*/
|
|
84
|
+
export declare function detectedDebugger(inspectorUrl?: string | undefined, execArgv?: readonly string[], nodeOptions?: string): 'inspector' | null;
|
|
85
|
+
/**
|
|
86
|
+
* Self-restart is enabled by default, disabled by an explicit false — and
|
|
87
|
+
* disabled by DEFAULT under a detected supervisor, which owns restarts and
|
|
88
|
+
* whose process group would take the replacement helper down with it.
|
|
89
|
+
*
|
|
90
|
+
* An explicit `true` still wins: an operator who has configured their unit
|
|
91
|
+
* for it (`KillMode=process`, or a wrapper that survives) is making a
|
|
92
|
+
* statement about their own deployment, and this should not overrule it.
|
|
93
|
+
*/
|
|
94
|
+
export declare function restartAllowed(config: {
|
|
95
|
+
allowRestart?: boolean;
|
|
96
|
+
}, env?: NodeJS.ProcessEnv, ppid?: number): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The port this process is serving on, read off the request that asked for
|
|
99
|
+
* the restart.
|
|
100
|
+
*
|
|
101
|
+
* The alternative is to parse it out of the launch argv, which is wrong for
|
|
102
|
+
* every host that binds from config or an env var. The Host header is what
|
|
103
|
+
* the browser actually reached us on, so it is the port the replacement has
|
|
104
|
+
* to take over — and it is already validated against Origin by the guard
|
|
105
|
+
* below before any of this runs.
|
|
106
|
+
* @returns the port, or null when the header carries none (a default port).
|
|
107
|
+
*/
|
|
108
|
+
export declare function servingPort(request: Pick<IncomingMessage, 'headers'>): number | null;
|
|
109
|
+
/** Whether a process-control request came from this Web host on loopback. */
|
|
110
|
+
export declare function trustedRestartRequest(request: Pick<IncomingMessage, 'headers' | 'socket'>): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Whether a download navigation may fetch a sensitive GET export.
|
|
113
|
+
* Browsers do NOT send an Origin header on same-origin GET navigations
|
|
114
|
+
* (`<a href="/..." download>`), so unlike process-control requests a missing
|
|
115
|
+
* Origin is the NORMAL shape of a user-initiated download and must pass.
|
|
116
|
+
* Keep the rest of the posture: loopback peer only, no proxy forwarding
|
|
117
|
+
* headers, and — when an Origin IS present (fetch/CORS attempts) — it must
|
|
118
|
+
* still match Host so a cross-origin page cannot read the export.
|
|
119
|
+
*/
|
|
120
|
+
export declare function trustedDownloadRequest(request: Pick<IncomingMessage, 'headers' | 'socket'>): boolean;
|
|
121
|
+
/** The exact boot invocation the detached restart helper replays. */
|
|
122
|
+
export declare function restartLaunch(): {
|
|
123
|
+
file: string;
|
|
124
|
+
args: string[];
|
|
125
|
+
cwd: string;
|
|
126
|
+
viaShell: boolean;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Platform-correct spawn invocation for the replacement host (#40 by
|
|
130
|
+
* @1123762794): on Windows a `detached` spawn maps to DETACHED_PROCESS — the
|
|
131
|
+
* new host gets NO console, and every console child it later spawns (e.g.
|
|
132
|
+
* ChatCode CLI sandbox tool runners) pops a visible node window. Wrapping the launch
|
|
133
|
+
* in `powershell -WindowStyle Hidden` gives the host a HIDDEN console that
|
|
134
|
+
* children inherit instead. POSIX keeps the plain detached spawn.
|
|
135
|
+
*/
|
|
136
|
+
export declare function respawnInvocation(launch: {
|
|
137
|
+
file: string;
|
|
138
|
+
args: string[];
|
|
139
|
+
viaShell: boolean;
|
|
140
|
+
}, platform?: NodeJS.Platform): {
|
|
141
|
+
file: string;
|
|
142
|
+
args: string[];
|
|
143
|
+
viaShell: boolean;
|
|
144
|
+
detached: boolean;
|
|
145
|
+
};
|
|
146
|
+
/** What scheduleRestart reports back to the caller for logging/response. */
|
|
147
|
+
export interface RestartResult {
|
|
148
|
+
pid: number;
|
|
149
|
+
helperPid: number | undefined;
|
|
150
|
+
logOut: string;
|
|
151
|
+
logErr: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Source for the detached helper that outlives this process and brings the
|
|
155
|
+
* replacement up.
|
|
156
|
+
*
|
|
157
|
+
* Extracted so the waiting can be tested by RUNNING it, which is the only
|
|
158
|
+
* way this class of bug shows itself: every part of the old helper looked
|
|
159
|
+
* right in isolation.
|
|
160
|
+
*
|
|
161
|
+
* What it fixes (#177, reported on Windows 11, reproducible every time): the
|
|
162
|
+
* helper slept a flat 1500ms and spawned. The old process had exited, but
|
|
163
|
+
* the listening socket had not been released yet, so the replacement died
|
|
164
|
+
* instantly with EADDRINUSE — and the spawn was wrapped in `catch {}`, so
|
|
165
|
+
* nothing was written anywhere. The user saw a restart button that did
|
|
166
|
+
* nothing. The docstring above it even claimed the helper "waits for our
|
|
167
|
+
* port to free up"; it never did.
|
|
168
|
+
*
|
|
169
|
+
* So: wait for the port to actually go quiet, then start, then CHECK that
|
|
170
|
+
* something came up, and write a diagnosis when it did not. A restart that
|
|
171
|
+
* fails must leave evidence — this one is invisible by construction, since
|
|
172
|
+
* the process that would have logged it is the one that just exited.
|
|
173
|
+
* @param port - the port the replacement must bind; when unknown, the helper
|
|
174
|
+
* falls back to the old fixed delay, which is better than nothing.
|
|
175
|
+
*/
|
|
176
|
+
export declare function restartHelperSource(spawned: {
|
|
177
|
+
file: string;
|
|
178
|
+
args: string[];
|
|
179
|
+
viaShell: boolean;
|
|
180
|
+
detached: boolean;
|
|
181
|
+
}, launch: {
|
|
182
|
+
cwd: string;
|
|
183
|
+
}, logs: {
|
|
184
|
+
out: string;
|
|
185
|
+
err: string;
|
|
186
|
+
}, port: number | null): string;
|
|
187
|
+
/**
|
|
188
|
+
* Relaunch this exact ChatCode CLI entry after a detached handoff, then stop this
|
|
189
|
+
* process. The helper outlives us (detached + unref), waits for our port to
|
|
190
|
+
* be released before starting the replacement, and logs under tmpdir.
|
|
191
|
+
* @param port - the port this process is serving on, so the helper can wait
|
|
192
|
+
* for it rather than guessing at a delay.
|
|
193
|
+
*/
|
|
194
|
+
export declare function scheduleRestart(port?: number | null): RestartResult;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP routes bridging the browser market UI to the host. This layer only
|
|
3
|
+
* parses requests, calls the service modules, and serializes responses —
|
|
4
|
+
* process spawning lives in dsh-cli.ts, filesystem reads in profile.ts,
|
|
5
|
+
* orchestration in install.ts / themes.ts / updates.ts.
|
|
6
|
+
*
|
|
7
|
+
* Security: the install route executes a shell command, so it accepts only
|
|
8
|
+
* same-origin POSTs and only sources present in the curated registry.
|
|
9
|
+
*/
|
|
10
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
11
|
+
import { type PluginCommandRuntime } from './dsh-cli.ts';
|
|
12
|
+
import { type AgentsLookup } from './agents.ts';
|
|
13
|
+
import { type Channel } from './channels.ts';
|
|
14
|
+
import { type Region } from './regions.ts';
|
|
15
|
+
import { type LoaderEntry } from './themes.ts';
|
|
16
|
+
export type { LoaderEntry } from './themes.ts';
|
|
17
|
+
export type { UpdateStatus } from './updates.ts';
|
|
18
|
+
export interface WebServerService {
|
|
19
|
+
register(route: {
|
|
20
|
+
kind: 'exact' | 'prefix';
|
|
21
|
+
path: string;
|
|
22
|
+
handler: (request: IncomingMessage, response: ServerResponse) => void | Promise<void>;
|
|
23
|
+
}): () => void;
|
|
24
|
+
}
|
|
25
|
+
export interface MarketHost {
|
|
26
|
+
webServer: WebServerService;
|
|
27
|
+
loader: {
|
|
28
|
+
entries(): Iterable<LoaderEntry>;
|
|
29
|
+
};
|
|
30
|
+
plugin(plugin: unknown, config: unknown): {
|
|
31
|
+
await(): Promise<unknown>;
|
|
32
|
+
dispose(): Promise<unknown> | void;
|
|
33
|
+
};
|
|
34
|
+
on?(event: string, callback: (fiber: {
|
|
35
|
+
entry?: {
|
|
36
|
+
options?: {
|
|
37
|
+
name?: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}) => void): () => void;
|
|
41
|
+
logger?: {
|
|
42
|
+
info?(message: string): void;
|
|
43
|
+
warn(message: string): void;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface MarketConfig {
|
|
47
|
+
/** Profile the market installs into; matches the profile serving this UI. */
|
|
48
|
+
profile: string;
|
|
49
|
+
/** Host-authoritative profile directory; ordinary DSH derives it from DSH_HOME. */
|
|
50
|
+
profileDirectory?: string;
|
|
51
|
+
/** Detached self-restart is unsafe under systemd/launchd/pm2; operators can disable it (#14). */
|
|
52
|
+
allowRestart?: boolean;
|
|
53
|
+
/** Which release channel the market offers ITSELF from; other plugins never follow it. */
|
|
54
|
+
channel?: Channel;
|
|
55
|
+
/** Which mirrors every outbound request uses; undefined until decided. */
|
|
56
|
+
region?: Region;
|
|
57
|
+
/** Snapshots retained per profile (issue #98); defaults to DEFAULT_MAX_SNAPSHOTS. */
|
|
58
|
+
maxSnapshots?: number;
|
|
59
|
+
}
|
|
60
|
+
export declare function marketVersion(): string;
|
|
61
|
+
/**
|
|
62
|
+
* Register the market's HTTP routes.
|
|
63
|
+
* @param host - Acquired webServer + shell services.
|
|
64
|
+
* @param config - Validated market configuration.
|
|
65
|
+
* @returns Disposer removing every registered route.
|
|
66
|
+
*/
|
|
67
|
+
export declare function mountMarketRoutes(host: MarketHost, config: MarketConfig, commandRuntime?: PluginCommandRuntime, agentsLookup?: AgentsLookup): () => void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The market's own settings namespace: the half that makes `allowRestart`
|
|
3
|
+
* a switch on the plugin configuration page instead of a line the user has
|
|
4
|
+
* to hand-write into cordis.yml.
|
|
5
|
+
*
|
|
6
|
+
* `allowRestart: false` is the documented answer for a host owned by
|
|
7
|
+
* systemd, launchd or pm2 — a supervisor restarts it, so the market's
|
|
8
|
+
* one-click restart must not launch a second one. Until now the only way to
|
|
9
|
+
* say that was editing YAML in the right place with the right indentation,
|
|
10
|
+
* where a stray space stops the profile booting.
|
|
11
|
+
*
|
|
12
|
+
* Only `allowRestart` is exposed. `profile` names which profile this
|
|
13
|
+
* instance manages: it is decided at mount from the composition or the
|
|
14
|
+
* command line, and a running instance cannot switch to another one, so
|
|
15
|
+
* offering it as a field would promise something the write cannot deliver.
|
|
16
|
+
*
|
|
17
|
+
* The release channel is NOT here either, and that is a correction rather
|
|
18
|
+
* than an omission. It was, briefly, and it made this namespace a second
|
|
19
|
+
* writer for a value the market already stores in its own state.json: the
|
|
20
|
+
* mount read the user's saved channel off disk, then `onChange` assigned
|
|
21
|
+
* `source().channel` — which knows nothing about that file — straight back
|
|
22
|
+
* over it. The choice survived exactly until the next settings event.
|
|
23
|
+
*
|
|
24
|
+
* Only a real host could show that; the unit lane mounts the routes without
|
|
25
|
+
* this layer at all. `allowRestart` needs this door because its only other
|
|
26
|
+
* one is hand-edited YAML. The channel has a control of its own on the
|
|
27
|
+
* plugin configuration page, so a second door bought nothing and cost the
|
|
28
|
+
* setting its memory.
|
|
29
|
+
*
|
|
30
|
+
* The wiring rides the scoped fiber, so a host with no settings service —
|
|
31
|
+
* every dsh before 0.1.0-rc.7 — simply never runs any of this and the entry
|
|
32
|
+
* configuration stands as composed. That is why this needs no version check
|
|
33
|
+
* of its own.
|
|
34
|
+
*
|
|
35
|
+
* It depends on the SERVICE and nothing else, which is the whole point of
|
|
36
|
+
* the shape below. This module used to import two convenience helpers,
|
|
37
|
+
* `installSettingsSection` and `settingsNamespace`, from
|
|
38
|
+
* `@deepseek-ai/dsh-settings`. dsh 0.1.2-alpha.1 deleted both — and a
|
|
39
|
+
* missing NAMED EXPORT is not a missing service. `ctx.inject` degrades
|
|
40
|
+
* quietly; an ESM named import that resolves to nothing is a SyntaxError at
|
|
41
|
+
* module evaluation, which cordis's loader reports as a failed entry and the
|
|
42
|
+
* host exits 1. Installing the market stopped the host from booting at all:
|
|
43
|
+
*
|
|
44
|
+
* SyntaxError: The requested module '@deepseek-ai/dsh-settings' does not
|
|
45
|
+
* provide an export named 'installSettingsSection'
|
|
46
|
+
*
|
|
47
|
+
* The service itself never changed — `sctx.settings.register(ns, schema,
|
|
48
|
+
* { base })` is identical in 0.1.0-rc.7 and 0.1.2-alpha.2. Only the two
|
|
49
|
+
* wrappers went away. So this inlines what the wrapper did (verified against
|
|
50
|
+
* its source: an inject, a register, a watch, and an unload effect) and
|
|
51
|
+
* validates the namespace here. Nothing about the graceful-degradation story
|
|
52
|
+
* changes; it just stops being conditional on an export that upstream is
|
|
53
|
+
* free to move.
|
|
54
|
+
*/
|
|
55
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
56
|
+
import z from '@deepseek-ai/schemastery';
|
|
57
|
+
/** Namespace the card on the browser side keys itself to. */
|
|
58
|
+
export declare const MARKET_SETTINGS_NS = "dsh-market";
|
|
59
|
+
/** The market settings a user may edit at runtime. */
|
|
60
|
+
export interface MarketSettings {
|
|
61
|
+
allowRestart: boolean;
|
|
62
|
+
}
|
|
63
|
+
export declare const MarketSettings: z<MarketSettings>;
|
|
64
|
+
/**
|
|
65
|
+
* Wire the namespace so a saved change reaches the routes immediately.
|
|
66
|
+
*
|
|
67
|
+
* The routes read `allowRestart` off this object on every request (the
|
|
68
|
+
* status route reports the capability, the restart route enforces it), so
|
|
69
|
+
* updating it in place is what makes a toggle take effect without a
|
|
70
|
+
* restart — which would be a poor thing to require of a setting whose whole
|
|
71
|
+
* subject is restarting.
|
|
72
|
+
*
|
|
73
|
+
* @param ctx - the plugin context owning the wiring.
|
|
74
|
+
* @param resolved - the live config object the routes read.
|
|
75
|
+
*/
|
|
76
|
+
export declare function installMarketSettings(ctx: Context, resolved: {
|
|
77
|
+
allowRestart?: boolean;
|
|
78
|
+
}): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ResolvedSkillMarketConfig, SkillListQuery, SkillListResult } from './types.ts';
|
|
2
|
+
/** Client for the public skill catalog and archive endpoints. */
|
|
3
|
+
export declare class SkillMarketApi {
|
|
4
|
+
private readonly config;
|
|
5
|
+
constructor(config: ResolvedSkillMarketConfig);
|
|
6
|
+
/** Fetch one validated catalog page. */
|
|
7
|
+
list(query?: SkillListQuery, signal?: AbortSignal): Promise<SkillListResult>;
|
|
8
|
+
/** Download a skill archive; the caller consumes and size-caps the body. */
|
|
9
|
+
download(id: number, signal?: AbortSignal): Promise<Response>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ResolvedSkillMarketConfig, InstalledSkill, SkillInstallLocation, SkillInstallResult } from './types.ts';
|
|
2
|
+
import type { SkillMarketApi } from './api.ts';
|
|
3
|
+
export declare const SKILL_MARKET_META_FILE = ".skill-market.json";
|
|
4
|
+
/** Installs validated catalog archives into ChatCode CLI skill roots. */
|
|
5
|
+
export declare class SkillMarketInstaller {
|
|
6
|
+
private readonly api;
|
|
7
|
+
private readonly config;
|
|
8
|
+
constructor(api: SkillMarketApi, config: ResolvedSkillMarketConfig);
|
|
9
|
+
/** Install or update one catalog skill for a local session workspace. */
|
|
10
|
+
install(options: {
|
|
11
|
+
readonly id: number;
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly version?: string;
|
|
14
|
+
readonly location: SkillInstallLocation;
|
|
15
|
+
readonly cwd: string;
|
|
16
|
+
readonly signal?: AbortSignal;
|
|
17
|
+
}): Promise<SkillInstallResult>;
|
|
18
|
+
private downloadArchive;
|
|
19
|
+
/** List market-managed skills visible from a local session workspace. */
|
|
20
|
+
installed(cwd: string): Promise<readonly InstalledSkill[]>;
|
|
21
|
+
}
|
|
22
|
+
/** Resolve the two skill roots visible to a session workspace. */
|
|
23
|
+
export declare function resolveSkillRoots(cwd: string): Promise<Record<SkillInstallLocation, string>>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SkillMarketApi } from './api.ts';
|
|
2
|
+
import { SkillMarketInstaller } from './installer.ts';
|
|
3
|
+
import type { ResolvedSkillMarketConfig } from './types.ts';
|
|
4
|
+
/** Shared skill-market operations consumed by Web routes and the terminal scene. */
|
|
5
|
+
export declare class SkillMarketRuntime {
|
|
6
|
+
readonly config: ResolvedSkillMarketConfig;
|
|
7
|
+
readonly api: SkillMarketApi;
|
|
8
|
+
readonly installer: SkillMarketInstaller;
|
|
9
|
+
constructor(config: ResolvedSkillMarketConfig);
|
|
10
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { SkillMarketRuntime } from './runtime.ts';
|
|
3
|
+
/** Register `/skill-market` and its full-screen terminal scene together. */
|
|
4
|
+
export declare function installSkillMarketTui(ctx: Context, runtime: SkillMarketRuntime): void;
|