@huanlin/dsh-plugin-tools-manager 0.2.0

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.
@@ -0,0 +1,79 @@
1
+ /**
2
+ * settings.ts — host-side bridge between the `tools-manager` settings namespace
3
+ * and the plugin's other halves (policy + gateway + registry).
4
+ *
5
+ * The composition `Config` (cordis.patch.yml) is the first-boot seed; once the
6
+ * `ctx.settings` service mounts, the user-editable layer takes over and the
7
+ * disabled set tracks every committed change. Headless assemblies without a
8
+ * settings provider fall back to the composition config (no persistence, no
9
+ * live reload).
10
+ *
11
+ * The bridge mirrors `dsh-interpreters/src/settings.ts`: a `source()` thunk the
12
+ * gateway and policy read in-process, plus an `onChange()` subscription the
13
+ * host entry uses to rebuild the disabled set on every committed change.
14
+ *
15
+ * @module dsh-tools-manager/settings
16
+ */
17
+ import { Config } from './config.js';
18
+ import { resolveConfig } from './config.js';
19
+ /** Settings namespace under which the disabled-tool list persists. */
20
+ export const SETTINGS_NAMESPACE = 'tools-manager';
21
+ /**
22
+ * Mirror of the dsh-settings internal `isUnloading` guard. The cordis const
23
+ * enum for fiber state is erased at compile time, so the literal states are
24
+ * matched numerically: 4 = DISPOSED, 5 = UNLOADING.
25
+ */
26
+ function isUnloading(ctx) {
27
+ const state = ctx.fiber?.state;
28
+ return state === 4 || state === 5;
29
+ }
30
+ /**
31
+ * Install the `tools-manager` settings namespace and return the bridge.
32
+ *
33
+ * The settings service is reached through `ctx.inject(['settings'], ...)` so a
34
+ * composition without a settings provider still loads the plugin (entry-source
35
+ * fallback, no persistence). Multi-fiber dedupe is handled by catching the
36
+ * `"already registered"` rejection.
37
+ * @param ctx - host context.
38
+ * @param entry - composition-layer config (cordis.patch.yml seed).
39
+ * @returns the bridge the gateway and policy consume.
40
+ */
41
+ export function installToolsManagerSettings(ctx, entry) {
42
+ const listeners = new Set();
43
+ let source = () => resolveConfig(entry);
44
+ const notify = () => {
45
+ for (const listener of [...listeners])
46
+ listener();
47
+ };
48
+ ctx.inject(['settings'], (sctx) => {
49
+ let scope;
50
+ try {
51
+ scope = sctx.settings.register(SETTINGS_NAMESPACE, Config, { base: entry });
52
+ }
53
+ catch (error) {
54
+ // Multi-fiber dedupe: the first registration owns the namespace; later
55
+ // fibers stay on the entry source and emit no notifications of their own.
56
+ if (!(error instanceof Error) || !error.message.includes('already registered'))
57
+ throw error;
58
+ ctx.logger('tools-manager').debug('settings namespace already registered — entry-source fallback');
59
+ return;
60
+ }
61
+ source = () => resolveConfig(scope.get());
62
+ sctx.effect(() => () => {
63
+ if (isUnloading(ctx))
64
+ return;
65
+ source = () => resolveConfig(entry);
66
+ notify();
67
+ });
68
+ notify();
69
+ scope.watch(() => {
70
+ if (isUnloading(ctx))
71
+ return;
72
+ notify();
73
+ });
74
+ });
75
+ return {
76
+ source: () => source(),
77
+ onChange: (cb) => { listeners.add(cb); },
78
+ };
79
+ }
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@huanlin/dsh-plugin-tools-manager",
3
+ "version": "0.2.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "keywords": [
8
+ "dsh-plugin"
9
+ ],
10
+ "description": "Lists every registered tool grouped by source plugin (tree) and supports globally disabling individual tools; settings card (via /tools-manager/api HTTP route) lets users toggle tools on/off.",
11
+ "type": "module",
12
+ "license": "AGPL-3.0",
13
+ "main": "./lib/index.js",
14
+ "types": "./lib/types/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./lib/types/index.d.ts",
18
+ "import": "./lib/index.js"
19
+ },
20
+ "./client": {
21
+ "default": "./lib/client.js"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "files": [
26
+ "lib/",
27
+ "cordis.patch.yml"
28
+ ],
29
+ "dsh": {
30
+ "bundle": {
31
+ "patch": "./cordis.patch.yml"
32
+ },
33
+ "client": {
34
+ "inject": [
35
+ "@deepseek-ai/dsh-client-ui-primitives",
36
+ "@deepseek-ai/dsh-client-ui-slots"
37
+ ],
38
+ "platform": "web"
39
+ }
40
+ },
41
+ "peerDependencies": {
42
+ "@deepseek-ai/cordis": "^4.0.1",
43
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
44
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
45
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-rc.1",
46
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
47
+ "@deepseek-ai/dsh-host-webserver": "^0.1.2-rc.1",
48
+ "@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
49
+ "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1",
50
+ "@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
51
+ "react": "^18.2.0",
52
+ "schemastery": "^3.18.0"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "@deepseek-ai/cordis": {
56
+ "optional": true
57
+ },
58
+ "@deepseek-ai/dsh-client-ui-primitives": {
59
+ "optional": true
60
+ },
61
+ "@deepseek-ai/dsh-client-ui-slots": {
62
+ "optional": true
63
+ },
64
+ "@deepseek-ai/dsh-client-ui-renderer": {
65
+ "optional": true
66
+ },
67
+ "@deepseek-ai/dsh-client-ui-settings": {
68
+ "optional": true
69
+ },
70
+ "@deepseek-ai/dsh-host-webserver": {
71
+ "optional": true
72
+ },
73
+ "@deepseek-ai/dsh-settings": {
74
+ "optional": true
75
+ },
76
+ "@deepseek-ai/dsh-system-prompt": {
77
+ "optional": true
78
+ },
79
+ "@deepseek-ai/dsh-tools": {
80
+ "optional": true
81
+ },
82
+ "react": {
83
+ "optional": true
84
+ },
85
+ "schemastery": {
86
+ "optional": true
87
+ }
88
+ },
89
+ "devDependencies": {
90
+ "@types/node": "^22.20.0",
91
+ "@types/react": "~18.3.1",
92
+ "esbuild": "^0.28.2",
93
+ "lightningcss": "^1.29.2",
94
+ "react": "^18.2.0",
95
+ "schemastery": "^3.18.0",
96
+ "tsdown": "^0.22.2",
97
+ "typescript": "^5.9.0",
98
+ "vitest": "^3.2.0"
99
+ },
100
+ "engines": {
101
+ "node": ">=18.0.0"
102
+ },
103
+ "scripts": {
104
+ "typecheck": "tsc --noEmit -p tsconfig.json",
105
+ "test": "vitest run",
106
+ "test:watch": "vitest",
107
+ "build": "tsc -p tsconfig.build.json && node scripts/build-client.mjs"
108
+ }
109
+ }