dsh-opencode 0.1.3 → 0.1.4
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/README.md +9 -7
- package/lib/client.d.ts +1738 -0
- package/lib/client.js +537 -0
- package/lib/commands.js +8 -37
- package/lib/config.js +13 -2
- package/lib/index.js +5 -10
- package/lib/transport.js +1 -1
- package/package.json +34 -2
- package/lib/keyring.js +0 -109
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opencode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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,22 @@
|
|
|
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-commands",
|
|
49
|
+
"@deepseek-ai/dsh-client-locale",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-commands",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-settings-models",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-primitives",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
57
|
+
"@deepseek-ai/dsh-client-store"
|
|
58
|
+
]
|
|
39
59
|
}
|
|
40
60
|
},
|
|
41
61
|
"dependencies": {
|
|
@@ -55,8 +75,18 @@
|
|
|
55
75
|
"devDependencies": {
|
|
56
76
|
"@deepseek-ai/cordis": "4.0.2",
|
|
57
77
|
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
|
78
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1",
|
|
58
79
|
"@deepseek-ai/dsh-atomic-write": "0.1.2-rc.1",
|
|
59
80
|
"@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
|
|
81
|
+
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
|
|
82
|
+
"@deepseek-ai/dsh-client-store": "0.1.2-rc.1",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-commands": "0.1.2-rc.1",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.1.2-rc.1",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.2-rc.1",
|
|
87
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
|
|
88
|
+
"@deepseek-ai/dsh-client-ui-settings-models": "0.1.2-rc.1",
|
|
89
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
|
|
60
90
|
"@deepseek-ai/dsh-commands": "0.1.2-rc.1",
|
|
61
91
|
"@deepseek-ai/dsh-credentials": "0.1.2-rc.1",
|
|
62
92
|
"@deepseek-ai/dsh-credentials-local": "0.1.2-rc.1",
|
|
@@ -71,6 +101,8 @@
|
|
|
71
101
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
72
102
|
"@earendil-works/pi-ai": "0.84.2",
|
|
73
103
|
"@types/node": "22.20.0",
|
|
104
|
+
"@types/react": "18.3.12",
|
|
105
|
+
"react": "18.3.1",
|
|
74
106
|
"tsdown": "0.22.2",
|
|
75
107
|
"typescript": "6.0.3",
|
|
76
108
|
"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 };
|