@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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Community bundle ordering — issue #98 (phase 2): let the user reorder the
|
|
3
|
+
* community bundles of the profile's layer stack, with author-declared
|
|
4
|
+
* before/after rules enforced before anything is written.
|
|
5
|
+
*
|
|
6
|
+
* Official in-box bundles (@deepseek-ai/dsh-base, @deepseek-ai/dsh-web-app,
|
|
7
|
+
* @deepseek-ai/dsh-headless) are fixed: they keep their exact positions in
|
|
8
|
+
* the stack, are never part of a user-supplied order, and are never added,
|
|
9
|
+
* removed or duplicated by a reorder (#98 boundary). The profile's own
|
|
10
|
+
* cordis.patch.yml and --patch overlays are not part of the bundle stack and
|
|
11
|
+
* are never touched here.
|
|
12
|
+
*
|
|
13
|
+
* Pure functions plus one manifest write-back; no processes, no network.
|
|
14
|
+
*/
|
|
15
|
+
/** Profile bundles that ship with the dsh host and must stay put (#98). */
|
|
16
|
+
export declare const INBOX_BUNDLES: Set<string>;
|
|
17
|
+
/** The bundle stack as it appears in the profile manifest. */
|
|
18
|
+
export interface BundleStack {
|
|
19
|
+
/** Full ordered list from dsh.profile.bundles. */
|
|
20
|
+
bundles: string[];
|
|
21
|
+
/** The subset that may be reordered (community bundles). */
|
|
22
|
+
community: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Author-declared ordering constraints of one bundle. */
|
|
25
|
+
export interface BundleRule {
|
|
26
|
+
name: string;
|
|
27
|
+
/** This bundle must load after every name in this list. */
|
|
28
|
+
after: string[];
|
|
29
|
+
/** This bundle must load before every name in this list. */
|
|
30
|
+
before: string[];
|
|
31
|
+
}
|
|
32
|
+
/** A violated before/after rule in the current or proposed order. */
|
|
33
|
+
export interface OrderConflict {
|
|
34
|
+
name: string;
|
|
35
|
+
reason: string;
|
|
36
|
+
}
|
|
37
|
+
/** Read the profile's bundle stack (empty when the manifest is unreadable). */
|
|
38
|
+
export declare function readBundleStack(profileDir: string): BundleStack;
|
|
39
|
+
/**
|
|
40
|
+
* Read each bundle's declared ordering rules from its package manifest
|
|
41
|
+
* (`dsh.bundle.order.{before,after}` — a list of bundle package names).
|
|
42
|
+
* Unresolvable packages and missing declarations contribute nothing.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readBundleRules(profileDir: string): BundleRule[];
|
|
45
|
+
/**
|
|
46
|
+
* Check a bundle order against the declared before/after rules. Rules naming
|
|
47
|
+
* bundles outside `order` are ignored (a rule for a not-yet-installed bundle
|
|
48
|
+
* must not block the current stack).
|
|
49
|
+
* @returns every violated rule with a readable reason; [] when all hold.
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateOrder(bundleNames: string[], rules: BundleRule[]): OrderConflict[];
|
|
52
|
+
/**
|
|
53
|
+
* Merge a community-bundle permutation into the full stack. Official in-box
|
|
54
|
+
* bundles keep their EXACT positions (never moved); community bundles are
|
|
55
|
+
* replaced by `newOrder` in order of appearance. Pure — nothing is written.
|
|
56
|
+
* @returns the merged full stack, or the rejection reason when `newOrder` is
|
|
57
|
+
* not a permutation of the community bundles (duplicates, additions,
|
|
58
|
+
* omissions, official names).
|
|
59
|
+
*/
|
|
60
|
+
export declare function mergeOrder(bundles: string[], newOrder: string[]): {
|
|
61
|
+
ok: true;
|
|
62
|
+
bundles: string[];
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
error: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Topologically sort the community bundles by their before/after rules — the
|
|
69
|
+
* "auto-fix" counterpart to validateOrder. Returns null when no declared rule
|
|
70
|
+
* applies to the current stack (nothing to suggest). With rules, Kahn's
|
|
71
|
+
* algorithm breaks ties by the CURRENT order: unconstrained bundles keep
|
|
72
|
+
* their current relative order and constrained bundles move only as far as
|
|
73
|
+
* the rules require — the suggestion is the minimal change that satisfies
|
|
74
|
+
* every rule, never an arbitrary canonical rewrite of a hand-picked order
|
|
75
|
+
* (issue #125 review).
|
|
76
|
+
* @returns the suggested community order, null when there are no rules, or a
|
|
77
|
+
* cycle report when the constraints cannot be satisfied (references to
|
|
78
|
+
* unlisted bundles ignored).
|
|
79
|
+
*/
|
|
80
|
+
export declare function suggestOrder(bundleNames: string[], rules: BundleRule[]): {
|
|
81
|
+
ok: true;
|
|
82
|
+
order: string[];
|
|
83
|
+
} | {
|
|
84
|
+
ok: false;
|
|
85
|
+
cycle: string[];
|
|
86
|
+
} | null;
|
|
87
|
+
/**
|
|
88
|
+
* Apply a new community-bundle order to the profile manifest. The official
|
|
89
|
+
* in-box bundles keep their exact positions; `newOrder` must be a permutation
|
|
90
|
+
* of the current community bundles (no duplicates, no additions, no
|
|
91
|
+
* omissions). On any failure the manifest is left untouched.
|
|
92
|
+
* @returns the new full stack on success, or an error description.
|
|
93
|
+
*/
|
|
94
|
+
export declare function applyBundleOrder(profileDir: string, newOrder: string[]): {
|
|
95
|
+
ok: true;
|
|
96
|
+
bundles: string[];
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
error: string;
|
|
100
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch-layer plugin toggles — hot disable/enable through the profile's
|
|
3
|
+
* user patch layer (cordis.patch.yml), the mechanism ported from
|
|
4
|
+
* Noob-stupid/dsh-plugin-hub's plugin console.
|
|
5
|
+
*
|
|
6
|
+
* DSH composes a web profile from the bundle layers + the user patch layer
|
|
7
|
+
* (`$CHATCODE_CLI_HOME/profiles/<name>/cordis.patch.yml`), with per-key override
|
|
8
|
+
* semantics: a patch row `- id: X` + `disabled: true` stops that loader
|
|
9
|
+
* entry, and `disabled: false` force-enables one a lower layer disabled.
|
|
10
|
+
* The profile's config-file watcher (HMR) re-composes within ~1s of the
|
|
11
|
+
* save — no restart — and the loader re-applies the same file on every
|
|
12
|
+
* boot, so the choice survives restarts through the official mechanism.
|
|
13
|
+
*
|
|
14
|
+
* The market ALSO keeps its own in-memory/state.json bookkeeping (hot-mount
|
|
15
|
+
* shims have no bundle row to patch, and the client's disable list drives
|
|
16
|
+
* the switches); this module is the durable, HMR-driven layer on top.
|
|
17
|
+
*
|
|
18
|
+
* Safety (borrowed from the plugin-hub implementation):
|
|
19
|
+
* - writes are serialized so concurrent toggles cannot interleave a
|
|
20
|
+
* read-modify-write;
|
|
21
|
+
* - an append is REFUSED when the patch file is not a valid entry list —
|
|
22
|
+
* a malformed file (e.g. a stray `[]` followed by items) is never made
|
|
23
|
+
* worse, the market reports it instead;
|
|
24
|
+
* - host infrastructure rows (transport / hot-reload / storage / settings
|
|
25
|
+
* chains) are protected and refuse to toggle.
|
|
26
|
+
*/
|
|
27
|
+
/** The slice of the loader tree this module needs. */
|
|
28
|
+
export interface PatchHost {
|
|
29
|
+
loader: {
|
|
30
|
+
entries(): Iterable<{
|
|
31
|
+
options?: {
|
|
32
|
+
id?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
config?: {
|
|
35
|
+
path?: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** True when the module name sits on the host infrastructure chain. */
|
|
42
|
+
export declare function isProtectedModule(moduleName: string | undefined): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the profile's user patch layer. Prefers the path the loader's
|
|
45
|
+
* cordis:include entry actually read (authoritative under hosts that own
|
|
46
|
+
* the profile directory, like DSH Desktop); falls back to the conventional
|
|
47
|
+
* `<profile>/cordis.patch.yml`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function findUserPatchPath(host: PatchHost, profileDir: string): string;
|
|
50
|
+
/** What the user patch layer currently says about rows. */
|
|
51
|
+
export interface PatchState {
|
|
52
|
+
/** Row ids the user patch disables (`disabled: true`). */
|
|
53
|
+
disables: string[];
|
|
54
|
+
/** Row ids the user patch force-enables (`disabled: false`). */
|
|
55
|
+
forced: string[];
|
|
56
|
+
/** Row ids the user patch inserts. */
|
|
57
|
+
inserts: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Line-wise scan of one patch file — the plugin-hub shapes. Deliberately
|
|
61
|
+
* not a YAML parse: the file may hold structures the market's dialect
|
|
62
|
+
* rejects, but a plain `- id: X` + `disabled: true|false` pair is enough
|
|
63
|
+
* to know what the user patch layer says.
|
|
64
|
+
*/
|
|
65
|
+
export declare function readUserPatchState(patchPath: string): PatchState;
|
|
66
|
+
/**
|
|
67
|
+
* User-authored insert rows that still load `packageName` (or one of its
|
|
68
|
+
* exported subpaths). This evidence deliberately stays separate from the
|
|
69
|
+
* package's own bundle declaration: uninstall may clean market-owned rows,
|
|
70
|
+
* but it must never rewrite an insert the user owns.
|
|
71
|
+
*
|
|
72
|
+
* A missing patch is the ordinary empty-profile shape. `null` means the
|
|
73
|
+
* existing file could not be read as DSH's patch dialect; callers must treat
|
|
74
|
+
* that as indeterminate and refuse the destructive step.
|
|
75
|
+
*/
|
|
76
|
+
export declare function userPatchPackageReferences(patchPath: string, packageName: string): string[] | null;
|
|
77
|
+
/**
|
|
78
|
+
* The user-patch row ids one installed package owns: its bundle patch's
|
|
79
|
+
* insert rows, plus the loader entries currently carrying its name.
|
|
80
|
+
* Empty for client-only packages (no bundle rows) — the market's own
|
|
81
|
+
* state.json mechanism covers those, and there is nothing to patch.
|
|
82
|
+
* Market-owned namespaces (hot-mount `mkt-*`, shim `client-*`) are
|
|
83
|
+
* excluded: their rows live in the market's own include subtree, and a
|
|
84
|
+
* permanent patch row targeting them would be a boot-time orphan.
|
|
85
|
+
*/
|
|
86
|
+
export declare function rowIdsForPackage(host: PatchHost, profileDirectory: string, packageName: string): string[];
|
|
87
|
+
/**
|
|
88
|
+
* The ids of OTHER plugins a package's bundle patch DISABLES — top-level
|
|
89
|
+
* `- id: X` + `disabled: true` rows targeting plugins it does not own. This is
|
|
90
|
+
* the precise marker of a bundle whose toggle-off can brick the boot (#224):
|
|
91
|
+
* dsh-postgres-backends disables session-persistence-jsonl, so once the market
|
|
92
|
+
* also disables the postgres backends nothing provides sessionPersistence.
|
|
93
|
+
*
|
|
94
|
+
* A bundle that merely RECONFIGURES a neighbour is deliberately NOT counted:
|
|
95
|
+
* the e2e fixture-cross tweaks dshm-fixture-b's config, and #147 requires
|
|
96
|
+
* disabling it to leave that neighbour live — dropping such a bundle from the
|
|
97
|
+
* stack broke its re-enable. Config-only side effects stay on the normal #147
|
|
98
|
+
* path; only a foreign `disabled: true` triggers the bundle removal. Removing
|
|
99
|
+
* the bundle still neutralizes any config side effects it carries, since its
|
|
100
|
+
* whole patch stops applying.
|
|
101
|
+
*
|
|
102
|
+
* Reads both patch sources like rowIdsForPackage — the declared dsh.bundle.patch
|
|
103
|
+
* and the conventional root cordis.patch.yml — so either form is detected.
|
|
104
|
+
*/
|
|
105
|
+
export declare function carrierDisableIds(profileDirectory: string, packageName: string): string[];
|
|
106
|
+
/**
|
|
107
|
+
* Per-package patch-layer flags for the installed list: names whose rows the
|
|
108
|
+
* user patch layer disables / force-enables. These cover toggles made
|
|
109
|
+
* OUTSIDE the market (hand-edited cordis.patch.yml, dsh-web-plugin-manager,
|
|
110
|
+
* the dsh CLI), which the market's own state.json never sees.
|
|
111
|
+
*/
|
|
112
|
+
export declare function packagePatchFlags(host: PatchHost, profileDirectory: string, names: readonly string[], state: PatchState): {
|
|
113
|
+
disabled: string[];
|
|
114
|
+
forced: string[];
|
|
115
|
+
};
|
|
116
|
+
/** Disable one row: append `- id: X` + `disabled: true` (idempotent). */
|
|
117
|
+
export declare function disableRow(patchPath: string, rowId: string): Promise<{
|
|
118
|
+
ok: boolean;
|
|
119
|
+
reason: string | null;
|
|
120
|
+
}>;
|
|
121
|
+
/** Enable one row: remove the `disabled: true` block; force-enable with
|
|
122
|
+
* `disabled: false` when a lower layer (bundle/home patch) holds it down. */
|
|
123
|
+
export declare function enableRow(patchPath: string, rowId: string): Promise<{
|
|
124
|
+
ok: boolean;
|
|
125
|
+
reason: string | null;
|
|
126
|
+
}>;
|
|
127
|
+
/** Remove every disable/force block the market (or the user) wrote for a
|
|
128
|
+
* row — the uninstall cleanup, so a removed plugin leaves no orphan rows. */
|
|
129
|
+
export declare function removeRowBlocks(patchPath: string, rowIds: readonly string[]): void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pnpm compatibility layer — everything the market needs to know about how
|
|
3
|
+
* different pnpm majors behave inside a dsh profile directory, kept pure and
|
|
4
|
+
* separately testable (test/unit + test/integration exercise this module
|
|
5
|
+
* against real pnpm 9/10/11).
|
|
6
|
+
*
|
|
7
|
+
* Verified behavior matrix (2026-08, pnpm 9.15.9 / 10.28.2 / 11.21.0):
|
|
8
|
+
* - workspace root, `add` without -w: pnpm 9 fails ERR_PNPM_ADDING_TO_ROOT;
|
|
9
|
+
* pnpm 10/11 succeed.
|
|
10
|
+
* - `add -w` where NO pnpm-workspace.yaml exists: ALL majors fail with
|
|
11
|
+
* "--workspace-root may only be used inside a workspace".
|
|
12
|
+
* - modules dir built by pnpm 9, then pnpm 10/11 mutate it: a modules-layout
|
|
13
|
+
* compatibility error (public-hoist-pattern on Unix; virtual-store path
|
|
14
|
+
* length can be the first mismatch pnpm reports on Windows).
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Decide the argv for a `dsh plugin <add|remove> …` call in the given profile.
|
|
18
|
+
*
|
|
19
|
+
* pnpm 9 refuses to add at a workspace root without -w (#17, #20); every
|
|
20
|
+
* pnpm major refuses -w when the directory is NOT a workspace. So the flag
|
|
21
|
+
* is injected exactly when the profile has a pnpm-workspace.yaml.
|
|
22
|
+
* @param profileDir - resolved profile directory (owns pnpm-workspace.yaml, or not).
|
|
23
|
+
* @param pluginArgs - the raw args, e.g. ['add', 'dshmarket@latest'].
|
|
24
|
+
* @returns args with -w injected when — and only when — the profile is a workspace root.
|
|
25
|
+
*/
|
|
26
|
+
export declare function pluginArgsFor(profileDir: string, pluginArgs: string[]): string[];
|
|
27
|
+
/** One recognized pnpm failure, with a bilingual explanation for the UI. */
|
|
28
|
+
/**
|
|
29
|
+
* The namespace whose packages the dsh runtime provides rather than npm.
|
|
30
|
+
*
|
|
31
|
+
* A peer dependency on one of these is a statement about the host, not a
|
|
32
|
+
* package to download — and several of them are never published at all.
|
|
33
|
+
*/
|
|
34
|
+
export declare const HOST_NAMESPACE_RE: RegExp;
|
|
35
|
+
export interface PnpmFailure {
|
|
36
|
+
code: 'adding-to-root' | 'not-a-workspace' | 'hoist-pattern-diff' | 'pnpm-missing' | 'release-age-violation' | 'ignored-builds' | 'git-prepare-not-allowed' | 'git-prepare-failed' | 'tarball-url-mismatch' | 'fetch-404' | 'transient-network' | 'fetch-timeout' | 'unexpected-store' | 'patch-failed' | 'missing-tarball-integrity' | 'windows-file-locked' | 'pnpm-unusable' | 'missing-local-dependency';
|
|
37
|
+
/** Bilingual, actionable message shown to the user instead of the raw wall of text. */
|
|
38
|
+
message: string;
|
|
39
|
+
/** True when re-running `pnpm install` in the profile is the documented recovery. */
|
|
40
|
+
recoverable: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Show this message INSTEAD of the captured output, not after it.
|
|
43
|
+
*
|
|
44
|
+
* Normally the raw text is worth keeping: it is pnpm's own account of what
|
|
45
|
+
* happened, and the explanation sits under it. Set only where the captured
|
|
46
|
+
* bytes carry nothing a user can read — cmd.exe writes its errors in the
|
|
47
|
+
* OEM code page, which arrives here as replacement characters, so pasting
|
|
48
|
+
* them under an explanation adds noise and hides the explanation (#502).
|
|
49
|
+
*/
|
|
50
|
+
replaceOutput?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The package pnpm could not resolve, when the failure names one.
|
|
53
|
+
*
|
|
54
|
+
* Exposed because the NAME alone does not say what went wrong: the same
|
|
55
|
+
* 404 is a ghost entry the user must delete when the package is a direct
|
|
56
|
+
* dependency of the profile, and an unpublished host peer the market can
|
|
57
|
+
* retry around when it is not (#289). Only a caller holding the profile
|
|
58
|
+
* manifest can tell those apart, so the classifier reports the fact and
|
|
59
|
+
* leaves the judgement to it.
|
|
60
|
+
*/
|
|
61
|
+
pkg?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Momentary network failures — worth exactly one automatic retry (#83).
|
|
65
|
+
* pnpm 5xx fetch codes, its meta-fetch give-up, and the raw socket errors
|
|
66
|
+
* that surface through dsh's wrapper. Permanent shapes (404, auth) are
|
|
67
|
+
* deliberately absent: retrying those just doubles the wait for bad news.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isTransientPnpmFailure(output: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* pnpm's per-request fetch timeout: the abort surfaces as a DOMException
|
|
72
|
+
* ("The operation was aborted due to timeout", code 23) through undici —
|
|
73
|
+
* pnpm logs it as `GET … error (23)` before giving up. This is the failure
|
|
74
|
+
* shape for large tarballs (github: sources download the WHOLE repo, even
|
|
75
|
+
* for a `#path:` subdirectory plugin) on slow networks: pnpm's default
|
|
76
|
+
* 60-second limit is simply not enough, so a plain retry fails again at the
|
|
77
|
+
* same limit. The market's recovery re-runs once with a longer
|
|
78
|
+
* fetchTimeout (see withHoistRecovery).
|
|
79
|
+
*/
|
|
80
|
+
export declare function isFetchTimeoutFailure(output: string): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Map a failed pnpm run's combined output to a known failure mode.
|
|
83
|
+
*
|
|
84
|
+
* dsh's own wrapper line ("dsh: pnpm failed in profile directory …") names no
|
|
85
|
+
* cause, so the market must recognize pnpm's real diagnostics itself (#20).
|
|
86
|
+
* @param output - stdout+stderr of the failed run.
|
|
87
|
+
* @param exitCode - the run's exit status, when the caller has it (null when
|
|
88
|
+
* the process was signalled). Only a
|
|
89
|
+
* failure whose whole signal IS the status reads it (#502); everything else
|
|
90
|
+
* is recognized from what pnpm said.
|
|
91
|
+
* @returns the classified failure, or null when unrecognized (raw output is then shown as-is).
|
|
92
|
+
*/
|
|
93
|
+
export declare function classifyPnpmFailure(output: string, exitCode?: number | null): PnpmFailure | null;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named plugin presets — issue #98 (phase 3), the "save different plugin
|
|
3
|
+
* combinations" product shape. A preset captures the community-bundle order
|
|
4
|
+
* and the disabled-plugin list of the profile at save time; applying one
|
|
5
|
+
* replays the composition under the candidate order (trialValidate), refuses
|
|
6
|
+
* on failure, auto-snapshots the profile (createProfileSnapshot), and only
|
|
7
|
+
* then writes the bundle order and disable list.
|
|
8
|
+
*
|
|
9
|
+
* Presets persist in `<profile>/.dsh-market/presets.json` (market-owned
|
|
10
|
+
* state, like snapshots) — deliberately separate from state.json, whose
|
|
11
|
+
* shape routes.ts owns.
|
|
12
|
+
*/
|
|
13
|
+
import { type TrialDiff, type TrialIssue } from './trial.ts';
|
|
14
|
+
/** Maximum presets stored per profile (quota — issue #98 analysis). */
|
|
15
|
+
export declare const MAX_PRESETS = 50;
|
|
16
|
+
export interface Preset {
|
|
17
|
+
name: string;
|
|
18
|
+
/** Community-bundle order this preset restores. */
|
|
19
|
+
bundleOrder: string[];
|
|
20
|
+
/** Disabled plugin names this preset restores. */
|
|
21
|
+
disabled: string[];
|
|
22
|
+
createdAt: number;
|
|
23
|
+
}
|
|
24
|
+
export interface PresetResult {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
/** Set when applyPreset auto-created a pre-change snapshot. */
|
|
28
|
+
snapshot?: string;
|
|
29
|
+
}
|
|
30
|
+
/** All saved presets, newest first. */
|
|
31
|
+
export declare function listPresets(profileDir: string): Preset[];
|
|
32
|
+
/**
|
|
33
|
+
* Save the current composition state as a named preset. The bundle order is
|
|
34
|
+
* validated against the current community bundles so a stale snapshot can
|
|
35
|
+
* never be stored.
|
|
36
|
+
*/
|
|
37
|
+
export declare function savePreset(profileDir: string, name: unknown, bundleOrder: unknown, disabled: unknown): PresetResult;
|
|
38
|
+
/** Delete a named preset. */
|
|
39
|
+
export declare function deletePreset(profileDir: string, name: unknown): PresetResult;
|
|
40
|
+
/** The concrete change a preset apply would make — computed BEFORE writing. */
|
|
41
|
+
export interface PresetChange {
|
|
42
|
+
/** Bundles whose position changes under the preset order. */
|
|
43
|
+
reordered: string[];
|
|
44
|
+
/** Plugins the preset would ENABLE (currently disabled, enabled by the preset). */
|
|
45
|
+
enabled: string[];
|
|
46
|
+
/** Plugins the preset would DISABLE (currently enabled, disabled by the preset). */
|
|
47
|
+
disabled: string[];
|
|
48
|
+
/** True when nothing would change. */
|
|
49
|
+
noop: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface PresetApplyResult extends PresetResult {
|
|
52
|
+
changes?: PresetChange;
|
|
53
|
+
/** Set when the preset order fails trial validation — errors + current-vs-candidate diff (issue #125 review). */
|
|
54
|
+
trial?: {
|
|
55
|
+
errors: TrialIssue[];
|
|
56
|
+
warnings: TrialIssue[];
|
|
57
|
+
diff: TrialDiff;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The preset's bundle set vs the profile's current community bundles —
|
|
62
|
+
* a stale preset (saved before a plugin was installed/uninstalled) can no
|
|
63
|
+
* longer be applied as-is, but its intent (enabled/disabled plugins,
|
|
64
|
+
* relative order) is still previewable.
|
|
65
|
+
*/
|
|
66
|
+
export interface PresetMismatch {
|
|
67
|
+
/** Bundles in the current profile that the preset does not mention. */
|
|
68
|
+
missing: string[];
|
|
69
|
+
/** Bundles the preset mentions that are not installed anymore. */
|
|
70
|
+
extra: string[];
|
|
71
|
+
/** True when the preset's bundle set differs from the current one. */
|
|
72
|
+
stale: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Preview what applying a preset would change, WITHOUT writing anything.
|
|
76
|
+
* A stale preset (bundle set mismatch) is NOT a hard failure: the preview
|
|
77
|
+
* reports the mismatch alongside the still-computable changes (relative
|
|
78
|
+
* order + enabled/disabled diffs over the intersection).
|
|
79
|
+
*/
|
|
80
|
+
export declare function previewPreset(profileDir: string, name: unknown): PresetResult & {
|
|
81
|
+
changes?: PresetChange;
|
|
82
|
+
mismatch?: PresetMismatch;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Apply a saved preset: trial-validate the candidate order first (refuse
|
|
86
|
+
* without writing on any boot-breaking issue), auto-snapshot the profile,
|
|
87
|
+
* then write the bundle order and the disable list. The response carries the
|
|
88
|
+
* change preview so the UI can report exactly what moved.
|
|
89
|
+
*/
|
|
90
|
+
export declare function applyPreset(profileDir: string, name: unknown, maxSnapshots?: number): PresetApplyResult;
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile filesystem reads — everything the market learns from a dsh
|
|
3
|
+
* profile directory (manifest, lockfile, installed package trees). Pure
|
|
4
|
+
* functions of the directory contents; no processes, no network.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Whether a profile name follows DSH's own directory-name contract.
|
|
8
|
+
*
|
|
9
|
+
* Keep this aligned with `@deepseek-ai/dsh-app-boot`'s
|
|
10
|
+
* `resolveProfileDir`: dots, spaces, and Unicode are ordinary name
|
|
11
|
+
* characters; only empty, traversal-shaped, launcher-owned, or
|
|
12
|
+
* separator-bearing names are refused.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isDshProfileName(profile: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a profile name beneath the canonical ChatCode CLI Home.
|
|
17
|
+
* An explicit directory is used by hosts, such as DSH Desktop, that own the
|
|
18
|
+
* active profile location rather than deriving it from process environment.
|
|
19
|
+
*/
|
|
20
|
+
export declare function profileDir(profile: string, explicitDir?: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* The in-box bundles dsh's profile templates install themselves — the ONLY
|
|
23
|
+
* names the market hides from the installed list. Community plugins may
|
|
24
|
+
* legitimately publish under the official scope (#28), so a whole-scope
|
|
25
|
+
* filter would make them invisible and fail install validation.
|
|
26
|
+
* (Diagnosis and fix proposed in #28 by @Lograthmic.)
|
|
27
|
+
*/
|
|
28
|
+
export declare const INBOX_BUNDLES: Set<string>;
|
|
29
|
+
/** Community dependencies of the profile (in-box bundles filtered out). */
|
|
30
|
+
export declare function readInstalled(profile: string, explicitDir?: string): Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* RAW dependency map of the profile manifest — including the in-box bundles
|
|
33
|
+
* readInstalled() filters out. This is the rollback snapshot (#65): restoring
|
|
34
|
+
* a filtered view would delete @deepseek-ai/dsh-base and friends.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readManifestDeps(profile: string, explicitDir?: string): Record<string, string>;
|
|
37
|
+
/** Exact rollback state owned by one profile package operation. */
|
|
38
|
+
export interface ProfileManifestSnapshot {
|
|
39
|
+
dependencies: Record<string, string>;
|
|
40
|
+
profileBundles: {
|
|
41
|
+
present: false;
|
|
42
|
+
} | {
|
|
43
|
+
present: true;
|
|
44
|
+
value: unknown;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Read dependencies and the exact `dsh.profile.bundles` field before a package operation. */
|
|
48
|
+
export declare function readProfileManifestSnapshot(profile: string, explicitDir?: string): ProfileManifestSnapshot;
|
|
49
|
+
/**
|
|
50
|
+
* Restore the profile manifest fields a package operation may mutate:
|
|
51
|
+
* `dependencies` and `dsh.profile.bundles`. pnpm and `dsh plugin add` can
|
|
52
|
+
* write both before a later fetch or build-script failure (#65, #69, #339),
|
|
53
|
+
* leaving either an unresolvable dependency or a bundle the next boot cannot
|
|
54
|
+
* activate. Every unrelated manifest field remains untouched. The lockfile is
|
|
55
|
+
* left as-is; pnpm reconciles it from the manifest on the next run.
|
|
56
|
+
*
|
|
57
|
+
* The write is atomic because rollback runs after another operation already
|
|
58
|
+
* failed; a partial repair must not turn a valid profile into invalid JSON.
|
|
59
|
+
* @returns names whose entries were dropped or reverted, empty when nothing changed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function restoreProfileManifest(profile: string, snapshot: ProfileManifestSnapshot, explicitDir?: string): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Remove a package from BOTH manifest lists — dependencies and
|
|
64
|
+
* dsh.profile.bundles. The uninstall counterpart of restoreProfileManifest:
|
|
65
|
+
* pnpm can fail a remove after deleting node_modules but before saving
|
|
66
|
+
* package.json (the #65 write-order's mirror image — a file locked mid-
|
|
67
|
+
* unlink aborts the run), leaving the manifest pointing at a package that
|
|
68
|
+
* no longer exists on disk. The next boot then fails to activate the ghost
|
|
69
|
+
* dependency. When disk truth says the package is gone, this finishes the
|
|
70
|
+
* removal the CLI could not. Every other manifest field is untouched.
|
|
71
|
+
*
|
|
72
|
+
* Written atomically because it runs only after something already went wrong
|
|
73
|
+
* mid-uninstall, so it is the worst place to leave a half-written manifest.
|
|
74
|
+
* @returns true when either list still mentioned the package.
|
|
75
|
+
*/
|
|
76
|
+
export declare function dropFromManifest(profile: string, name: string, explicitDir?: string): boolean;
|
|
77
|
+
/** The version actually present in the profile's node_modules, or null. */
|
|
78
|
+
export declare function readInstalledVersion(profile: string, name: string, explicitDir?: string): string | null;
|
|
79
|
+
/** The installed package manifest, or null when absent or malformed. */
|
|
80
|
+
export declare function readInstalledManifest(profile: string, name: string, explicitDir?: string): unknown | null;
|
|
81
|
+
/**
|
|
82
|
+
* Whether a package or one of its direct dependencies ships a native addon.
|
|
83
|
+
*
|
|
84
|
+
* The question behind it: can unloading this plugin actually free its files?
|
|
85
|
+
* For ordinary JavaScript, yes — and on POSIX it does not even matter,
|
|
86
|
+
* because replacing an open file leaves the old inode to whoever holds it.
|
|
87
|
+
* For a native addon it is no on both counts: Node has no dlclose, so once a
|
|
88
|
+
* `.node` is loaded the process holds it until it exits. On Windows that
|
|
89
|
+
* turns "uninstall, then install again" into an EPERM on the rename, which
|
|
90
|
+
* is what @yandidan1 hit with node-hid (#441) — and no amount of disabling,
|
|
91
|
+
* unmounting or uninstalling from inside the running process can fix it.
|
|
92
|
+
*
|
|
93
|
+
* Deliberately a cheap structural check rather than a scan. Walking a
|
|
94
|
+
* dependency's tree for `*.node` means recursing through packages that can
|
|
95
|
+
* be tens of thousands of files, on the uninstall path, to answer a question
|
|
96
|
+
* three `existsSync` calls answer for every native module built or shipped
|
|
97
|
+
* the conventional way: node-gyp's `build/Release`, prebuild's `prebuilds/`,
|
|
98
|
+
* and the `binding.gyp` that names the addon in the first place.
|
|
99
|
+
*
|
|
100
|
+
* Direct dependencies are included because that is where these live: the
|
|
101
|
+
* plugin is JavaScript and the addon is a package it depends on, hoisted to
|
|
102
|
+
* the profile root beside it.
|
|
103
|
+
* @param profile - profile name.
|
|
104
|
+
* @param name - the installed package to ask about.
|
|
105
|
+
* @param explicitDir - resolved profile directory, when the caller has it.
|
|
106
|
+
* @returns true when a native addon is present in the package or a direct dependency.
|
|
107
|
+
*/
|
|
108
|
+
export declare function holdsNativeAddon(profile: string, name: string, explicitDir?: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Strong repository identities for a locally linked dependency (#141).
|
|
111
|
+
* Explicit github: specs already carry this evidence; only link:/file: need
|
|
112
|
+
* filesystem discovery. This compatibility wrapper returns only declared
|
|
113
|
+
* package.json identities; Git origins are exposed separately as hints.
|
|
114
|
+
*/
|
|
115
|
+
export declare function readInstalledRepoIdentities(profile: string, name: string, spec: string, explicitDir?: string): string[];
|
|
116
|
+
export interface InstalledRepoEvidence {
|
|
117
|
+
identities: string[];
|
|
118
|
+
hints: string[];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Discover declared repository identities and weaker local-origin hints. A
|
|
122
|
+
* package.json repository declaration is authoritative; Git origin is only a
|
|
123
|
+
* disambiguation hint because a checkout may legitimately point at a fork.
|
|
124
|
+
*/
|
|
125
|
+
export declare function readInstalledRepoEvidence(profile: string, name: string, spec: string, explicitDir?: string): InstalledRepoEvidence;
|
|
126
|
+
/** Pinned commit per `owner/repo` from the profile lockfile's codeload tarball URLs. */
|
|
127
|
+
export declare function readLockCommits(profile: string, explicitDir?: string): Map<string, string>;
|
|
128
|
+
/**
|
|
129
|
+
* Commit recorded for a non-codeload git resolution (`type: git` in pnpm's
|
|
130
|
+
* lockfile). Matched against the install spec so a Gitea/GitLab URL can
|
|
131
|
+
* compare HEAD without mistaking a same-named npm package (#525).
|
|
132
|
+
*/
|
|
133
|
+
export declare function readGitResolutionCommit(profile: string, spec: string, explicitDir?: string): string | null;
|
|
134
|
+
/** True when the installed package's manifest declares a dsh plugin surface. */
|
|
135
|
+
export declare function hasDshManifest(dir: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* True when the package's declared entry artifact actually exists — github
|
|
138
|
+
* source checkouts of build-required plugins ship no lib/, and promoting one
|
|
139
|
+
* into the bundle layer bricks the next boot (ERR_MODULE_NOT_FOUND kills the
|
|
140
|
+
* whole profile, #18).
|
|
141
|
+
*/
|
|
142
|
+
export declare function entryArtifactExists(dir: string): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Package names a bundle patch mounts — the `name:` rows of the package's
|
|
145
|
+
* declared `dsh.bundle.patch` file. Line-wise on purpose: the strict
|
|
146
|
+
* hot-mount parser rejects config/expression rows, but for "what does this
|
|
147
|
+
* bundle bring in" any name row counts.
|
|
148
|
+
*/
|
|
149
|
+
export declare function bundlePatchTargets(dir: string): string[];
|
|
150
|
+
/**
|
|
151
|
+
* Loader entry ids a bundle patch inserts. Cordis refuses to boot a tree
|
|
152
|
+
* with a duplicate entry id ("duplicate loader entry id: storage", #122), so
|
|
153
|
+
* these are what two bundles can collide on.
|
|
154
|
+
*/
|
|
155
|
+
export declare function bundlePatchEntryIds(dir: string): string[];
|
|
156
|
+
/**
|
|
157
|
+
* Loader entry ids the patch INSERTS — the rows the package owns, as opposed
|
|
158
|
+
* to rows of OTHER plugins it merely configures (#147).
|
|
159
|
+
*
|
|
160
|
+
* A bundle patch has two kinds of entry:
|
|
161
|
+
*
|
|
162
|
+
* - insert: ← rows this package brings into the tree
|
|
163
|
+
* - id: vision-router
|
|
164
|
+
* name: dsh-vision-router
|
|
165
|
+
* - id: attachment-local ← someone else's row, only reconfigured
|
|
166
|
+
* config: { maxImageBytes: … }
|
|
167
|
+
*
|
|
168
|
+
* Treating both as "this package's rows" made disabling one plugin write
|
|
169
|
+
* `disabled: true` onto the official rows it tuned — killing attachments and
|
|
170
|
+
* the DeepSeek model with it.
|
|
171
|
+
*/
|
|
172
|
+
export declare function bundlePatchInsertedIds(dir: string): string[];
|
|
173
|
+
/**
|
|
174
|
+
* `name:` and `id:` rows of the package's declared bundle patch. Line-wise
|
|
175
|
+
* on purpose: the strict hot-mount parser rejects config/expression rows,
|
|
176
|
+
* but for "what does this bundle bring in" any row counts. `insertedIds` is
|
|
177
|
+
* the subset nested under an `insert:` key (#147).
|
|
178
|
+
*/
|
|
179
|
+
/**
|
|
180
|
+
* Rows of one patch file. Exported because a package may ship its patch at
|
|
181
|
+
* the conventional path INSTEAD of declaring `dsh.bundle.patch`, and the
|
|
182
|
+
* patch layer has to read that one by the same rules — a second hand-rolled
|
|
183
|
+
* scan drifted from this one and re-introduced #147 on that path (it closed
|
|
184
|
+
* the insert block only on `id:` lines, so `- disable:` followed by nested
|
|
185
|
+
* ids claimed the neighbour's rows).
|
|
186
|
+
*/
|
|
187
|
+
export declare function parsePatchRows(text: string): {
|
|
188
|
+
names: string[];
|
|
189
|
+
ids: string[];
|
|
190
|
+
insertedIds: string[];
|
|
191
|
+
};
|
|
192
|
+
/** The profile manifest's `dsh.profile.bundles` — what the CLI reconciled. */
|
|
193
|
+
export declare function readProfileBundles(profileDirectory: string): string[];
|
|
194
|
+
/**
|
|
195
|
+
* Drop one bundle from the profile manifest's `dsh.profile.bundles`, leaving
|
|
196
|
+
* the package installed as a dependency. This is the carrier-bundle half of a
|
|
197
|
+
* toggle-off (#224): a bundle whose patch reconfigures plugins it does NOT own
|
|
198
|
+
* (dsh-postgres-backends disables session-persistence-jsonl and reroutes
|
|
199
|
+
* storage-domain) keeps applying those side-effect rows on every boot while it
|
|
200
|
+
* stays in the stack, and the #147 ownership rule deliberately never writes
|
|
201
|
+
* them — so removing the bundle from the stack is the only thing that stops
|
|
202
|
+
* them all at once. The package itself stays installed; enabling re-adds it.
|
|
203
|
+
* @returns true when the bundle was present and removed.
|
|
204
|
+
*/
|
|
205
|
+
export declare function removeProfileBundle(profileDirectory: string, name: string): boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Re-add a bundle to `dsh.profile.bundles` after a carrier toggle-off (#224).
|
|
208
|
+
* Idempotent: a bundle already present is left untouched. The name is appended
|
|
209
|
+
* (the install flow appends too); the loader re-validates ordering on the next
|
|
210
|
+
* composition, so a declared before/after rule surfaces there rather than here.
|
|
211
|
+
* @returns true when the bundle was added, false when it was already present.
|
|
212
|
+
*/
|
|
213
|
+
export declare function addProfileBundle(profileDirectory: string, name: string): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Loader entry ids a newly added package would collide on with bundles the
|
|
216
|
+
* profile ALREADY loads (#122).
|
|
217
|
+
*
|
|
218
|
+
* Cordis hard-fails the whole tree on a duplicate id, so this is not a
|
|
219
|
+
* cosmetic conflict: installing a TUI bundle into a web profile (both
|
|
220
|
+
* declare `id: storage`) leaves DSH unable to start at all, with an error
|
|
221
|
+
* naming neither plugin. Checked against the profile's own bundle list so a
|
|
222
|
+
* package is never compared with itself.
|
|
223
|
+
* @returns colliding ids mapped to the already-installed bundle that owns them.
|
|
224
|
+
*/
|
|
225
|
+
export declare function conflictingEntryIds(profileDirectory: string, candidate: string, installedBundles: readonly string[]): {
|
|
226
|
+
id: string;
|
|
227
|
+
owner: string;
|
|
228
|
+
}[];
|
|
229
|
+
/**
|
|
230
|
+
* Whether the loader has anything to load for this package: its own entry
|
|
231
|
+
* artifact, or — for CARRIER bundles — patch rows naming other packages that
|
|
232
|
+
* do have one.
|
|
233
|
+
*
|
|
234
|
+
* Carriers are why `entryArtifactExists` alone is the wrong test (#103):
|
|
235
|
+
* `@linxin666/dsh-skins` ships skin assets plus a patch mounting
|
|
236
|
+
* `@linxin666/dsh-client-ui-skin-center`, and declares no main/exports/
|
|
237
|
+
* index.js of its own. Judged by its own entry it looks like the
|
|
238
|
+
* source-only checkout the #18 guard removes — so the market both flagged it
|
|
239
|
+
* broken AND uninstalled it right after installing.
|
|
240
|
+
* @param profileDirectory - resolved profile directory (host-authoritative under Desktop).
|
|
241
|
+
* @param name - installed package name.
|
|
242
|
+
*/
|
|
243
|
+
export declare function hasLoadableEntry(profileDirectory: string, name: string): boolean;
|
|
244
|
+
/** Plugin subdirectories (depth 2) of a collection checkout, as relative paths. */
|
|
245
|
+
export declare function pluginSubdirs(root: string): string[];
|
|
246
|
+
/**
|
|
247
|
+
* Allow the given packages' build scripts in the profile's
|
|
248
|
+
* pnpm-workspace.yaml `allowBuilds` block (the key dsh profiles use),
|
|
249
|
+
* merging with existing entries and leaving the rest of the yaml intact.
|
|
250
|
+
* (#6 by @qichuang321.)
|
|
251
|
+
* @returns every package now allowed.
|
|
252
|
+
*/
|
|
253
|
+
export declare function setAllowBuilds(profile: string, packages: string[], explicitDir?: string): string[];
|