@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,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The market's release channels: which build of ITSELF it offers.
|
|
3
|
+
*
|
|
4
|
+
* Only the market follows this. Other plugins are never pulled from a
|
|
5
|
+
* prerelease on the strength of a setting the user made about the market —
|
|
6
|
+
* opting into early builds is volunteering to try THIS plugin early, not to
|
|
7
|
+
* be handed every other author's unreleased work.
|
|
8
|
+
*
|
|
9
|
+
* The model lives in its own module because it is the part with rules
|
|
10
|
+
* rather than plumbing: three channels, one of them hidden, a mapping to
|
|
11
|
+
* npm dist-tags, and a resolution order that has already been got wrong
|
|
12
|
+
* once (see `resolveChannel`).
|
|
13
|
+
*/
|
|
14
|
+
/** A channel the market can follow. */
|
|
15
|
+
export type Channel = 'stable' | 'beta' | 'dev';
|
|
16
|
+
/**
|
|
17
|
+
* The npm dist-tag each channel installs from.
|
|
18
|
+
*
|
|
19
|
+
* `dev` is published straight from a branch with no git tag behind it, so a
|
|
20
|
+
* version carries a timestamp and a short SHA (`1.15.0-dev.20260818-3f1432e`)
|
|
21
|
+
* and is never reused. That is what makes a dev build disposable: nothing in
|
|
22
|
+
* the repository's history refers to it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DIST_TAG: Record<Channel, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Every channel a user may pick. All three, always.
|
|
27
|
+
*
|
|
28
|
+
* `dev` was behind a developer-mode switch for one version, on the reasoning
|
|
29
|
+
* that a build published straight off a branch should not sit beside
|
|
30
|
+
* "stable" looking like a third degree of caution. The switch cost more than
|
|
31
|
+
* it bought: a stored mode, a route to change it, a rule for what happens to
|
|
32
|
+
* a dev choice when it is turned off, and a control whose own purpose needed
|
|
33
|
+
* explaining. A plainly labelled option a user can read is simpler than a
|
|
34
|
+
* hidden one plus the machinery that hides it — the label does the work the
|
|
35
|
+
* gate was doing.
|
|
36
|
+
*/
|
|
37
|
+
export declare const CHANNELS: readonly Channel[];
|
|
38
|
+
/** Narrow an untrusted value to a Channel, or null. */
|
|
39
|
+
export declare function asChannel(value: unknown): Channel | null;
|
|
40
|
+
/**
|
|
41
|
+
* Which channel applies right now.
|
|
42
|
+
*
|
|
43
|
+
* A choice on record always wins — including "stable" while a prerelease is
|
|
44
|
+
* running, which is the only way back off a channel. Only the ABSENCE of a
|
|
45
|
+
* choice is derived, and then from what is actually running: installing
|
|
46
|
+
* `dshmarket@beta` by hand IS the subscription, and treating that as
|
|
47
|
+
* "stable" costs updates rather than just clarity — on the stable channel
|
|
48
|
+
* `latest` (1.13.1) is not newer than an installed 1.14.0-beta.1, so the
|
|
49
|
+
* market answers "up to date" and the next beta is never offered.
|
|
50
|
+
*
|
|
51
|
+
* Which makes `undefined` load-bearing: it has to survive both the settings
|
|
52
|
+
* schema (no `.default`) and state.json (field omitted) or "never chose"
|
|
53
|
+
* silently becomes "chose stable".
|
|
54
|
+
*
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveChannel(setting: Channel | undefined, version: string): Channel;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile composition diagnostics — issue #98 (phase 1): the check-only
|
|
3
|
+
* "plugin loading layer and conflict view".
|
|
4
|
+
*
|
|
5
|
+
* Pure filesystem analysis of one dsh profile directory; no processes, no
|
|
6
|
+
* network, no writes. It answers, for the profile the market is serving:
|
|
7
|
+
*
|
|
8
|
+
* 1. What is the actual bundle stack (dsh.profile.bundles order) and where
|
|
9
|
+
* does each layer come from (official in-box bundle vs community, the
|
|
10
|
+
* dependency spec, the resolved directory)?
|
|
11
|
+
* 2. Which loader entry ids does the composed tree contain, and are any
|
|
12
|
+
* duplicated across layers (the "duplicate loader entry id" boot failure
|
|
13
|
+
* from #98)? Which rows does a later layer override?
|
|
14
|
+
* 3. Does any installed plugin pull a DSH host core package
|
|
15
|
+
* (@deepseek-ai/dsh, @deepseek-ai/dsh-tools, @deepseek-ai/cordis, …) in
|
|
16
|
+
* as an ordinary dependency — the dsh-excel-chat failure mode where the
|
|
17
|
+
* plugin's copy gets hoisted to the profile root and shadows the host's
|
|
18
|
+
* version (tool calls die, minimal preset fails to mount)?
|
|
19
|
+
* 4. Are there multiple versions of one core package in the lockfile, and
|
|
20
|
+
* do plugin peerDependencies ranges match the resolved core version?
|
|
21
|
+
* 5. Do effective user/home patch entries reference npm package roots that
|
|
22
|
+
* are installed in the profile-visible node_modules ancestry?
|
|
23
|
+
*
|
|
24
|
+
* The composition step mirrors @deepseek-ai/dsh-app-boot's applyEntryPatches
|
|
25
|
+
* (same js-yaml dialect incl. `!!js` scalars), so the rows reported here are
|
|
26
|
+
* what actually mounts at boot.
|
|
27
|
+
*/
|
|
28
|
+
export { findDshInstallDir } from './dsh-install.ts';
|
|
29
|
+
/** Boot-breaking or confirmed problems vs informational warnings. */
|
|
30
|
+
export interface CheckSummary {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
errors: string[];
|
|
33
|
+
warnings: string[];
|
|
34
|
+
}
|
|
35
|
+
/** One layer of the bundle stack, in `dsh.profile.bundles` order. */
|
|
36
|
+
export interface BundleLayer {
|
|
37
|
+
name: string;
|
|
38
|
+
/** Dependency spec from the profile package.json (npm range, git, link:…). */
|
|
39
|
+
source: string;
|
|
40
|
+
/** 'official' = in-box dsh bundle; 'community' = everything else. */
|
|
41
|
+
kind: 'official' | 'community';
|
|
42
|
+
/** Resolved package directory; null when the package is not installed. */
|
|
43
|
+
directory: string | null;
|
|
44
|
+
/** Absolute path of the layer's patch file; null when undeclared/missing. */
|
|
45
|
+
patchPath: string | null;
|
|
46
|
+
/**
|
|
47
|
+
* An in-box bundle whose directory could not be located — a gap in what
|
|
48
|
+
* this process can see, not a defect in the profile (#369). Distinct from
|
|
49
|
+
* `error`, which asserts the profile will not boot.
|
|
50
|
+
*/
|
|
51
|
+
unresolvedInbox?: boolean;
|
|
52
|
+
/** Why this layer cannot load at boot (missing dir / no dsh.bundle / …). */
|
|
53
|
+
error: string | null;
|
|
54
|
+
/** Loader entry ids this bundle's patch inserts. */
|
|
55
|
+
entries: string[];
|
|
56
|
+
/** The patch file exists but could not be parsed as the entry-list dialect. */
|
|
57
|
+
parseError: string | null;
|
|
58
|
+
/** Author-declared ordering constraints (issue #98 phase 2), when present. */
|
|
59
|
+
order?: {
|
|
60
|
+
before?: string[];
|
|
61
|
+
after?: string[];
|
|
62
|
+
/** Violated rules for THIS bundle in the current stack order. */
|
|
63
|
+
conflicts?: Array<{
|
|
64
|
+
name: string;
|
|
65
|
+
reason: string;
|
|
66
|
+
}>;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** One loader row of the composed tree, with the layer that introduced it. */
|
|
70
|
+
export interface LoaderRow {
|
|
71
|
+
id: string;
|
|
72
|
+
/** Bundle package name, 'user-patch' (profile cordis.patch.yml) or 'home-patch'. */
|
|
73
|
+
layer: string;
|
|
74
|
+
kind: 'insert' | 'patch';
|
|
75
|
+
name?: string;
|
|
76
|
+
}
|
|
77
|
+
/** An id present in more than one composed row — the #98 duplicate-id boot failure. */
|
|
78
|
+
export interface DuplicateId {
|
|
79
|
+
id: string;
|
|
80
|
+
/** Every layer that inserts/defines this id. */
|
|
81
|
+
layers: string[];
|
|
82
|
+
count: number;
|
|
83
|
+
}
|
|
84
|
+
/** A non-insert patch row that merged into an existing entry (later layer wins). */
|
|
85
|
+
export interface OverrideRow {
|
|
86
|
+
id: string;
|
|
87
|
+
layer: string;
|
|
88
|
+
/** Layers that introduced the targeted entry earlier in the stack. */
|
|
89
|
+
overriddenLayers: string[];
|
|
90
|
+
}
|
|
91
|
+
/** A patch row that matched nothing at boot (dsh warns and skips it). */
|
|
92
|
+
export interface OrphanRow {
|
|
93
|
+
id: string;
|
|
94
|
+
layer: string;
|
|
95
|
+
reason: string;
|
|
96
|
+
}
|
|
97
|
+
/** Directional verdict for one confirmed peer mismatch (issue #201 diagnostics). */
|
|
98
|
+
export interface PeerRisk {
|
|
99
|
+
plugin: string;
|
|
100
|
+
peer: string;
|
|
101
|
+
range: string;
|
|
102
|
+
resolved: string;
|
|
103
|
+
direction: 'belowMin' | 'aboveMax';
|
|
104
|
+
}
|
|
105
|
+
export interface PeerWarning {
|
|
106
|
+
plugin: string;
|
|
107
|
+
peer: string;
|
|
108
|
+
range: string;
|
|
109
|
+
resolved: string;
|
|
110
|
+
reason: 'aboveMax' | 'optional';
|
|
111
|
+
}
|
|
112
|
+
/** classifyPeer result: risk / warning / none — none means informational. */
|
|
113
|
+
export type PeerVerdict = {
|
|
114
|
+
kind: 'risk';
|
|
115
|
+
risk: PeerRisk;
|
|
116
|
+
} | {
|
|
117
|
+
kind: 'warning';
|
|
118
|
+
warning: PeerWarning;
|
|
119
|
+
} | {
|
|
120
|
+
kind: 'none';
|
|
121
|
+
};
|
|
122
|
+
/** A plugin peerDependencies range vs the resolved version. */
|
|
123
|
+
export interface PeerMismatch {
|
|
124
|
+
plugin: string;
|
|
125
|
+
name: string;
|
|
126
|
+
range: string;
|
|
127
|
+
resolved: string | null;
|
|
128
|
+
/** False = confirmed incompatible; null = could not be evaluated. */
|
|
129
|
+
satisfied: boolean | null;
|
|
130
|
+
/**
|
|
131
|
+
* The declaring plugin marked this peer `optional` in
|
|
132
|
+
* `peerDependenciesMeta`. Carried so the summary can hold the same line
|
|
133
|
+
* `classifyPeer` already does: an optional peer that does not match is
|
|
134
|
+
* the plugin saying "I work without this", not a broken install (#275).
|
|
135
|
+
*/
|
|
136
|
+
optional?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* The directional verdict, attached by `/dsh-market/check` for rows that
|
|
139
|
+
* did not match. It is computed on the server because the client cannot
|
|
140
|
+
* read `peerDependenciesMeta` off disk, and the tiering would otherwise
|
|
141
|
+
* have to be guessed from the range string (#201).
|
|
142
|
+
*/
|
|
143
|
+
verdict?: PeerVerdict;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Loader entries sharing one NAME across DIFFERENT layers — the Loader
|
|
147
|
+
* registers plugins by name, so a later layer's row with the same name
|
|
148
|
+
* shadows the earlier one at runtime. Same-layer rows sharing a name are
|
|
149
|
+
* routine (a bundle defining several entries under one name) and are never
|
|
150
|
+
* reported here. Unlike duplicate ids (report.duplicates), which fail the
|
|
151
|
+
* boot outright, shadowing names only decide which entry wins at runtime.
|
|
152
|
+
*/
|
|
153
|
+
export interface DuplicateName {
|
|
154
|
+
name: string;
|
|
155
|
+
/** Every layer that inserts/defines a row with this name. */
|
|
156
|
+
layers: string[];
|
|
157
|
+
count: number;
|
|
158
|
+
}
|
|
159
|
+
/** Distinct resolved versions of one core package found in the lockfile. */
|
|
160
|
+
export interface MultiVersion {
|
|
161
|
+
name: string;
|
|
162
|
+
versions: string[];
|
|
163
|
+
/** Version hoisted at the profile root, when present. */
|
|
164
|
+
hoisted: string | null;
|
|
165
|
+
}
|
|
166
|
+
/** The full check report for one profile. */
|
|
167
|
+
export interface CheckReport {
|
|
168
|
+
profile: string;
|
|
169
|
+
scannedAt: number;
|
|
170
|
+
bundles: BundleLayer[];
|
|
171
|
+
rows: LoaderRow[];
|
|
172
|
+
duplicates: DuplicateId[];
|
|
173
|
+
duplicateNames: DuplicateName[];
|
|
174
|
+
overrides: OverrideRow[];
|
|
175
|
+
orphans: OrphanRow[];
|
|
176
|
+
peerMismatches: PeerMismatch[];
|
|
177
|
+
multiVersion: MultiVersion[];
|
|
178
|
+
/** Before/after rule conflicts in the CURRENT bundle order (issue #98 phase 2). */
|
|
179
|
+
orderConflicts: Array<{
|
|
180
|
+
name: string;
|
|
181
|
+
reason: string;
|
|
182
|
+
}>;
|
|
183
|
+
/** LOOT-style auto-fix: a community order satisfying every declared rule. */
|
|
184
|
+
suggestedOrder: {
|
|
185
|
+
ok: true;
|
|
186
|
+
order: string[];
|
|
187
|
+
} | {
|
|
188
|
+
ok: false;
|
|
189
|
+
cycle: string[];
|
|
190
|
+
} | null;
|
|
191
|
+
summary: CheckSummary;
|
|
192
|
+
}
|
|
193
|
+
export interface CheckOptions {
|
|
194
|
+
/** DSH host install dir; auto-detected from the CLI entry or Desktop resources when omitted. */
|
|
195
|
+
dshInstallDir?: string;
|
|
196
|
+
/** ChatCode CLI home for the home-level patch layer; legacy DSH_HOME remains a read-only compatibility input. */
|
|
197
|
+
homeDir?: string;
|
|
198
|
+
}
|
|
199
|
+
/** Parse entry-list source with the DSH dialect; null when it is not a list. */
|
|
200
|
+
export declare function parsePatchText(text: string): unknown[] | null;
|
|
201
|
+
/** Parse one entry-list patch file with the DSH dialect; null when unreadable. */
|
|
202
|
+
export declare function parsePatchFile(path: string): unknown[] | null;
|
|
203
|
+
/** DSH host core packages: what the dsh installation ships under @deepseek-ai. */
|
|
204
|
+
export declare function corePackageNames(dshInstallDir: string | null): Set<string>;
|
|
205
|
+
/** Compare two semver strings: negative | zero | positive (prerelease < release of same base). */
|
|
206
|
+
export declare function compareSemver(a: string, b: string): number;
|
|
207
|
+
/**
|
|
208
|
+
* Minimal range matcher for the peer-range check: `*`, exact, ^, ~, >=, >,
|
|
209
|
+
* <=, <, whitespace-separated pairs, and `||` alternatives. Anything else
|
|
210
|
+
* returns null (unknown — reported, not asserted).
|
|
211
|
+
*
|
|
212
|
+
* Prerelease handling follows npm's semver rule, evaluated at the comparator
|
|
213
|
+
* SET level (one `||` alternative is one set): a version carrying a
|
|
214
|
+
* prerelease tag only satisfies a set when at least one comparator in that
|
|
215
|
+
* set shares the version's [major, minor, patch] tuple AND carries a
|
|
216
|
+
* prerelease of its own; then every comparator is checked normally. So
|
|
217
|
+
* `^0.1.0` never matches `0.2.0-rc.1` (nor `0.1.0-rc.5`), while
|
|
218
|
+
* `>=1.2.3-rc.1 <2.0.0` does match `1.2.3-rc.2` (issue #98 analysis).
|
|
219
|
+
* Discovery can opt into npm's `includePrerelease` behaviour because every
|
|
220
|
+
* published DSH host line is itself prerelease; diagnostics retain the npm
|
|
221
|
+
* default unless a caller explicitly asks for that wider admission.
|
|
222
|
+
*/
|
|
223
|
+
export declare function satisfiesRange(version: string, range: string, options?: {
|
|
224
|
+
includePrerelease?: boolean;
|
|
225
|
+
}): boolean | null;
|
|
226
|
+
interface ResolvableLoaderRow extends LoaderRow {
|
|
227
|
+
activation: 'required' | 'conditional';
|
|
228
|
+
}
|
|
229
|
+
export interface LayerInput {
|
|
230
|
+
label: string;
|
|
231
|
+
kind: 'bundle' | 'user' | 'home';
|
|
232
|
+
patches: unknown[];
|
|
233
|
+
parseError: string | null;
|
|
234
|
+
}
|
|
235
|
+
interface Composed {
|
|
236
|
+
rows: LoaderRow[];
|
|
237
|
+
resolvableRows: ResolvableLoaderRow[];
|
|
238
|
+
duplicates: DuplicateId[];
|
|
239
|
+
overrides: OverrideRow[];
|
|
240
|
+
orphans: OrphanRow[];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Apply the layer stack over an empty root exactly like the dsh boot include.
|
|
244
|
+
* Exported so the trial-start validation (src/trial.ts) can replay the
|
|
245
|
+
* composition with a candidate bundle order BEFORE anything is written.
|
|
246
|
+
*/
|
|
247
|
+
export declare function composeLayers(layers: LayerInput[]): Composed;
|
|
248
|
+
/**
|
|
249
|
+
* Build the bundle layer stack for a profile under a GIVEN bundle order —
|
|
250
|
+
* the manifest order for analyzeProfile, or a candidate order for trial
|
|
251
|
+
* validation (src/trial.ts). Bundle resolution mirrors the boot exactly:
|
|
252
|
+
* the dsh installation anchor first (in-box bundles always come from the
|
|
253
|
+
* running dsh, never a profile-local copy), then Node's module search from
|
|
254
|
+
* the profile directory (covers community bundles and pnpm workspace-root
|
|
255
|
+
* hoisting). A single code path keeps the check report and the trial
|
|
256
|
+
* validation from ever disagreeing about what a bundle is or where it lives.
|
|
257
|
+
*/
|
|
258
|
+
export declare function buildBundleLayers(profileDirectory: string, bundleNames: string[], specs: Record<string, string>, dshInstallDir: string | null): {
|
|
259
|
+
bundles: BundleLayer[];
|
|
260
|
+
layers: LayerInput[];
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Analyze one profile directory (issue #98, phase 1). Pure function of the
|
|
264
|
+
* directory contents — safe to call on every market open.
|
|
265
|
+
*/
|
|
266
|
+
export declare function analyzeProfile(profileDirectory: string, options?: CheckOptions): CheckReport;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-contract compatibility preflight for #195.
|
|
3
|
+
*
|
|
4
|
+
* Pure evaluation of what `analyzeProfile()` already reports: a confirmed
|
|
5
|
+
* peer mismatch (`satisfied === false`) is translated into a directional
|
|
6
|
+
* verdict:
|
|
7
|
+
*
|
|
8
|
+
* - `belowMin`: the resolved version is older than every alternative's lower
|
|
9
|
+
* bound — the environment is too old for the plugin's declared contract.
|
|
10
|
+
* - `aboveMax`: the resolved version is newer than every alternative's upper
|
|
11
|
+
* bound (or the exact pin). This is only a risk when the author expressed
|
|
12
|
+
* an explicit upper bound or exact pin; otherwise it is a warning, because
|
|
13
|
+
* the ecosystem currently has many sloppy `^0.0.1`-style declarations that
|
|
14
|
+
* work in practice.
|
|
15
|
+
*
|
|
16
|
+
* Everything else stays informational: `*`, prerelease-vs-`*` artifacts,
|
|
17
|
+
* unparseable ranges, and optional peers never produce a risk here.
|
|
18
|
+
*/
|
|
19
|
+
import { type CheckOptions, type DuplicateName, type PeerRisk, type PeerWarning, type PeerVerdict } from './check.ts';
|
|
20
|
+
export type CompatibilityRisk = PeerRisk;
|
|
21
|
+
export type CompatibilityWarning = PeerWarning;
|
|
22
|
+
/** Re-exported so consumers can keep importing PeerVerdict from this module. */
|
|
23
|
+
export type { PeerVerdict };
|
|
24
|
+
export interface CompatibilityAssessment {
|
|
25
|
+
risks: CompatibilityRisk[];
|
|
26
|
+
warnings: CompatibilityWarning[];
|
|
27
|
+
/**
|
|
28
|
+
* Cross-layer duplicate loader NAMES, carried through from the same
|
|
29
|
+
* `analyzeProfile` run the peer checks already pay for (#230).
|
|
30
|
+
*
|
|
31
|
+
* The report has always computed these and deliberately kept them out of
|
|
32
|
+
* `summary.warnings`, because flagging an already-messy but working
|
|
33
|
+
* profile is a false positive nobody can act on. Diffing before against
|
|
34
|
+
* after is what makes them actionable: a collision this operation
|
|
35
|
+
* INTRODUCED is one the operation can also undo.
|
|
36
|
+
*/
|
|
37
|
+
duplicateNames: DuplicateName[];
|
|
38
|
+
}
|
|
39
|
+
/** Translate one confirmed peer mismatch into a directional verdict. */
|
|
40
|
+
export declare function classifyPeer(plugin: string, peer: string, range: string, resolved: string | null, optional: boolean): PeerVerdict;
|
|
41
|
+
/** Whether a peer is declared optional in the installed plugin manifest. */
|
|
42
|
+
export declare function isOptionalPeer(profileDirectory: string, plugin: string, peer: string): boolean;
|
|
43
|
+
/** Evaluate the current profile with the same machinery `/dsh-market/check` uses. */
|
|
44
|
+
export declare function assessCompatibility(profileDirectory: string, options?: CheckOptions): CompatibilityAssessment;
|
|
45
|
+
/** Risks present after a mutation but absent before it. */
|
|
46
|
+
export declare function introducedRisks(before: CompatibilityAssessment, after: CompatibilityAssessment): CompatibilityRisk[];
|
|
47
|
+
/**
|
|
48
|
+
* Cross-layer name collisions present after a mutation but absent before it
|
|
49
|
+
* (#230 by @dxc-dxc).
|
|
50
|
+
*
|
|
51
|
+
* Keyed by NAME alone, not by the layer set: a collision the operation made
|
|
52
|
+
* worse — same name, now shadowing across one more layer — is still the same
|
|
53
|
+
* collision the profile already had, and re-reporting it would put the
|
|
54
|
+
* operator back in front of a problem they did not just cause.
|
|
55
|
+
*
|
|
56
|
+
* This is what makes surfacing these safe at all. The underlying
|
|
57
|
+
* `duplicateNames` is informational precisely because a healthy-but-messy
|
|
58
|
+
* profile can carry collisions indefinitely; only the newly introduced ones
|
|
59
|
+
* are attributable to the install that just ran, and therefore undoable by
|
|
60
|
+
* rolling it back.
|
|
61
|
+
*/
|
|
62
|
+
export declare function introducedDuplicateNames(before: CompatibilityAssessment, after: CompatibilityAssessment): DuplicateName[];
|
|
63
|
+
/** Convenience wrapper matching the profile helper signature. */
|
|
64
|
+
export declare function assessProfile(profile: string, explicitDir?: string): CompatibilityAssessment;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Versioned, read-only diagnostics shared by the host route and client. */
|
|
2
|
+
export declare const DIAGNOSTIC_SCHEMA: 'dsh-market/diagnostics/v1';
|
|
3
|
+
/** Conservative first set of known, identity-sensitive host contracts. */
|
|
4
|
+
export declare const KNOWN_SHARED_HOST_PACKAGES: readonly ['@deepseek-ai/cordis', '@deepseek-ai/dsh-attachment', '@deepseek-ai/dsh-llm', '@deepseek-ai/dsh-system-prompt', '@deepseek-ai/dsh-tools'];
|
|
5
|
+
export interface PackageManifestFact {
|
|
6
|
+
packageName: string;
|
|
7
|
+
manifest: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface SharedHostPackageDependencyFinding {
|
|
10
|
+
code: 'shared-host-package-dependency';
|
|
11
|
+
severity: 'warning';
|
|
12
|
+
subject: {
|
|
13
|
+
kind: 'package';
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
evidence: {
|
|
17
|
+
basis: 'manifest-declaration';
|
|
18
|
+
dependency: string;
|
|
19
|
+
declaredRange: string;
|
|
20
|
+
declaredIn: 'dependencies';
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export type DiagnosticFinding = SharedHostPackageDependencyFinding;
|
|
24
|
+
export interface DiagnosticReportV1 {
|
|
25
|
+
schema: typeof DIAGNOSTIC_SCHEMA;
|
|
26
|
+
findings: DiagnosticFinding[];
|
|
27
|
+
}
|
|
28
|
+
/** Build a stable diagnostic envelope from installed package manifests. */
|
|
29
|
+
export declare function diagnosePackageManifests(packages: readonly PackageManifestFact[]): DiagnosticReportV1;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery-time DSH compatibility metadata.
|
|
3
|
+
*
|
|
4
|
+
* The public catalog does not carry npm manifests. Fetching every manifest
|
|
5
|
+
* while the market opens would turn one catalog request into more than a
|
|
6
|
+
* thousand registry requests, so this module supplies a bounded, on-demand
|
|
7
|
+
* index. Successful public manifest facts are cached beside the market's
|
|
8
|
+
* profile state; conclusions are never cached because they depend on the DSH
|
|
9
|
+
* version of the process serving the page.
|
|
10
|
+
*/
|
|
11
|
+
export type HostCompatibilityStatus = 'compatible' | 'incompatible' | 'unknown';
|
|
12
|
+
export type HostCompatibilityBasis = 'manifest' | 'undeclared' | 'unavailable';
|
|
13
|
+
export interface HostRequirementDeclaration {
|
|
14
|
+
kind: 'engine' | 'peer';
|
|
15
|
+
/** Present only for a peer-derived declaration. */
|
|
16
|
+
package?: string;
|
|
17
|
+
range: string;
|
|
18
|
+
}
|
|
19
|
+
export interface HostCompatibility {
|
|
20
|
+
status: HostCompatibilityStatus;
|
|
21
|
+
basis: HostCompatibilityBasis;
|
|
22
|
+
/** Human-readable intersection of every raw declaration. */
|
|
23
|
+
requirement: string | null;
|
|
24
|
+
declarations: HostRequirementDeclaration[];
|
|
25
|
+
}
|
|
26
|
+
export interface NpmManifestFacts {
|
|
27
|
+
version: string | null;
|
|
28
|
+
enginesDsh: string | null;
|
|
29
|
+
peerDependencies: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
type FetchLike = (url: string, init?: {
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
}) => Promise<Response>;
|
|
35
|
+
/** Keep only the small public subset of an npm manifest needed by discovery. */
|
|
36
|
+
export declare function manifestFacts(value: unknown): NpmManifestFacts;
|
|
37
|
+
/**
|
|
38
|
+
* Derive the current host verdict from raw manifest facts.
|
|
39
|
+
*
|
|
40
|
+
* Every valid declaration is conjunctive: an explicit `engines.dsh` and all
|
|
41
|
+
* host peers must agree. A malformed declaration keeps a passing result
|
|
42
|
+
* unknown, but cannot erase a definite mismatch from another declaration.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deriveHostCompatibility(facts: NpmManifestFacts | null, hostVersion: string | null, hostPackages: ReadonlySet<string>): HostCompatibility;
|
|
45
|
+
/**
|
|
46
|
+
* Durable, bounded lookup of npm `latest` manifests.
|
|
47
|
+
*
|
|
48
|
+
* Failed requests are intentionally memory-only and short-lived: a mirror
|
|
49
|
+
* outage must not become a day-long false "undeclared" result on disk.
|
|
50
|
+
*/
|
|
51
|
+
export declare class DiscoveryManifestIndex {
|
|
52
|
+
private readonly cacheFile;
|
|
53
|
+
private readonly entries;
|
|
54
|
+
private readonly failures;
|
|
55
|
+
private readonly inflight;
|
|
56
|
+
private readonly fetcher;
|
|
57
|
+
private readonly now;
|
|
58
|
+
private readonly ttlMs;
|
|
59
|
+
private readonly concurrency;
|
|
60
|
+
private loaded;
|
|
61
|
+
private consecutiveFailures;
|
|
62
|
+
private unavailableUntil;
|
|
63
|
+
private dirty;
|
|
64
|
+
private activeFetches;
|
|
65
|
+
private readonly fetchWaiters;
|
|
66
|
+
constructor(cacheFile: string, options?: {
|
|
67
|
+
fetcher?: FetchLike;
|
|
68
|
+
now?: () => number;
|
|
69
|
+
ttlMs?: number;
|
|
70
|
+
concurrency?: number;
|
|
71
|
+
});
|
|
72
|
+
private load;
|
|
73
|
+
private persist;
|
|
74
|
+
/** One semaphore for the whole index, including overlapping HTTP batches. */
|
|
75
|
+
private withFetchPermit;
|
|
76
|
+
private fetchOne;
|
|
77
|
+
/** Look up a bounded batch while never exceeding the configured fan-out. */
|
|
78
|
+
lookup(names: readonly string[], registry: string): Promise<Record<string, NpmManifestFacts | null>>;
|
|
79
|
+
}
|
|
80
|
+
export {};
|