dsh-plugin-shop 0.4.0 → 0.4.2

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.
@@ -6,8 +6,10 @@ export declare const zh: {
6
6
  error: string;
7
7
  retry: string;
8
8
  search: string;
9
+ all: string;
9
10
  catalog: string;
10
11
  catalogStats: string;
12
+ stars: string;
11
13
  categoryTool: string;
12
14
  categoryProvider: string;
13
15
  categoryUi: string;
@@ -46,6 +48,12 @@ export declare const zh: {
46
48
  installedVersion: string;
47
49
  latestVersion: string;
48
50
  update: string;
51
+ installed: string;
52
+ uninstall: string;
53
+ uninstalling: string;
54
+ uninstallFailed: string;
55
+ uninstallTransportFailed: string;
56
+ uninstalledRestartNotice: string;
49
57
  enabledSwitch: string;
50
58
  toggleFailed: string;
51
59
  hotApplyNote: string;
@@ -59,8 +67,10 @@ export declare const en: {
59
67
  error: string;
60
68
  retry: string;
61
69
  search: string;
70
+ all: string;
62
71
  catalog: string;
63
72
  catalogStats: string;
73
+ stars: string;
64
74
  categoryTool: string;
65
75
  categoryProvider: string;
66
76
  categoryUi: string;
@@ -99,6 +109,12 @@ export declare const en: {
99
109
  installedVersion: string;
100
110
  latestVersion: string;
101
111
  update: string;
112
+ installed: string;
113
+ uninstall: string;
114
+ uninstalling: string;
115
+ uninstallFailed: string;
116
+ uninstallTransportFailed: string;
117
+ uninstalledRestartNotice: string;
102
118
  enabledSwitch: string;
103
119
  toggleFailed: string;
104
120
  hotApplyNote: string;
@@ -81,6 +81,28 @@ export declare function reduceInstall(state: InstallView, event: InstallEvent):
81
81
  * it matches other people's package names, not ours.
82
82
  */
83
83
  export declare function isShopLike(name: string): boolean;
84
+ declare const CATEGORY_KEYS: {
85
+ readonly tool: "categoryTool";
86
+ readonly provider: "categoryProvider";
87
+ readonly ui: "categoryUi";
88
+ readonly workflow: "categoryWorkflow";
89
+ readonly integration: "categoryIntegration";
90
+ readonly other: "categoryOther";
91
+ };
84
92
  /** The locale key for one entry's category — derived entries read as `other`
85
93
  * (§6.1: a derived listing has no declared category). */
86
94
  export declare function categoryKey(entry: CatalogEntry): ShopLocaleKey;
95
+ /** The category vocabulary as a type, derived from the map above so the
96
+ * client never repeats the six literals. */
97
+ export type Category = keyof typeof CATEGORY_KEYS;
98
+ /** The six categories in display order (map insertion order). */
99
+ export declare const CATEGORY_ORDER: Category[];
100
+ /** The locale key for one bare category value (the filter buttons). */
101
+ export declare function categoryLocaleKey(category: Category): ShopLocaleKey;
102
+ /** Sort the shelf: stars descending, un-starred entries last, name ascending
103
+ * (case-insensitive) on ties (spec 2026-08-26-github-stars-design.md D1).
104
+ * Display-time only — the catalog's own name sort is untouched. */
105
+ export declare function sortByStars(entries: CatalogEntry[], stars: Record<string, number>): CatalogEntry[];
106
+ /** 999 → "999"; 1000 → "1k"; 1234 → "1.2k"; 1500 → "1.5k"; 99999 → "100k". */
107
+ export declare function formatStars(n: number): string;
108
+ export {};
@@ -1,4 +1,5 @@
1
1
  /** Install driving hook for one entry: start, poll to terminal, reset. */
2
+ import { type Dispatch, type SetStateAction } from 'react';
2
3
  import { type InstallView } from './present.ts';
3
4
  import type { InstallArgs, ShopInstallResult, ShopInstallStatusResult } from '../host/index.ts';
4
5
  export interface UseInstallResult {
@@ -6,6 +7,14 @@ export interface UseInstallResult {
6
7
  start: (args: InstallArgs) => Promise<void>;
7
8
  reset: () => void;
8
9
  }
10
+ /** The poll loop shared by the install and uninstall drivers: while the view
11
+ * is `running`, poll once per second and fold each status through the
12
+ * reducer. A poll failure is transient — the host retains the record, so the
13
+ * next tick finds it. The rejection handler must be present: an unhandled
14
+ * rejection here would escape the poll loop. */
15
+ export declare function usePollStatus(view: InstallView, setView: Dispatch<SetStateAction<InstallView>>, installStatus: (args: {
16
+ installId: string;
17
+ }) => Promise<ShopInstallStatusResult>): void;
9
18
  /** Drive one install: rejections, the polling loop at INSTALL_POLL_MS, and
10
19
  * terminal states. The interval is cleared on unmount and whenever the view
11
20
  * leaves `running`, so a done/failed/rejected install never polls again. */
@@ -0,0 +1,21 @@
1
+ /** Uninstall driving hook for one entry: start, poll to terminal. Shares the
2
+ * install view machine and poll loop; the only difference is the start
3
+ * mapping — an uninstall business failure (not in the catalog / not
4
+ * installed) lands in the `failed` view with the host's published detail,
5
+ * never in the install `rejected` codes, which belong to the install gate
6
+ * (§7.2). */
7
+ import type { ShopInstallStatusResult, ShopUninstallResult } from '../host/index.ts';
8
+ import type { InstallView } from './present.ts';
9
+ export interface UseUninstallResult {
10
+ view: InstallView;
11
+ start: (args: {
12
+ name: string;
13
+ }) => Promise<void>;
14
+ }
15
+ /** Drive one uninstall: the host's business union, the shared polling loop,
16
+ * and terminal states. The `rejected` install state never occurs here. */
17
+ export declare function useUninstall(uninstall: (args: {
18
+ name: string;
19
+ }) => Promise<ShopUninstallResult>, installStatus: (args: {
20
+ installId: string;
21
+ }) => Promise<ShopInstallStatusResult>): UseUninstallResult;
@@ -7,6 +7,9 @@ export interface CatalogSnapshot {
7
7
  builtAt: string;
8
8
  entries: CatalogEntry[];
9
9
  denied: DeniedEntry[];
10
+ /** GitHub star counts by package name; {} when the pointer names no
11
+ * sidecar or the sidecar could not be fetched/verified (spec §5). */
12
+ stars: Record<string, number>;
10
13
  }
11
14
  export interface CatalogResult {
12
15
  snapshot: CatalogSnapshot;
@@ -32,6 +35,8 @@ export interface LoadCatalogOptions {
32
35
  * only when the transport itself failed — the fetch threw or returned a
33
36
  * non-2xx (§10). A schemaVersion higher than this build supports, a malformed
34
37
  * pointer or data file, an absolute data URL, or a sha256 mismatch — fresh or
35
- * cached — throws even when a cache exists; never silently degraded.
38
+ * cached — throws even when a cache exists; never silently degraded. The stars
39
+ * sidecar is the sole exception: any irregularity there, a refused url
40
+ * included, degrades to no stars (spec §5).
36
41
  */
37
42
  export declare function loadCatalog(options: LoadCatalogOptions): Promise<CatalogResult>;
@@ -1,4 +1,7 @@
1
- /** Install executor: spawn the dsh CLI, stream its output, serialize per profile. */
1
+ /** Plugin-command executor: spawn the dsh CLI, stream its output, serialize
2
+ * per profile. One implementation drives both `dsh plugin add` (install) and
3
+ * `dsh plugin remove` (uninstall); the only differences are the verb and the
4
+ * post-exit manifest confirmation. */
2
5
  export type InstallState = 'running' | 'done' | 'failed';
3
6
  export interface InstallStatus {
4
7
  state: InstallState;
@@ -13,11 +16,6 @@ interface RunningInstall {
13
16
  }
14
17
  /**
15
18
  * Run one `dsh plugin --profile <profile> add <spec>` and track it.
16
- * Never rolls back; a failure surfaces stderr verbatim plus the recovery hint
17
- * (§10). The shop never passes build-script flags: `allowBuilds` stays the
18
- * user's explicit decision in the CLI (§7.2).
19
- * The child inherits the current environment unless `env` is given — the
20
- * real-install test pins DSH_HOME to a temporary directory this way.
21
19
  * When `expectedName` is given, a zero exit is confirmed against the profile
22
20
  * manifest (§7.2 step 6) before the install reports `done`.
23
21
  */
@@ -29,4 +27,18 @@ export declare function startInstall(options: {
29
27
  expectedName?: string;
30
28
  onStatus?: (status: InstallStatus) => void;
31
29
  }): RunningInstall;
30
+ /**
31
+ * Run one `dsh plugin --profile <profile> remove <name>` and track it.
32
+ * When `expectedName` is given, a zero exit is confirmed against the profile
33
+ * manifest — the bundle must actually have LEFT `dsh.profile.bundles` — before
34
+ * the uninstall reports `done`.
35
+ */
36
+ export declare function startUninstall(options: {
37
+ profile: string;
38
+ name: string;
39
+ dshBin?: string;
40
+ env?: NodeJS.ProcessEnv;
41
+ expectedName?: string;
42
+ onStatus?: (status: InstallStatus) => void;
43
+ }): RunningInstall;
32
44
  export {};
@@ -49,11 +49,25 @@ export interface ShopSetEnabledResult {
49
49
  ok: boolean;
50
50
  detail?: string;
51
51
  }
52
- /** `shop/outdated` entry (§7.3): one installed plugin behind the catalog. */
53
- export interface ShopOutdatedEntry {
52
+ /** `shop/uninstallStart` result (§7.3): a name outside the catalog or not
53
+ * installed is a typed wire value with an author-readable `detail`, not a
54
+ * thrown RPC error. */
55
+ export type ShopUninstallResult = {
56
+ ok: true;
57
+ installId: string;
58
+ } | {
59
+ ok: false;
60
+ detail: string;
61
+ };
62
+ /** `shop/installed` entry (§7.3): one installed catalog plugin. `installed`
63
+ * is the profile manifest's dependency spec verbatim (a range, a tag, or
64
+ * `workspace:*`); `outdated` is the Host's verdict that the installed version
65
+ * sits behind the catalog's — the client never does version math. */
66
+ export interface ShopInstalledEntry {
54
67
  name: string;
55
68
  installed: string;
56
69
  latest: string;
70
+ outdated: boolean;
57
71
  }
58
72
  /** `shop/catalog` result (§7.3), plus the denied list for the install gate's UI. */
59
73
  export interface ShopCatalogResult {
@@ -62,6 +76,9 @@ export interface ShopCatalogResult {
62
76
  stale: boolean;
63
77
  plugins: CatalogEntry[];
64
78
  denied: DeniedEntry[];
79
+ /** GitHub star counts by package name; {} when the pointer names no sidecar
80
+ * or the sidecar could not be fetched/verified (§5). */
81
+ stars: Record<string, number>;
65
82
  }
66
83
  /** Remote-only service exposing the shop Remote methods of §7.3.
67
84
  *
@@ -124,7 +141,24 @@ export declare class ShopGateway extends TypertRemoteService {
124
141
  installStatus(args: {
125
142
  installId: string;
126
143
  }): ShopInstallStatusResult;
127
- /** Installed plugins whose installed version is older than the catalog's (§7.3). */
128
- outdated(): Promise<ShopOutdatedEntry[]>;
144
+ /** Installed catalog plugins (§7.3): every entry of the snapshot the profile
145
+ * manifest declares as a dependency, with the Host's `outdated` verdict
146
+ * attached. The tab's shelf cards and its installed section both derive
147
+ * from this one list. */
148
+ installed(): Promise<ShopInstalledEntry[]>;
149
+ /** Whether an installed dependency spec sits behind the catalog's version.
150
+ * A spec identical to the catalog version is current by definition; a
151
+ * pnpm-written non-semver spec like `workspace:*` is not reportable and
152
+ * reads as current rather than killing the RPC. */
153
+ private isBehind;
154
+ /** Uninstall one installed catalog plugin from the profile (§7.3 follow-up
155
+ * amendment). Removing revokes privilege rather than granting it, so there
156
+ * is no acknowledgement gate. The name must be a catalog entry the profile
157
+ * manifest declares as a dependency — the RPC cannot remove profile
158
+ * dependencies the shop does not manage (the base bundle, the shop
159
+ * itself). The same install records/polling serve the client. */
160
+ uninstall(args: {
161
+ name: string;
162
+ }): Promise<ShopUninstallResult>;
129
163
  }
130
164
  export default ShopGateway;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-shop",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "The DeepSeek Harness plugin shop: browse, install, enable, and update dsh plugins from a git-auditable catalog.",
5
5
  "repository": {
6
6
  "type": "git",