@bud.sh/app 0.5.0 → 0.6.0
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 +41 -31
- package/dist/client/assets/bud/design.js +1 -1
- package/dist/client/assets/canvas-Bih9EdKJ.js +1 -0
- package/dist/client/assets/difference-worker-Bzg-rizy.js +8 -0
- package/dist/client/assets/dist-CdE5wBkg.js +5 -0
- package/dist/client/assets/files-1dLuoM2f.js +1 -0
- package/dist/client/assets/i18n-CkO6VFI0.js +1 -0
- package/dist/client/assets/index-Cn2mxroU.css +2 -0
- package/dist/client/assets/{index-ChANGtl-.js → index-DtISWZp9.js} +2 -2
- package/dist/client/assets/pages-BJ-tNJ4J.js +1 -0
- package/dist/client/assets/{project-branches-DO897zM6.js → project-branches-Ce3rXrkc.js} +1 -1
- package/dist/client/assets/project-comments-CPUONfs8.js +1 -0
- package/dist/client/assets/project-thread-links-C-TGkq59.js +1 -0
- package/dist/client/assets/{project-threads-Lay351p4.js → project-threads-Bv7IDBgi.js} +105 -105
- package/dist/client/assets/project-work-DAE9-olg.js +1 -0
- package/dist/client/assets/{task-design-Avb2RO4w.js → task-design-CwySIAOl.js} +3 -3
- package/dist/client/assets/tasks-KWsCLi_h.js +3 -0
- package/dist/client/assets/wasm-inline-DSUyFn1L.js +1 -0
- package/dist/client/assets/workspace-CVdcfaaB.js +2 -0
- package/dist/client/index.html +3 -3
- package/dist/hosted/assets/{canvas-V36732ER.js → canvas-AII16n9i.js} +97 -6
- package/dist/hosted/assets/{comment-data-CF2ZV_3k.js → comment-data-BXfMElfx.js} +2004 -402
- package/dist/hosted/assets/dist-BCSTeNf4.js +4785 -0
- package/dist/hosted/assets/{files-DjSCjfU7.js → files-D_1yeAVO.js} +10 -5
- package/dist/hosted/assets/{pages-BzjzeuPu.js → pages-CN_SbKWA.js} +3 -3
- package/dist/hosted/assets/{project-branches-BT97J9i7.js → project-branches-Bxp0DCwg.js} +1 -1
- package/dist/hosted/assets/{project-thread-links-BRLgByEe.js → project-thread-links-KqQoKBLE.js} +76 -4
- package/dist/{node-host/assets/screen-CZXWJEds.js → hosted/assets/screen-DpAcDUKR.js} +29 -1
- package/dist/hosted/assets/tasks-D66LlwxM.js +1423 -0
- package/dist/hosted/assets/wasm-inline-Dl9tqabx.js +4 -0
- package/dist/hosted/hosted.js +7885 -6219
- package/dist/node/assets/Stream-CAm1eJ2n.js +16604 -0
- package/dist/{server/assets/bridge-B_Blt55E.js → node/assets/bridge-DQSBYHmw.js} +124 -290
- package/dist/node/assets/config-9_jWwNBh.js +1067 -0
- package/dist/node/assets/load-config.server-CMVtRVmO.js +261 -0
- package/dist/node/assets/module-3GgtT4Xs.js +308 -0
- package/dist/node/assets/server-DTQFuoX2.js +846 -0
- package/dist/node/assets/src-D-kG1GxB.js +2 -0
- package/dist/node/assets/{src-CerrKjID.js → src-Dwe9APUx.js} +93 -3
- package/dist/node/assets/src-DysjfbM8.js +8592 -0
- package/dist/node/bridge.js +1 -845
- package/dist/node/cli.js +206 -0
- package/dist/node/design.js +811 -13
- package/dist/node/index.js +2 -739
- package/dist/node/plugins.js +5711 -0
- package/dist/node/server.js +1 -6746
- package/dist/node/vite.js +121 -0
- package/dist/{server/assets/canvas-Dc1mYCwQ.js → node-host/assets/canvas-BeDoufy1.js} +97 -7
- package/dist/node-host/assets/{comment-data-DyIZNpfG.js → comment-data-DE2T9yTj.js} +1980 -376
- package/dist/node-host/assets/dist-BCSTeNf4.js +4785 -0
- package/dist/node-host/assets/{files-Dh2TiQZq.js → files-Dl-PTS09.js} +11 -6
- package/dist/node-host/assets/{pages-BxpjbYhs.js → pages-DL2sk6_U.js} +3 -3
- package/dist/node-host/assets/{project-branches-B7HUGiVK.js → project-branches-DGp5ELct.js} +1 -1
- package/dist/{server/assets/project-thread-links-CBOpf6zk.js → node-host/assets/project-thread-links-CgBV3Jcm.js} +76 -5
- package/dist/{hosted/assets/screen-CKp2C7kx.js → node-host/assets/screen-B55yyVfb.js} +29 -1
- package/dist/node-host/assets/tasks-DZRNkoxe.js +1425 -0
- package/dist/node-host/assets/wasm-inline-Dl9tqabx.js +4 -0
- package/dist/node-host/node-host.js +6127 -4438
- package/dist/server/assets/{branch-previews-ClkoJ0lM.js → branch-previews-DedrpnVR.js} +1555 -673
- package/dist/{node-host/assets/canvas-TRUfxfL5.js → server/assets/canvas-CJWQ-jjv.js} +98 -6
- package/dist/server/assets/{comment-data-CsjukwAW.js → comment-data-Rg42ToTW.js} +1666 -47
- package/dist/server/assets/dist-BCSTeNf4.js +4785 -0
- package/dist/server/assets/{events-iHpLGr3k.js → events-BH_rAu7O.js} +155 -20
- package/dist/server/assets/{files-E9mSFeoc.js → files-CPJqKeMo.js} +12 -7
- package/dist/server/assets/{listener-DN5TyOjJ.js → listener-D61O6PzF.js} +708 -12
- package/dist/server/assets/{pages-BBBXyJWV.js → pages-KJY_Ba92.js} +4 -4
- package/dist/server/assets/{project-branches-B0YIK6Ur.js → project-branches-qG9ACZvo.js} +2 -2
- package/dist/{node-host/assets/project-thread-links-CauJF0Cz.js → server/assets/project-thread-links-CqK0lqCF.js} +77 -4
- package/dist/{node-host/assets/tasks-request-ZWmbc8fE.js → server/assets/project-work-DoIwxWMm.js} +87 -2
- package/dist/server/assets/run-BJ8r5jSh.js +572 -0
- package/dist/server/assets/{screen-BIQA2mr4.js → screen-CBrHPFug.js} +30 -2
- package/dist/server/assets/{server-DxK-UB_Z.js → server-Dkbp5stG.js} +1521 -793
- package/dist/server/assets/{services-BRrgXYlT.js → services-BTfig8A8.js} +234 -997
- package/dist/server/assets/tasks-Bgu5Lg9Y.js +1427 -0
- package/dist/server/assets/wasm-inline-Dl9tqabx.js +4 -0
- package/dist/server/capture.js +1 -2
- package/dist/server/migration.js +569 -12
- package/dist/server/runtime.js +7 -5
- package/dist/server/server.js +3 -3
- package/dist/types/assets/{config-DIC2cf_S.d.ts → config-CvcYmE2s.d.ts} +188 -50
- package/dist/types/assets/{contract-CAT-XFNq.d.ts → contract-B7yuuqSn.d.ts} +44 -2
- package/dist/types/assets/{items-CaVkByHk.d.ts → items-BQdaVksf.d.ts} +12 -1
- package/dist/types/assets/memory-state-BBW-FAVA.d.ts +236 -0
- package/dist/types/assets/picker-Be5Gx4WR.d.ts +9 -0
- package/dist/types/assets/{task-design-xJOhRNWh.d.ts → task-design-BDHKFHpp.d.ts} +3 -1
- package/dist/types/bridge.d.ts +1 -1
- package/dist/types/companion.d.ts +3 -3
- package/dist/types/design.d.ts +2 -2
- package/dist/types/hosted.d.ts +3 -3
- package/dist/types/index.d.ts +2 -2
- package/dist/types/node-host.d.ts +2 -2
- package/dist/types/plugins.d.ts +445 -0
- package/dist/types/screen.d.ts +2 -2
- package/dist/types/server.d.ts +2 -228
- package/dist/types/vite.d.ts +16 -0
- package/package.json +19 -3
- package/dist/client/assets/canvas-Cu6R6xxT.js +0 -1
- package/dist/client/assets/difference-worker-jfTSn-Tw.js +0 -8
- package/dist/client/assets/files-js6ElfkU.js +0 -1
- package/dist/client/assets/i18n-DxqFr2mi.js +0 -1
- package/dist/client/assets/index-CFFxP0gS.css +0 -2
- package/dist/client/assets/pages-6_lhiQmz.js +0 -1
- package/dist/client/assets/project-comments-DFFKVpia.js +0 -1
- package/dist/client/assets/project-thread-links-NLFWQRD2.js +0 -1
- package/dist/client/assets/project-work-du0Y-L5Y.js +0 -1
- package/dist/client/assets/tasks-CA-E8bbK.js +0 -1
- package/dist/client/assets/tasks-request-C55IeuiP.js +0 -1
- package/dist/client/assets/workspace-Cw5HvX5d.js +0 -2
- package/dist/hosted/assets/tasks-Dj7AyBJB.js +0 -649
- package/dist/hosted/assets/tasks-request-DZob623r.js +0 -113
- package/dist/node-host/assets/tasks-Bs1IOpeU.js +0 -651
- package/dist/server/assets/project-work-qSKFO5yj.js +0 -88
- package/dist/server/assets/tasks-CiXodsLN.js +0 -652
- package/dist/server/assets/tasks-request-DhwCzpRi.js +0 -115
- package/dist/types/assets/picker-D1Bw3ndx.d.ts +0 -14
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import { rn as parseElementAnchor } from "./events-BH_rAu7O.js";
|
|
2
|
+
//#region app/task-context.ts
|
|
3
|
+
var hash = /^[a-f0-9]{64}$/;
|
|
4
|
+
function object(value) {
|
|
5
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
6
|
+
}
|
|
7
|
+
function point(value) {
|
|
8
|
+
let input = object(value);
|
|
9
|
+
if (!input) return null;
|
|
10
|
+
let { x, y } = input;
|
|
11
|
+
return typeof x === "number" && typeof y === "number" && Number.isFinite(x) && Number.isFinite(y) ? {
|
|
12
|
+
x,
|
|
13
|
+
y
|
|
14
|
+
} : null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Validates a stored task context.
|
|
18
|
+
* @param value - Untrusted stored data.
|
|
19
|
+
* @returns The context, or null when there is none or it can't be read.
|
|
20
|
+
*/
|
|
21
|
+
function parseTaskContext(value) {
|
|
22
|
+
let input = object(value);
|
|
23
|
+
if (!input || input.version !== 1 || typeof input.thread !== "string") return null;
|
|
24
|
+
let page = object(input.page);
|
|
25
|
+
let code = object(input.code);
|
|
26
|
+
let element = null;
|
|
27
|
+
try {
|
|
28
|
+
element = input.element ? parseElementAnchor(input.element) : null;
|
|
29
|
+
} catch {}
|
|
30
|
+
return {
|
|
31
|
+
version: 1,
|
|
32
|
+
thread: input.thread.slice(0, 200),
|
|
33
|
+
page: page && typeof page.id === "string" && typeof page.path === "string" ? {
|
|
34
|
+
id: page.id,
|
|
35
|
+
path: page.path,
|
|
36
|
+
title: typeof page.title === "string" ? page.title : page.path
|
|
37
|
+
} : null,
|
|
38
|
+
viewport: typeof input.viewport === "number" ? input.viewport : null,
|
|
39
|
+
branch: typeof input.branch === "string" ? input.branch : null,
|
|
40
|
+
point: point(input.point),
|
|
41
|
+
element,
|
|
42
|
+
image: typeof input.image === "string" && hash.test(input.image) ? input.image : null,
|
|
43
|
+
code: code && typeof code.path === "string" && typeof code.startLine === "number" && typeof code.endLine === "number" ? {
|
|
44
|
+
path: code.path,
|
|
45
|
+
startLine: code.startLine,
|
|
46
|
+
endLine: code.endLine,
|
|
47
|
+
commit: typeof code.commit === "string" ? code.commit : null
|
|
48
|
+
} : null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validates what a browser sends with Make task.
|
|
53
|
+
* @param value - The request's `context`.
|
|
54
|
+
* @returns The screenshot's bytes, the element and the point, each when given and valid.
|
|
55
|
+
*/
|
|
56
|
+
function parseTaskContextInput(value) {
|
|
57
|
+
let input = object(value);
|
|
58
|
+
if (!input) return {
|
|
59
|
+
image: null,
|
|
60
|
+
element: null,
|
|
61
|
+
point: null
|
|
62
|
+
};
|
|
63
|
+
let image = null;
|
|
64
|
+
if (typeof input.image === "string" && input.image.length <= 3e6) try {
|
|
65
|
+
image = Uint8Array.from(atob(input.image), (character) => character.charCodeAt(0));
|
|
66
|
+
} catch {}
|
|
67
|
+
let element = null;
|
|
68
|
+
try {
|
|
69
|
+
element = input.element ? parseElementAnchor(input.element) : null;
|
|
70
|
+
} catch {}
|
|
71
|
+
return {
|
|
72
|
+
image,
|
|
73
|
+
element,
|
|
74
|
+
point: point(input.point)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region ../factory/src/lib/run.ts
|
|
79
|
+
/** Every run state, in the order a run passes them. */
|
|
80
|
+
var RUN_STATES = [
|
|
81
|
+
"provisioning",
|
|
82
|
+
"working",
|
|
83
|
+
"review",
|
|
84
|
+
"needs_context",
|
|
85
|
+
"changes",
|
|
86
|
+
"approved",
|
|
87
|
+
"pushing",
|
|
88
|
+
"pushed",
|
|
89
|
+
"merged",
|
|
90
|
+
"failed",
|
|
91
|
+
"discarded"
|
|
92
|
+
];
|
|
93
|
+
/** States in which a run waits for people, and its sandbox sleeps after a while. */
|
|
94
|
+
var RUN_WAITING_STATES = [
|
|
95
|
+
"review",
|
|
96
|
+
"needs_context",
|
|
97
|
+
"failed"
|
|
98
|
+
];
|
|
99
|
+
/** The line an agent ends its reply with to ask a person for what it needs. */
|
|
100
|
+
var NEEDS_CONTEXT_MARKER = "NEEDS CONTEXT:";
|
|
101
|
+
/**
|
|
102
|
+
* The question an agent's reply asks a person, from its `NEEDS CONTEXT:` line.
|
|
103
|
+
* @param reply - The agent's last reply.
|
|
104
|
+
* @returns The question, or null when the agent didn't ask one.
|
|
105
|
+
*/
|
|
106
|
+
function askedQuestion(reply) {
|
|
107
|
+
let lines = reply.split("\n");
|
|
108
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
109
|
+
let line = lines[index].trim().replace(/^[*_`>\s]+/, "");
|
|
110
|
+
if (line.toUpperCase().startsWith("NEEDS CONTEXT:")) {
|
|
111
|
+
let question = [line.slice(14), ...lines.slice(index + 1)].join("\n").replace(/^[*_`\s]+|[*_`\s]+$/g, "");
|
|
112
|
+
return question ? question.slice(0, 2e3) : null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
/** States a run can't leave; a new run starts the task again. */
|
|
118
|
+
var ENDED_RUN_STATES = [
|
|
119
|
+
"pushed",
|
|
120
|
+
"merged",
|
|
121
|
+
"discarded"
|
|
122
|
+
];
|
|
123
|
+
/** A step the run's state doesn't allow, such as approving a run that is still working. */
|
|
124
|
+
var RunTransitionError = class extends Error {
|
|
125
|
+
state;
|
|
126
|
+
event;
|
|
127
|
+
constructor(state, event) {
|
|
128
|
+
super(`A run can't ${event} while it is ${state ?? "not started"}.`);
|
|
129
|
+
this.state = state;
|
|
130
|
+
this.event = event;
|
|
131
|
+
this.name = "RunTransitionError";
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var MAX_ACTIVITY = 50;
|
|
135
|
+
var MAX_ACTIVITY_TEXT = 500;
|
|
136
|
+
var MAX_PREVIOUS = 10;
|
|
137
|
+
var MAX_SUMMARY = 1e4;
|
|
138
|
+
/**
|
|
139
|
+
* The branch a task's run works on: the prefix, the task id and a short slug of its title.
|
|
140
|
+
* @param prefix - Such as `dev/`.
|
|
141
|
+
* @param taskId - The task's id.
|
|
142
|
+
* @param title - The task's title.
|
|
143
|
+
* @returns Such as `dev/fw-123-make-the-heading-larger`.
|
|
144
|
+
*/
|
|
145
|
+
function runBranch(prefix, taskId, title) {
|
|
146
|
+
let slug = title.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
|
|
147
|
+
return `${prefix}${taskId.toLowerCase().replace(/[^a-z0-9._-]+/g, "-")}${slug ? `-${slug}` : ""}`;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Whether a run is still going: started and neither pushed nor discarded.
|
|
151
|
+
* @param run - The task's run, if any.
|
|
152
|
+
* @returns Whether it is active.
|
|
153
|
+
*/
|
|
154
|
+
function runActive(run) {
|
|
155
|
+
return Boolean(run && !ENDED_RUN_STATES.includes(run.state));
|
|
156
|
+
}
|
|
157
|
+
function withActivity(run, entry, at) {
|
|
158
|
+
let line = {
|
|
159
|
+
at,
|
|
160
|
+
kind: entry.kind,
|
|
161
|
+
text: entry.text.slice(0, MAX_ACTIVITY_TEXT)
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
...run,
|
|
165
|
+
activity: [...run.activity, line].slice(-50)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function refuse(run, event) {
|
|
169
|
+
throw new RunTransitionError(run?.state ?? null, event);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Starts a task's run, keeping a short note of the run before it.
|
|
173
|
+
* @param previous - The task's last run, which must have ended or failed.
|
|
174
|
+
* @param start - What the run starts from.
|
|
175
|
+
* @param at - The time.
|
|
176
|
+
* @returns The new run, the task's status and the sandbox to set up.
|
|
177
|
+
*/
|
|
178
|
+
function startRun(previous, start, at) {
|
|
179
|
+
if (previous && runActive(previous) && previous.state !== "failed") refuse(previous, "start");
|
|
180
|
+
let earlier = previous ? [{
|
|
181
|
+
id: previous.id,
|
|
182
|
+
state: previous.state,
|
|
183
|
+
endedAt: at
|
|
184
|
+
}, ...previous.previous] : [];
|
|
185
|
+
let run = {
|
|
186
|
+
version: 1,
|
|
187
|
+
id: start.id,
|
|
188
|
+
state: "provisioning",
|
|
189
|
+
failedIn: null,
|
|
190
|
+
provider: start.provider,
|
|
191
|
+
sandbox: null,
|
|
192
|
+
harness: start.harness,
|
|
193
|
+
model: start.model,
|
|
194
|
+
session: null,
|
|
195
|
+
ports: {
|
|
196
|
+
dev: null,
|
|
197
|
+
agent: null
|
|
198
|
+
},
|
|
199
|
+
asleep: false,
|
|
200
|
+
branch: runBranch(start.branchPrefix, start.taskId, start.title),
|
|
201
|
+
base: {
|
|
202
|
+
branch: start.base,
|
|
203
|
+
commit: null
|
|
204
|
+
},
|
|
205
|
+
head: null,
|
|
206
|
+
pushed: null,
|
|
207
|
+
summary: null,
|
|
208
|
+
question: null,
|
|
209
|
+
activity: [],
|
|
210
|
+
error: null,
|
|
211
|
+
startedBy: start.by,
|
|
212
|
+
approvedBy: null,
|
|
213
|
+
createdAt: at,
|
|
214
|
+
updatedAt: at,
|
|
215
|
+
previous: earlier.slice(0, MAX_PREVIOUS)
|
|
216
|
+
};
|
|
217
|
+
let effects = previous?.state === "failed" ? [{ type: "destroy" }] : [];
|
|
218
|
+
return {
|
|
219
|
+
run: withActivity(run, {
|
|
220
|
+
kind: "status",
|
|
221
|
+
text: "Started"
|
|
222
|
+
}, at),
|
|
223
|
+
status: "inProgress",
|
|
224
|
+
effects: [...effects, { type: "provision" }]
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The next step of a run: the state machine of the factory.
|
|
229
|
+
* @param run - The run as stored.
|
|
230
|
+
* @param event - What happened.
|
|
231
|
+
* @param at - The time.
|
|
232
|
+
* @returns The run to save, the task status that follows and what Bud does next.
|
|
233
|
+
*/
|
|
234
|
+
function advanceRun(run, event, at) {
|
|
235
|
+
let next = {
|
|
236
|
+
...run,
|
|
237
|
+
updatedAt: at
|
|
238
|
+
};
|
|
239
|
+
switch (event.type) {
|
|
240
|
+
case "ready":
|
|
241
|
+
if (run.state !== "provisioning") refuse(run, "become ready");
|
|
242
|
+
return {
|
|
243
|
+
run: withActivity({
|
|
244
|
+
...next,
|
|
245
|
+
state: "working",
|
|
246
|
+
sandbox: event.sandbox,
|
|
247
|
+
session: event.session,
|
|
248
|
+
ports: event.ports,
|
|
249
|
+
base: {
|
|
250
|
+
...run.base,
|
|
251
|
+
commit: event.commit
|
|
252
|
+
}
|
|
253
|
+
}, {
|
|
254
|
+
kind: "status",
|
|
255
|
+
text: "Agent working"
|
|
256
|
+
}, at),
|
|
257
|
+
effects: []
|
|
258
|
+
};
|
|
259
|
+
case "created":
|
|
260
|
+
if (run.state !== "provisioning") refuse(run, "record its sandbox");
|
|
261
|
+
return {
|
|
262
|
+
run: {
|
|
263
|
+
...next,
|
|
264
|
+
sandbox: event.sandbox
|
|
265
|
+
},
|
|
266
|
+
effects: []
|
|
267
|
+
};
|
|
268
|
+
case "activity":
|
|
269
|
+
if (![
|
|
270
|
+
"provisioning",
|
|
271
|
+
"working",
|
|
272
|
+
"changes"
|
|
273
|
+
].includes(run.state)) refuse(run, "report activity");
|
|
274
|
+
return {
|
|
275
|
+
run: withActivity(next, event.entry, at),
|
|
276
|
+
effects: []
|
|
277
|
+
};
|
|
278
|
+
case "idle": {
|
|
279
|
+
if (run.state !== "working" && run.state !== "changes") refuse(run, "finish");
|
|
280
|
+
let question = askedQuestion(event.summary);
|
|
281
|
+
if (question) return {
|
|
282
|
+
run: withActivity({
|
|
283
|
+
...next,
|
|
284
|
+
state: "needs_context",
|
|
285
|
+
question,
|
|
286
|
+
summary: event.summary.slice(0, MAX_SUMMARY),
|
|
287
|
+
head: event.head ?? run.head
|
|
288
|
+
}, {
|
|
289
|
+
kind: "status",
|
|
290
|
+
text: "Needs context"
|
|
291
|
+
}, at),
|
|
292
|
+
effects: [{ type: "doze" }]
|
|
293
|
+
};
|
|
294
|
+
return {
|
|
295
|
+
run: withActivity({
|
|
296
|
+
...next,
|
|
297
|
+
state: "review",
|
|
298
|
+
question: null,
|
|
299
|
+
summary: event.summary.slice(0, MAX_SUMMARY),
|
|
300
|
+
head: event.head ?? run.head
|
|
301
|
+
}, {
|
|
302
|
+
kind: "status",
|
|
303
|
+
text: "Needs approval"
|
|
304
|
+
}, at),
|
|
305
|
+
status: "needsApproval",
|
|
306
|
+
effects: [{ type: "doze" }]
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
case "answer":
|
|
310
|
+
if (run.state !== "needs_context") refuse(run, "take an answer");
|
|
311
|
+
return {
|
|
312
|
+
run: withActivity({
|
|
313
|
+
...next,
|
|
314
|
+
state: "changes",
|
|
315
|
+
question: null
|
|
316
|
+
}, {
|
|
317
|
+
kind: "message",
|
|
318
|
+
text: `${event.by.name}: ${event.message}`
|
|
319
|
+
}, at),
|
|
320
|
+
effects: [{
|
|
321
|
+
type: "send",
|
|
322
|
+
message: event.message
|
|
323
|
+
}]
|
|
324
|
+
};
|
|
325
|
+
case "changes":
|
|
326
|
+
if (run.state !== "review") refuse(run, "take changes");
|
|
327
|
+
return {
|
|
328
|
+
run: withActivity({
|
|
329
|
+
...next,
|
|
330
|
+
state: "changes"
|
|
331
|
+
}, {
|
|
332
|
+
kind: "message",
|
|
333
|
+
text: `${event.by.name}: ${event.message}`
|
|
334
|
+
}, at),
|
|
335
|
+
status: "inProgress",
|
|
336
|
+
effects: [{
|
|
337
|
+
type: "send",
|
|
338
|
+
message: event.message
|
|
339
|
+
}]
|
|
340
|
+
};
|
|
341
|
+
case "approve":
|
|
342
|
+
if (run.state !== "review") refuse(run, "be approved");
|
|
343
|
+
return {
|
|
344
|
+
run: withActivity({
|
|
345
|
+
...next,
|
|
346
|
+
state: "pushing",
|
|
347
|
+
approvedBy: event.by
|
|
348
|
+
}, {
|
|
349
|
+
kind: "status",
|
|
350
|
+
text: `Approved by ${event.by.name}`
|
|
351
|
+
}, at),
|
|
352
|
+
effects: [{ type: "push" }]
|
|
353
|
+
};
|
|
354
|
+
case "pushed":
|
|
355
|
+
if (run.state !== "pushing" && run.state !== "approved") refuse(run, "be pushed");
|
|
356
|
+
return {
|
|
357
|
+
run: withActivity({
|
|
358
|
+
...next,
|
|
359
|
+
state: "pushed",
|
|
360
|
+
pushed: event.commit,
|
|
361
|
+
error: null,
|
|
362
|
+
asleep: true
|
|
363
|
+
}, {
|
|
364
|
+
kind: "status",
|
|
365
|
+
text: `Pushed ${run.branch}`
|
|
366
|
+
}, at),
|
|
367
|
+
status: "readyToMerge",
|
|
368
|
+
effects: [{ type: "stop" }]
|
|
369
|
+
};
|
|
370
|
+
case "merged":
|
|
371
|
+
if (run.state !== "pushed") refuse(run, "be merged");
|
|
372
|
+
return {
|
|
373
|
+
run: withActivity({
|
|
374
|
+
...next,
|
|
375
|
+
state: "merged"
|
|
376
|
+
}, {
|
|
377
|
+
kind: "status",
|
|
378
|
+
text: `Merged ${run.branch}`
|
|
379
|
+
}, at),
|
|
380
|
+
status: "merged",
|
|
381
|
+
effects: [{ type: "destroy" }]
|
|
382
|
+
};
|
|
383
|
+
case "discard":
|
|
384
|
+
if (![
|
|
385
|
+
"review",
|
|
386
|
+
"needs_context",
|
|
387
|
+
"failed",
|
|
388
|
+
"provisioning",
|
|
389
|
+
"working",
|
|
390
|
+
"changes"
|
|
391
|
+
].includes(run.state)) refuse(run, "be discarded");
|
|
392
|
+
return {
|
|
393
|
+
run: withActivity({
|
|
394
|
+
...next,
|
|
395
|
+
state: "discarded"
|
|
396
|
+
}, {
|
|
397
|
+
kind: "status",
|
|
398
|
+
text: "Discarded"
|
|
399
|
+
}, at),
|
|
400
|
+
status: "open",
|
|
401
|
+
effects: [{ type: "destroy" }]
|
|
402
|
+
};
|
|
403
|
+
case "fail":
|
|
404
|
+
if (ENDED_RUN_STATES.includes(run.state) || run.state === "failed") refuse(run, "fail");
|
|
405
|
+
return {
|
|
406
|
+
run: withActivity({
|
|
407
|
+
...next,
|
|
408
|
+
state: "failed",
|
|
409
|
+
failedIn: run.state,
|
|
410
|
+
error: {
|
|
411
|
+
message: event.message.slice(0, MAX_ACTIVITY_TEXT),
|
|
412
|
+
at,
|
|
413
|
+
retryable: event.retryable
|
|
414
|
+
}
|
|
415
|
+
}, {
|
|
416
|
+
kind: "error",
|
|
417
|
+
text: event.message
|
|
418
|
+
}, at),
|
|
419
|
+
effects: run.sandbox && !run.asleep ? [{ type: "doze" }] : []
|
|
420
|
+
};
|
|
421
|
+
case "sleep":
|
|
422
|
+
if (run.asleep || !RUN_WAITING_STATES.includes(run.state)) refuse(run, "sleep");
|
|
423
|
+
return {
|
|
424
|
+
run: withActivity({
|
|
425
|
+
...next,
|
|
426
|
+
asleep: true
|
|
427
|
+
}, {
|
|
428
|
+
kind: "status",
|
|
429
|
+
text: "Sandbox asleep"
|
|
430
|
+
}, at),
|
|
431
|
+
effects: [{ type: "stop" }]
|
|
432
|
+
};
|
|
433
|
+
case "wake":
|
|
434
|
+
if (!run.asleep || ENDED_RUN_STATES.includes(run.state)) refuse(run, "wake");
|
|
435
|
+
return {
|
|
436
|
+
run: withActivity({
|
|
437
|
+
...next,
|
|
438
|
+
asleep: false
|
|
439
|
+
}, {
|
|
440
|
+
kind: "status",
|
|
441
|
+
text: "Sandbox awake"
|
|
442
|
+
}, at),
|
|
443
|
+
effects: []
|
|
444
|
+
};
|
|
445
|
+
case "retry": {
|
|
446
|
+
if (run.state !== "failed" || !run.failedIn || !run.error?.retryable) refuse(run, "be retried");
|
|
447
|
+
let state = run.failedIn;
|
|
448
|
+
return {
|
|
449
|
+
run: withActivity({
|
|
450
|
+
...next,
|
|
451
|
+
state,
|
|
452
|
+
failedIn: null,
|
|
453
|
+
error: null
|
|
454
|
+
}, {
|
|
455
|
+
kind: "status",
|
|
456
|
+
text: "Retrying"
|
|
457
|
+
}, at),
|
|
458
|
+
effects: [...state === "provisioning" && run.sandbox ? [{ type: "destroy" }] : [], {
|
|
459
|
+
type: "resume",
|
|
460
|
+
state
|
|
461
|
+
}]
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function isObject(value) {
|
|
467
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
468
|
+
}
|
|
469
|
+
function text(value, field, max, nullable = false) {
|
|
470
|
+
if (nullable && value === null) return value;
|
|
471
|
+
if (typeof value !== "string" || value.length > max) throw new TypeError(`Invalid run ${field}.`);
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
function state(value, field) {
|
|
475
|
+
if (!RUN_STATES.includes(value)) throw new TypeError(`Invalid run ${field}.`);
|
|
476
|
+
return value;
|
|
477
|
+
}
|
|
478
|
+
function port(value) {
|
|
479
|
+
if (value === null || value === void 0) return null;
|
|
480
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 65535) throw new TypeError("Invalid run port.");
|
|
481
|
+
return value;
|
|
482
|
+
}
|
|
483
|
+
function ports(value) {
|
|
484
|
+
if (value === void 0) return {
|
|
485
|
+
dev: null,
|
|
486
|
+
agent: null
|
|
487
|
+
};
|
|
488
|
+
if (!isObject(value)) throw new TypeError("Invalid run ports.");
|
|
489
|
+
let terminal = port(value.terminal);
|
|
490
|
+
let preview = port(value.preview);
|
|
491
|
+
return {
|
|
492
|
+
dev: port(value.dev),
|
|
493
|
+
agent: port(value.agent),
|
|
494
|
+
...terminal ? { terminal } : {},
|
|
495
|
+
...preview ? { preview } : {}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function person(value, field) {
|
|
499
|
+
if (!isObject(value)) throw new TypeError(`Invalid run ${field}.`);
|
|
500
|
+
return {
|
|
501
|
+
name: text(value.name, field, 1e3),
|
|
502
|
+
email: text(value.email, field, 1e3)
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Validates a run record read from a task's metadata.
|
|
507
|
+
* @param value - Untrusted stored data.
|
|
508
|
+
* @returns The run.
|
|
509
|
+
*/
|
|
510
|
+
function parseRunRecord(value) {
|
|
511
|
+
if (!isObject(value) || value.version !== 1) throw new TypeError("Invalid run.");
|
|
512
|
+
let base = value.base;
|
|
513
|
+
if (!isObject(base)) throw new TypeError("Invalid run base.");
|
|
514
|
+
let error = value.error;
|
|
515
|
+
if (error !== null && !isObject(error)) throw new TypeError("Invalid run error.");
|
|
516
|
+
if (!Array.isArray(value.activity) || value.activity.length > MAX_ACTIVITY) throw new TypeError("Invalid run activity.");
|
|
517
|
+
if (!Array.isArray(value.previous) || value.previous.length > MAX_PREVIOUS) throw new TypeError("Invalid earlier runs.");
|
|
518
|
+
return {
|
|
519
|
+
version: 1,
|
|
520
|
+
id: text(value.id, "id", 100),
|
|
521
|
+
state: state(value.state, "state"),
|
|
522
|
+
failedIn: value.failedIn === null ? null : state(value.failedIn, "failedIn"),
|
|
523
|
+
provider: text(value.provider, "provider", 200),
|
|
524
|
+
sandbox: text(value.sandbox, "sandbox", 500, true),
|
|
525
|
+
harness: text(value.harness, "harness", 200),
|
|
526
|
+
model: text(value.model, "model", 200),
|
|
527
|
+
session: text(value.session, "session", 500, true),
|
|
528
|
+
ports: ports(value.ports),
|
|
529
|
+
asleep: value.asleep === true,
|
|
530
|
+
branch: text(value.branch, "branch", 300),
|
|
531
|
+
base: {
|
|
532
|
+
branch: text(base.branch, "base", 300),
|
|
533
|
+
commit: text(base.commit, "base", 100, true)
|
|
534
|
+
},
|
|
535
|
+
head: text(value.head, "head", 100, true),
|
|
536
|
+
pushed: text(value.pushed, "pushed", 100, true),
|
|
537
|
+
summary: text(value.summary, "summary", MAX_SUMMARY, true),
|
|
538
|
+
question: value.question === void 0 ? null : text(value.question, "question", 2e3, true),
|
|
539
|
+
activity: value.activity.map((entry) => {
|
|
540
|
+
if (!isObject(entry) || ![
|
|
541
|
+
"status",
|
|
542
|
+
"message",
|
|
543
|
+
"tool",
|
|
544
|
+
"error"
|
|
545
|
+
].includes(entry.kind)) throw new TypeError("Invalid run activity.");
|
|
546
|
+
return {
|
|
547
|
+
at: text(entry.at, "activity", 64),
|
|
548
|
+
kind: entry.kind,
|
|
549
|
+
text: text(entry.text, "activity", MAX_ACTIVITY_TEXT)
|
|
550
|
+
};
|
|
551
|
+
}),
|
|
552
|
+
error: error === null ? null : {
|
|
553
|
+
message: text(error.message, "error", MAX_ACTIVITY_TEXT),
|
|
554
|
+
at: text(error.at, "error", 64),
|
|
555
|
+
retryable: error.retryable === true
|
|
556
|
+
},
|
|
557
|
+
startedBy: person(value.startedBy, "startedBy"),
|
|
558
|
+
approvedBy: value.approvedBy === null ? null : person(value.approvedBy, "approvedBy"),
|
|
559
|
+
createdAt: text(value.createdAt, "createdAt", 64),
|
|
560
|
+
updatedAt: text(value.updatedAt, "updatedAt", 64),
|
|
561
|
+
previous: value.previous.map((entry) => {
|
|
562
|
+
if (!isObject(entry)) throw new TypeError("Invalid earlier run.");
|
|
563
|
+
return {
|
|
564
|
+
id: text(entry.id, "previous", 100),
|
|
565
|
+
state: state(entry.state, "previous"),
|
|
566
|
+
endedAt: text(entry.endedAt, "previous", 64)
|
|
567
|
+
};
|
|
568
|
+
})
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
//#endregion
|
|
572
|
+
export { parseRunRecord as a, parseTaskContext as c, advanceRun as i, parseTaskContextInput as l, RUN_WAITING_STATES as n, runActive as o, RunTransitionError as r, startRun as s, NEEDS_CONTEXT_MARKER as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { N as parseThreadFilter, P as parseThreadId, R as parseThreadSnapshot, b as predictThreadReply, i as routes, j as parseThread, v as predictThreadCreate, x as predictThreadStatus, y as predictThreadDelete } from "./events-BH_rAu7O.js";
|
|
2
|
+
import { Dn as toast, Nn as t, _ as requestComments, a as saveThreads, b as writeOptimistically, g as CommentsRequestError, i as saveThread, l as projectStore, n as unavailableComments, o as threadMatches, x as writeRows, y as plainRow } from "./comment-data-Rg42ToTW.js";
|
|
3
3
|
//#region app/client/project-comments.ts
|
|
4
4
|
var viewers = /* @__PURE__ */ new Map();
|
|
5
5
|
function parseViewer(value) {
|
|
@@ -11,6 +11,13 @@ function parseViewer(value) {
|
|
|
11
11
|
};
|
|
12
12
|
throw new TypeError("Invalid viewer.");
|
|
13
13
|
}
|
|
14
|
+
function parseMadeTask(value) {
|
|
15
|
+
if (!value || typeof value !== "object" || !("item" in value) || !("thread" in value) || !value.item || typeof value.item !== "object" || !("id" in value.item) || typeof value.item.id !== "string" || !value.item.id || value.item.id.length > 256) throw new TypeError("Invalid task.");
|
|
16
|
+
return {
|
|
17
|
+
item: { id: value.item.id },
|
|
18
|
+
thread: parseThread(value.thread)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
14
21
|
function parseDeletion(value) {
|
|
15
22
|
if (!value || typeof value !== "object" || !("thread" in value)) throw new TypeError("Invalid deletion.");
|
|
16
23
|
return { thread: value.thread === null ? null : parseThread(value.thread) };
|
|
@@ -234,6 +241,10 @@ function createProjectComments(options) {
|
|
|
234
241
|
if (!detailFailures.size) error = "";
|
|
235
242
|
}
|
|
236
243
|
} catch (cause) {
|
|
244
|
+
if (!signal.aborted && turn === generation && cause instanceof CommentsRequestError && cause.code === "not-found") {
|
|
245
|
+
await forget(id);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
237
248
|
if (!signal.aborted && turn === generation) {
|
|
238
249
|
detailFailures.add(id);
|
|
239
250
|
error = cause instanceof Error ? cause.message : t("app.client.projectComments.couldNotLoadDiscussion");
|
|
@@ -382,6 +393,23 @@ function createProjectComments(options) {
|
|
|
382
393
|
};
|
|
383
394
|
},
|
|
384
395
|
/**
|
|
396
|
+
* Turns a discussion into a task in the task store, linked to it.
|
|
397
|
+
* @param threadId - The discussion.
|
|
398
|
+
* @param context - What the canvas found around the comment: a screenshot and its element.
|
|
399
|
+
* @returns The new task's id.
|
|
400
|
+
*/
|
|
401
|
+
async makeTask(threadId, context) {
|
|
402
|
+
requireCapability("link");
|
|
403
|
+
let id = parseThreadId(threadId);
|
|
404
|
+
let made;
|
|
405
|
+
await operate(routes.comments.makeTask.href({ id }), context ? { context } : {}, parseMadeTask, (result) => {
|
|
406
|
+
if (result.thread.id !== id) throw new CommentsRequestError(t("app.client.projectComments.refreshBeforeTryingAgain"), 409, "uncertain");
|
|
407
|
+
made = result.item;
|
|
408
|
+
return merge(result.thread);
|
|
409
|
+
}, t("app.client.projectComments.taskCreated"), id);
|
|
410
|
+
return made;
|
|
411
|
+
},
|
|
412
|
+
/**
|
|
385
413
|
* Deletes one of the viewer's messages; its first message deletes the whole discussion.
|
|
386
414
|
* @param threadId - The discussion.
|
|
387
415
|
* @param messageId - The message to delete.
|