@try-works/dsh-righthand 0.1.19 → 0.1.20

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,14 @@
1
+ /**
2
+ * Righthand panel client half: a collapsible right-side panel inside the
3
+ * DSH Web GUI showing the plugin's live state - settings, store keys,
4
+ * tasks and events - and mutating it through the /righthand/* routes the
5
+ * host half (src/gui.ts) registers. Same-plugin GUI: no separate package.
6
+ */
7
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
8
+ /** Required services: the slot registry (client runtime). */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Client plugin body: register the panel into the frame-wide overlay slot.
12
+ */
13
+ export declare function apply(ctx: ClientContext): void;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAI3E,6DAA6D;AAC7D,eAAO,MAAM,MAAM,UAAY,CAAA;AA2J/B;;GAEG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAM9C"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Righthand panel client half: a collapsible right-side panel inside the
3
+ * DSH Web GUI showing the plugin's live state - settings, store keys,
4
+ * tasks and events - and mutating it through the /righthand/* routes the
5
+ * host half (src/gui.ts) registers. Same-plugin GUI: no separate package.
6
+ */
7
+ import { createElement as h, useEffect, useState, } from 'react';
8
+ import { createPortal } from 'react-dom';
9
+ /** Required services: the slot registry (client runtime). */
10
+ export const inject = ['slots'];
11
+ const C = {
12
+ bg: '#15171a',
13
+ panel: '#1b1e23',
14
+ row: '#23272e',
15
+ border: '#2d323a',
16
+ text: '#e6e8ec',
17
+ dim: '#9aa3ad',
18
+ accent: '#3b82f6',
19
+ green: '#3fbf6e',
20
+ red: '#e5484d',
21
+ amber: '#d9a13b',
22
+ };
23
+ const EMPTY = { settings: {}, storeKeys: [], tasks: [], events: [] };
24
+ function fmt(s, n) {
25
+ try {
26
+ const t = JSON.stringify(s);
27
+ return t === undefined ? '' : (t.length > n ? t.slice(0, n) + '...' : t);
28
+ }
29
+ catch {
30
+ return String(s);
31
+ }
32
+ }
33
+ function Row(props) {
34
+ return h('div', { style: { display: 'flex', gap: 8, justifyContent: 'space-between', padding: '4px 0', borderBottom: '1px solid ' + C.border, fontSize: 12 } }, h('span', { style: { color: C.dim, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, props.label), h('span', { style: { color: props.tone ?? C.text, fontFamily: 'monospace', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '55%' } }, props.value));
35
+ }
36
+ function Btn(props) {
37
+ const base = {
38
+ background: C.row, color: props.danger ? C.red : (props.tone ?? C.text),
39
+ border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 10px',
40
+ fontSize: 11, cursor: 'pointer', whiteSpace: 'nowrap'
41
+ };
42
+ return h('button', { style: base, onClick: props.onClick }, props.label);
43
+ }
44
+ function Section(props) {
45
+ return h('div', { style: { marginTop: 14 } }, h('div', { style: { fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.dim, marginBottom: 6 } }, props.title), props.children);
46
+ }
47
+ function RighthandPanel() {
48
+ const [collapsed, setCollapsed] = useState(false);
49
+ const [state, setState] = useState(EMPTY);
50
+ const [error, setError] = useState('');
51
+ const [patch, setPatch] = useState('{}');
52
+ const [newKey, setNewKey] = useState('');
53
+ const [newValue, setNewValue] = useState('');
54
+ const load = () => {
55
+ fetch('/righthand/state').then(r => r.json()).then((d) => { setState(d); setError(''); })
56
+ .catch((e) => setError(String(e)));
57
+ };
58
+ useEffect(() => { load(); }, []);
59
+ const post = (path, body, then) => {
60
+ fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) })
61
+ .then(r => r.json()).then((d) => { if (!d.ok && d.error)
62
+ setError(String(d.error)); then(); })
63
+ .catch((e) => setError(String(e)));
64
+ };
65
+ const railStyle = {
66
+ position: 'fixed', right: 0, top: 0, bottom: 0, width: 44, background: C.panel,
67
+ borderLeft: '1px solid ' + C.border, display: 'flex', flexDirection: 'column',
68
+ alignItems: 'center', paddingTop: 12, gap: 10, zIndex: 9998
69
+ };
70
+ const panelStyle = {
71
+ position: 'fixed', right: 0, top: 0, bottom: 0, width: 340, background: C.bg,
72
+ borderLeft: '1px solid ' + C.border, padding: 12, overflowY: 'auto', zIndex: 9998,
73
+ fontFamily: 'ui-sans-serif, system-ui, sans-serif', color: C.text, fontSize: 13
74
+ };
75
+ const toggle = h('button', {
76
+ style: { background: 'none', border: 'none', color: C.dim, fontSize: 18, cursor: 'pointer' },
77
+ onClick: () => setCollapsed(!collapsed),
78
+ }, collapsed ? '<' : '>');
79
+ const refreshBtn = h(Btn, { label: 'Refresh', onClick: load });
80
+ if (collapsed) {
81
+ return createPortal(h('div', { style: railStyle, 'data-dsh-righthand-panel': 'collapsed' }, toggle, h('span', { style: { color: C.green, fontSize: 10, width: 8, height: 8, borderRadius: '50%', background: C.green } }), h('span', { style: { color: C.dim, fontSize: 11, writingMode: 'vertical-rl', letterSpacing: '0.12em', userSelect: 'none' } }, 'Righthand')), document.body);
82
+ }
83
+ return createPortal(h('div', { style: panelStyle, 'data-dsh-righthand-panel': 'expanded' }, h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 } }, h('span', { style: { fontWeight: 600, letterSpacing: '0.05em' } }, 'Righthand'), h('span', { style: { display: 'flex', gap: 6 } }, refreshBtn, toggle)), error !== '' ? h('div', { style: { color: C.red, fontSize: 11, marginBottom: 8 } }, error) : null, h(Section, { title: 'Settings' }, Object.entries(state.settings).map(([k, v]) => h(Row, { key: k, label: k, value: fmt(v, 90) })), h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } }, h('input', {
84
+ value: patch, onChange: (e) => setPatch(e.target.value),
85
+ style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' },
86
+ }), h(Btn, { label: 'Patch', onClick: () => {
87
+ try {
88
+ const p = JSON.parse(patch);
89
+ post('/righthand/settings/set', { patch: p }, load);
90
+ }
91
+ catch {
92
+ setError('patch must be JSON');
93
+ }
94
+ } }))), h(Section, { title: 'Store (' + state.storeKeys.length + ')' }, state.storeKeys.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(empty)') : null, state.storeKeys.map(k => h('div', { key: k, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } }, h('span', { style: { flex: 1, fontFamily: 'monospace', fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, k), h(Btn, { label: 'Delete', danger: true, onClick: () => post('/righthand/store/delete', { key: k }, load) }))), h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } }, h('input', { placeholder: 'key', value: newKey, onChange: (e) => setNewKey(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }), h('input', { placeholder: 'json value', value: newValue, onChange: (e) => setNewValue(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }), h(Btn, { label: 'Put', onClick: () => {
95
+ if (newKey === '') {
96
+ setError('key required');
97
+ return;
98
+ }
99
+ try {
100
+ const v = JSON.parse(newValue === '' ? 'null' : newValue);
101
+ post('/righthand/store/put', { key: newKey, value: v }, () => { load(); setNewKey(''); setNewValue(''); });
102
+ }
103
+ catch {
104
+ setError('value must be JSON');
105
+ }
106
+ } }))), h(Section, { title: 'Tasks (' + state.tasks.length + ')' }, state.tasks.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null, state.tasks.map((t) => h('div', { key: t.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } }, h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, (t.state === 'done' ? '[x] ' : t.state === 'failed' ? '[!] ' : '[ ] ') + t.title), h(Btn, { label: 'Done', tone: C.green, onClick: () => post('/righthand/task/update', { id: t.id, state: 'done' }, load) }), h(Btn, { label: 'Fail', danger: true, onClick: () => post('/righthand/task/update', { id: t.id, state: 'failed' }, load) })))), h(Section, { title: 'Events (' + state.events.length + ')' }, state.events.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null, state.events.map((e) => h('div', { key: e.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } }, h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, e.title + ' @ ' + e.at + ' [' + e.state + ']'), e.state === 'pending' ? h(Btn, { label: 'Cancel', danger: true, onClick: () => post('/righthand/event/cancel', { id: e.id }, load) }) : null)))), document.body);
107
+ }
108
+ /**
109
+ * Client plugin body: register the panel into the frame-wide overlay slot.
110
+ */
111
+ export function apply(ctx) {
112
+ ctx.slots.inject('shell.overlay', () => ctx.slots.register({
113
+ name: 'shell.overlay',
114
+ id: 'righthand-panel',
115
+ order: 60,
116
+ }, RighthandPanel));
117
+ }
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
package/lib/client.js ADDED
@@ -0,0 +1,373 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@try-works/dsh-righthand",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let react_dom = require("react-dom");
9
+ //#region src/client/index.ts
10
+ /**
11
+ * Righthand panel client half: a collapsible right-side panel inside the
12
+ * DSH Web GUI showing the plugin's live state - settings, store keys,
13
+ * tasks and events - and mutating it through the /righthand/* routes the
14
+ * host half (src/gui.ts) registers. Same-plugin GUI: no separate package.
15
+ */
16
+ /** Required services: the slot registry (client runtime). */
17
+ const inject = ["slots"];
18
+ const C = {
19
+ bg: "#15171a",
20
+ panel: "#1b1e23",
21
+ row: "#23272e",
22
+ border: "#2d323a",
23
+ text: "#e6e8ec",
24
+ dim: "#9aa3ad",
25
+ accent: "#3b82f6",
26
+ green: "#3fbf6e",
27
+ red: "#e5484d",
28
+ amber: "#d9a13b"
29
+ };
30
+ const EMPTY = {
31
+ settings: {},
32
+ storeKeys: [],
33
+ tasks: [],
34
+ events: []
35
+ };
36
+ function fmt(s, n) {
37
+ try {
38
+ const t = JSON.stringify(s);
39
+ return t === void 0 ? "" : t.length > n ? t.slice(0, n) + "..." : t;
40
+ } catch {
41
+ return String(s);
42
+ }
43
+ }
44
+ function Row(props) {
45
+ return (0, react.createElement)("div", { style: {
46
+ display: "flex",
47
+ gap: 8,
48
+ justifyContent: "space-between",
49
+ padding: "4px 0",
50
+ borderBottom: "1px solid " + C.border,
51
+ fontSize: 12
52
+ } }, (0, react.createElement)("span", { style: {
53
+ color: C.dim,
54
+ overflow: "hidden",
55
+ textOverflow: "ellipsis",
56
+ whiteSpace: "nowrap"
57
+ } }, props.label), (0, react.createElement)("span", { style: {
58
+ color: props.tone ?? C.text,
59
+ fontFamily: "monospace",
60
+ overflow: "hidden",
61
+ textOverflow: "ellipsis",
62
+ whiteSpace: "nowrap",
63
+ maxWidth: "55%"
64
+ } }, props.value));
65
+ }
66
+ function Btn(props) {
67
+ const base = {
68
+ background: C.row,
69
+ color: props.danger ? C.red : props.tone ?? C.text,
70
+ border: "1px solid " + C.border,
71
+ borderRadius: 6,
72
+ padding: "3px 10px",
73
+ fontSize: 11,
74
+ cursor: "pointer",
75
+ whiteSpace: "nowrap"
76
+ };
77
+ return (0, react.createElement)("button", {
78
+ style: base,
79
+ onClick: props.onClick
80
+ }, props.label);
81
+ }
82
+ function Section(props) {
83
+ return (0, react.createElement)("div", { style: { marginTop: 14 } }, (0, react.createElement)("div", { style: {
84
+ fontSize: 11,
85
+ letterSpacing: "0.12em",
86
+ textTransform: "uppercase",
87
+ color: C.dim,
88
+ marginBottom: 6
89
+ } }, props.title), props.children);
90
+ }
91
+ function RighthandPanel() {
92
+ const [collapsed, setCollapsed] = (0, react.useState)(false);
93
+ const [state, setState] = (0, react.useState)(EMPTY);
94
+ const [error, setError] = (0, react.useState)("");
95
+ const [patch, setPatch] = (0, react.useState)("{}");
96
+ const [newKey, setNewKey] = (0, react.useState)("");
97
+ const [newValue, setNewValue] = (0, react.useState)("");
98
+ const load = () => {
99
+ fetch("/righthand/state").then((r) => r.json()).then((d) => {
100
+ setState(d);
101
+ setError("");
102
+ }).catch((e) => setError(String(e)));
103
+ };
104
+ (0, react.useEffect)(() => {
105
+ load();
106
+ }, []);
107
+ const post = (path, body, then) => {
108
+ fetch(path, {
109
+ method: "POST",
110
+ headers: { "content-type": "application/json" },
111
+ body: JSON.stringify(body)
112
+ }).then((r) => r.json()).then((d) => {
113
+ if (!d.ok && d.error) setError(String(d.error));
114
+ then();
115
+ }).catch((e) => setError(String(e)));
116
+ };
117
+ const railStyle = {
118
+ position: "fixed",
119
+ right: 0,
120
+ top: 0,
121
+ bottom: 0,
122
+ width: 44,
123
+ background: C.panel,
124
+ borderLeft: "1px solid " + C.border,
125
+ display: "flex",
126
+ flexDirection: "column",
127
+ alignItems: "center",
128
+ paddingTop: 12,
129
+ gap: 10,
130
+ zIndex: 9998
131
+ };
132
+ const panelStyle = {
133
+ position: "fixed",
134
+ right: 0,
135
+ top: 0,
136
+ bottom: 0,
137
+ width: 340,
138
+ background: C.bg,
139
+ borderLeft: "1px solid " + C.border,
140
+ padding: 12,
141
+ overflowY: "auto",
142
+ zIndex: 9998,
143
+ fontFamily: "ui-sans-serif, system-ui, sans-serif",
144
+ color: C.text,
145
+ fontSize: 13
146
+ };
147
+ const toggle = (0, react.createElement)("button", {
148
+ style: {
149
+ background: "none",
150
+ border: "none",
151
+ color: C.dim,
152
+ fontSize: 18,
153
+ cursor: "pointer"
154
+ },
155
+ onClick: () => setCollapsed(!collapsed)
156
+ }, collapsed ? "<" : ">");
157
+ const refreshBtn = (0, react.createElement)(Btn, {
158
+ label: "Refresh",
159
+ onClick: load
160
+ });
161
+ if (collapsed) return (0, react_dom.createPortal)((0, react.createElement)("div", {
162
+ style: railStyle,
163
+ "data-dsh-righthand-panel": "collapsed"
164
+ }, toggle, (0, react.createElement)("span", { style: {
165
+ color: C.green,
166
+ fontSize: 10,
167
+ width: 8,
168
+ height: 8,
169
+ borderRadius: "50%",
170
+ background: C.green
171
+ } }), (0, react.createElement)("span", { style: {
172
+ color: C.dim,
173
+ fontSize: 11,
174
+ writingMode: "vertical-rl",
175
+ letterSpacing: "0.12em",
176
+ userSelect: "none"
177
+ } }, "Righthand")), document.body);
178
+ return (0, react_dom.createPortal)((0, react.createElement)("div", {
179
+ style: panelStyle,
180
+ "data-dsh-righthand-panel": "expanded"
181
+ }, (0, react.createElement)("div", { style: {
182
+ display: "flex",
183
+ justifyContent: "space-between",
184
+ alignItems: "center",
185
+ marginBottom: 4
186
+ } }, (0, react.createElement)("span", { style: {
187
+ fontWeight: 600,
188
+ letterSpacing: "0.05em"
189
+ } }, "Righthand"), (0, react.createElement)("span", { style: {
190
+ display: "flex",
191
+ gap: 6
192
+ } }, refreshBtn, toggle)), error !== "" ? (0, react.createElement)("div", { style: {
193
+ color: C.red,
194
+ fontSize: 11,
195
+ marginBottom: 8
196
+ } }, error) : null, (0, react.createElement)(Section, { title: "Settings" }, Object.entries(state.settings).map(([k, v]) => (0, react.createElement)(Row, {
197
+ key: k,
198
+ label: k,
199
+ value: fmt(v, 90)
200
+ })), (0, react.createElement)("div", { style: {
201
+ display: "flex",
202
+ gap: 6,
203
+ marginTop: 8
204
+ } }, (0, react.createElement)("input", {
205
+ value: patch,
206
+ onChange: (e) => setPatch(e.target.value),
207
+ style: {
208
+ flex: 1,
209
+ background: C.row,
210
+ color: C.text,
211
+ border: "1px solid " + C.border,
212
+ borderRadius: 6,
213
+ padding: "3px 8px",
214
+ fontSize: 11,
215
+ fontFamily: "monospace"
216
+ }
217
+ }), (0, react.createElement)(Btn, {
218
+ label: "Patch",
219
+ onClick: () => {
220
+ try {
221
+ const p = JSON.parse(patch);
222
+ post("/righthand/settings/set", { patch: p }, load);
223
+ } catch {
224
+ setError("patch must be JSON");
225
+ }
226
+ }
227
+ }))), (0, react.createElement)(Section, { title: "Store (" + state.storeKeys.length + ")" }, state.storeKeys.length === 0 ? (0, react.createElement)("div", { style: {
228
+ color: C.dim,
229
+ fontSize: 12
230
+ } }, "(empty)") : null, state.storeKeys.map((k) => (0, react.createElement)("div", {
231
+ key: k,
232
+ style: {
233
+ display: "flex",
234
+ gap: 6,
235
+ alignItems: "center",
236
+ padding: "2px 0"
237
+ }
238
+ }, (0, react.createElement)("span", { style: {
239
+ flex: 1,
240
+ fontFamily: "monospace",
241
+ fontSize: 12,
242
+ overflow: "hidden",
243
+ textOverflow: "ellipsis",
244
+ whiteSpace: "nowrap"
245
+ } }, k), (0, react.createElement)(Btn, {
246
+ label: "Delete",
247
+ danger: true,
248
+ onClick: () => post("/righthand/store/delete", { key: k }, load)
249
+ }))), (0, react.createElement)("div", { style: {
250
+ display: "flex",
251
+ gap: 6,
252
+ marginTop: 8
253
+ } }, (0, react.createElement)("input", {
254
+ placeholder: "key",
255
+ value: newKey,
256
+ onChange: (e) => setNewKey(e.target.value),
257
+ style: {
258
+ flex: 1,
259
+ background: C.row,
260
+ color: C.text,
261
+ border: "1px solid " + C.border,
262
+ borderRadius: 6,
263
+ padding: "3px 8px",
264
+ fontSize: 11,
265
+ fontFamily: "monospace"
266
+ }
267
+ }), (0, react.createElement)("input", {
268
+ placeholder: "json value",
269
+ value: newValue,
270
+ onChange: (e) => setNewValue(e.target.value),
271
+ style: {
272
+ flex: 1,
273
+ background: C.row,
274
+ color: C.text,
275
+ border: "1px solid " + C.border,
276
+ borderRadius: 6,
277
+ padding: "3px 8px",
278
+ fontSize: 11,
279
+ fontFamily: "monospace"
280
+ }
281
+ }), (0, react.createElement)(Btn, {
282
+ label: "Put",
283
+ onClick: () => {
284
+ if (newKey === "") {
285
+ setError("key required");
286
+ return;
287
+ }
288
+ try {
289
+ const v = JSON.parse(newValue === "" ? "null" : newValue);
290
+ post("/righthand/store/put", {
291
+ key: newKey,
292
+ value: v
293
+ }, () => {
294
+ load();
295
+ setNewKey("");
296
+ setNewValue("");
297
+ });
298
+ } catch {
299
+ setError("value must be JSON");
300
+ }
301
+ }
302
+ }))), (0, react.createElement)(Section, { title: "Tasks (" + state.tasks.length + ")" }, state.tasks.length === 0 ? (0, react.createElement)("div", { style: {
303
+ color: C.dim,
304
+ fontSize: 12
305
+ } }, "(none)") : null, state.tasks.map((t) => (0, react.createElement)("div", {
306
+ key: t.id,
307
+ style: {
308
+ display: "flex",
309
+ gap: 6,
310
+ alignItems: "center",
311
+ padding: "2px 0"
312
+ }
313
+ }, (0, react.createElement)("span", { style: {
314
+ flex: 1,
315
+ fontSize: 12,
316
+ overflow: "hidden",
317
+ textOverflow: "ellipsis",
318
+ whiteSpace: "nowrap"
319
+ } }, (t.state === "done" ? "[x] " : t.state === "failed" ? "[!] " : "[ ] ") + t.title), (0, react.createElement)(Btn, {
320
+ label: "Done",
321
+ tone: C.green,
322
+ onClick: () => post("/righthand/task/update", {
323
+ id: t.id,
324
+ state: "done"
325
+ }, load)
326
+ }), (0, react.createElement)(Btn, {
327
+ label: "Fail",
328
+ danger: true,
329
+ onClick: () => post("/righthand/task/update", {
330
+ id: t.id,
331
+ state: "failed"
332
+ }, load)
333
+ })))), (0, react.createElement)(Section, { title: "Events (" + state.events.length + ")" }, state.events.length === 0 ? (0, react.createElement)("div", { style: {
334
+ color: C.dim,
335
+ fontSize: 12
336
+ } }, "(none)") : null, state.events.map((e) => (0, react.createElement)("div", {
337
+ key: e.id,
338
+ style: {
339
+ display: "flex",
340
+ gap: 6,
341
+ alignItems: "center",
342
+ padding: "2px 0"
343
+ }
344
+ }, (0, react.createElement)("span", { style: {
345
+ flex: 1,
346
+ fontSize: 12,
347
+ overflow: "hidden",
348
+ textOverflow: "ellipsis",
349
+ whiteSpace: "nowrap"
350
+ } }, e.title + " @ " + e.at + " [" + e.state + "]"), e.state === "pending" ? (0, react.createElement)(Btn, {
351
+ label: "Cancel",
352
+ danger: true,
353
+ onClick: () => post("/righthand/event/cancel", { id: e.id }, load)
354
+ }) : null)))), document.body);
355
+ }
356
+ /**
357
+ * Client plugin body: register the panel into the frame-wide overlay slot.
358
+ */
359
+ function apply(ctx) {
360
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
361
+ name: "shell.overlay",
362
+ id: "righthand-panel",
363
+ order: 60
364
+ }, RighthandPanel));
365
+ }
366
+ //#endregion
367
+ exports.apply = apply;
368
+ exports.inject = inject;
369
+ return module.exports;
370
+ }
371
+ });
372
+
373
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["h","useState","createPortal"],"sources":["../src/client/index.ts"],"sourcesContent":["/**\n * Righthand panel client half: a collapsible right-side panel inside the\n * DSH Web GUI showing the plugin's live state - settings, store keys,\n * tasks and events - and mutating it through the /righthand/* routes the\n * host half (src/gui.ts) registers. Same-plugin GUI: no separate package.\n */\n\nimport {\n createElement as h,\n useEffect,\n useState,\n type CSSProperties,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\n\n/** Required services: the slot registry (client runtime). */\nexport const inject = ['slots']\n\nconst C = {\n bg: '#15171a',\n panel: '#1b1e23',\n row: '#23272e',\n border: '#2d323a',\n text: '#e6e8ec',\n dim: '#9aa3ad',\n accent: '#3b82f6',\n green: '#3fbf6e',\n red: '#e5484d',\n amber: '#d9a13b',\n}\n\ninterface State {\n settings: Record<string, unknown>\n storeKeys: string[]\n tasks: any[]\n events: any[]\n}\n\nconst EMPTY: State = { settings: {}, storeKeys: [], tasks: [], events: [] }\n\nfunction fmt(s: unknown, n: number): string {\n try { const t = JSON.stringify(s); return t === undefined ? '' : (t.length > n ? t.slice(0, n) + '...' : t) }\n catch { return String(s) }\n}\n\nfunction Row(props: { label: string; value: string; tone?: string }): ReturnType<typeof h> {\n return h('div', { style: { display: 'flex', gap: 8, justifyContent: 'space-between', padding: '4px 0', borderBottom: '1px solid ' + C.border, fontSize: 12 } },\n h('span', { style: { color: C.dim, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, props.label),\n h('span', { style: { color: props.tone ?? C.text, fontFamily: 'monospace', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '55%' } }, props.value),\n )\n}\n\nfunction Btn(props: { label: string; onClick: () => void; tone?: string; danger?: boolean }): ReturnType<typeof h> {\n const base: CSSProperties = {\n background: C.row, color: props.danger ? C.red : (props.tone ?? C.text),\n border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 10px',\n fontSize: 11, cursor: 'pointer', whiteSpace: 'nowrap'\n }\n return h('button', { style: base, onClick: props.onClick }, props.label)\n}\n\nfunction Section(props: { title: string; children?: any }): ReturnType<typeof h> {\n return h('div', { style: { marginTop: 14 } },\n h('div', { style: { fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.dim, marginBottom: 6 } }, props.title),\n props.children,\n )\n}\n\nfunction RighthandPanel(): ReturnType<typeof h> {\n const [collapsed, setCollapsed] = useState(false)\n const [state, setState] = useState<State>(EMPTY)\n const [error, setError] = useState('')\n const [patch, setPatch] = useState('{}')\n const [newKey, setNewKey] = useState('')\n const [newValue, setNewValue] = useState('')\n\n const load = (): void => {\n fetch('/righthand/state').then(r => r.json()).then((d: State) => { setState(d); setError('') })\n .catch((e: Error) => setError(String(e)))\n }\n useEffect(() => { load() }, [])\n\n const post = (path: string, body: unknown, then: () => void): void => {\n fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) })\n .then(r => r.json()).then((d: any) => { if (!d.ok && d.error) setError(String(d.error)); then() })\n .catch((e: Error) => setError(String(e)))\n }\n\n const railStyle: CSSProperties = {\n position: 'fixed', right: 0, top: 0, bottom: 0, width: 44, background: C.panel,\n borderLeft: '1px solid ' + C.border, display: 'flex', flexDirection: 'column',\n alignItems: 'center', paddingTop: 12, gap: 10, zIndex: 9998\n }\n const panelStyle: CSSProperties = {\n position: 'fixed', right: 0, top: 0, bottom: 0, width: 340, background: C.bg,\n borderLeft: '1px solid ' + C.border, padding: 12, overflowY: 'auto', zIndex: 9998,\n fontFamily: 'ui-sans-serif, system-ui, sans-serif', color: C.text, fontSize: 13\n }\n\n const toggle = h('button', {\n style: { background: 'none', border: 'none', color: C.dim, fontSize: 18, cursor: 'pointer' },\n onClick: () => setCollapsed(!collapsed),\n }, collapsed ? '<' : '>')\n\n const refreshBtn = h(Btn, { label: 'Refresh', onClick: load })\n\n if (collapsed) {\n return createPortal(h('div', { style: railStyle, 'data-dsh-righthand-panel': 'collapsed' },\n toggle,\n h('span', { style: { color: C.green, fontSize: 10, width: 8, height: 8, borderRadius: '50%', background: C.green } }),\n h('span', { style: { color: C.dim, fontSize: 11, writingMode: 'vertical-rl', letterSpacing: '0.12em', userSelect: 'none' } }, 'Righthand'),\n ), document.body)\n }\n\n return createPortal(h('div', { style: panelStyle, 'data-dsh-righthand-panel': 'expanded' },\n h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 } },\n h('span', { style: { fontWeight: 600, letterSpacing: '0.05em' } }, 'Righthand'),\n h('span', { style: { display: 'flex', gap: 6 } }, refreshBtn, toggle),\n ),\n error !== '' ? h('div', { style: { color: C.red, fontSize: 11, marginBottom: 8 } }, error) : null,\n\n h(Section, { title: 'Settings' },\n Object.entries(state.settings).map(([k, v]) => h(Row, { key: k, label: k, value: fmt(v, 90) })),\n h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } },\n h('input', {\n value: patch, onChange: (e: any) => setPatch(e.target.value),\n style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' },\n }),\n h(Btn, { label: 'Patch', onClick: () => {\n try { const p = JSON.parse(patch); post('/righthand/settings/set', { patch: p }, load) }\n catch { setError('patch must be JSON') }\n } }),\n ),\n ),\n\n h(Section, { title: 'Store (' + state.storeKeys.length + ')' },\n state.storeKeys.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(empty)') : null,\n state.storeKeys.map(k => h('div', { key: k, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },\n h('span', { style: { flex: 1, fontFamily: 'monospace', fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, k),\n h(Btn, { label: 'Delete', danger: true, onClick: () => post('/righthand/store/delete', { key: k }, load) }),\n )),\n h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } },\n h('input', { placeholder: 'key', value: newKey, onChange: (e: any) => setNewKey(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }),\n h('input', { placeholder: 'json value', value: newValue, onChange: (e: any) => setNewValue(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }),\n h(Btn, { label: 'Put', onClick: () => {\n if (newKey === '') { setError('key required'); return }\n try { const v = JSON.parse(newValue === '' ? 'null' : newValue); post('/righthand/store/put', { key: newKey, value: v }, () => { load(); setNewKey(''); setNewValue('') }) }\n catch { setError('value must be JSON') }\n } }),\n ),\n ),\n\n h(Section, { title: 'Tasks (' + state.tasks.length + ')' },\n state.tasks.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null,\n state.tasks.map((t: any) => h('div', { key: t.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },\n h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, (t.state === 'done' ? '[x] ' : t.state === 'failed' ? '[!] ' : '[ ] ') + t.title),\n h(Btn, { label: 'Done', tone: C.green, onClick: () => post('/righthand/task/update', { id: t.id, state: 'done' }, load) }),\n h(Btn, { label: 'Fail', danger: true, onClick: () => post('/righthand/task/update', { id: t.id, state: 'failed' }, load) }),\n )),\n ),\n\n h(Section, { title: 'Events (' + state.events.length + ')' },\n state.events.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null,\n state.events.map((e: any) => h('div', { key: e.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },\n h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, e.title + ' @ ' + e.at + ' [' + e.state + ']'),\n e.state === 'pending' ? h(Btn, { label: 'Cancel', danger: true, onClick: () => post('/righthand/event/cancel', { id: e.id }, load) }) : null,\n )),\n ),\n ), document.body)\n}\n\n/**\n * Client plugin body: register the panel into the frame-wide overlay slot.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'righthand-panel',\n order: 60,\n }, RighthandPanel))\n}"],"mappings":"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"}
package/lib/gui.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * gui.ts - the righthand GUI host half: HTTP routes under /righthand/* on
3
+ * the DSH web server that read and mutate the same domains the tools use.
4
+ * The client half (src/client/index.ts) renders these as a panel inside the
5
+ * DSH Web GUI. Mounts only when a webServer exists (the Web surface);
6
+ * elsewhere the child fiber simply does not start.
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis';
9
+ export declare const name = "righthand-gui";
10
+ export declare const inject: string[];
11
+ export declare function apply(ctx: Context): void;
12
+ //# sourceMappingURL=gui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gui.d.ts","sourceRoot":"","sources":["../src/gui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AASlD,eAAO,MAAM,IAAI,kBAAkB,CAAA;AACnC,eAAO,MAAM,MAAM,UAA6C,CAAA;AAwBhE,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkHxC"}
package/lib/gui.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * gui.ts - the righthand GUI host half: HTTP routes under /righthand/* on
3
+ * the DSH web server that read and mutate the same domains the tools use.
4
+ * The client half (src/client/index.ts) renders these as a panel inside the
5
+ * DSH Web GUI. Mounts only when a webServer exists (the Web surface);
6
+ * elsewhere the child fiber simply does not start.
7
+ */
8
+ import { settingsNamespace } from '@deepseek-ai/dsh-settings';
9
+ import { storeDomain } from "./store-tools.js";
10
+ import { taskDomain } from "./task-tools.js";
11
+ import { eventsDomain } from "./events-tools.js";
12
+ export const name = 'righthand-gui';
13
+ export const inject = ['webServer', 'storageDomain', 'settings'];
14
+ const ns = settingsNamespace('righthand');
15
+ function json(res, code, body) {
16
+ const text = JSON.stringify(body);
17
+ res.writeHead(code, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
18
+ res.end(text);
19
+ }
20
+ function readBody(req) {
21
+ return new Promise((resolve, reject) => {
22
+ const chunks = [];
23
+ let bytes = 0;
24
+ req.on('data', (c) => {
25
+ bytes += c.length;
26
+ if (bytes > 65536) {
27
+ reject(new Error('body too large'));
28
+ req.destroy();
29
+ }
30
+ else
31
+ chunks.push(c);
32
+ });
33
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
34
+ req.on('error', reject);
35
+ });
36
+ }
37
+ export function apply(ctx) {
38
+ let domains;
39
+ let ready;
40
+ ctx.effect(() => {
41
+ ready = (async () => {
42
+ const [store, tasks, events] = await Promise.all([
43
+ ctx.storageDomain.open(storeDomain),
44
+ ctx.storageDomain.open(taskDomain),
45
+ ctx.storageDomain.open(eventsDomain),
46
+ ]);
47
+ domains = { store, tasks, events };
48
+ })();
49
+ return () => { };
50
+ });
51
+ const ensure = async () => {
52
+ if (domains === undefined) {
53
+ await ready;
54
+ }
55
+ if (domains === undefined)
56
+ throw new Error('righthand domains not open');
57
+ return domains;
58
+ };
59
+ const getSettings = () => {
60
+ const v = ctx.settings.get(ns);
61
+ return v ?? {};
62
+ };
63
+ const disposers = [];
64
+ ctx.effect(() => () => { for (const d of disposers.splice(0))
65
+ d(); });
66
+ const route = (path, handler) => {
67
+ disposers.push(ctx.webServer.register({ kind: 'exact', path, handler }));
68
+ };
69
+ route('/righthand/state', async (_req, res) => {
70
+ try {
71
+ const d = await ensure();
72
+ const storeKeys = [...d.store.table('rows').keys()];
73
+ const tasks = [...d.tasks.table('tasks').entries()];
74
+ const events = [...d.events.table('events').entries()];
75
+ json(res, 200, {
76
+ settings: getSettings(),
77
+ storeKeys,
78
+ tasks: tasks.map(([id, row]) => ({ id, ...row })),
79
+ events: events.map(([id, row]) => ({ id, ...row })),
80
+ });
81
+ }
82
+ catch (e) {
83
+ json(res, 500, { error: String(e) });
84
+ }
85
+ });
86
+ route('/righthand/settings/set', async (req, res) => {
87
+ try {
88
+ const body = JSON.parse(await readBody(req));
89
+ await ctx.settings.update(ns, body.patch);
90
+ json(res, 200, { ok: true });
91
+ }
92
+ catch (e) {
93
+ json(res, 400, { error: String(e) });
94
+ }
95
+ });
96
+ route('/righthand/store/put', async (req, res) => {
97
+ try {
98
+ const d = await ensure();
99
+ const body = JSON.parse(await readBody(req));
100
+ if (typeof body.key !== 'string' || body.key === '')
101
+ throw new Error('key required');
102
+ await d.store.table('rows').put(body.key, { value: body.value ?? null, updatedAt: new Date().toISOString() });
103
+ const writes = d.store.global.get();
104
+ await d.store.global.set({ writes: writes.writes + 1 });
105
+ json(res, 200, { ok: true });
106
+ }
107
+ catch (e) {
108
+ json(res, 400, { error: String(e) });
109
+ }
110
+ });
111
+ route('/righthand/store/delete', async (req, res) => {
112
+ try {
113
+ const d = await ensure();
114
+ const body = JSON.parse(await readBody(req));
115
+ const existed = await d.store.table('rows').delete(body.key);
116
+ json(res, 200, { ok: true, existed });
117
+ }
118
+ catch (e) {
119
+ json(res, 400, { error: String(e) });
120
+ }
121
+ });
122
+ route('/righthand/task/update', async (req, res) => {
123
+ try {
124
+ const d = await ensure();
125
+ const body = JSON.parse(await readBody(req));
126
+ const row = await d.tasks.table('tasks').get(body.id);
127
+ if (row === undefined) {
128
+ json(res, 404, { error: 'task not found' });
129
+ return;
130
+ }
131
+ const next = { ...row };
132
+ if (typeof body.state === 'string')
133
+ next.state = body.state;
134
+ if (body.result !== undefined)
135
+ next.result = body.result;
136
+ await d.tasks.table('tasks').put(body.id, next);
137
+ json(res, 200, { ok: true });
138
+ }
139
+ catch (e) {
140
+ json(res, 400, { error: String(e) });
141
+ }
142
+ });
143
+ route('/righthand/event/cancel', async (req, res) => {
144
+ try {
145
+ const d = await ensure();
146
+ const body = JSON.parse(await readBody(req));
147
+ const row = await d.events.table('events').get(body.id);
148
+ if (row === undefined) {
149
+ json(res, 404, { error: 'event not found' });
150
+ return;
151
+ }
152
+ await d.events.table('events').put(body.id, { ...row, state: 'cancelled' });
153
+ json(res, 200, { ok: true });
154
+ }
155
+ catch (e) {
156
+ json(res, 400, { error: String(e) });
157
+ }
158
+ });
159
+ }
160
+ //# sourceMappingURL=gui.js.map
package/lib/gui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gui.js","sourceRoot":"","sources":["../src/gui.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -25,6 +25,7 @@
25
25
  * - notify-tools: rh_notify_send over ntfy.sh (keyless)
26
26
  * - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
27
27
  * - guard-tools: tools/pre-execute policy (config.rules)
28
+ * - gui: /righthand/* web routes + the client panel (src/client)
28
29
  * - skills: the packaged dsh-righthand skill (ctx.skills)
29
30
  *
30
31
  * @module @try-works/dsh-righthand
@@ -41,6 +42,7 @@ import * as placesTools from './places-tools.ts';
41
42
  import * as filesTools from './files-tools.ts';
42
43
  import * as eventsTools from './events-tools.ts';
43
44
  import * as notifyTools from './notify-tools.ts';
45
+ import * as guiTools from './gui.ts';
44
46
  import * as righthandSkills from './skills.ts';
45
47
  import type { GuardRule } from './guard-tools.ts';
46
48
  export declare const name = "dsh-righthand";
@@ -58,7 +60,7 @@ export interface RighthandConfig {
58
60
  * instead of failing the whole plugin.
59
61
  */
60
62
  export declare function apply(ctx: Context, config?: RighthandConfig): void;
61
- export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills };
63
+ export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guiTools, guardTools, righthandSkills };
62
64
  export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from './skills.ts';
63
65
  export type { GuardRule } from './guard-tools.ts';
64
66
  export { guardFactsFor } from './guard-tools.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,eAAe,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,eAAO,MAAM,IAAI,kBAAkB,CAAA;AAEnC,iFAAiF;AACjF,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAElC,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,eAAoB,GAAG,IAAI,CAatE;AAGD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAClK,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACtF,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC5E,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AACpC,OAAO,KAAK,eAAe,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,eAAO,MAAM,IAAI,kBAAkB,CAAA;AAEnC,iFAAiF;AACjF,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAElC,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,eAAoB,GAAG,IAAI,CActE;AAGD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAC5K,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACtF,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC5E,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
package/lib/index.js CHANGED
@@ -25,6 +25,7 @@
25
25
  * - notify-tools: rh_notify_send over ntfy.sh (keyless)
26
26
  * - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
27
27
  * - guard-tools: tools/pre-execute policy (config.rules)
28
+ * - gui: /righthand/* web routes + the client panel (src/client)
28
29
  * - skills: the packaged dsh-righthand skill (ctx.skills)
29
30
  *
30
31
  * @module @try-works/dsh-righthand
@@ -40,6 +41,7 @@ import * as placesTools from "./places-tools.js";
40
41
  import * as filesTools from "./files-tools.js";
41
42
  import * as eventsTools from "./events-tools.js";
42
43
  import * as notifyTools from "./notify-tools.js";
44
+ import * as guiTools from "./gui.js";
43
45
  import * as righthandSkills from "./skills.js";
44
46
  export const name = 'dsh-righthand';
45
47
  /** The combined plugin needs no services itself; each child waits on its own. */
@@ -61,11 +63,12 @@ export function apply(ctx, config = {}) {
61
63
  ctx.plugin(filesTools);
62
64
  ctx.plugin(eventsTools);
63
65
  ctx.plugin(notifyTools);
66
+ ctx.plugin(guiTools);
64
67
  ctx.plugin(guardTools, { rules: config.rules ?? [] });
65
68
  ctx.plugin(righthandSkills);
66
69
  }
67
70
  // Individual modules stay importable for selective mounting.
68
- export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills };
71
+ export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guiTools, guardTools, righthandSkills };
69
72
  export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from "./skills.js";
70
73
  export { guardFactsFor } from "./guard-tools.js";
71
74
  export { isBlockedIP, guardedFetch, normalizeForecast, normalizeAir } from "./weather-tools.js";
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,eAAe,MAAM,aAAa,CAAA;AAG9C,MAAM,CAAC,MAAM,IAAI,GAAG,eAAe,CAAA;AAEnC,iFAAiF;AACjF,MAAM,CAAC,MAAM,MAAM,GAAa,EAAE,CAAA;AAQlC;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,SAA0B,EAAE;IAC9D,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACtB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACxB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACxB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACtB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAA;IACrD,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;AAC7B,CAAC;AAED,6DAA6D;AAC7D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAClK,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AACpC,OAAO,KAAK,eAAe,MAAM,aAAa,CAAA;AAG9C,MAAM,CAAC,MAAM,IAAI,GAAG,eAAe,CAAA;AAEnC,iFAAiF;AACjF,MAAM,CAAC,MAAM,MAAM,GAAa,EAAE,CAAA;AAQlC;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,SAA0B,EAAE;IAC9D,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACtB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACxB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACxB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACtB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACpB,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAA;IACrD,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;AAC7B,CAAC;AAED,6DAA6D;AAC7D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAC5K,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@try-works/dsh-righthand",
3
3
  "description": "DeepSeek Harness plugin: DSH-native righthand tools — durable KV store, credential/settings management, governed exec, and a tool guard",
4
- "version": "0.1.19",
4
+ "version": "0.1.20",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -10,15 +10,20 @@
10
10
  "types": "./lib/index.d.ts",
11
11
  "default": "./lib/index.js"
12
12
  },
13
+ "./client": {
14
+ "types": "./lib/client/index.d.ts",
15
+ "default": "./lib/client.js"
16
+ },
13
17
  "./src/*": "./src/*",
14
18
  "./cordis.patch.yml": "./cordis.patch.yml",
15
19
  "./package.json": "./package.json"
16
20
  },
17
21
  "scripts": {
18
22
  "build": "tsc -p tsconfig.build.json",
23
+ "bundle": "tsdown",
19
24
  "test": "vitest run",
20
25
  "typecheck": "tsc --noEmit",
21
- "prepack": "npm run build"
26
+ "prepack": "npm run build && npm run bundle"
22
27
  },
23
28
  "peerDependencies": {
24
29
  "@deepseek-ai/cordis": "^4.0.1",
@@ -68,7 +73,16 @@
68
73
  "@deepseek-ai/dsh-code-runtime": "file:D:/deepseek-harness/packages/code-runtime/code-runtime",
69
74
  "@deepseek-ai/dsh-attachment": "file:D:/deepseek-harness/packages/attachment/attachment",
70
75
  "@deepseek-ai/dsh-commands": "file:D:/deepseek-harness/packages/interaction/commands",
71
- "@deepseek-ai/dsh-skill": "file:D:/deepseek-harness/packages/skill/skill"
76
+ "@deepseek-ai/dsh-skill": "file:D:/deepseek-harness/packages/skill/skill",
77
+ "@deepseek-ai/dsh-host-webserver": "file:D:/deepseek-harness/packages/host/webserver",
78
+ "@deepseek-ai/dsh-client-runtime": "file:D:/deepseek-harness/packages/client/runtime",
79
+ "@deepseek-ai/dsh-client-ui-layout": "file:D:/deepseek-harness/packages/client/ui-layout",
80
+ "@deepseek-ai/dsh-client-ui-slots": "file:D:/deepseek-harness/packages/client/ui-slots",
81
+ "tsdown": "^0.22.2",
82
+ "react": "^18.2.0",
83
+ "react-dom": "^18.2.0",
84
+ "@types/react": "~18.3.1",
85
+ "@types/react-dom": "~18.3.1"
72
86
  },
73
87
  "files": [
74
88
  "lib",
@@ -82,6 +96,13 @@
82
96
  "dsh": {
83
97
  "bundle": {
84
98
  "patch": "./cordis.patch.yml"
99
+ },
100
+ "client": {
101
+ "platform": "web",
102
+ "inject": [
103
+ "@deepseek-ai/dsh-client-runtime"
104
+ ],
105
+ "external": []
85
106
  }
86
107
  },
87
108
  "repository": {
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Righthand panel client half: a collapsible right-side panel inside the
3
+ * DSH Web GUI showing the plugin's live state - settings, store keys,
4
+ * tasks and events - and mutating it through the /righthand/* routes the
5
+ * host half (src/gui.ts) registers. Same-plugin GUI: no separate package.
6
+ */
7
+
8
+ import {
9
+ createElement as h,
10
+ useEffect,
11
+ useState,
12
+ type CSSProperties,
13
+ } from 'react'
14
+ import { createPortal } from 'react-dom'
15
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
16
+ import type {} from '@deepseek-ai/dsh-client-ui-slots'
17
+ import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
18
+
19
+ /** Required services: the slot registry (client runtime). */
20
+ export const inject = ['slots']
21
+
22
+ const C = {
23
+ bg: '#15171a',
24
+ panel: '#1b1e23',
25
+ row: '#23272e',
26
+ border: '#2d323a',
27
+ text: '#e6e8ec',
28
+ dim: '#9aa3ad',
29
+ accent: '#3b82f6',
30
+ green: '#3fbf6e',
31
+ red: '#e5484d',
32
+ amber: '#d9a13b',
33
+ }
34
+
35
+ interface State {
36
+ settings: Record<string, unknown>
37
+ storeKeys: string[]
38
+ tasks: any[]
39
+ events: any[]
40
+ }
41
+
42
+ const EMPTY: State = { settings: {}, storeKeys: [], tasks: [], events: [] }
43
+
44
+ function fmt(s: unknown, n: number): string {
45
+ try { const t = JSON.stringify(s); return t === undefined ? '' : (t.length > n ? t.slice(0, n) + '...' : t) }
46
+ catch { return String(s) }
47
+ }
48
+
49
+ function Row(props: { label: string; value: string; tone?: string }): ReturnType<typeof h> {
50
+ return h('div', { style: { display: 'flex', gap: 8, justifyContent: 'space-between', padding: '4px 0', borderBottom: '1px solid ' + C.border, fontSize: 12 } },
51
+ h('span', { style: { color: C.dim, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, props.label),
52
+ h('span', { style: { color: props.tone ?? C.text, fontFamily: 'monospace', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '55%' } }, props.value),
53
+ )
54
+ }
55
+
56
+ function Btn(props: { label: string; onClick: () => void; tone?: string; danger?: boolean }): ReturnType<typeof h> {
57
+ const base: CSSProperties = {
58
+ background: C.row, color: props.danger ? C.red : (props.tone ?? C.text),
59
+ border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 10px',
60
+ fontSize: 11, cursor: 'pointer', whiteSpace: 'nowrap'
61
+ }
62
+ return h('button', { style: base, onClick: props.onClick }, props.label)
63
+ }
64
+
65
+ function Section(props: { title: string; children?: any }): ReturnType<typeof h> {
66
+ return h('div', { style: { marginTop: 14 } },
67
+ h('div', { style: { fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.dim, marginBottom: 6 } }, props.title),
68
+ props.children,
69
+ )
70
+ }
71
+
72
+ function RighthandPanel(): ReturnType<typeof h> {
73
+ const [collapsed, setCollapsed] = useState(false)
74
+ const [state, setState] = useState<State>(EMPTY)
75
+ const [error, setError] = useState('')
76
+ const [patch, setPatch] = useState('{}')
77
+ const [newKey, setNewKey] = useState('')
78
+ const [newValue, setNewValue] = useState('')
79
+
80
+ const load = (): void => {
81
+ fetch('/righthand/state').then(r => r.json()).then((d: State) => { setState(d); setError('') })
82
+ .catch((e: Error) => setError(String(e)))
83
+ }
84
+ useEffect(() => { load() }, [])
85
+
86
+ const post = (path: string, body: unknown, then: () => void): void => {
87
+ fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) })
88
+ .then(r => r.json()).then((d: any) => { if (!d.ok && d.error) setError(String(d.error)); then() })
89
+ .catch((e: Error) => setError(String(e)))
90
+ }
91
+
92
+ const railStyle: CSSProperties = {
93
+ position: 'fixed', right: 0, top: 0, bottom: 0, width: 44, background: C.panel,
94
+ borderLeft: '1px solid ' + C.border, display: 'flex', flexDirection: 'column',
95
+ alignItems: 'center', paddingTop: 12, gap: 10, zIndex: 9998
96
+ }
97
+ const panelStyle: CSSProperties = {
98
+ position: 'fixed', right: 0, top: 0, bottom: 0, width: 340, background: C.bg,
99
+ borderLeft: '1px solid ' + C.border, padding: 12, overflowY: 'auto', zIndex: 9998,
100
+ fontFamily: 'ui-sans-serif, system-ui, sans-serif', color: C.text, fontSize: 13
101
+ }
102
+
103
+ const toggle = h('button', {
104
+ style: { background: 'none', border: 'none', color: C.dim, fontSize: 18, cursor: 'pointer' },
105
+ onClick: () => setCollapsed(!collapsed),
106
+ }, collapsed ? '<' : '>')
107
+
108
+ const refreshBtn = h(Btn, { label: 'Refresh', onClick: load })
109
+
110
+ if (collapsed) {
111
+ return createPortal(h('div', { style: railStyle, 'data-dsh-righthand-panel': 'collapsed' },
112
+ toggle,
113
+ h('span', { style: { color: C.green, fontSize: 10, width: 8, height: 8, borderRadius: '50%', background: C.green } }),
114
+ h('span', { style: { color: C.dim, fontSize: 11, writingMode: 'vertical-rl', letterSpacing: '0.12em', userSelect: 'none' } }, 'Righthand'),
115
+ ), document.body)
116
+ }
117
+
118
+ return createPortal(h('div', { style: panelStyle, 'data-dsh-righthand-panel': 'expanded' },
119
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 } },
120
+ h('span', { style: { fontWeight: 600, letterSpacing: '0.05em' } }, 'Righthand'),
121
+ h('span', { style: { display: 'flex', gap: 6 } }, refreshBtn, toggle),
122
+ ),
123
+ error !== '' ? h('div', { style: { color: C.red, fontSize: 11, marginBottom: 8 } }, error) : null,
124
+
125
+ h(Section, { title: 'Settings' },
126
+ Object.entries(state.settings).map(([k, v]) => h(Row, { key: k, label: k, value: fmt(v, 90) })),
127
+ h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } },
128
+ h('input', {
129
+ value: patch, onChange: (e: any) => setPatch(e.target.value),
130
+ style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' },
131
+ }),
132
+ h(Btn, { label: 'Patch', onClick: () => {
133
+ try { const p = JSON.parse(patch); post('/righthand/settings/set', { patch: p }, load) }
134
+ catch { setError('patch must be JSON') }
135
+ } }),
136
+ ),
137
+ ),
138
+
139
+ h(Section, { title: 'Store (' + state.storeKeys.length + ')' },
140
+ state.storeKeys.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(empty)') : null,
141
+ state.storeKeys.map(k => h('div', { key: k, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },
142
+ h('span', { style: { flex: 1, fontFamily: 'monospace', fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, k),
143
+ h(Btn, { label: 'Delete', danger: true, onClick: () => post('/righthand/store/delete', { key: k }, load) }),
144
+ )),
145
+ h('div', { style: { display: 'flex', gap: 6, marginTop: 8 } },
146
+ h('input', { placeholder: 'key', value: newKey, onChange: (e: any) => setNewKey(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }),
147
+ h('input', { placeholder: 'json value', value: newValue, onChange: (e: any) => setNewValue(e.target.value), style: { flex: 1, background: C.row, color: C.text, border: '1px solid ' + C.border, borderRadius: 6, padding: '3px 8px', fontSize: 11, fontFamily: 'monospace' } }),
148
+ h(Btn, { label: 'Put', onClick: () => {
149
+ if (newKey === '') { setError('key required'); return }
150
+ try { const v = JSON.parse(newValue === '' ? 'null' : newValue); post('/righthand/store/put', { key: newKey, value: v }, () => { load(); setNewKey(''); setNewValue('') }) }
151
+ catch { setError('value must be JSON') }
152
+ } }),
153
+ ),
154
+ ),
155
+
156
+ h(Section, { title: 'Tasks (' + state.tasks.length + ')' },
157
+ state.tasks.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null,
158
+ state.tasks.map((t: any) => h('div', { key: t.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },
159
+ h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, (t.state === 'done' ? '[x] ' : t.state === 'failed' ? '[!] ' : '[ ] ') + t.title),
160
+ h(Btn, { label: 'Done', tone: C.green, onClick: () => post('/righthand/task/update', { id: t.id, state: 'done' }, load) }),
161
+ h(Btn, { label: 'Fail', danger: true, onClick: () => post('/righthand/task/update', { id: t.id, state: 'failed' }, load) }),
162
+ )),
163
+ ),
164
+
165
+ h(Section, { title: 'Events (' + state.events.length + ')' },
166
+ state.events.length === 0 ? h('div', { style: { color: C.dim, fontSize: 12 } }, '(none)') : null,
167
+ state.events.map((e: any) => h('div', { key: e.id, style: { display: 'flex', gap: 6, alignItems: 'center', padding: '2px 0' } },
168
+ h('span', { style: { flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, e.title + ' @ ' + e.at + ' [' + e.state + ']'),
169
+ e.state === 'pending' ? h(Btn, { label: 'Cancel', danger: true, onClick: () => post('/righthand/event/cancel', { id: e.id }, load) }) : null,
170
+ )),
171
+ ),
172
+ ), document.body)
173
+ }
174
+
175
+ /**
176
+ * Client plugin body: register the panel into the frame-wide overlay slot.
177
+ */
178
+ export function apply(ctx: ClientContext): void {
179
+ ctx.slots.inject('shell.overlay', () => ctx.slots.register({
180
+ name: 'shell.overlay',
181
+ id: 'righthand-panel',
182
+ order: 60,
183
+ }, RighthandPanel))
184
+ }
package/src/gui.ts ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * gui.ts - the righthand GUI host half: HTTP routes under /righthand/* on
3
+ * the DSH web server that read and mutate the same domains the tools use.
4
+ * The client half (src/client/index.ts) renders these as a panel inside the
5
+ * DSH Web GUI. Mounts only when a webServer exists (the Web surface);
6
+ * elsewhere the child fiber simply does not start.
7
+ */
8
+
9
+ import type { Context } from '@deepseek-ai/cordis'
10
+ import type { IncomingMessage, ServerResponse } from 'node:http'
11
+ import { settingsNamespace } from '@deepseek-ai/dsh-settings'
12
+ import { storeDomain } from './store-tools.ts'
13
+ import { taskDomain } from './task-tools.ts'
14
+ import { eventsDomain } from './events-tools.ts'
15
+ // Type-only: activates the cordis Context merge for ctx.webServer.
16
+ import type {} from '@deepseek-ai/dsh-host-webserver'
17
+
18
+ export const name = 'righthand-gui'
19
+ export const inject = ['webServer', 'storageDomain', 'settings']
20
+
21
+ const ns = settingsNamespace('righthand')
22
+
23
+ function json(res: ServerResponse, code: number, body: unknown): void {
24
+ const text = JSON.stringify(body)
25
+ res.writeHead(code, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' })
26
+ res.end(text)
27
+ }
28
+
29
+ function readBody(req: IncomingMessage): Promise<string> {
30
+ return new Promise((resolve, reject) => {
31
+ const chunks: Buffer[] = []
32
+ let bytes = 0
33
+ req.on('data', (c: Buffer) => {
34
+ bytes += c.length
35
+ if (bytes > 65536) { reject(new Error('body too large')); req.destroy() }
36
+ else chunks.push(c)
37
+ })
38
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
39
+ req.on('error', reject)
40
+ })
41
+ }
42
+
43
+ export function apply(ctx: Context): void {
44
+ let domains: { store: any; tasks: any; events: any } | undefined
45
+ let ready: Promise<void> | undefined
46
+
47
+ ctx.effect(() => {
48
+ ready = (async () => {
49
+ const [store, tasks, events] = await Promise.all([
50
+ ctx.storageDomain.open(storeDomain),
51
+ ctx.storageDomain.open(taskDomain),
52
+ ctx.storageDomain.open(eventsDomain),
53
+ ])
54
+ domains = { store, tasks, events }
55
+ })()
56
+ return () => { }
57
+ })
58
+
59
+ const ensure = async (): Promise<NonNullable<typeof domains>> => {
60
+ if (domains === undefined) { await ready }
61
+ if (domains === undefined) throw new Error('righthand domains not open')
62
+ return domains
63
+ }
64
+
65
+ const getSettings = () => {
66
+ const v = ctx.settings.get(ns) as Record<string, unknown> | undefined
67
+ return v ?? {}
68
+ }
69
+
70
+ const disposers: Array<() => void> = []
71
+ ctx.effect(() => () => { for (const d of disposers.splice(0)) d() })
72
+
73
+ const route = (path: string, handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>): void => {
74
+ disposers.push(ctx.webServer.register({ kind: 'exact', path, handler }))
75
+ }
76
+
77
+ route('/righthand/state', async (_req, res) => {
78
+ try {
79
+ const d = await ensure()
80
+ const storeKeys = [...d.store.table('rows').keys()]
81
+ const tasks = [...d.tasks.table('tasks').entries()]
82
+ const events = [...d.events.table('events').entries()]
83
+ json(res, 200, {
84
+ settings: getSettings(),
85
+ storeKeys,
86
+ tasks: tasks.map(([id, row]) => ({ id, ...row })),
87
+ events: events.map(([id, row]) => ({ id, ...row })),
88
+ })
89
+ } catch (e) {
90
+ json(res, 500, { error: String(e) })
91
+ }
92
+ })
93
+
94
+ route('/righthand/settings/set', async (req, res) => {
95
+ try {
96
+ const body = JSON.parse(await readBody(req))
97
+ await ctx.settings.update(ns, body.patch)
98
+ json(res, 200, { ok: true })
99
+ } catch (e) {
100
+ json(res, 400, { error: String(e) })
101
+ }
102
+ })
103
+
104
+ route('/righthand/store/put', async (req, res) => {
105
+ try {
106
+ const d = await ensure()
107
+ const body = JSON.parse(await readBody(req))
108
+ if (typeof body.key !== 'string' || body.key === '') throw new Error('key required')
109
+ await d.store.table('rows').put(body.key, { value: body.value ?? null, updatedAt: new Date().toISOString() })
110
+ const writes = d.store.global.get()
111
+ await d.store.global.set({ writes: writes.writes + 1 })
112
+ json(res, 200, { ok: true })
113
+ } catch (e) {
114
+ json(res, 400, { error: String(e) })
115
+ }
116
+ })
117
+
118
+ route('/righthand/store/delete', async (req, res) => {
119
+ try {
120
+ const d = await ensure()
121
+ const body = JSON.parse(await readBody(req))
122
+ const existed = await d.store.table('rows').delete(body.key)
123
+ json(res, 200, { ok: true, existed })
124
+ } catch (e) {
125
+ json(res, 400, { error: String(e) })
126
+ }
127
+ })
128
+
129
+ route('/righthand/task/update', async (req, res) => {
130
+ try {
131
+ const d = await ensure()
132
+ const body = JSON.parse(await readBody(req))
133
+ const row = await d.tasks.table('tasks').get(body.id)
134
+ if (row === undefined) { json(res, 404, { error: 'task not found' }); return }
135
+ const next: any = { ...row }
136
+ if (typeof body.state === 'string') next.state = body.state
137
+ if (body.result !== undefined) next.result = body.result
138
+ await d.tasks.table('tasks').put(body.id, next)
139
+ json(res, 200, { ok: true })
140
+ } catch (e) {
141
+ json(res, 400, { error: String(e) })
142
+ }
143
+ })
144
+
145
+ route('/righthand/event/cancel', async (req, res) => {
146
+ try {
147
+ const d = await ensure()
148
+ const body = JSON.parse(await readBody(req))
149
+ const row = await d.events.table('events').get(body.id)
150
+ if (row === undefined) { json(res, 404, { error: 'event not found' }); return }
151
+ await d.events.table('events').put(body.id, { ...row, state: 'cancelled' })
152
+ json(res, 200, { ok: true })
153
+ } catch (e) {
154
+ json(res, 400, { error: String(e) })
155
+ }
156
+ })
157
+ }
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@
25
25
  * - notify-tools: rh_notify_send over ntfy.sh (keyless)
26
26
  * - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
27
27
  * - guard-tools: tools/pre-execute policy (config.rules)
28
+ * - gui: /righthand/* web routes + the client panel (src/client)
28
29
  * - skills: the packaged dsh-righthand skill (ctx.skills)
29
30
  *
30
31
  * @module @try-works/dsh-righthand
@@ -42,6 +43,7 @@ import * as placesTools from './places-tools.ts'
42
43
  import * as filesTools from './files-tools.ts'
43
44
  import * as eventsTools from './events-tools.ts'
44
45
  import * as notifyTools from './notify-tools.ts'
46
+ import * as guiTools from './gui.ts'
45
47
  import * as righthandSkills from './skills.ts'
46
48
  import type { GuardRule } from './guard-tools.ts'
47
49
 
@@ -73,12 +75,13 @@ export function apply(ctx: Context, config: RighthandConfig = {}): void {
73
75
  ctx.plugin(filesTools)
74
76
  ctx.plugin(eventsTools)
75
77
  ctx.plugin(notifyTools)
78
+ ctx.plugin(guiTools)
76
79
  ctx.plugin(guardTools, { rules: config.rules ?? [] })
77
80
  ctx.plugin(righthandSkills)
78
81
  }
79
82
 
80
83
  // Individual modules stay importable for selective mounting.
81
- export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills }
84
+ export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, placesTools, filesTools, eventsTools, notifyTools, guiTools, guardTools, righthandSkills }
82
85
  export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from './skills.ts'
83
86
  export type { GuardRule } from './guard-tools.ts'
84
87
  export { guardFactsFor } from './guard-tools.ts'