dsh-caveman 0.1.4 → 0.1.6
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/lib/client.js +122 -0
- package/lib/index.js +71 -3
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -6,6 +6,110 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
const React = require("react");
|
|
8
8
|
|
|
9
|
+
// ---- Settings → General row: caveman default mode --------------------
|
|
10
|
+
// Reads and writes the host's global default through /caveman/default
|
|
11
|
+
// (the settings-document namespace 'caveman'). New sessions start with
|
|
12
|
+
// this default; the badge still cycles the per-session value. Mirrors
|
|
13
|
+
// dsh-rtk's row — without this client-side slot registration the settings
|
|
14
|
+
// page shows no caveman entry at all (the host namespace alone is not
|
|
15
|
+
// enough; the panel enumerates slot items, not namespaces).
|
|
16
|
+
const CAVEMAN_MODES = [
|
|
17
|
+
"off",
|
|
18
|
+
"lite",
|
|
19
|
+
"full",
|
|
20
|
+
"ultra",
|
|
21
|
+
"wenyan-lite",
|
|
22
|
+
"wenyan-full",
|
|
23
|
+
"wenyan-ultra",
|
|
24
|
+
];
|
|
25
|
+
function CavemanDefaultRow() {
|
|
26
|
+
const [mode, setMode] = React.useState(null);
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
let cancelled = false;
|
|
29
|
+
fetch("/caveman/default")
|
|
30
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
31
|
+
.then((data) => {
|
|
32
|
+
if (!cancelled && data && CAVEMAN_MODES.indexOf(data.defaultMode) !== -1) {
|
|
33
|
+
setMode(data.defaultMode);
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
.catch(() => {});
|
|
37
|
+
return () => {
|
|
38
|
+
cancelled = true;
|
|
39
|
+
};
|
|
40
|
+
}, []);
|
|
41
|
+
const change = (next) => {
|
|
42
|
+
fetch("/caveman/default", {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "content-type": "application/json" },
|
|
45
|
+
body: JSON.stringify({ defaultMode: next }),
|
|
46
|
+
})
|
|
47
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
48
|
+
.then((data) => {
|
|
49
|
+
if (data && data.ok) setMode(data.defaultMode);
|
|
50
|
+
})
|
|
51
|
+
.catch(() => {});
|
|
52
|
+
};
|
|
53
|
+
return React.createElement(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
style: {
|
|
57
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2)",
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
gap: "8px",
|
|
60
|
+
padding: "16px 0",
|
|
61
|
+
display: "flex",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
React.createElement(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
style: {
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
flex: "1",
|
|
70
|
+
gap: "4px",
|
|
71
|
+
minWidth: "0",
|
|
72
|
+
paddingRight: "48px",
|
|
73
|
+
display: "flex",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
React.createElement(
|
|
77
|
+
"div",
|
|
78
|
+
{ style: { color: "var(--dsw-alias-label-primary)", fontSize: "14px", lineHeight: "22px" } },
|
|
79
|
+
"caveman 默认档位",
|
|
80
|
+
),
|
|
81
|
+
React.createElement(
|
|
82
|
+
"div",
|
|
83
|
+
{ style: { color: "var(--dsw-alias-label-tertiary)", fontSize: "12px", lineHeight: "18px" } },
|
|
84
|
+
"新会话默认档位(默认 full);徽章仍按会话切换",
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
React.createElement(
|
|
88
|
+
"select",
|
|
89
|
+
{
|
|
90
|
+
value: mode === null ? "" : mode,
|
|
91
|
+
disabled: mode === null,
|
|
92
|
+
onChange: (e) => change(e.target.value),
|
|
93
|
+
title: mode === null ? "loading" : mode,
|
|
94
|
+
style: {
|
|
95
|
+
background: "var(--dsw-alias-bg-module-platform)",
|
|
96
|
+
height: "36px",
|
|
97
|
+
color: "var(--dsw-alias-label-primary)",
|
|
98
|
+
cursor: "pointer",
|
|
99
|
+
border: "none",
|
|
100
|
+
borderRadius: "18px",
|
|
101
|
+
padding: "0 14px",
|
|
102
|
+
fontSize: "14px",
|
|
103
|
+
lineHeight: "22px",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
mode === null
|
|
107
|
+
? React.createElement("option", { value: "" }, "…")
|
|
108
|
+
: CAVEMAN_MODES.map((m) => React.createElement("option", { key: m, value: m }, m)),
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
9
113
|
// Badge display is centralized in dsh-badges: this plugin only registers
|
|
10
114
|
// a badge descriptor (fetch-mode: initial GET + toggle-response self-
|
|
11
115
|
// update + 5s re-sync). No session projection is involved; per-session
|
|
@@ -74,6 +178,24 @@ window.__ModuleLoader__.load({
|
|
|
74
178
|
if (register()) return;
|
|
75
179
|
Promise.resolve().then(() => tryRegister(500));
|
|
76
180
|
});
|
|
181
|
+
|
|
182
|
+
// Settings → General row: registered when the settings section is
|
|
183
|
+
// declared (slots.inject defers until then). The row owns its own
|
|
184
|
+
// read/write via /caveman/default — no inject face needed.
|
|
185
|
+
ctx.slots.inject("settings.general.item", () => {
|
|
186
|
+
try {
|
|
187
|
+
ctx.slots.register(
|
|
188
|
+
{
|
|
189
|
+
name: "settings.general.item",
|
|
190
|
+
id: "caveman-default",
|
|
191
|
+
order: 11,
|
|
192
|
+
},
|
|
193
|
+
CavemanDefaultRow,
|
|
194
|
+
);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.error("[dsh-caveman] settings row registration failed:", e);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
77
199
|
}
|
|
78
200
|
|
|
79
201
|
exports.apply = apply;
|
package/lib/index.js
CHANGED
|
@@ -79,8 +79,15 @@ export function apply(ctx) {
|
|
|
79
79
|
// Sessions WITHOUT a sidecar entry follow this live default (full).
|
|
80
80
|
let defaultMode = 'full'
|
|
81
81
|
let cavemanScope = null
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// `settings` is a cordis Service (`ctx.settings`) — reach it through an
|
|
83
|
+
// injection edge. `ctx.get('settings')` at apply time returns undefined on
|
|
84
|
+
// 0.1.2-rc.1 (the provider publishes asynchronously), which silently skipped
|
|
85
|
+
// this registration: the Settings row then read a live value while every
|
|
86
|
+
// write answered 503 "settings unavailable" (found + fixed 2026-09-12).
|
|
87
|
+
// Same pattern as @linxin666/dsh-pet / web-ui-settings: ctx.inject(['settings']).
|
|
88
|
+
ctx.inject(['settings'], (settingsCtx) => {
|
|
89
|
+
const settings = settingsCtx.settings
|
|
90
|
+
if (settings === undefined) return
|
|
84
91
|
try {
|
|
85
92
|
cavemanScope = settings.register(
|
|
86
93
|
'caveman',
|
|
@@ -95,7 +102,7 @@ export function apply(ctx) {
|
|
|
95
102
|
} catch (err) {
|
|
96
103
|
console.warn('[caveman] settings namespace registration failed:', err && err.message)
|
|
97
104
|
}
|
|
98
|
-
}
|
|
105
|
+
})
|
|
99
106
|
|
|
100
107
|
// ---- per-session mode state: sidecar JSON keyed by session id ----------
|
|
101
108
|
// Truth source for the mode. Sessions WITHOUT an entry use the live
|
|
@@ -256,6 +263,67 @@ export function apply(ctx) {
|
|
|
256
263
|
}
|
|
257
264
|
}
|
|
258
265
|
|
|
266
|
+
// ---- Settings row read/write: GET/POST /caveman/default -----------------
|
|
267
|
+
// The Settings → General row ('caveman-default') reads and writes the global
|
|
268
|
+
// default mode through this route; all state lives in the settings document
|
|
269
|
+
// via the registered 'caveman' namespace (same shape as dsh-rtk's
|
|
270
|
+
// /rtk/default, which is the only reason rtk showed a row and caveman did
|
|
271
|
+
// not — the row is a CLIENT registration, not an automatic consequence of
|
|
272
|
+
// the namespace).
|
|
273
|
+
if (webServer !== undefined) {
|
|
274
|
+
try {
|
|
275
|
+
webServer.register({
|
|
276
|
+
kind: 'exact',
|
|
277
|
+
path: '/caveman/default',
|
|
278
|
+
handler: async (req, res) => {
|
|
279
|
+
const send = (status, body) => {
|
|
280
|
+
res.writeHead(status, { 'content-type': 'application/json' })
|
|
281
|
+
res.end(JSON.stringify(body))
|
|
282
|
+
}
|
|
283
|
+
if (req.method === 'GET') {
|
|
284
|
+
send(200, { defaultMode })
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
if (req.method !== 'POST') {
|
|
288
|
+
send(405, { ok: false, error: 'method not allowed' })
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
if (cavemanScope === null) {
|
|
292
|
+
send(503, { ok: false, error: 'settings unavailable' })
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
let raw = ''
|
|
296
|
+
try {
|
|
297
|
+
for await (const chunk of req) raw += chunk
|
|
298
|
+
} catch (e) {
|
|
299
|
+
send(400, { ok: false, error: 'bad body' })
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
let next
|
|
303
|
+
try {
|
|
304
|
+
next = JSON.parse(raw || '{}').defaultMode
|
|
305
|
+
} catch (e) {
|
|
306
|
+
next = undefined
|
|
307
|
+
}
|
|
308
|
+
if (typeof next !== 'string' || !VALID.includes(next)) {
|
|
309
|
+
send(400, { ok: false, error: 'defaultMode must be one of: ' + VALID.join(', ') })
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
await cavemanScope.update({ defaultMode: next })
|
|
314
|
+
const stored = cavemanScope.get()
|
|
315
|
+
defaultMode = stored && VALID.includes(stored.defaultMode) ? stored.defaultMode : 'full'
|
|
316
|
+
send(200, { ok: true, defaultMode })
|
|
317
|
+
} catch (e) {
|
|
318
|
+
send(500, { ok: false, error: 'persist failed' })
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
})
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error('[caveman] /caveman/default route registration failed:', e && e.message)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
259
327
|
const systemPrompt = ctx.get('systemPrompt')
|
|
260
328
|
if (systemPrompt !== undefined) {
|
|
261
329
|
systemPrompt.section({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-caveman",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"./client": "./lib/client.js",
|
|
9
9
|
"./package.json": "./package.json"
|
|
10
10
|
},
|
|
11
|
-
"description": "Per-session caveman mode state + composer dock badge + /caveman command + prompt-section injection. Writes NO session events: mode state lives in a $DSH_HOME/plugin-state sidecar keyed by session id (default from the 'caveman' settings namespace), and the badge reads GET /caveman/state (fetch mode). The KNOWN event-type registration is kept read-only for legacy sessions. Caveman skills ship from the deployment shared skill library (see ~/.dsh/skills), not from this package. Compatible with @deepseek-ai/dsh-settings 0.1.2+: the namespace is passed as a literal string because the settingsNamespace brand helper was removed upstream (broken named import on 0.1.2-rc.1 boot).",
|
|
11
|
+
"description": "Per-session caveman mode state + composer dock badge + /caveman command + prompt-section injection. Writes NO session events: mode state lives in a $DSH_HOME/plugin-state sidecar keyed by session id (default from the 'caveman' settings namespace), and the badge reads GET /caveman/state (fetch mode). The KNOWN event-type registration is kept read-only for legacy sessions. Caveman skills ship from the deployment shared skill library (see ~/.dsh/skills), not from this package. Compatible with @deepseek-ai/dsh-settings 0.1.2+: the namespace is passed as a literal string because the settingsNamespace brand helper was removed upstream (broken named import on 0.1.2-rc.1 boot). 0.1.5 adds the Settings -> General row (client slot settings.general.item + host route GET/POST /caveman/default) so the default mode is editable in the UI; a registered host namespace alone does NOT produce a settings row. 0.1.6 fixes the registration itself: reach the settings service through ctx.inject(['settings'], ...) instead of ctx.get('settings') at apply time (which returns undefined on 0.1.2-rc.1, so the namespace was never registered and every write to POST /caveman/default answered 503 (settings unavailable).",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"keywords": [
|
|
14
14
|
"dsh",
|