@fungi.computer/parakeet-testing 0.1.4 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { SessionActivity, SessionExtensionSlots } from "@fungi.computer/shiitake/client";
2
2
  import { type Json } from "@fungi.computer/shiitake/extensions";
3
+ import type { WhistlePrompt } from "@fungi.computer/whistle";
3
4
  import type { WhistleCatalogV1 } from "@fungi.computer/whistle/catalog";
4
5
  /** Activity facts for a Session with nothing queued or running. */
5
6
  export declare const idleActivity: SessionActivity;
@@ -40,3 +41,31 @@ export declare const slashParityFlow: {
40
41
  readonly choose: "Fern bed";
41
42
  readonly notice: "Watered the fern bed.";
42
43
  };
44
+ /** The state of one decision a fixture holds, shaped like the Parakeet reducer's. */
45
+ export type AwaitingFixtureState = Readonly<{
46
+ highlight: number;
47
+ toggled: ReadonlySet<string>;
48
+ other: string;
49
+ phase: "choose" | "other" | "confirm" | "sending" | "refused";
50
+ refusal?: string;
51
+ details: boolean;
52
+ }>;
53
+ /** One decision shown at one moment, held identically by every renderer's test. */
54
+ export type AwaitingFixture = Readonly<{
55
+ /** What the fixture shows, for test names. */
56
+ name: string;
57
+ kind: "question" | "approval";
58
+ prompt: Extract<WhistlePrompt, {
59
+ type: "decision";
60
+ }>;
61
+ state: AwaitingFixtureState;
62
+ /** One-based place among all waiting decisions. */
63
+ position: number;
64
+ /** Every waiting decision. */
65
+ total: number;
66
+ }>;
67
+ /**
68
+ * The decisions every renderer must draw the same way. Each Parakeet renderer
69
+ * renders every fixture and holds its output to `decisionView`.
70
+ */
71
+ export declare const awaitingFixtures: readonly AwaitingFixture[];
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { parseExtensionJson, } from "@fungi.computer/shiitake/extensions";
2
+ import { parsePrompt } from "@fungi.computer/whistle/wire";
2
3
  import { z } from "zod";
3
4
  /** Activity facts for a Session with nothing queued or running. */
4
5
  export const idleActivity = {
@@ -125,3 +126,166 @@ export const slashParityFlow = {
125
126
  choose: "Fern bed",
126
127
  notice: "Watered the fern bed.",
127
128
  };
129
+ function decision(input) {
130
+ const prompt = parsePrompt({ type: "decision", ...input });
131
+ if (prompt.type !== "decision")
132
+ throw new Error("Expected a decision prompt");
133
+ return prompt;
134
+ }
135
+ const storage = decision({
136
+ message: "Which store should hold the notes?",
137
+ options: [
138
+ {
139
+ value: "SQLite",
140
+ label: "SQLite",
141
+ description: "Keep notes on this computer.",
142
+ },
143
+ {
144
+ value: "PostgreSQL",
145
+ label: "PostgreSQL",
146
+ description: "Use the shared database.",
147
+ },
148
+ ],
149
+ other: {
150
+ label: "Other…",
151
+ placeholder: "Write your own answer",
152
+ maxLength: 4_000,
153
+ },
154
+ });
155
+ const deliverables = decision({
156
+ message: "Which deliverables should ship?",
157
+ summary: "Question 1 of 2",
158
+ options: [
159
+ { value: "Docs", label: "Docs", description: "Explain usage." },
160
+ { value: "Tests", label: "Tests", description: "Verify behavior." },
161
+ { value: "Examples", label: "Examples", description: "Show it working." },
162
+ ],
163
+ multiple: true,
164
+ other: {
165
+ label: "Other…",
166
+ placeholder: "Write your own answer",
167
+ maxLength: 4_000,
168
+ },
169
+ });
170
+ const approval = decision({
171
+ message: "Allow `git add hello.js`?",
172
+ summary: "Research Agent wants to run this outside the sandbox, as you.",
173
+ facts: [
174
+ { label: "Folder", value: "~/src/garden" },
175
+ { label: "Why", value: "“Git metadata is read-only”" },
176
+ ],
177
+ options: [
178
+ { value: "approve", label: "Approve once" },
179
+ { value: "always", label: "Always allow “git add” in this project…" },
180
+ { value: "deny", label: "Deny" },
181
+ ],
182
+ other: {
183
+ label: "Deny and say why…",
184
+ placeholder: "A short reason for the Agent (optional)",
185
+ maxLength: 512,
186
+ blank: "deny",
187
+ },
188
+ });
189
+ const confirmation = decision({
190
+ message: "Always allow “git add” in this project?",
191
+ summary: "Git hooks in this project can run code as you, and this Agent can add hooks.",
192
+ body: "Any Workspace Agent here can then run `git add …` without asking.",
193
+ options: [
194
+ { value: "back", label: "Back" },
195
+ { value: "always-allow", label: "Always allow “git add” and run it now" },
196
+ ],
197
+ escape: "back",
198
+ });
199
+ const start = {
200
+ highlight: 0,
201
+ toggled: new Set(),
202
+ other: "",
203
+ phase: "choose",
204
+ details: false,
205
+ };
206
+ /**
207
+ * The decisions every renderer must draw the same way. Each Parakeet renderer
208
+ * renders every fixture and holds its output to `decisionView`.
209
+ */
210
+ export const awaitingFixtures = [
211
+ {
212
+ name: "single",
213
+ kind: "question",
214
+ prompt: storage,
215
+ state: start,
216
+ position: 1,
217
+ total: 1,
218
+ },
219
+ {
220
+ name: "multiple toggled",
221
+ kind: "question",
222
+ prompt: deliverables,
223
+ state: { ...start, highlight: 2, toggled: new Set(["Docs", "Examples"]) },
224
+ position: 1,
225
+ total: 1,
226
+ },
227
+ {
228
+ name: "other typing",
229
+ kind: "question",
230
+ prompt: storage,
231
+ state: { ...start, highlight: 2, other: "MySQL", phase: "other" },
232
+ position: 1,
233
+ total: 1,
234
+ },
235
+ {
236
+ name: "2 of 3",
237
+ kind: "question",
238
+ prompt: storage,
239
+ state: { ...start, highlight: 1 },
240
+ position: 2,
241
+ total: 3,
242
+ },
243
+ {
244
+ name: "sending",
245
+ kind: "question",
246
+ prompt: storage,
247
+ state: { ...start, phase: "sending" },
248
+ position: 1,
249
+ total: 1,
250
+ },
251
+ {
252
+ name: "refused",
253
+ kind: "question",
254
+ prompt: storage,
255
+ state: {
256
+ ...start,
257
+ phase: "refused",
258
+ refusal: "That question is already closed.",
259
+ },
260
+ position: 1,
261
+ total: 1,
262
+ },
263
+ {
264
+ name: "approval",
265
+ kind: "approval",
266
+ prompt: approval,
267
+ state: start,
268
+ position: 1,
269
+ total: 1,
270
+ },
271
+ {
272
+ name: "approval confirm",
273
+ kind: "approval",
274
+ prompt: confirmation,
275
+ state: start,
276
+ position: 1,
277
+ total: 2,
278
+ },
279
+ {
280
+ name: "approval refused",
281
+ kind: "approval",
282
+ prompt: approval,
283
+ state: {
284
+ ...start,
285
+ phase: "refused",
286
+ refusal: "This request changed. Look again before answering.",
287
+ },
288
+ position: 1,
289
+ total: 1,
290
+ },
291
+ ];
@@ -19,6 +19,45 @@ type SlashParityCase = Readonly<{
19
19
 
20
20
  One input every renderer must complete identically.
21
21
 
22
+ ---
23
+
24
+ ### AwaitingFixtureState
25
+
26
+ ```ts
27
+ type AwaitingFixtureState = Readonly<{
28
+ highlight: number;
29
+ toggled: ReadonlySet<string>;
30
+ other: string;
31
+ phase: "choose" | "other" | "confirm" | "sending" | "refused";
32
+ refusal?: string;
33
+ details: boolean;
34
+ }>;
35
+ ```
36
+
37
+ The state of one decision a fixture holds, shaped like the Parakeet reducer's.
38
+
39
+ ---
40
+
41
+ ### AwaitingFixture
42
+
43
+ ```ts
44
+ type AwaitingFixture = Readonly<{
45
+ name: string;
46
+ kind: "question" | "approval";
47
+ prompt: Extract<
48
+ WhistlePrompt,
49
+ {
50
+ type: "decision";
51
+ }
52
+ >;
53
+ state: AwaitingFixtureState;
54
+ position: number;
55
+ total: number;
56
+ }>;
57
+ ```
58
+
59
+ One decision shown at one moment, held identically by every renderer's test.
60
+
22
61
  ## Variables
23
62
 
24
63
  ### idleActivity
@@ -81,6 +120,17 @@ The flow every renderer runs: `/water`, choose the fern bed, see the result.
81
120
  | <a id="property-choose"></a> `choose` | `"Fern bed"` | `"Fern bed"` |
82
121
  | <a id="property-notice"></a> `notice` | `"Watered the fern bed."` | `"Watered the fern bed."` |
83
122
 
123
+ ---
124
+
125
+ ### awaitingFixtures
126
+
127
+ ```ts
128
+ const awaitingFixtures: readonly AwaitingFixture[];
129
+ ```
130
+
131
+ The decisions every renderer must draw the same way. Each Parakeet renderer
132
+ renders every fixture and holds its output to `decisionView`.
133
+
84
134
  ## Functions
85
135
 
86
136
  ### queuedActivity()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/parakeet-testing",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "description": "Test-only garden extension and slash-parity fixtures for a typed Shiitake Session, shared by every Parakeet-protocol renderer's tests",
6
6
  "type": "module",
@@ -19,8 +19,8 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "dependencies": {
22
- "@fungi.computer/shiitake": "0.5.0",
23
- "@fungi.computer/whistle": "0.2.0",
22
+ "@fungi.computer/shiitake": "0.7.0",
23
+ "@fungi.computer/whistle": "0.3.0",
24
24
  "zod": "4.4.3"
25
25
  },
26
26
  "devDependencies": {