dsh-opencode 0.1.3 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-opencode",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Out-of-tree DSH bundle with live dynamic OpenCode Zen / Go model catalogs",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -12,6 +12,10 @@
12
12
  "types": "./lib/index.d.ts",
13
13
  "import": "./lib/index.js"
14
14
  },
15
+ "./client": {
16
+ "types": "./lib/client.d.ts",
17
+ "default": "./lib/client.js"
18
+ },
15
19
  "./cordis.patch.yml": "./cordis.patch.yml",
16
20
  "./package.json": "./package.json"
17
21
  },
@@ -27,7 +31,7 @@
27
31
  },
28
32
  "packageManager": "pnpm@11.7.0",
29
33
  "scripts": {
30
- "build": "tsdown",
34
+ "build": "tsdown && tsdown --config tsdown.client.config.ts",
31
35
  "typecheck": "tsc --noEmit",
32
36
  "test": "vitest run",
33
37
  "test:live": "OPENCODE_LIVE_TESTS=1 vitest run tests/live.spec.ts",
@@ -36,6 +40,21 @@
36
40
  "dsh": {
37
41
  "bundle": {
38
42
  "patch": "./cordis.patch.yml"
43
+ },
44
+ "client": {
45
+ "platform": "web",
46
+ "inject": [
47
+ "@deepseek-ai/dsh-api-remotes",
48
+ "@deepseek-ai/dsh-client-locale",
49
+ "@deepseek-ai/dsh-client-ui-layout",
50
+ "@deepseek-ai/dsh-client-ui-commands",
51
+ "@deepseek-ai/dsh-client-ui-settings",
52
+ "@deepseek-ai/dsh-client-ui-settings-models",
53
+ "@deepseek-ai/dsh-client-ui-primitives",
54
+ "@deepseek-ai/dsh-client-ui-slots",
55
+ "@deepseek-ai/dsh-client-ui-renderer",
56
+ "@deepseek-ai/dsh-client-store"
57
+ ]
39
58
  }
40
59
  },
41
60
  "dependencies": {
@@ -55,8 +74,18 @@
55
74
  "devDependencies": {
56
75
  "@deepseek-ai/cordis": "4.0.2",
57
76
  "@deepseek-ai/dsh-agent": "0.1.2-rc.1",
77
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1",
58
78
  "@deepseek-ai/dsh-atomic-write": "0.1.2-rc.1",
59
79
  "@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
80
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
81
+ "@deepseek-ai/dsh-client-store": "0.1.2-rc.1",
82
+ "@deepseek-ai/dsh-client-ui-commands": "0.1.2-rc.1",
83
+ "@deepseek-ai/dsh-client-ui-layout": "0.1.2-rc.1",
84
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
85
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
86
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
87
+ "@deepseek-ai/dsh-client-ui-settings-models": "0.1.2-rc.1",
88
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
60
89
  "@deepseek-ai/dsh-commands": "0.1.2-rc.1",
61
90
  "@deepseek-ai/dsh-credentials": "0.1.2-rc.1",
62
91
  "@deepseek-ai/dsh-credentials-local": "0.1.2-rc.1",
@@ -71,6 +100,8 @@
71
100
  "@deepseek-ai/schemastery": "^3.18.2",
72
101
  "@earendil-works/pi-ai": "0.84.2",
73
102
  "@types/node": "22.20.0",
103
+ "@types/react": "18.3.12",
104
+ "react": "18.3.1",
74
105
  "tsdown": "0.22.2",
75
106
  "typescript": "6.0.3",
76
107
  "vitest": "4.1.8",
package/lib/keyring.js DELETED
@@ -1,109 +0,0 @@
1
- import { SETTINGS_NAMESPACE } from "./index.js";
2
- import { assertUsableApiKey } from "@deepseek-ai/dsh-llm";
3
- //#region src/keyring.ts
4
- /**
5
- * Read one reference's presence, treating an absent credential service as a
6
- * stable `false` rather than a throw: the caller wants facts, not a diagnosis.
7
- */
8
- async function refState(ctx, ref) {
9
- const credentials = ctx.get("credentials");
10
- if (credentials === void 0) return {
11
- configured: false,
12
- writable: false
13
- };
14
- const described = await credentials.describe(ref);
15
- return described === void 0 ? {
16
- configured: false,
17
- writable: false
18
- } : {
19
- configured: described.configured,
20
- writable: described.writable
21
- };
22
- }
23
- /**
24
- * Read the state a key store is about to operate against.
25
- * @param ctx - the plugin context.
26
- * @param providers - the currently resolved provider profiles.
27
- * @returns the immutable snapshot for before/after comparison.
28
- */
29
- async function snapshotKeyring(ctx, providers) {
30
- const settings = ctx.get("settings");
31
- const sectionValue = settings === void 0 ? void 0 : settings.get(SETTINGS_NAMESPACE);
32
- const refs = /* @__PURE__ */ new Map();
33
- for (const { apiKeyEnv } of providers) if (!refs.has(apiKeyEnv)) refs.set(apiKeyEnv, await refState(ctx, apiKeyEnv));
34
- return {
35
- section: JSON.stringify(sectionValue ?? null),
36
- refs
37
- };
38
- }
39
- /**
40
- * Verify a key store left no stray change. Compares the section snapshot and
41
- * every reference the plugin knows with a stable JSON text, so a change in
42
- * either is caught regardless of ordering.
43
- * @param before - the snapshot taken before the store.
44
- * @param after - the snapshot taken after the store.
45
- * @param refs - the references the store wrote (the only ones allowed to move).
46
- * @returns a failure line, or `undefined` when only the intended refs changed.
47
- */
48
- function verifyNoStrayChange(before, after, refs) {
49
- if (before.section !== after.section) return `opencode-live: the settings section changed while storing the key (${SETTINGS_NAMESPACE})`;
50
- for (const [ref, state] of before.refs) {
51
- const next = after.refs.get(ref);
52
- if (next === void 0) return `opencode-live: credential ${ref} vanished after storing the key`;
53
- if (state.configured === next.configured && state.writable === next.writable) continue;
54
- if (!refs.includes(ref)) return `opencode-live: an unrelated credential reference changed (${ref})`;
55
- }
56
- for (const [ref, next] of after.refs) {
57
- if (before.refs.has(ref)) continue;
58
- if (!refs.includes(ref)) return `opencode-live: an unrelated credential reference appeared (${ref})`;
59
- if (!next.configured) return `opencode-live: the stored reference ${ref} did not become configured`;
60
- }
61
- }
62
- /**
63
- * Store one OpenCode key through the DSH credential seam.
64
- *
65
- * This is the whole write surface a command uses. Validation runs before any
66
- * write, so a key that would be refused is never persisted. The write is
67
- * fenced by `snapshotKeyring` before and after; a stray settings or unrelated
68
- * credential change fails the call with a diagnostic instead of silently
69
- * committing alongside the key.
70
- * @param ctx - the plugin context.
71
- * @param providers - the currently resolved provider profiles.
72
- * @param value - the key typed into the command's input field.
73
- * @returns `undefined` on success, or a failure line naming the exact problem.
74
- */
75
- async function storeApiKey(ctx, providers, value) {
76
- try {
77
- assertUsableApiKey(value, "opencode-live", "input");
78
- } catch (error) {
79
- return error.message;
80
- }
81
- const credentials = ctx.get("credentials");
82
- if (credentials === void 0) return "opencode-live: no credentials service is mounted; export the API key in the launch environment instead";
83
- const before = await snapshotKeyring(ctx, providers);
84
- const targets = [...new Set([...providers].map(({ apiKeyEnv }) => apiKeyEnv))];
85
- try {
86
- for (const ref of targets) await credentials.set(ref, value);
87
- } catch (error) {
88
- return `opencode-live: could not store the API key (${error.message})`;
89
- }
90
- return verifyNoStrayChange(before, await snapshotKeyring(ctx, providers), targets);
91
- }
92
- /**
93
- * Presence facts for the status path: whether a key is configured, without
94
- * ever exposing a value.
95
- * @param ctx - the plugin context.
96
- * @param providers - the currently resolved provider profiles.
97
- * @returns whether the shared reference is configured.
98
- */
99
- async function keyConfigured(ctx, providers) {
100
- const refs = [...new Set([...providers].map(({ apiKeyEnv }) => apiKeyEnv))];
101
- return (await Promise.all(refs.map((ref) => refState(ctx, ref)))).some((state) => state.configured);
102
- }
103
- /** Whether any reference is read-only, so the status can say so. */
104
- async function keyReadonly(ctx, providers) {
105
- const refs = [...new Set([...providers].map(({ apiKeyEnv }) => apiKeyEnv))];
106
- return (await Promise.all(refs.map((ref) => refState(ctx, ref)))).some((state) => !state.writable);
107
- }
108
- //#endregion
109
- export { keyConfigured, keyReadonly, snapshotKeyring, storeApiKey, verifyNoStrayChange };