@try-works/dsh-righthand 0.1.7 → 0.1.8
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 +8 -4
- package/lib/events-tools.d.ts +44 -0
- package/lib/events-tools.d.ts.map +1 -0
- package/lib/events-tools.js +219 -0
- package/lib/events-tools.js.map +1 -0
- package/lib/index.d.ts +11 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +12 -3
- package/lib/index.js.map +1 -1
- package/lib/notify-tools.d.ts +18 -0
- package/lib/notify-tools.d.ts.map +1 -0
- package/lib/notify-tools.js +52 -0
- package/lib/notify-tools.js.map +1 -0
- package/lib/secrets-tools.d.ts +2 -0
- package/lib/secrets-tools.d.ts.map +1 -1
- package/lib/secrets-tools.js +2 -1
- package/lib/secrets-tools.js.map +1 -1
- package/lib/weather-tools.d.ts +6 -0
- package/lib/weather-tools.d.ts.map +1 -1
- package/lib/weather-tools.js +1 -5
- package/lib/weather-tools.js.map +1 -1
- package/package.json +1 -1
- package/skills/dsh-righthand/SKILL.md +18 -3
- package/src/events-tools.ts +241 -0
- package/src/index.ts +13 -3
- package/src/notify-tools.ts +62 -0
- package/src/secrets-tools.ts +2 -1
- package/src/weather-tools.ts +8 -2
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ dsh --profile <profile> --patch ./cordis.patch.yml
|
|
|
29
29
|
| `rh_text_summarise` / `rh_text_extract` / `rh_text_classify` / `rh_text_translate` | text | `ctx.llm` (one model call per verb) |
|
|
30
30
|
| `rh_weather_forecast` / `rh_weather_air` | weather | Open-Meteo (keyless), every request through the SSRF-guarded fetcher |
|
|
31
31
|
| `rh_files_put` / `rh_files_get` / `rh_files_list` / `rh_files_share` / `rh_files_delete` | files | Cloudflare R2 (S3-compatible, SigV4-signed; credentials from `R2_ACCESS_KEY_ID` / `R2_SECRET_ACCESS_KEY`, bucket from settings) |
|
|
32
|
+
| `rh_events_create` / `rh_events_due` / `rh_events_list` / `rh_events_free` / `rh_events_cancel` | events | `ctx.storageDomain` (typed `righthand_events` domain; the agent is the scheduler — `rh_events_due` runs each turn) |
|
|
33
|
+
| `rh_notify_send` | notify | ntfy.sh (keyless — the topic name is the only secret) |
|
|
32
34
|
| `rh_credential_describe` / `rh_credential_set` / `rh_credential_unset` | secrets | `ctx.credentials` (values never echoed) |
|
|
33
35
|
| `rh_settings_get` / `rh_settings_set` | secrets | `ctx.settings` (namespace `righthand`) |
|
|
34
36
|
| `rh_run` | exec | `ctx.subprocess` (collect mode, bounded output) |
|
|
@@ -69,6 +71,7 @@ Namespace "righthand" (registered by the secrets family):
|
|
|
69
71
|
| `defaultScriptPrefix` | "rh-" | default name prefix for generated workers/scripts |
|
|
70
72
|
| `defaultZone` | "" | default Cloudflare zone |
|
|
71
73
|
| `defaultR2Bucket` | "" | default R2 bucket for `rh_files_*` |
|
|
74
|
+
| `defaultNotifyTopic` | "" | default ntfy topic for `rh_notify_send` |
|
|
72
75
|
|
|
73
76
|
`rh_settings_get` returns the resolved values; `rh_settings_set` merges a
|
|
74
77
|
partial patch (persisted by the harness settings provider).
|
|
@@ -144,10 +147,11 @@ so the agent cannot deploy or destroy without the gate.
|
|
|
144
147
|
|
|
145
148
|
## Service availability
|
|
146
149
|
|
|
147
|
-
The store and
|
|
148
|
-
provides (`storage` + `storage-json` + `storage-domain` rows). In a
|
|
149
|
-
without it — e.g. the headless bundle — those
|
|
150
|
-
|
|
150
|
+
The store, task and events families need `ctx.storageDomain`, which the web
|
|
151
|
+
profile provides (`storage` + `storage-json` + `storage-domain` rows). In a
|
|
152
|
+
profile without it — e.g. the headless bundle — those fourteen tools stay
|
|
153
|
+
dormant and the other nineteen tools (secrets, settings, exec, text, weather,
|
|
154
|
+
files, notify) still register; the plugin never fails the boot.
|
|
151
155
|
|
|
152
156
|
## Development
|
|
153
157
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* events-tools — rh_events_* over ctx.storageDomain.
|
|
3
|
+
* Reminders and the free-slot query. The agent IS the scheduler:
|
|
4
|
+
* rh_events_due is the check the agent runs each turn — an event whose
|
|
5
|
+
* time has come is returned once (pending → notified), so a missed run
|
|
6
|
+
* cannot go quiet without a record. Repeating events are one-off here;
|
|
7
|
+
* a real scheduler is the documented Cloudflare cron escalation.
|
|
8
|
+
* @module dsh-righthand/events-tools
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { Domain } from '@deepseek-ai/dsh-storage-domain';
|
|
12
|
+
export declare const name = "righthand-events";
|
|
13
|
+
export declare const inject: string[];
|
|
14
|
+
export interface Event {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
detail: string;
|
|
18
|
+
at: string;
|
|
19
|
+
state: 'pending' | 'notified' | 'cancelled';
|
|
20
|
+
createdAt: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const eventsDomain: {
|
|
23
|
+
name: string;
|
|
24
|
+
version: number;
|
|
25
|
+
tables: {
|
|
26
|
+
events: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
detail: string;
|
|
30
|
+
at: string;
|
|
31
|
+
state: "pending" | "notified" | "cancelled";
|
|
32
|
+
createdAt: string;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export type EventsDomain = Domain<typeof eventsDomain>;
|
|
37
|
+
/**
|
|
38
|
+
* Free slots: gaps of at least durationMinutes between pending events at or
|
|
39
|
+
* after now, within working hours 09:00–17:00, over the next horizonHours.
|
|
40
|
+
* Pure and exported for tests.
|
|
41
|
+
*/
|
|
42
|
+
export declare function freeSlots(events: readonly Event[], now: Date, durationMinutes: number, horizonHours?: number): string[];
|
|
43
|
+
export declare function apply(ctx: Context): void;
|
|
44
|
+
//# sourceMappingURL=events-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-tools.d.ts","sourceRoot":"","sources":["../src/events-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAA;AAG7D,eAAO,MAAM,IAAI,qBAAqB,CAAA;AACtC,eAAO,MAAM,MAAM,UAA6B,CAAA;AAEhD,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAavB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,YAAY,CAAC,CAAA;AAMtD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,SAAK,GAAG,MAAM,EAAE,CA6BnH;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAwJxC"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* events-tools — rh_events_* over ctx.storageDomain.
|
|
3
|
+
* Reminders and the free-slot query. The agent IS the scheduler:
|
|
4
|
+
* rh_events_due is the check the agent runs each turn — an event whose
|
|
5
|
+
* time has come is returned once (pending → notified), so a missed run
|
|
6
|
+
* cannot go quiet without a record. Repeating events are one-off here;
|
|
7
|
+
* a real scheduler is the documented Cloudflare cron escalation.
|
|
8
|
+
* @module dsh-righthand/events-tools
|
|
9
|
+
*/
|
|
10
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
11
|
+
import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
export const name = 'righthand-events';
|
|
14
|
+
export const inject = ['tools', 'storageDomain'];
|
|
15
|
+
export const eventsDomain = defineDomain({
|
|
16
|
+
name: 'righthand_events',
|
|
17
|
+
version: 1,
|
|
18
|
+
tables: {
|
|
19
|
+
events: domainTable(z.object({
|
|
20
|
+
id: z.string(),
|
|
21
|
+
title: z.string(),
|
|
22
|
+
detail: z.string(),
|
|
23
|
+
at: z.string(),
|
|
24
|
+
state: z.enum(['pending', 'notified', 'cancelled']),
|
|
25
|
+
createdAt: z.string(),
|
|
26
|
+
})),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
function newId() {
|
|
30
|
+
return 'e-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 6);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Free slots: gaps of at least durationMinutes between pending events at or
|
|
34
|
+
* after now, within working hours 09:00–17:00, over the next horizonHours.
|
|
35
|
+
* Pure and exported for tests.
|
|
36
|
+
*/
|
|
37
|
+
export function freeSlots(events, now, durationMinutes, horizonHours = 24) {
|
|
38
|
+
const horizonEnd = now.getTime() + horizonHours * 3600000;
|
|
39
|
+
const busy = events
|
|
40
|
+
.filter(e => e.state === 'pending')
|
|
41
|
+
.map(e => new Date(e.at).getTime())
|
|
42
|
+
.filter(t => Number.isFinite(t) && t >= now.getTime() && t <= horizonEnd)
|
|
43
|
+
.sort((a, b) => a - b);
|
|
44
|
+
const slots = [];
|
|
45
|
+
let cursor = now.getTime();
|
|
46
|
+
const dayStart = (t) => {
|
|
47
|
+
const d = new Date(t);
|
|
48
|
+
d.setHours(9, 0, 0, 0);
|
|
49
|
+
return d.getTime();
|
|
50
|
+
};
|
|
51
|
+
const dayEnd = (t) => {
|
|
52
|
+
const d = new Date(t);
|
|
53
|
+
d.setHours(17, 0, 0, 0);
|
|
54
|
+
return d.getTime();
|
|
55
|
+
};
|
|
56
|
+
const need = durationMinutes * 60000;
|
|
57
|
+
for (const b of busy) {
|
|
58
|
+
let from = Math.max(cursor, dayStart(cursor));
|
|
59
|
+
if (from < b && b - from >= need && from + need <= dayEnd(from) && from + need <= horizonEnd) {
|
|
60
|
+
slots.push(new Date(from).toISOString());
|
|
61
|
+
}
|
|
62
|
+
cursor = Math.max(b, dayEnd(cursor) + 1);
|
|
63
|
+
if (cursor > horizonEnd)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
return slots;
|
|
67
|
+
}
|
|
68
|
+
export function apply(ctx) {
|
|
69
|
+
let domain;
|
|
70
|
+
let ready;
|
|
71
|
+
ctx.effect(() => {
|
|
72
|
+
ready = (async () => {
|
|
73
|
+
domain = await ctx.storageDomain.open(eventsDomain);
|
|
74
|
+
})();
|
|
75
|
+
return () => { };
|
|
76
|
+
});
|
|
77
|
+
const ensure = async () => {
|
|
78
|
+
if (domain === undefined) {
|
|
79
|
+
await ready;
|
|
80
|
+
}
|
|
81
|
+
if (domain === undefined)
|
|
82
|
+
throw new Error('righthand events are not open (storageDomain not mounted)');
|
|
83
|
+
return domain;
|
|
84
|
+
};
|
|
85
|
+
const all = async () => {
|
|
86
|
+
const d = await ensure();
|
|
87
|
+
return [...d.table('events').entries()].map(([, e]) => e);
|
|
88
|
+
};
|
|
89
|
+
ctx.tools.register(defineTool({
|
|
90
|
+
name: 'rh_events_create',
|
|
91
|
+
description: 'Schedule a reminder at an ISO datetime. One-off: the agent checks rh_events_due each turn and the event is delivered exactly once (pending to notified), so a missed run is never silently dropped.',
|
|
92
|
+
parameters: {
|
|
93
|
+
title: { type: 'string', required: true, description: 'What to be reminded of.' },
|
|
94
|
+
at: { type: 'string', required: true, description: 'ISO datetime when it is due, e.g. 2026-08-31T09:00:00Z.' },
|
|
95
|
+
detail: { type: 'string', description: 'Optional longer note.' },
|
|
96
|
+
},
|
|
97
|
+
output: {
|
|
98
|
+
schema: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
additionalProperties: false,
|
|
101
|
+
properties: {
|
|
102
|
+
id: { type: 'string', required: true },
|
|
103
|
+
title: { type: 'string', required: true },
|
|
104
|
+
at: { type: 'string', required: true },
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
render: (_args, value) => [{ type: 'text', text: 'event ' + value.id + ': ' + value.title + ' at ' + value.at }],
|
|
108
|
+
},
|
|
109
|
+
async execute(args) {
|
|
110
|
+
const d = await ensure();
|
|
111
|
+
const at = new Date(args.at);
|
|
112
|
+
if (Number.isNaN(at.getTime()))
|
|
113
|
+
throw new Error('at must be a valid ISO datetime');
|
|
114
|
+
const event = {
|
|
115
|
+
id: newId(),
|
|
116
|
+
title: args.title.trim(),
|
|
117
|
+
detail: args.detail ?? '',
|
|
118
|
+
at: at.toISOString(),
|
|
119
|
+
state: 'pending',
|
|
120
|
+
createdAt: new Date().toISOString(),
|
|
121
|
+
};
|
|
122
|
+
if (event.title === '')
|
|
123
|
+
throw new Error('an event needs a title');
|
|
124
|
+
await d.table('events').put(event.id, event);
|
|
125
|
+
return { id: event.id, title: event.title, at: event.at };
|
|
126
|
+
},
|
|
127
|
+
}));
|
|
128
|
+
ctx.tools.register(defineTool({
|
|
129
|
+
name: 'rh_events_due',
|
|
130
|
+
description: 'The pending events whose time has come (at <= now). Each is delivered exactly once: returned events are marked notified. This is the check to run every turn — the agent is the scheduler.',
|
|
131
|
+
parameters: {},
|
|
132
|
+
output: {
|
|
133
|
+
schema: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
additionalProperties: false,
|
|
136
|
+
properties: {
|
|
137
|
+
due: { type: 'array', required: true, items: { type: 'json' } },
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
render: (_args, value) => [{ type: 'text', text: value.due.length === 0 ? '(nothing due)' : value.due.map((e) => e.title + ' at ' + e.at).join(' / ') }],
|
|
141
|
+
},
|
|
142
|
+
async execute() {
|
|
143
|
+
const d = await ensure();
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
const due = [];
|
|
146
|
+
for (const e of [...d.table('events').entries()].map(([, v]) => v)) {
|
|
147
|
+
if (e.state === 'pending' && new Date(e.at).getTime() <= now) {
|
|
148
|
+
const notified = { ...e, state: 'notified' };
|
|
149
|
+
await d.table('events').put(e.id, notified);
|
|
150
|
+
due.push(notified);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
due.sort((a, b) => a.at.localeCompare(b.at));
|
|
154
|
+
return { due: due.map(e => ({ id: e.id, title: e.title, detail: e.detail, at: e.at })) };
|
|
155
|
+
},
|
|
156
|
+
}));
|
|
157
|
+
ctx.tools.register(defineTool({
|
|
158
|
+
name: 'rh_events_list',
|
|
159
|
+
description: 'List events: upcoming pending ones first, then notified and cancelled.',
|
|
160
|
+
parameters: {
|
|
161
|
+
state: { type: 'string', description: 'Filter: pending | notified | cancelled. Omit for all.' },
|
|
162
|
+
},
|
|
163
|
+
output: {
|
|
164
|
+
schema: { type: 'array', items: { type: 'json' } },
|
|
165
|
+
render: (_args, value) => [{ type: 'text', text: value.length === 0 ? '(no events)' : value.map((e) => e.at + ' ' + e.title + ' [' + e.state + ']').join(' / ') }],
|
|
166
|
+
},
|
|
167
|
+
async execute(args) {
|
|
168
|
+
const events = await all();
|
|
169
|
+
const wanted = args.state ?? null;
|
|
170
|
+
const filtered = wanted ? events.filter(e => e.state === wanted) : events;
|
|
171
|
+
const rank = { pending: 0, notified: 1, cancelled: 2 };
|
|
172
|
+
filtered.sort((a, b) => (rank[a.state] - rank[b.state]) || a.at.localeCompare(b.at));
|
|
173
|
+
return filtered.map(e => ({ id: e.id, title: e.title, detail: e.detail, at: e.at, state: e.state }));
|
|
174
|
+
},
|
|
175
|
+
}));
|
|
176
|
+
ctx.tools.register(defineTool({
|
|
177
|
+
name: 'rh_events_free',
|
|
178
|
+
description: 'When is there nothing booked: the next free slots of at least durationMinutes within working hours (09:00-17:00) over the next horizonHours.',
|
|
179
|
+
parameters: {
|
|
180
|
+
durationMinutes: { type: 'integer', required: true, description: 'How long the free block must be.' },
|
|
181
|
+
horizonHours: { type: 'integer', description: 'How far ahead to look (default 24).' },
|
|
182
|
+
},
|
|
183
|
+
output: {
|
|
184
|
+
schema: { type: 'array', items: { type: 'string' } },
|
|
185
|
+
render: (_args, value) => [{ type: 'text', text: value.length === 0 ? '(no free slot)' : value.join(' / ') }],
|
|
186
|
+
},
|
|
187
|
+
async execute(args) {
|
|
188
|
+
const events = await all();
|
|
189
|
+
return freeSlots(events, new Date(), args.durationMinutes, args.horizonHours ?? 24);
|
|
190
|
+
},
|
|
191
|
+
}));
|
|
192
|
+
ctx.tools.register(defineTool({
|
|
193
|
+
name: 'rh_events_cancel',
|
|
194
|
+
description: 'Cancel an event by id. Returns whether it existed. Cancelled events stay in the record — a cancellation is news too.',
|
|
195
|
+
parameters: {
|
|
196
|
+
id: { type: 'string', required: true, description: 'The event id.' },
|
|
197
|
+
},
|
|
198
|
+
output: {
|
|
199
|
+
schema: {
|
|
200
|
+
type: 'object',
|
|
201
|
+
additionalProperties: false,
|
|
202
|
+
properties: {
|
|
203
|
+
id: { type: 'string', required: true },
|
|
204
|
+
existed: { type: 'boolean', required: true },
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
render: (_args, value) => [{ type: 'text', text: 'cancelled ' + value.id + ': ' + value.existed }],
|
|
208
|
+
},
|
|
209
|
+
async execute(args) {
|
|
210
|
+
const d = await ensure();
|
|
211
|
+
const e = d.table('events').get(args.id);
|
|
212
|
+
if (e === undefined)
|
|
213
|
+
return { id: args.id, existed: false };
|
|
214
|
+
await d.table('events').put(args.id, { ...e, state: 'cancelled' });
|
|
215
|
+
return { id: args.id, existed: true };
|
|
216
|
+
},
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=events-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-tools.js","sourceRoot":"","sources":["../src/events-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAE3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,CAAA;AACtC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;AAWhD,MAAM,CAAC,MAAM,YAAY,GAAG,YAAY,CAAC;IACvC,IAAI,EAAE,kBAAkB;IACxB,OAAO,EAAE,CAAC;IACV,MAAM,EAAE;QACN,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;YAC3B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;YACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;YACjB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;YAClB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;YACd,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;YACnD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;SACtB,CAAC,CAAC;KACJ;CACF,CAAC,CAAA;AAIF,SAAS,KAAK;IACZ,OAAO,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACtF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAAwB,EAAE,GAAS,EAAE,eAAuB,EAAE,YAAY,GAAG,EAAE;IACvG,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,YAAY,GAAG,OAAO,CAAA;IACzD,MAAM,IAAI,GAAG,MAAM;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC;SAClC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,UAAU,CAAC;SACxE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxB,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1B,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE;QACrC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACrB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACtB,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;IACpB,CAAC,CAAA;IACD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE;QACnC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACrB,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACvB,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;IACpB,CAAC,CAAA;IACD,MAAM,IAAI,GAAG,eAAe,GAAG,KAAK,CAAA;IACpC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAC7C,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC;YAC7F,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;QAC1C,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACxC,IAAI,MAAM,GAAG,UAAU;YAAE,MAAK;IAChC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAY;IAChC,IAAI,MAAgC,CAAA;IACpC,IAAI,KAAgC,CAAA;IAEpC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE;QACd,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE;YAClB,MAAM,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACrD,CAAC,CAAC,EAAE,CAAA;QACJ,OAAO,GAAG,EAAE,GAAyC,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,KAAK,IAA2B,EAAE;QAC/C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAAC,MAAM,KAAK,CAAC;QAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;QACtG,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,GAAG,GAAG,KAAK,IAAsB,EAAE;QACvC,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QACxB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3D,CAAC,CAAA;IAED,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,qMAAqM;QAClN,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,yBAAyB,EAAE;YACjF,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,yDAAyD,EAAE;YAC9G,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uBAAuB,EAAE;SACjE;QACD,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACtC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;iBACvC;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC,EAAE,EAAE,CAAC;SACjH;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;YACxB,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC5B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;YAClF,MAAM,KAAK,GAAU;gBACnB,EAAE,EAAE,KAAK,EAAE;gBACX,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;gBACzB,EAAE,EAAE,EAAE,CAAC,WAAW,EAAE;gBACpB,KAAK,EAAE,SAAS;gBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAA;YACD,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;YACjE,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;YAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAA;QAC3D,CAAC;KACF,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,4LAA4L;QACzM,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;iBAChE;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;SAC9J;QACD,KAAK,CAAC,OAAO;YACX,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,MAAM,GAAG,GAAY,EAAE,CAAA;YACvB,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,GAAG,EAAE,CAAC;oBAC7D,MAAM,QAAQ,GAAU,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;oBACnD,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;oBAC3C,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;gBACpB,CAAC;YACH,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAC5C,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAU,EAAE,CAAA;QACnG,CAAC;KACF,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,wEAAwE;QACrF,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uDAAuD,EAAE;SAChG;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YAClD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAE,KAAe,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;SACnL;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAA;YAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAA;YACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;YACzE,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAA4B,CAAA;YAChF,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACpF,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAU,CAAA;QAC/G,CAAC;KACF,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,8IAA8I;QAC3J,UAAU,EAAE;YACV,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kCAAkC,EAAE;YACrG,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,qCAAqC,EAAE;SACtF;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACpD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAE,KAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;SAC5H;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAA;YAC1B,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;QACrF,CAAC;KACF,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,sHAAsH;QACnI,UAAU,EAAE;YACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE;SACrE;QACD,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACtC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;iBAC7C;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;SACnG;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;YACxB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACxC,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;YAC3D,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;YAClE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACvC,CAAC;KACF,CAAC,CAAC,CAAA;AACL,CAAC"}
|
package/lib/index.d.ts
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* The package's plugin entry (name/inject/apply) mounts the tool families
|
|
9
9
|
* and the packaged skill as child fibers; each child waits on its own
|
|
10
10
|
* services, so a
|
|
11
|
-
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
-
*
|
|
11
|
+
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
+
* store/task/events families dormant and the other nineteen tools
|
|
13
|
+
* (secrets, settings, exec, text, weather, files, notify) instead of
|
|
14
|
+
* failing the boot.
|
|
13
15
|
*
|
|
14
16
|
* Modules (each individually mountable via `export * as ...`):
|
|
15
17
|
* - store-tools: rh_store_put/get/delete/list over ctx.storageDomain
|
|
@@ -18,6 +20,8 @@
|
|
|
18
20
|
* - text-tools: rh_text_summarise/extract/classify/translate over ctx.llm
|
|
19
21
|
* - weather-tools: rh_weather_forecast/air over Open-Meteo (keyless, SSRF-guarded)
|
|
20
22
|
* - files-tools: rh_files_put/get/list/share/delete over Cloudflare R2
|
|
23
|
+
* - events-tools: rh_events_create/due/list/free/cancel over ctx.storageDomain
|
|
24
|
+
* - notify-tools: rh_notify_send over ntfy.sh (keyless)
|
|
21
25
|
* - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
|
|
22
26
|
* - guard-tools: tools/pre-execute policy (config.rules)
|
|
23
27
|
* - skills: the packaged dsh-righthand skill (ctx.skills)
|
|
@@ -33,6 +37,8 @@ import * as taskTools from './task-tools.ts';
|
|
|
33
37
|
import * as textTools from './text-tools.ts';
|
|
34
38
|
import * as weatherTools from './weather-tools.ts';
|
|
35
39
|
import * as filesTools from './files-tools.ts';
|
|
40
|
+
import * as eventsTools from './events-tools.ts';
|
|
41
|
+
import * as notifyTools from './notify-tools.ts';
|
|
36
42
|
import * as righthandSkills from './skills.ts';
|
|
37
43
|
import type { GuardRule } from './guard-tools.ts';
|
|
38
44
|
export declare const name = "dsh-righthand";
|
|
@@ -50,7 +56,7 @@ export interface RighthandConfig {
|
|
|
50
56
|
* instead of failing the whole plugin.
|
|
51
57
|
*/
|
|
52
58
|
export declare function apply(ctx: Context, config?: RighthandConfig): void;
|
|
53
|
-
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, guardTools, righthandSkills };
|
|
59
|
+
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills };
|
|
54
60
|
export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from './skills.ts';
|
|
55
61
|
export type { GuardRule } from './guard-tools.ts';
|
|
56
62
|
export { guardFactsFor } from './guard-tools.ts';
|
|
@@ -58,6 +64,8 @@ export type { GuardFacts } from './guard-tools.ts';
|
|
|
58
64
|
export { isBlockedIP, guardedFetch, normalizeForecast, normalizeAir } from './weather-tools.ts';
|
|
59
65
|
export { createR2Client, R2_ACCESS_KEY_REF, R2_SECRET_KEY_REF } from './files-tools.ts';
|
|
60
66
|
export { signRequest, presignGet } from './sigv4.ts';
|
|
67
|
+
export { freeSlots } from './events-tools.ts';
|
|
68
|
+
export type { Event } from './events-tools.ts';
|
|
61
69
|
export type { R2Options, ListEntry } from './files-tools.ts';
|
|
62
70
|
export type { WeatherConfig, ForecastOut, AirOut } from './weather-tools.ts';
|
|
63
71
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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,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,CAYtE;AAGD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AACrJ,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,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"}
|
package/lib/index.js
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* The package's plugin entry (name/inject/apply) mounts the tool families
|
|
9
9
|
* and the packaged skill as child fibers; each child waits on its own
|
|
10
10
|
* services, so a
|
|
11
|
-
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
-
*
|
|
11
|
+
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
+
* store/task/events families dormant and the other nineteen tools
|
|
13
|
+
* (secrets, settings, exec, text, weather, files, notify) instead of
|
|
14
|
+
* failing the boot.
|
|
13
15
|
*
|
|
14
16
|
* Modules (each individually mountable via `export * as ...`):
|
|
15
17
|
* - store-tools: rh_store_put/get/delete/list over ctx.storageDomain
|
|
@@ -18,6 +20,8 @@
|
|
|
18
20
|
* - text-tools: rh_text_summarise/extract/classify/translate over ctx.llm
|
|
19
21
|
* - weather-tools: rh_weather_forecast/air over Open-Meteo (keyless, SSRF-guarded)
|
|
20
22
|
* - files-tools: rh_files_put/get/list/share/delete over Cloudflare R2
|
|
23
|
+
* - events-tools: rh_events_create/due/list/free/cancel over ctx.storageDomain
|
|
24
|
+
* - notify-tools: rh_notify_send over ntfy.sh (keyless)
|
|
21
25
|
* - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
|
|
22
26
|
* - guard-tools: tools/pre-execute policy (config.rules)
|
|
23
27
|
* - skills: the packaged dsh-righthand skill (ctx.skills)
|
|
@@ -32,6 +36,8 @@ import * as taskTools from "./task-tools.js";
|
|
|
32
36
|
import * as textTools from "./text-tools.js";
|
|
33
37
|
import * as weatherTools from "./weather-tools.js";
|
|
34
38
|
import * as filesTools from "./files-tools.js";
|
|
39
|
+
import * as eventsTools from "./events-tools.js";
|
|
40
|
+
import * as notifyTools from "./notify-tools.js";
|
|
35
41
|
import * as righthandSkills from "./skills.js";
|
|
36
42
|
export const name = 'dsh-righthand';
|
|
37
43
|
/** The combined plugin needs no services itself; each child waits on its own. */
|
|
@@ -50,14 +56,17 @@ export function apply(ctx, config = {}) {
|
|
|
50
56
|
ctx.plugin(textTools);
|
|
51
57
|
ctx.plugin(weatherTools);
|
|
52
58
|
ctx.plugin(filesTools);
|
|
59
|
+
ctx.plugin(eventsTools);
|
|
60
|
+
ctx.plugin(notifyTools);
|
|
53
61
|
ctx.plugin(guardTools, { rules: config.rules ?? [] });
|
|
54
62
|
ctx.plugin(righthandSkills);
|
|
55
63
|
}
|
|
56
64
|
// Individual modules stay importable for selective mounting.
|
|
57
|
-
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, guardTools, righthandSkills };
|
|
65
|
+
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills };
|
|
58
66
|
export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from "./skills.js";
|
|
59
67
|
export { guardFactsFor } from "./guard-tools.js";
|
|
60
68
|
export { isBlockedIP, guardedFetch, normalizeForecast, normalizeAir } from "./weather-tools.js";
|
|
61
69
|
export { createR2Client, R2_ACCESS_KEY_REF, R2_SECRET_KEY_REF } from "./files-tools.js";
|
|
62
70
|
export { signRequest, presignGet } from "./sigv4.js";
|
|
71
|
+
export { freeSlots } from "./events-tools.js";
|
|
63
72
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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,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,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,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AACrJ,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,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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notify-tools — rh_notify_send over ntfy.sh (keyless).
|
|
3
|
+
* Interrupt yourself on your own devices: publish to a topic; any phone
|
|
4
|
+
* subscribed to that topic gets it. The topic name is the only secret —
|
|
5
|
+
* choose one nobody can guess, like the digest of a random string.
|
|
6
|
+
* @module dsh-righthand/notify-tools
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
export declare const name = "righthand-notify";
|
|
10
|
+
export declare const inject: string[];
|
|
11
|
+
export interface NotifyConfig {
|
|
12
|
+
/** ntfy server base URL; default https://ntfy.sh (keyless publish). */
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
/** Topic to publish to; defaults to the righthand settings defaultNotifyTopic. */
|
|
15
|
+
topic?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function apply(ctx: Context, config?: NotifyConfig): void;
|
|
18
|
+
//# sourceMappingURL=notify-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify-tools.d.ts","sourceRoot":"","sources":["../src/notify-tools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,eAAO,MAAM,IAAI,qBAAqB,CAAA;AACtC,eAAO,MAAM,MAAM,UAAwB,CAAA;AAE3C,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,YAAiB,GAAG,IAAI,CAqCnE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notify-tools — rh_notify_send over ntfy.sh (keyless).
|
|
3
|
+
* Interrupt yourself on your own devices: publish to a topic; any phone
|
|
4
|
+
* subscribed to that topic gets it. The topic name is the only secret —
|
|
5
|
+
* choose one nobody can guess, like the digest of a random string.
|
|
6
|
+
* @module dsh-righthand/notify-tools
|
|
7
|
+
*/
|
|
8
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
9
|
+
import { settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
10
|
+
import { guardedFetch } from "./weather-tools.js";
|
|
11
|
+
export const name = 'righthand-notify';
|
|
12
|
+
export const inject = ['tools', 'settings'];
|
|
13
|
+
export function apply(ctx, config = {}) {
|
|
14
|
+
const ns = settingsNamespace('righthand');
|
|
15
|
+
const baseUrl = config.baseUrl ?? 'https://ntfy.sh';
|
|
16
|
+
ctx.tools.register(defineTool({
|
|
17
|
+
name: 'rh_notify_send',
|
|
18
|
+
description: 'Interrupt yourself on your own devices: publish a notification to a ntfy.sh topic (keyless). Any device subscribed to that topic receives it. The topic name is the only secret — use an unguessable one. Defaults: priority 1 and auto-delete after 24h.',
|
|
19
|
+
parameters: {
|
|
20
|
+
message: { type: 'string', required: true, description: 'The notification body.' },
|
|
21
|
+
title: { type: 'string', description: 'Notification title.' },
|
|
22
|
+
topic: { type: 'string', description: 'Topic to publish to; defaults to the settings defaultNotifyTopic.' },
|
|
23
|
+
priority: { type: 'integer', description: '1 (low/default) to 5 (urgent). Default 1.' },
|
|
24
|
+
},
|
|
25
|
+
output: {
|
|
26
|
+
schema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
properties: {
|
|
30
|
+
topic: { type: 'string', required: true },
|
|
31
|
+
sent: { type: 'boolean', required: true },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
render: (_args, value) => [{ type: 'text', text: 'notified ' + value.topic }],
|
|
35
|
+
},
|
|
36
|
+
async execute(args) {
|
|
37
|
+
const settings = ctx.settings.get(ns);
|
|
38
|
+
const topic = args.topic ?? config.topic ?? settings?.defaultNotifyTopic ?? '';
|
|
39
|
+
if (topic === '')
|
|
40
|
+
throw new Error('notify topic is not set (arg, plugin config, or settings defaultNotifyTopic)');
|
|
41
|
+
const priority = Math.min(Math.max(args.priority ?? 1, 1), 5);
|
|
42
|
+
const headers = { 'Priority': String(priority), 'X-TTL': '24h' };
|
|
43
|
+
if (args.title !== undefined)
|
|
44
|
+
headers['Title'] = args.title;
|
|
45
|
+
await guardedFetch(baseUrl + '/' + encodeURIComponent(topic), {
|
|
46
|
+
init: { method: 'POST', body: args.message, headers },
|
|
47
|
+
});
|
|
48
|
+
return { topic, sent: true };
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=notify-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify-tools.js","sourceRoot":"","sources":["../src/notify-tools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,CAAA;AACtC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;AAS3C,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,SAAuB,EAAE;IAC3D,MAAM,EAAE,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,iBAAiB,CAAA;IAEnD,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,2PAA2P;QACxQ,UAAU,EAAE;YACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wBAAwB,EAAE;YAClF,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;YAC7D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mEAAmE,EAAE;YAC3G,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,2CAA2C,EAAE;SACxF;QACD,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;iBAC1C;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;SAC9E;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAgD,CAAA;YACpF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,QAAQ,EAAE,kBAAkB,IAAI,EAAE,CAAA;YAC9E,IAAI,KAAK,KAAK,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAA;YACjH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAC7D,MAAM,OAAO,GAA2B,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;YACxF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;YAC3D,MAAM,YAAY,CAAC,OAAO,GAAG,GAAG,GAAG,kBAAkB,CAAC,KAAK,CAAC,EAAE;gBAC5D,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE;aACtD,CAAC,CAAA;YACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;QAC9B,CAAC;KACF,CAAC,CAAC,CAAA;AACL,CAAC"}
|
package/lib/secrets-tools.d.ts
CHANGED
|
@@ -21,11 +21,13 @@ export declare const righthandSettingsSchema: z<Schemastery.ObjectS<{
|
|
|
21
21
|
defaultScriptPrefix: z<string, string>;
|
|
22
22
|
defaultZone: z<string, string>;
|
|
23
23
|
defaultR2Bucket: z<string, string>;
|
|
24
|
+
defaultNotifyTopic: z<string, string>;
|
|
24
25
|
}>, Schemastery.ObjectT<{
|
|
25
26
|
accountId: z<string, string>;
|
|
26
27
|
defaultScriptPrefix: z<string, string>;
|
|
27
28
|
defaultZone: z<string, string>;
|
|
28
29
|
defaultR2Bucket: z<string, string>;
|
|
30
|
+
defaultNotifyTopic: z<string, string>;
|
|
29
31
|
}>>;
|
|
30
32
|
/** Register the settings namespace + the secret/credential tools. */
|
|
31
33
|
export declare function apply(ctx: Context): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets-tools.d.ts","sourceRoot":"","sources":["../src/secrets-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,sBAAsB,CAAA;AACvC,eAAO,MAAM,MAAM,UAAuC,CAAA;AAE1D,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,uBAAuB
|
|
1
|
+
{"version":3,"file":"secrets-tools.d.ts","sourceRoot":"","sources":["../src/secrets-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,sBAAsB,CAAA;AACvC,eAAO,MAAM,MAAM,UAAuC,CAAA;AAE1D,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,uBAAuB;;;;;;;;;;;;GAMlC,CAAA;AAEF,qEAAqE;AACrE,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkHxC"}
|
package/lib/secrets-tools.js
CHANGED
|
@@ -17,6 +17,7 @@ export const righthandSettingsSchema = z.object({
|
|
|
17
17
|
defaultScriptPrefix: z.string().default('rh-'),
|
|
18
18
|
defaultZone: z.string().default(''),
|
|
19
19
|
defaultR2Bucket: z.string().default(''),
|
|
20
|
+
defaultNotifyTopic: z.string().default(''),
|
|
20
21
|
});
|
|
21
22
|
/** Register the settings namespace + the secret/credential tools. */
|
|
22
23
|
export function apply(ctx) {
|
|
@@ -105,7 +106,7 @@ export function apply(ctx) {
|
|
|
105
106
|
},
|
|
106
107
|
async execute() {
|
|
107
108
|
const v = scope.get();
|
|
108
|
-
return { accountId: v.accountId, defaultScriptPrefix: v.defaultScriptPrefix, defaultZone: v.defaultZone, defaultR2Bucket: v.defaultR2Bucket };
|
|
109
|
+
return { accountId: v.accountId, defaultScriptPrefix: v.defaultScriptPrefix, defaultZone: v.defaultZone, defaultR2Bucket: v.defaultR2Bucket, defaultNotifyTopic: v.defaultNotifyTopic };
|
|
109
110
|
},
|
|
110
111
|
}));
|
|
111
112
|
ctx.tools.register(defineTool({
|
package/lib/secrets-tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets-tools.js","sourceRoot":"","sources":["../src/secrets-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAA;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,CAAA;AAS1D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACjC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC9C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"secrets-tools.js","sourceRoot":"","sources":["../src/secrets-tools.ts"],"names":[],"mappings":"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"}
|
package/lib/weather-tools.d.ts
CHANGED
|
@@ -28,9 +28,15 @@ export declare function isBlockedIP(ip: string): boolean;
|
|
|
28
28
|
* Fetch one URL with the SSRF checklist. `fetchImpl` and `resolve` are
|
|
29
29
|
* injectable for tests; production uses the globals.
|
|
30
30
|
*/
|
|
31
|
+
export interface GuardedFetchInit {
|
|
32
|
+
method?: string;
|
|
33
|
+
body?: string;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
}
|
|
31
36
|
export declare function guardedFetch(url: string, deps?: {
|
|
32
37
|
fetchImpl?: typeof fetch;
|
|
33
38
|
resolve?: (host: string) => Promise<string[]>;
|
|
39
|
+
init?: GuardedFetchInit;
|
|
34
40
|
}): Promise<string>;
|
|
35
41
|
/**
|
|
36
42
|
* Normalize the Open-Meteo forecast response into a stable digest shape:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weather-tools.d.ts","sourceRoot":"","sources":["../src/weather-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,eAAO,MAAM,IAAI,sBAAsB,CAAA;AACvC,eAAO,MAAM,MAAM,UAAY,CAAA;AAE/B,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAWD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAoB/C;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CAAO,
|
|
1
|
+
{"version":3,"file":"weather-tools.d.ts","sourceRoot":"","sources":["../src/weather-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,eAAO,MAAM,IAAI,sBAAsB,CAAA;AACvC,eAAO,MAAM,MAAM,UAAY,CAAA;AAE/B,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAWD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAoB/C;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,gBAAgB,CAAA;CAAO,GAC9G,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACpH,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAC9E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,GAAG,WAAW,CAmBxD;AAED,qDAAqD;AACrD,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAW9C;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,aAAkB,GAAG,IAAI,CAyEpE"}
|
package/lib/weather-tools.js
CHANGED
|
@@ -58,10 +58,6 @@ export function isBlockedIP(ip) {
|
|
|
58
58
|
}
|
|
59
59
|
return true;
|
|
60
60
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Fetch one URL with the SSRF checklist. `fetchImpl` and `resolve` are
|
|
63
|
-
* injectable for tests; production uses the globals.
|
|
64
|
-
*/
|
|
65
61
|
export async function guardedFetch(url, deps = {}) {
|
|
66
62
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67
63
|
const resolve = deps.resolve ?? (async (host) => (await lookup(host, { all: true })).map(a => a.address));
|
|
@@ -73,7 +69,7 @@ export async function guardedFetch(url, deps = {}) {
|
|
|
73
69
|
const ips = await resolve(parsed.hostname);
|
|
74
70
|
if (ips.length === 0 || ips.some(isBlockedIP))
|
|
75
71
|
throw new Error('blocked: destination is not a public host');
|
|
76
|
-
const res = await fetchImpl(current, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), redirect: 'manual' });
|
|
72
|
+
const res = await fetchImpl(current, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), redirect: 'manual', method: deps.init?.method ?? 'GET', body: deps.init?.body, headers: deps.init?.headers });
|
|
77
73
|
if (res.status >= 300 && res.status < 400) {
|
|
78
74
|
const next = res.headers.get('location');
|
|
79
75
|
if (next === null)
|
package/lib/weather-tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weather-tools.js","sourceRoot":"","sources":["../src/weather-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAA;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,CAAA;AAQ/B,MAAM,QAAQ,GAA4B;IACxC,WAAW,EAAE,wCAAwC;IACrD,MAAM,EAAE,uDAAuD;CAChE,CAAA;AAED,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;AACtC,MAAM,aAAa,GAAG,CAAC,CAAA;AACvB,MAAM,gBAAgB,GAAG,KAAK,CAAA;AAE9B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IAC1B,IAAI,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACxC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,IAAI,CAAA;QAChD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,IAAI,CAAA;QACrC,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;QAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK;YAAE,OAAO,IAAI,CAAA;QAClD,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACjE,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACzH,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACvC,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;
|
|
1
|
+
{"version":3,"file":"weather-tools.js","sourceRoot":"","sources":["../src/weather-tools.ts"],"names":[],"mappings":"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"}
|
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.
|
|
4
|
+
"version": "0.1.8",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dsh-righthand
|
|
3
|
-
description: Use when a task needs the righthand toolkit — durable key-value storage (rh_store_*), credential and settings management (rh_credential_* / rh_settings_*), governed command execution (rh_run / rh_run_bg), or its tool guard policy. Covers tool reference, guard semantics, and service availability.
|
|
3
|
+
description: Use when a task needs the righthand toolkit — durable key-value storage (rh_store_*), a task board (rh_task_*), reminders (rh_events_*), credential and settings management (rh_credential_* / rh_settings_*), governed command execution (rh_run / rh_run_bg), language work (rh_text_*), weather/air data (rh_weather_*), R2 file tools (rh_files_*), ntfy push (rh_notify_send), or its tool guard policy. Covers tool reference, guard semantics, and service availability.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# dsh-righthand
|
|
@@ -19,6 +19,8 @@ The righthand toolkit: DSH-native tools over the harness's own services. Use thi
|
|
|
19
19
|
| text | `rh_text_summarise` / `rh_text_extract` / `rh_text_classify` / `rh_text_translate` | `ctx.llm` (one model call per verb) | Language work: shorten, turn into JSON matching a schema, sort into your labels with confidence, or translate preserving formatting. |
|
|
20
20
|
| weather | `rh_weather_forecast` / `rh_weather_air` | Open-Meteo (keyless) via the SSRF-guarded fetcher | Current conditions + 3-day min/max, or PM2.5/PM10/AQI, for a lat/lon. Keyless only — anything needing an API token is out of scope. |
|
|
21
21
|
| files | `rh_files_put` / `rh_files_get` / `rh_files_list` / `rh_files_share` / `rh_files_delete` | Cloudflare R2 (the user's own account) | Store/read/list/share/delete objects in an R2 bucket. `rh_files_share` returns a presigned download URL valid for N minutes (default 60, max 7 days) — anyone with the URL can read it for that window. |
|
|
22
|
+
| events | `rh_events_create` / `rh_events_due` / `rh_events_list` / `rh_events_free` / `rh_events_cancel` | `ctx.storageDomain` (typed `righthand_events` domain) | Reminders. The agent IS the scheduler: `rh_events_due` each turn returns pending events whose time has come and marks them notified — delivered exactly once, never silently dropped. `rh_events_free` finds free slots within local working hours 09:00–17:00. |
|
|
23
|
+
| notify | `rh_notify_send` | ntfy.sh (keyless) | Interrupt yourself on your own devices: publish to a topic; subscribed devices receive it. The topic name is the only secret — use an unguessable one. |
|
|
22
24
|
| guard | (policy, not a tool) | `ctx.tools` `tools/pre-execute` | Configured via plugin config `rules`; gates tools by name prefix with `allow` / `deny` / `ask` modes. |
|
|
23
25
|
|
|
24
26
|
## Store semantics
|
|
@@ -27,6 +29,18 @@ The righthand toolkit: DSH-native tools over the harness's own services. Use thi
|
|
|
27
29
|
- `rh_store_get` returns `{ found, key, value?, updatedAt? }` — `found: false` means the key is absent, not an error.
|
|
28
30
|
- Writes are durable (backend flush before commit) and serialized on one write chain; values must be JSON-serializable.
|
|
29
31
|
|
|
32
|
+
## Events semantics
|
|
33
|
+
|
|
34
|
+
- One domain `righthand_events`; states `pending` → `notified` (or `cancelled`).
|
|
35
|
+
- `rh_events_due` is the per-turn check: pending events with `at <= now` are returned once and marked notified, so a missed turn leaves a visible record, never silence.
|
|
36
|
+
- `rh_events_free` works in local time, working hours 09:00–17:00; durations are in minutes.
|
|
37
|
+
- One-off events only; a real scheduler (Cloudflare cron) is the documented escalation.
|
|
38
|
+
|
|
39
|
+
## Notify semantics
|
|
40
|
+
|
|
41
|
+
- Keyless publish to ntfy.sh; the topic name is the only secret (choose an unguessable one, like a random string).
|
|
42
|
+
- Priority 1–5; title optional; auto-delete after 24h. Publishing goes through the SSRF-guarded fetcher.
|
|
43
|
+
|
|
30
44
|
## Files semantics
|
|
31
45
|
|
|
32
46
|
- Cloudflare R2, the user's own account: accountId from settings, credentials `R2_ACCESS_KEY_ID` / `R2_SECRET_ACCESS_KEY` from the credential provider, bucket from settings `defaultR2Bucket` (or plugin config).
|
|
@@ -68,6 +82,7 @@ The righthand toolkit: DSH-native tools over the harness's own services. Use thi
|
|
|
68
82
|
| `defaultScriptPrefix` | `"rh-"` | default name prefix for generated workers/scripts |
|
|
69
83
|
| `defaultZone` | `""` | default Cloudflare zone |
|
|
70
84
|
| `defaultR2Bucket` | `""` | default R2 bucket for `rh_files_*` |
|
|
85
|
+
| `defaultNotifyTopic` | `""` | default ntfy topic for `rh_notify_send` |
|
|
71
86
|
|
|
72
87
|
## Guard policy
|
|
73
88
|
|
|
@@ -77,5 +92,5 @@ Rules come from the plugin config (`rules: [{ toolPrefix, mode, ask?, destructiv
|
|
|
77
92
|
|
|
78
93
|
## Service availability
|
|
79
94
|
|
|
80
|
-
- **web profile**: all
|
|
81
|
-
- **other profiles** (e.g. headless): the store and
|
|
95
|
+
- **web profile**: all thirty-three tools register (`storageDomain` is provided by the web app rows).
|
|
96
|
+
- **other profiles** (e.g. headless): the store, task and events families stay dormant (no `storageDomain`); the other nineteen tools (secrets, settings, exec, text, weather, files, notify) still register. The plugin never fails the boot.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* events-tools — rh_events_* over ctx.storageDomain.
|
|
3
|
+
* Reminders and the free-slot query. The agent IS the scheduler:
|
|
4
|
+
* rh_events_due is the check the agent runs each turn — an event whose
|
|
5
|
+
* time has come is returned once (pending → notified), so a missed run
|
|
6
|
+
* cannot go quiet without a record. Repeating events are one-off here;
|
|
7
|
+
* a real scheduler is the documented Cloudflare cron escalation.
|
|
8
|
+
* @module dsh-righthand/events-tools
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
12
|
+
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
13
|
+
import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'
|
|
14
|
+
import type { Domain } from '@deepseek-ai/dsh-storage-domain'
|
|
15
|
+
import { z } from 'zod'
|
|
16
|
+
|
|
17
|
+
export const name = 'righthand-events'
|
|
18
|
+
export const inject = ['tools', 'storageDomain']
|
|
19
|
+
|
|
20
|
+
export interface Event {
|
|
21
|
+
id: string
|
|
22
|
+
title: string
|
|
23
|
+
detail: string
|
|
24
|
+
at: string
|
|
25
|
+
state: 'pending' | 'notified' | 'cancelled',
|
|
26
|
+
createdAt: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const eventsDomain = defineDomain({
|
|
30
|
+
name: 'righthand_events',
|
|
31
|
+
version: 1,
|
|
32
|
+
tables: {
|
|
33
|
+
events: domainTable(z.object({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
title: z.string(),
|
|
36
|
+
detail: z.string(),
|
|
37
|
+
at: z.string(),
|
|
38
|
+
state: z.enum(['pending', 'notified', 'cancelled']),
|
|
39
|
+
createdAt: z.string(),
|
|
40
|
+
})),
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export type EventsDomain = Domain<typeof eventsDomain>
|
|
45
|
+
|
|
46
|
+
function newId(): string {
|
|
47
|
+
return 'e-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 6)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Free slots: gaps of at least durationMinutes between pending events at or
|
|
52
|
+
* after now, within working hours 09:00–17:00, over the next horizonHours.
|
|
53
|
+
* Pure and exported for tests.
|
|
54
|
+
*/
|
|
55
|
+
export function freeSlots(events: readonly Event[], now: Date, durationMinutes: number, horizonHours = 24): string[] {
|
|
56
|
+
const horizonEnd = now.getTime() + horizonHours * 3600000
|
|
57
|
+
const busy = events
|
|
58
|
+
.filter(e => e.state === 'pending')
|
|
59
|
+
.map(e => new Date(e.at).getTime())
|
|
60
|
+
.filter(t => Number.isFinite(t) && t >= now.getTime() && t <= horizonEnd)
|
|
61
|
+
.sort((a, b) => a - b)
|
|
62
|
+
const slots: string[] = []
|
|
63
|
+
let cursor = now.getTime()
|
|
64
|
+
const dayStart = (t: number): number => {
|
|
65
|
+
const d = new Date(t)
|
|
66
|
+
d.setHours(9, 0, 0, 0)
|
|
67
|
+
return d.getTime()
|
|
68
|
+
}
|
|
69
|
+
const dayEnd = (t: number): number => {
|
|
70
|
+
const d = new Date(t)
|
|
71
|
+
d.setHours(17, 0, 0, 0)
|
|
72
|
+
return d.getTime()
|
|
73
|
+
}
|
|
74
|
+
const need = durationMinutes * 60000
|
|
75
|
+
for (const b of busy) {
|
|
76
|
+
let from = Math.max(cursor, dayStart(cursor))
|
|
77
|
+
if (from < b && b - from >= need && from + need <= dayEnd(from) && from + need <= horizonEnd) {
|
|
78
|
+
slots.push(new Date(from).toISOString())
|
|
79
|
+
}
|
|
80
|
+
cursor = Math.max(b, dayEnd(cursor) + 1)
|
|
81
|
+
if (cursor > horizonEnd) break
|
|
82
|
+
}
|
|
83
|
+
return slots
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function apply(ctx: Context): void {
|
|
87
|
+
let domain: EventsDomain | undefined
|
|
88
|
+
let ready: Promise<void> | undefined
|
|
89
|
+
|
|
90
|
+
ctx.effect(() => {
|
|
91
|
+
ready = (async () => {
|
|
92
|
+
domain = await ctx.storageDomain.open(eventsDomain)
|
|
93
|
+
})()
|
|
94
|
+
return () => { /* domain facility owns the domain */ }
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const ensure = async (): Promise<EventsDomain> => {
|
|
98
|
+
if (domain === undefined) { await ready; }
|
|
99
|
+
if (domain === undefined) throw new Error('righthand events are not open (storageDomain not mounted)')
|
|
100
|
+
return domain
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const all = async (): Promise<Event[]> => {
|
|
104
|
+
const d = await ensure()
|
|
105
|
+
return [...d.table('events').entries()].map(([, e]) => e)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
ctx.tools.register(defineTool({
|
|
109
|
+
name: 'rh_events_create',
|
|
110
|
+
description: 'Schedule a reminder at an ISO datetime. One-off: the agent checks rh_events_due each turn and the event is delivered exactly once (pending to notified), so a missed run is never silently dropped.',
|
|
111
|
+
parameters: {
|
|
112
|
+
title: { type: 'string', required: true, description: 'What to be reminded of.' },
|
|
113
|
+
at: { type: 'string', required: true, description: 'ISO datetime when it is due, e.g. 2026-08-31T09:00:00Z.' },
|
|
114
|
+
detail: { type: 'string', description: 'Optional longer note.' },
|
|
115
|
+
},
|
|
116
|
+
output: {
|
|
117
|
+
schema: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
properties: {
|
|
121
|
+
id: { type: 'string', required: true },
|
|
122
|
+
title: { type: 'string', required: true },
|
|
123
|
+
at: { type: 'string', required: true },
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
render: (_args, value) => [{ type: 'text', text: 'event ' + value.id + ': ' + value.title + ' at ' + value.at }],
|
|
127
|
+
},
|
|
128
|
+
async execute(args) {
|
|
129
|
+
const d = await ensure()
|
|
130
|
+
const at = new Date(args.at)
|
|
131
|
+
if (Number.isNaN(at.getTime())) throw new Error('at must be a valid ISO datetime')
|
|
132
|
+
const event: Event = {
|
|
133
|
+
id: newId(),
|
|
134
|
+
title: args.title.trim(),
|
|
135
|
+
detail: args.detail ?? '',
|
|
136
|
+
at: at.toISOString(),
|
|
137
|
+
state: 'pending',
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
}
|
|
140
|
+
if (event.title === '') throw new Error('an event needs a title')
|
|
141
|
+
await d.table('events').put(event.id, event)
|
|
142
|
+
return { id: event.id, title: event.title, at: event.at }
|
|
143
|
+
},
|
|
144
|
+
}))
|
|
145
|
+
|
|
146
|
+
ctx.tools.register(defineTool({
|
|
147
|
+
name: 'rh_events_due',
|
|
148
|
+
description: 'The pending events whose time has come (at <= now). Each is delivered exactly once: returned events are marked notified. This is the check to run every turn — the agent is the scheduler.',
|
|
149
|
+
parameters: {},
|
|
150
|
+
output: {
|
|
151
|
+
schema: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
additionalProperties: false,
|
|
154
|
+
properties: {
|
|
155
|
+
due: { type: 'array', required: true, items: { type: 'json' } },
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
render: (_args, value) => [{ type: 'text', text: value.due.length === 0 ? '(nothing due)' : value.due.map((e: any) => e.title + ' at ' + e.at).join(' / ') }],
|
|
159
|
+
},
|
|
160
|
+
async execute() {
|
|
161
|
+
const d = await ensure()
|
|
162
|
+
const now = Date.now()
|
|
163
|
+
const due: Event[] = []
|
|
164
|
+
for (const e of [...d.table('events').entries()].map(([, v]) => v)) {
|
|
165
|
+
if (e.state === 'pending' && new Date(e.at).getTime() <= now) {
|
|
166
|
+
const notified: Event = { ...e, state: 'notified' }
|
|
167
|
+
await d.table('events').put(e.id, notified)
|
|
168
|
+
due.push(notified)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
due.sort((a, b) => a.at.localeCompare(b.at))
|
|
172
|
+
return { due: due.map(e => ({ id: e.id, title: e.title, detail: e.detail, at: e.at })) as any[] }
|
|
173
|
+
},
|
|
174
|
+
}))
|
|
175
|
+
|
|
176
|
+
ctx.tools.register(defineTool({
|
|
177
|
+
name: 'rh_events_list',
|
|
178
|
+
description: 'List events: upcoming pending ones first, then notified and cancelled.',
|
|
179
|
+
parameters: {
|
|
180
|
+
state: { type: 'string', description: 'Filter: pending | notified | cancelled. Omit for all.' },
|
|
181
|
+
},
|
|
182
|
+
output: {
|
|
183
|
+
schema: { type: 'array', items: { type: 'json' } },
|
|
184
|
+
render: (_args, value) => [{ type: 'text', text: value.length === 0 ? '(no events)' : (value as any[]).map((e: any) => e.at + ' ' + e.title + ' [' + e.state + ']').join(' / ') }],
|
|
185
|
+
},
|
|
186
|
+
async execute(args) {
|
|
187
|
+
const events = await all()
|
|
188
|
+
const wanted = args.state ?? null
|
|
189
|
+
const filtered = wanted ? events.filter(e => e.state === wanted) : events
|
|
190
|
+
const rank = { pending: 0, notified: 1, cancelled: 2 } as Record<string, number>
|
|
191
|
+
filtered.sort((a, b) => (rank[a.state] - rank[b.state]) || a.at.localeCompare(b.at))
|
|
192
|
+
return filtered.map(e => ({ id: e.id, title: e.title, detail: e.detail, at: e.at, state: e.state })) as any[]
|
|
193
|
+
},
|
|
194
|
+
}))
|
|
195
|
+
|
|
196
|
+
ctx.tools.register(defineTool({
|
|
197
|
+
name: 'rh_events_free',
|
|
198
|
+
description: 'When is there nothing booked: the next free slots of at least durationMinutes within working hours (09:00-17:00) over the next horizonHours.',
|
|
199
|
+
parameters: {
|
|
200
|
+
durationMinutes: { type: 'integer', required: true, description: 'How long the free block must be.' },
|
|
201
|
+
horizonHours: { type: 'integer', description: 'How far ahead to look (default 24).' },
|
|
202
|
+
},
|
|
203
|
+
output: {
|
|
204
|
+
schema: { type: 'array', items: { type: 'string' } },
|
|
205
|
+
render: (_args, value) => [{ type: 'text', text: value.length === 0 ? '(no free slot)' : (value as string[]).join(' / ') }],
|
|
206
|
+
},
|
|
207
|
+
async execute(args) {
|
|
208
|
+
const events = await all()
|
|
209
|
+
return freeSlots(events, new Date(), args.durationMinutes, args.horizonHours ?? 24)
|
|
210
|
+
},
|
|
211
|
+
}))
|
|
212
|
+
|
|
213
|
+
ctx.tools.register(defineTool({
|
|
214
|
+
name: 'rh_events_cancel',
|
|
215
|
+
description: 'Cancel an event by id. Returns whether it existed. Cancelled events stay in the record — a cancellation is news too.',
|
|
216
|
+
parameters: {
|
|
217
|
+
id: { type: 'string', required: true, description: 'The event id.' },
|
|
218
|
+
},
|
|
219
|
+
output: {
|
|
220
|
+
schema: {
|
|
221
|
+
type: 'object',
|
|
222
|
+
additionalProperties: false,
|
|
223
|
+
properties: {
|
|
224
|
+
id: { type: 'string', required: true },
|
|
225
|
+
existed: { type: 'boolean', required: true },
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
render: (_args, value) => [{ type: 'text', text: 'cancelled ' + value.id + ': ' + value.existed }],
|
|
229
|
+
},
|
|
230
|
+
async execute(args) {
|
|
231
|
+
const d = await ensure()
|
|
232
|
+
const e = d.table('events').get(args.id)
|
|
233
|
+
if (e === undefined) return { id: args.id, existed: false }
|
|
234
|
+
await d.table('events').put(args.id, { ...e, state: 'cancelled' })
|
|
235
|
+
return { id: args.id, existed: true }
|
|
236
|
+
},
|
|
237
|
+
}))
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
package/src/index.ts
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* The package's plugin entry (name/inject/apply) mounts the tool families
|
|
9
9
|
* and the packaged skill as child fibers; each child waits on its own
|
|
10
10
|
* services, so a
|
|
11
|
-
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
-
*
|
|
11
|
+
* profile without `storageDomain` (e.g. headless) simply gets the
|
|
12
|
+
* store/task/events families dormant and the other nineteen tools
|
|
13
|
+
* (secrets, settings, exec, text, weather, files, notify) instead of
|
|
14
|
+
* failing the boot.
|
|
13
15
|
*
|
|
14
16
|
* Modules (each individually mountable via `export * as ...`):
|
|
15
17
|
* - store-tools: rh_store_put/get/delete/list over ctx.storageDomain
|
|
@@ -18,6 +20,8 @@
|
|
|
18
20
|
* - text-tools: rh_text_summarise/extract/classify/translate over ctx.llm
|
|
19
21
|
* - weather-tools: rh_weather_forecast/air over Open-Meteo (keyless, SSRF-guarded)
|
|
20
22
|
* - files-tools: rh_files_put/get/list/share/delete over Cloudflare R2
|
|
23
|
+
* - events-tools: rh_events_create/due/list/free/cancel over ctx.storageDomain
|
|
24
|
+
* - notify-tools: rh_notify_send over ntfy.sh (keyless)
|
|
21
25
|
* - exec-tools: rh_run / rh_run_bg over ctx.subprocess + ctx.jobs
|
|
22
26
|
* - guard-tools: tools/pre-execute policy (config.rules)
|
|
23
27
|
* - skills: the packaged dsh-righthand skill (ctx.skills)
|
|
@@ -34,6 +38,8 @@ import * as taskTools from './task-tools.ts'
|
|
|
34
38
|
import * as textTools from './text-tools.ts'
|
|
35
39
|
import * as weatherTools from './weather-tools.ts'
|
|
36
40
|
import * as filesTools from './files-tools.ts'
|
|
41
|
+
import * as eventsTools from './events-tools.ts'
|
|
42
|
+
import * as notifyTools from './notify-tools.ts'
|
|
37
43
|
import * as righthandSkills from './skills.ts'
|
|
38
44
|
import type { GuardRule } from './guard-tools.ts'
|
|
39
45
|
|
|
@@ -62,12 +68,14 @@ export function apply(ctx: Context, config: RighthandConfig = {}): void {
|
|
|
62
68
|
ctx.plugin(textTools)
|
|
63
69
|
ctx.plugin(weatherTools)
|
|
64
70
|
ctx.plugin(filesTools)
|
|
71
|
+
ctx.plugin(eventsTools)
|
|
72
|
+
ctx.plugin(notifyTools)
|
|
65
73
|
ctx.plugin(guardTools, { rules: config.rules ?? [] })
|
|
66
74
|
ctx.plugin(righthandSkills)
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
// Individual modules stay importable for selective mounting.
|
|
70
|
-
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, guardTools, righthandSkills }
|
|
78
|
+
export { storeTools, secretsTools, execTools, taskTools, textTools, weatherTools, filesTools, eventsTools, notifyTools, guardTools, righthandSkills }
|
|
71
79
|
export { SKILL_NAME, SKILL_DESCRIPTION, skillDirectory, skillBody } from './skills.ts'
|
|
72
80
|
export type { GuardRule } from './guard-tools.ts'
|
|
73
81
|
export { guardFactsFor } from './guard-tools.ts'
|
|
@@ -75,6 +83,8 @@ export type { GuardFacts } from './guard-tools.ts'
|
|
|
75
83
|
export { isBlockedIP, guardedFetch, normalizeForecast, normalizeAir } from './weather-tools.ts'
|
|
76
84
|
export { createR2Client, R2_ACCESS_KEY_REF, R2_SECRET_KEY_REF } from './files-tools.ts'
|
|
77
85
|
export { signRequest, presignGet } from './sigv4.ts'
|
|
86
|
+
export { freeSlots } from './events-tools.ts'
|
|
87
|
+
export type { Event } from './events-tools.ts'
|
|
78
88
|
export type { R2Options, ListEntry } from './files-tools.ts'
|
|
79
89
|
export type { WeatherConfig, ForecastOut, AirOut } from './weather-tools.ts'
|
|
80
90
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notify-tools — rh_notify_send over ntfy.sh (keyless).
|
|
3
|
+
* Interrupt yourself on your own devices: publish to a topic; any phone
|
|
4
|
+
* subscribed to that topic gets it. The topic name is the only secret —
|
|
5
|
+
* choose one nobody can guess, like the digest of a random string.
|
|
6
|
+
* @module dsh-righthand/notify-tools
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
10
|
+
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
11
|
+
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
12
|
+
import { guardedFetch } from './weather-tools.ts'
|
|
13
|
+
|
|
14
|
+
export const name = 'righthand-notify'
|
|
15
|
+
export const inject = ['tools', 'settings']
|
|
16
|
+
|
|
17
|
+
export interface NotifyConfig {
|
|
18
|
+
/** ntfy server base URL; default https://ntfy.sh (keyless publish). */
|
|
19
|
+
baseUrl?: string
|
|
20
|
+
/** Topic to publish to; defaults to the righthand settings defaultNotifyTopic. */
|
|
21
|
+
topic?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function apply(ctx: Context, config: NotifyConfig = {}): void {
|
|
25
|
+
const ns = settingsNamespace('righthand')
|
|
26
|
+
const baseUrl = config.baseUrl ?? 'https://ntfy.sh'
|
|
27
|
+
|
|
28
|
+
ctx.tools.register(defineTool({
|
|
29
|
+
name: 'rh_notify_send',
|
|
30
|
+
description: 'Interrupt yourself on your own devices: publish a notification to a ntfy.sh topic (keyless). Any device subscribed to that topic receives it. The topic name is the only secret — use an unguessable one. Defaults: priority 1 and auto-delete after 24h.',
|
|
31
|
+
parameters: {
|
|
32
|
+
message: { type: 'string', required: true, description: 'The notification body.' },
|
|
33
|
+
title: { type: 'string', description: 'Notification title.' },
|
|
34
|
+
topic: { type: 'string', description: 'Topic to publish to; defaults to the settings defaultNotifyTopic.' },
|
|
35
|
+
priority: { type: 'integer', description: '1 (low/default) to 5 (urgent). Default 1.' },
|
|
36
|
+
},
|
|
37
|
+
output: {
|
|
38
|
+
schema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
properties: {
|
|
42
|
+
topic: { type: 'string', required: true },
|
|
43
|
+
sent: { type: 'boolean', required: true },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
render: (_args, value) => [{ type: 'text', text: 'notified ' + value.topic }],
|
|
47
|
+
},
|
|
48
|
+
async execute(args) {
|
|
49
|
+
const settings = ctx.settings.get(ns) as { defaultNotifyTopic?: string } | undefined
|
|
50
|
+
const topic = args.topic ?? config.topic ?? settings?.defaultNotifyTopic ?? ''
|
|
51
|
+
if (topic === '') throw new Error('notify topic is not set (arg, plugin config, or settings defaultNotifyTopic)')
|
|
52
|
+
const priority = Math.min(Math.max(args.priority ?? 1, 1), 5)
|
|
53
|
+
const headers: Record<string, string> = { 'Priority': String(priority), 'X-TTL': '24h' }
|
|
54
|
+
if (args.title !== undefined) headers['Title'] = args.title
|
|
55
|
+
await guardedFetch(baseUrl + '/' + encodeURIComponent(topic), {
|
|
56
|
+
init: { method: 'POST', body: args.message, headers },
|
|
57
|
+
})
|
|
58
|
+
return { topic, sent: true }
|
|
59
|
+
},
|
|
60
|
+
}))
|
|
61
|
+
}
|
|
62
|
+
|
package/src/secrets-tools.ts
CHANGED
|
@@ -28,6 +28,7 @@ export const righthandSettingsSchema = z.object({
|
|
|
28
28
|
defaultScriptPrefix: z.string().default('rh-'),
|
|
29
29
|
defaultZone: z.string().default(''),
|
|
30
30
|
defaultR2Bucket: z.string().default(''),
|
|
31
|
+
defaultNotifyTopic: z.string().default(''),
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
/** Register the settings namespace + the secret/credential tools. */
|
|
@@ -120,7 +121,7 @@ export function apply(ctx: Context): void {
|
|
|
120
121
|
},
|
|
121
122
|
async execute() {
|
|
122
123
|
const v = scope.get()
|
|
123
|
-
return { accountId: v.accountId, defaultScriptPrefix: v.defaultScriptPrefix, defaultZone: v.defaultZone, defaultR2Bucket: v.defaultR2Bucket }
|
|
124
|
+
return { accountId: v.accountId, defaultScriptPrefix: v.defaultScriptPrefix, defaultZone: v.defaultZone, defaultR2Bucket: v.defaultR2Bucket, defaultNotifyTopic: v.defaultNotifyTopic }
|
|
124
125
|
},
|
|
125
126
|
}))
|
|
126
127
|
|
package/src/weather-tools.ts
CHANGED
|
@@ -65,9 +65,15 @@ export function isBlockedIP(ip: string): boolean {
|
|
|
65
65
|
* Fetch one URL with the SSRF checklist. `fetchImpl` and `resolve` are
|
|
66
66
|
* injectable for tests; production uses the globals.
|
|
67
67
|
*/
|
|
68
|
+
export interface GuardedFetchInit {
|
|
69
|
+
method?: string
|
|
70
|
+
body?: string
|
|
71
|
+
headers?: Record<string, string>
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
export async function guardedFetch(
|
|
69
75
|
url: string,
|
|
70
|
-
deps: { fetchImpl?: typeof fetch; resolve?: (host: string) => Promise<string[]
|
|
76
|
+
deps: { fetchImpl?: typeof fetch; resolve?: (host: string) => Promise<string[]>; init?: GuardedFetchInit } = {},
|
|
71
77
|
): Promise<string> {
|
|
72
78
|
const fetchImpl = deps.fetchImpl ?? fetch
|
|
73
79
|
const resolve = deps.resolve ?? (async (host: string) => (await lookup(host, { all: true })).map(a => a.address))
|
|
@@ -78,7 +84,7 @@ export async function guardedFetch(
|
|
|
78
84
|
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') throw new Error('blocked: non-http(s) URL')
|
|
79
85
|
const ips = await resolve(parsed.hostname)
|
|
80
86
|
if (ips.length === 0 || ips.some(isBlockedIP)) throw new Error('blocked: destination is not a public host')
|
|
81
|
-
const res = await fetchImpl(current, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), redirect: 'manual' })
|
|
87
|
+
const res = await fetchImpl(current, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), redirect: 'manual', method: deps.init?.method ?? 'GET', body: deps.init?.body, headers: deps.init?.headers })
|
|
82
88
|
if (res.status >= 300 && res.status < 400) {
|
|
83
89
|
const next = res.headers.get('location')
|
|
84
90
|
if (next === null) throw new Error('blocked: redirect without location')
|