@fungi.computer/whistle 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +373 -2
- package/dist/catalog.d.ts +459 -0
- package/dist/catalog.js +147 -0
- package/dist/html.d.ts +14 -0
- package/dist/html.js +11 -0
- package/dist/index.d.ts +253 -0
- package/dist/index.js +694 -0
- package/dist/interaction.d.ts +59 -0
- package/dist/interaction.js +131 -0
- package/dist/keymap.d.ts +34 -0
- package/dist/keymap.js +36 -0
- package/dist/wire.d.ts +380 -0
- package/dist/wire.js +299 -0
- package/docs/api/README.md +17 -0
- package/docs/api/catalog.md +498 -0
- package/docs/api/html.md +45 -0
- package/docs/api/index.md +675 -0
- package/docs/api/interaction.md +124 -0
- package/docs/api/wire.md +1033 -0
- package/package.json +87 -3
package/dist/wire.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
const json = z.json();
|
|
3
|
+
/** Host-owned availability carried by every discovered agent row. */
|
|
4
|
+
export const WhistleAvailabilitySchema = z.discriminatedUnion("status", [
|
|
5
|
+
z
|
|
6
|
+
.object({
|
|
7
|
+
/** The action can currently be invoked. */
|
|
8
|
+
status: z.literal("available"),
|
|
9
|
+
})
|
|
10
|
+
.strict(),
|
|
11
|
+
z
|
|
12
|
+
.object({
|
|
13
|
+
/** The action cannot currently be invoked. */
|
|
14
|
+
status: z.literal("unavailable"),
|
|
15
|
+
/** Host-supplied explanation suitable for presentation to a caller. */
|
|
16
|
+
reason: z.string(),
|
|
17
|
+
})
|
|
18
|
+
.strict(),
|
|
19
|
+
]);
|
|
20
|
+
/** The JSON value grammar shared by Whistle transports and App adapters. */
|
|
21
|
+
export const WhistleJsonValueSchema = json;
|
|
22
|
+
/** One JSON object, used for action schemas and custom presentation data. */
|
|
23
|
+
export const WhistleJsonObjectSchema = z.record(z.string(), WhistleJsonValueSchema);
|
|
24
|
+
/** Parse copied JSON data at an untrusted transport boundary. */
|
|
25
|
+
export const parseJsonValue = (value) => WhistleJsonValueSchema.parse(value);
|
|
26
|
+
/** Parse a copied JSON object at an untrusted transport boundary. */
|
|
27
|
+
export const parseJsonObject = (value) => WhistleJsonObjectSchema.parse(value);
|
|
28
|
+
/** General portable failure data for adapters that cross a transport. */
|
|
29
|
+
export const WhistleFailureSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
code: z.string().min(1).max(160),
|
|
32
|
+
message: z.string().min(1).max(512),
|
|
33
|
+
details: WhistleJsonValueSchema.optional(),
|
|
34
|
+
})
|
|
35
|
+
.strict();
|
|
36
|
+
/** Parse failure data without carrying an Error or stack across the wire. */
|
|
37
|
+
export const parseFailure = (value) => WhistleFailureSchema.parse(value);
|
|
38
|
+
/** The JSON object shape used by Whistle action schemas. */
|
|
39
|
+
export const WhistleActionSchemaSchema = WhistleJsonObjectSchema;
|
|
40
|
+
const meaningful = z.string().refine((value) => value.trim().length > 0);
|
|
41
|
+
const availabilitySchema = WhistleAvailabilitySchema;
|
|
42
|
+
/** Validate renderer-neutral presentation data attached to an action. */
|
|
43
|
+
export const WhistleActionPresentationSchema = z.union([
|
|
44
|
+
z.object({ type: z.literal("action") }).strict(),
|
|
45
|
+
z
|
|
46
|
+
.object({
|
|
47
|
+
type: z.literal("custom"),
|
|
48
|
+
data: WhistleJsonObjectSchema,
|
|
49
|
+
})
|
|
50
|
+
.strict(),
|
|
51
|
+
z
|
|
52
|
+
.object({
|
|
53
|
+
type: z.literal("choice"),
|
|
54
|
+
options: z.array(z.object({
|
|
55
|
+
value: WhistleJsonValueSchema,
|
|
56
|
+
label: meaningful,
|
|
57
|
+
description: meaningful.optional(),
|
|
58
|
+
})),
|
|
59
|
+
})
|
|
60
|
+
.strict(),
|
|
61
|
+
z
|
|
62
|
+
.object({
|
|
63
|
+
type: z.literal("form"),
|
|
64
|
+
submitLabel: meaningful.optional(),
|
|
65
|
+
})
|
|
66
|
+
.strict(),
|
|
67
|
+
z
|
|
68
|
+
.object({
|
|
69
|
+
type: z.literal("confirmation"),
|
|
70
|
+
message: meaningful,
|
|
71
|
+
confirmLabel: meaningful.optional(),
|
|
72
|
+
cancelLabel: meaningful.optional(),
|
|
73
|
+
})
|
|
74
|
+
.strict(),
|
|
75
|
+
]);
|
|
76
|
+
/** Validate the serializable action contract carried by a command. */
|
|
77
|
+
export const WhistleActionDataSchema = z
|
|
78
|
+
.object({
|
|
79
|
+
inputSchema: WhistleActionSchemaSchema.optional(),
|
|
80
|
+
outputSchema: WhistleActionSchemaSchema.optional(),
|
|
81
|
+
presentation: WhistleActionPresentationSchema.optional(),
|
|
82
|
+
})
|
|
83
|
+
.strict();
|
|
84
|
+
const safeOrder = z
|
|
85
|
+
.number()
|
|
86
|
+
.int()
|
|
87
|
+
.refine((value) => Number.isSafeInteger(value));
|
|
88
|
+
/** Validate aliases and argument mapping metadata for slash commands. */
|
|
89
|
+
export const WhistleSlashArgumentsSchema = z
|
|
90
|
+
.object({
|
|
91
|
+
hint: meaningful.pipe(z.string().max(120)),
|
|
92
|
+
words: z
|
|
93
|
+
.array(z
|
|
94
|
+
.object({
|
|
95
|
+
word: z.string().regex(/^\S{1,64}$/u),
|
|
96
|
+
description: meaningful.pipe(z.string().max(512)).optional(),
|
|
97
|
+
arguments: WhistleJsonObjectSchema,
|
|
98
|
+
})
|
|
99
|
+
.strict())
|
|
100
|
+
.max(32)
|
|
101
|
+
.optional(),
|
|
102
|
+
text: z
|
|
103
|
+
.object({
|
|
104
|
+
field: meaningful.pipe(z.string().max(120)),
|
|
105
|
+
arguments: WhistleJsonObjectSchema,
|
|
106
|
+
requestIdField: meaningful.pipe(z.string().max(120)).optional(),
|
|
107
|
+
})
|
|
108
|
+
.strict()
|
|
109
|
+
.optional(),
|
|
110
|
+
})
|
|
111
|
+
.strict()
|
|
112
|
+
.refine((grammar) => grammar.words !== undefined || grammar.text !== undefined, "slash arguments need words or text");
|
|
113
|
+
const orderedProjectionSchema = z
|
|
114
|
+
.object({ order: safeOrder.optional() })
|
|
115
|
+
.strict();
|
|
116
|
+
/** Validate explicit membership and ordering across Whistle surfaces. */
|
|
117
|
+
export const WhistleCommandProjectionsSchema = z
|
|
118
|
+
.object({
|
|
119
|
+
bindings: z
|
|
120
|
+
.object({
|
|
121
|
+
order: safeOrder.optional(),
|
|
122
|
+
values: z.array(meaningful).max(16),
|
|
123
|
+
})
|
|
124
|
+
.strict()
|
|
125
|
+
.optional(),
|
|
126
|
+
agent: z
|
|
127
|
+
.object({
|
|
128
|
+
keybind: meaningful.optional(),
|
|
129
|
+
order: safeOrder.optional(),
|
|
130
|
+
})
|
|
131
|
+
.strict()
|
|
132
|
+
.optional(),
|
|
133
|
+
help: orderedProjectionSchema.optional(),
|
|
134
|
+
menu: orderedProjectionSchema.optional(),
|
|
135
|
+
palette: orderedProjectionSchema.optional(),
|
|
136
|
+
slash: z
|
|
137
|
+
.object({
|
|
138
|
+
aliases: z.array(meaningful).max(16),
|
|
139
|
+
order: safeOrder.optional(),
|
|
140
|
+
arguments: WhistleSlashArgumentsSchema.optional(),
|
|
141
|
+
})
|
|
142
|
+
.strict()
|
|
143
|
+
.optional(),
|
|
144
|
+
})
|
|
145
|
+
.strict();
|
|
146
|
+
/** Validate data-only command definitions supplied by an adapter. */
|
|
147
|
+
export const WhistleCommandDefinitionSchema = z
|
|
148
|
+
.object({
|
|
149
|
+
id: meaningful.refine((value) => !value.includes(":")),
|
|
150
|
+
title: meaningful,
|
|
151
|
+
category: meaningful,
|
|
152
|
+
description: meaningful.optional(),
|
|
153
|
+
projections: WhistleCommandProjectionsSchema.optional(),
|
|
154
|
+
action: WhistleActionDataSchema.optional(),
|
|
155
|
+
availability: availabilitySchema.optional(),
|
|
156
|
+
})
|
|
157
|
+
.strict();
|
|
158
|
+
/** Parse action metadata once before an adapter constructs a Whistle command. */
|
|
159
|
+
export const parseAction = (value) => WhistleActionDataSchema.parse(value);
|
|
160
|
+
/** Parse the Whistle-owned projection metadata supplied by an App. */
|
|
161
|
+
export const parseProjections = (value) => WhistleCommandProjectionsSchema.parse(value);
|
|
162
|
+
/** Parse an availability fact while preserving its reason. */
|
|
163
|
+
export const parseAvailability = (value) => availabilitySchema.parse(value);
|
|
164
|
+
/** Parse one data-only command definition before an adapter creates a command. */
|
|
165
|
+
export const parseCommandDefinition = (value) => WhistleCommandDefinitionSchema.parse(value);
|
|
166
|
+
/** Semantic action data; client presentation is intentionally not wire data. */
|
|
167
|
+
const WhistleAgentActionSchema = z
|
|
168
|
+
.object({
|
|
169
|
+
inputSchema: WhistleActionSchemaSchema.optional(),
|
|
170
|
+
outputSchema: WhistleActionSchemaSchema.optional(),
|
|
171
|
+
})
|
|
172
|
+
.strict();
|
|
173
|
+
/** One neutral agent row emitted by Whistle's `snapshot.agent` projection. */
|
|
174
|
+
export const WhistleAgentProjectionSchema = z
|
|
175
|
+
.object({
|
|
176
|
+
commandId: z.string(),
|
|
177
|
+
sourceId: z.string(),
|
|
178
|
+
scope: z.string().optional(),
|
|
179
|
+
title: z.string(),
|
|
180
|
+
category: z.string(),
|
|
181
|
+
description: z.string().optional(),
|
|
182
|
+
order: z.number(),
|
|
183
|
+
availability: WhistleAvailabilitySchema,
|
|
184
|
+
action: WhistleAgentActionSchema.optional(),
|
|
185
|
+
keybind: z.string().optional(),
|
|
186
|
+
})
|
|
187
|
+
.strict();
|
|
188
|
+
/** A neutral Whistle agent projection collection. */
|
|
189
|
+
export const WhistleAgentProjectionsSchema = z.array(WhistleAgentProjectionSchema);
|
|
190
|
+
/** Decode an untrusted agent projection collection at the wire boundary. */
|
|
191
|
+
export const parse = (value) => WhistleAgentProjectionsSchema.parse(value);
|
|
192
|
+
/** Longest prompt answer or message an interaction carries. */
|
|
193
|
+
export const interactionTextLimit = 8192;
|
|
194
|
+
const shortText = meaningful.pipe(z.string().max(interactionTextLimit));
|
|
195
|
+
const webUrl = z.url({ protocol: /^https?$/u });
|
|
196
|
+
/** Validate renderer-neutral interaction prompts received from a host. */
|
|
197
|
+
export const WhistlePromptSchema = z.discriminatedUnion("type", [
|
|
198
|
+
z
|
|
199
|
+
.object({
|
|
200
|
+
type: z.literal("choice"),
|
|
201
|
+
message: shortText,
|
|
202
|
+
collapsedGroup: shortText.optional(),
|
|
203
|
+
options: z
|
|
204
|
+
.array(z
|
|
205
|
+
.object({
|
|
206
|
+
value: shortText,
|
|
207
|
+
label: shortText,
|
|
208
|
+
description: shortText.optional(),
|
|
209
|
+
group: shortText.optional(),
|
|
210
|
+
})
|
|
211
|
+
.strict())
|
|
212
|
+
.min(1)
|
|
213
|
+
.max(256),
|
|
214
|
+
})
|
|
215
|
+
.strict(),
|
|
216
|
+
z
|
|
217
|
+
.object({
|
|
218
|
+
type: z.literal("text"),
|
|
219
|
+
message: shortText,
|
|
220
|
+
placeholder: shortText.optional(),
|
|
221
|
+
secret: z.boolean().optional(),
|
|
222
|
+
})
|
|
223
|
+
.strict(),
|
|
224
|
+
z
|
|
225
|
+
.object({
|
|
226
|
+
type: z.literal("confirmation"),
|
|
227
|
+
message: shortText,
|
|
228
|
+
confirmLabel: shortText.optional(),
|
|
229
|
+
cancelLabel: shortText.optional(),
|
|
230
|
+
})
|
|
231
|
+
.strict(),
|
|
232
|
+
]);
|
|
233
|
+
/** Validate interaction notices received from a host. */
|
|
234
|
+
export const WhistleNoticeSchema = z.discriminatedUnion("type", [
|
|
235
|
+
z
|
|
236
|
+
.object({
|
|
237
|
+
type: z.literal("info"),
|
|
238
|
+
message: shortText,
|
|
239
|
+
links: z
|
|
240
|
+
.array(z.object({ url: webUrl, label: shortText.optional() }).strict())
|
|
241
|
+
.max(16)
|
|
242
|
+
.optional(),
|
|
243
|
+
})
|
|
244
|
+
.strict(),
|
|
245
|
+
z.object({ type: z.literal("progress"), message: shortText }).strict(),
|
|
246
|
+
z
|
|
247
|
+
.object({
|
|
248
|
+
type: z.literal("handoff"),
|
|
249
|
+
url: webUrl,
|
|
250
|
+
code: shortText.optional(),
|
|
251
|
+
message: shortText.optional(),
|
|
252
|
+
})
|
|
253
|
+
.strict(),
|
|
254
|
+
z.object({ type: z.literal("success"), message: shortText }).strict(),
|
|
255
|
+
]);
|
|
256
|
+
/** Parse one interaction prompt at the boundary where a client renders it. */
|
|
257
|
+
export const parsePrompt = (value) => WhistlePromptSchema.parse(value);
|
|
258
|
+
/** Parse one interaction notice at the boundary where a client renders it. */
|
|
259
|
+
export const parseNotice = (value) => WhistleNoticeSchema.parse(value);
|
|
260
|
+
const answerSchemas = {
|
|
261
|
+
confirmation: (prompt) => {
|
|
262
|
+
WhistlePromptSchema.options[2].parse(prompt);
|
|
263
|
+
return z.boolean();
|
|
264
|
+
},
|
|
265
|
+
text: (prompt) => {
|
|
266
|
+
WhistlePromptSchema.options[1].parse(prompt);
|
|
267
|
+
return z.string().max(interactionTextLimit);
|
|
268
|
+
},
|
|
269
|
+
choice: (prompt) => {
|
|
270
|
+
const request = WhistlePromptSchema.options[0].parse(prompt);
|
|
271
|
+
const answer = z
|
|
272
|
+
.string()
|
|
273
|
+
.refine((value) => request.options.some((option) => option.value === value));
|
|
274
|
+
return answer;
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
/** Capture a prompt's parsed answer contract before handing it to a renderer. */
|
|
278
|
+
export function createPromptAnswerParser(prompt) {
|
|
279
|
+
const schema = answerSchemas[prompt.type](prompt);
|
|
280
|
+
return (value) => schema.parse(value);
|
|
281
|
+
}
|
|
282
|
+
/** Parse the answer a human gave to one prompt before the command sees it. */
|
|
283
|
+
export function parsePromptAnswer(prompt, value) {
|
|
284
|
+
return createPromptAnswerParser(prompt)(value);
|
|
285
|
+
}
|
|
286
|
+
/** Capture a typed answer decoder; invalid input stays an explicit outcome. */
|
|
287
|
+
export function createPromptAnswerDecoder(prompt) {
|
|
288
|
+
const schema = answerSchemas[prompt.type](prompt);
|
|
289
|
+
return (value) => {
|
|
290
|
+
const result = schema.safeParse(value);
|
|
291
|
+
return result.success
|
|
292
|
+
? { kind: "accepted", value: result.data }
|
|
293
|
+
: { kind: "invalid", cause: result.error };
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/** Decode a human answer without throwing so renderers can handle invalid input. */
|
|
297
|
+
export function decodePromptAnswer(prompt, value) {
|
|
298
|
+
return createPromptAnswerDecoder(prompt)(value);
|
|
299
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
**@fungi.computer/whistle**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# @fungi.computer/whistle
|
|
8
|
+
|
|
9
|
+
## Modules
|
|
10
|
+
|
|
11
|
+
| Module | Description |
|
|
12
|
+
| ----------------------------- | ----------- |
|
|
13
|
+
| [catalog](catalog.md) | - |
|
|
14
|
+
| [html](html.md) | - |
|
|
15
|
+
| [index](index.md) | - |
|
|
16
|
+
| [interaction](interaction.md) | - |
|
|
17
|
+
| [wire](wire.md) | - |
|