setup-agent 0.0.2 → 0.0.4
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 +10 -6
- package/dist/cli.d.ts +51 -45
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -30
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +4 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +13 -5
- package/dist/client.js.map +1 -1
- package/dist/host.d.ts +8 -10
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +79 -76
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/presets.d.ts +23 -25
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +4 -3
- package/dist/presets.js.map +1 -1
- package/dist/protocol.d.ts +260 -262
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +5 -3
- package/dist/protocol.js.map +1 -1
- package/package.json +21 -14
- package/src/cli.test.ts +464 -0
- package/src/cli.ts +80 -40
- package/src/client.test.ts +54 -0
- package/src/client.ts +14 -6
- package/src/host.test.ts +883 -0
- package/src/host.ts +30 -7
- package/src/presets.ts +4 -3
- package/src/protocol.ts +10 -3
package/src/host.ts
CHANGED
|
@@ -34,10 +34,10 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
34
34
|
|
|
35
35
|
const requireOpen = () => {
|
|
36
36
|
if (state.createdAt === null) {
|
|
37
|
-
throw reject("not-created", "the
|
|
37
|
+
throw reject("not-created", "the setup has not been created yet");
|
|
38
38
|
}
|
|
39
39
|
if (isClosed(state)) {
|
|
40
|
-
throw reject("closed", `the
|
|
40
|
+
throw reject("closed", `the setup is ${state.status}`);
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -90,7 +90,7 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
90
90
|
if (state.products.some((product) => product.slug === seed.product)) {
|
|
91
91
|
throw reject(
|
|
92
92
|
"invalid-input",
|
|
93
|
-
`"${seed.product}" is already part of this
|
|
93
|
+
`"${seed.product}" is already part of this setup`,
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
96
|
} else if (kind !== "text" && !seed.options?.length) {
|
|
@@ -98,13 +98,36 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
98
98
|
}
|
|
99
99
|
if (
|
|
100
100
|
seed.multiple &&
|
|
101
|
-
(kind !== "choice" ||
|
|
101
|
+
(kind !== "choice" ||
|
|
102
|
+
seed.options?.some((option) => option.variants?.length))
|
|
102
103
|
) {
|
|
103
104
|
throw reject(
|
|
104
105
|
"invalid-input",
|
|
105
106
|
"only a choice whose options have no variants accepts several answers",
|
|
106
107
|
);
|
|
107
108
|
}
|
|
109
|
+
const unique = (ids: readonly string[]) => new Set(ids).size === ids.length;
|
|
110
|
+
if (
|
|
111
|
+
!unique(seed.options?.map((option) => option.id) ?? []) ||
|
|
112
|
+
seed.options?.some(
|
|
113
|
+
(option) =>
|
|
114
|
+
!unique(option.variants?.map((variant) => variant.id) ?? []),
|
|
115
|
+
)
|
|
116
|
+
) {
|
|
117
|
+
throw reject("invalid-input", "option and variant ids must be unique");
|
|
118
|
+
}
|
|
119
|
+
if (
|
|
120
|
+
seed.options?.some(
|
|
121
|
+
(option) =>
|
|
122
|
+
option.id.includes(":") ||
|
|
123
|
+
option.variants?.some((variant) => variant.id.includes(":")),
|
|
124
|
+
)
|
|
125
|
+
) {
|
|
126
|
+
throw reject(
|
|
127
|
+
"invalid-input",
|
|
128
|
+
'option and variant ids cannot contain ":", which separates them in an answer',
|
|
129
|
+
);
|
|
130
|
+
}
|
|
108
131
|
if (
|
|
109
132
|
seed.default !== undefined &&
|
|
110
133
|
!seed.options?.some((option) => option.id === seed.default)
|
|
@@ -177,7 +200,7 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
177
200
|
const commands = useStatewireCommands<Checkout.Commands>({
|
|
178
201
|
"checkout/create": ({ id, products, instructions }) => {
|
|
179
202
|
if (state.id === id) {
|
|
180
|
-
throw reject("already-created", "the
|
|
203
|
+
throw reject("already-created", "the setup already exists");
|
|
181
204
|
}
|
|
182
205
|
const fresh = initialCheckoutState();
|
|
183
206
|
if (!isAgentPresent(state)) state.agent = fresh.agent;
|
|
@@ -306,7 +329,7 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
306
329
|
plan.feedback = params.feedback.trim();
|
|
307
330
|
},
|
|
308
331
|
"checkout/cancel": () => {
|
|
309
|
-
if (state.
|
|
332
|
+
if (state.createdAt === null || isClosed(state)) return;
|
|
310
333
|
state.status = "cancelled";
|
|
311
334
|
dismissOpenInputs();
|
|
312
335
|
},
|
|
@@ -428,7 +451,7 @@ const useCheckoutHost = (restored: unknown) => {
|
|
|
428
451
|
};
|
|
429
452
|
};
|
|
430
453
|
|
|
431
|
-
/** The
|
|
454
|
+
/** The setup statewire host; pass the durable object's restored snapshot. */
|
|
432
455
|
export const CheckoutHost = (restored?: unknown) =>
|
|
433
456
|
resource(useCheckoutHost)(restored);
|
|
434
457
|
|
package/src/presets.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type PresetId = "framework" | "llm-provider" | "project";
|
|
|
10
10
|
export type PresetOverrides = {
|
|
11
11
|
/** Restrict the options to these ids, in this order; one id locks the choice in. */
|
|
12
12
|
only?: readonly string[];
|
|
13
|
-
/** Options the agent found itself, listed before the preset's own. */
|
|
13
|
+
/** Options the agent found itself, listed before the preset's own; `only` leaves them out. */
|
|
14
14
|
found?: readonly { id: string; description?: string }[];
|
|
15
15
|
default?: string;
|
|
16
16
|
optional?: boolean;
|
|
@@ -139,7 +139,8 @@ export const INPUT_PRESETS: Record<PresetId, Preset> = {
|
|
|
139
139
|
},
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
-
export const isPresetId = (id: string): id is PresetId =>
|
|
142
|
+
export const isPresetId = (id: string): id is PresetId =>
|
|
143
|
+
Object.hasOwn(INPUT_PRESETS, id);
|
|
143
144
|
|
|
144
145
|
/** Build the seed for a standard input, throwing on an unknown preset, option or default. */
|
|
145
146
|
export const presetInput = (
|
|
@@ -164,7 +165,7 @@ export const presetInput = (
|
|
|
164
165
|
}
|
|
165
166
|
return { ...option, label: option.id };
|
|
166
167
|
});
|
|
167
|
-
const options = [...found, ...listed];
|
|
168
|
+
const options = overrides.only ? listed : [...found, ...listed];
|
|
168
169
|
const fallback = options.some((o) => o.id === preset.default)
|
|
169
170
|
? preset.default
|
|
170
171
|
: undefined;
|
package/src/protocol.ts
CHANGED
|
@@ -282,12 +282,17 @@ export const isClosed = (state: Checkout.State) =>
|
|
|
282
282
|
export const finishProposed = (state: Checkout.State) =>
|
|
283
283
|
!isClosed(state) && state.completion !== undefined;
|
|
284
284
|
|
|
285
|
-
/** True
|
|
285
|
+
/** True while a message the user sent after the agent proposed to close still waits for the agent. */
|
|
286
286
|
export const followedUpSinceProposal = (state: Checkout.State) => {
|
|
287
287
|
const proposedAt = state.completion?.proposedAt;
|
|
288
288
|
return (
|
|
289
289
|
proposedAt !== undefined &&
|
|
290
|
-
state.log.some(
|
|
290
|
+
state.log.some(
|
|
291
|
+
(entry) =>
|
|
292
|
+
entry.role === "user" &&
|
|
293
|
+
entry.at > proposedAt &&
|
|
294
|
+
entry.acknowledgedAt === undefined,
|
|
295
|
+
)
|
|
291
296
|
);
|
|
292
297
|
};
|
|
293
298
|
|
|
@@ -376,7 +381,9 @@ export const isOptionIcon = (value: string): value is OptionIcon =>
|
|
|
376
381
|
(OPTION_ICONS as readonly string[]).includes(value);
|
|
377
382
|
|
|
378
383
|
export const parseChoiceAnswer = (answer: string) => {
|
|
379
|
-
const
|
|
384
|
+
const parts = answer.split(":");
|
|
385
|
+
if (parts.length > 2) return { option: answer };
|
|
386
|
+
const [option = "", variant] = parts;
|
|
380
387
|
return { option, ...(variant !== undefined && { variant }) };
|
|
381
388
|
};
|
|
382
389
|
|