@krapht/ork 1.0.0-alpha.14 → 1.0.0-alpha.15
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/__build_info__-Bsb1kjgF.mjs +340 -0
- package/dist/{store-CleF7KeS.mjs → attach-BHO3X3cf.mjs} +16 -19
- package/dist/{attach-CdtGX9se.mjs → attach-CPespxlQ.mjs} +5 -4
- package/dist/bin.mjs +64 -1339
- package/dist/brief-za0ozN_E.mjs +58 -0
- package/dist/{builtin-files-Bdq23IIi.mjs → builtin-files-2bHf76x-.mjs} +1 -1
- package/dist/{completion--ywde-56.mjs → completion-CQ2UYKuJ.mjs} +5 -5
- package/dist/context-BNqDw9z1.mjs +106 -0
- package/dist/{find-BVX-bL4u.mjs → find-BYLlszqj.mjs} +1 -1
- package/dist/follow-ups-B4GJ3Vzw.mjs +461 -0
- package/dist/{format-CvTE5CZQ.mjs → format-C8MsFj8_.mjs} +19 -5
- package/dist/{help-groups-CpR2UzSn.mjs → help-groups-CQ98mLjF.mjs} +4 -0
- package/dist/{in-a-run-cL5N9gpH.mjs → in-a-run-Bp0k0J09.mjs} +1 -1
- package/dist/{__build_info__-B82-dGJY.mjs → install-DWtXTq4y.mjs} +3 -227
- package/dist/{limits-Dhe--wmX.mjs → limits-B1qzS4cX.mjs} +1 -1
- package/dist/{mcp-CsmboyXv.mjs → mcp-BOrVkyhN.mjs} +6 -6
- package/dist/{once-CrwI-ZdN.mjs → once-C1fL3GVo.mjs} +3 -3
- package/dist/orphan-guard-BFKg8VSd.mjs +58 -0
- package/dist/{pause-DssrYcda.mjs → pause-DOMK-R8V.mjs} +3 -3
- package/dist/post-BzA6Qobq.mjs +44 -0
- package/dist/{relay-DASRgsTQ.mjs → relay-OWuu4fib.mjs} +1 -1
- package/dist/run--4-1xAF2.mjs +1451 -0
- package/dist/{run-D8divGCs.mjs → run-CiPsW9Kf.mjs} +1 -1
- package/dist/{send-CXv8bx0i.mjs → send-CnNNW-ot.mjs} +2 -2
- package/dist/{src-njdtejgZ.mjs → src-B9zWIVqo.mjs} +129 -12
- package/dist/{src-8Mul0695.mjs → src-DQKz2eOH.mjs} +322 -75
- package/dist/{src-C7z_6fhn.mjs → src-DcrhgipG.mjs} +17 -10
- package/dist/{src-tsuZRu0H.mjs → src-Dr_fTSu-.mjs} +4832 -4155
- package/dist/store-oKJ-cCf3.mjs +16 -0
- package/dist/ui/assets/app-Bdc6OBeZ.css +1 -0
- package/dist/ui/assets/app-Drp8Dm9y.js +111 -0
- package/dist/ui/assets/{index-D-_uPI2v.js → index-BtwkftKe.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-CNO1M0qT.mjs → ui-CzKlsCnm.mjs} +3 -3
- package/dist/{usage-BVXi0iFY.mjs → usage-DHGNk2JL.mjs} +3 -3
- package/dist/{context-Y_I4Mofq.mjs → validate-Bs_gg22g.mjs} +4 -104
- package/dist/{watch-DVNIciHp.mjs → watch-CCCfw3n7.mjs} +19 -5
- package/dist/{workflows-B30QkwTk.mjs → workflows-CW28ZU-z.mjs} +2 -2
- package/dist/{worktrees-DD4_TpkH.mjs → worktrees-CyE8aF6j.mjs} +1 -1
- package/package.json +1 -1
- package/dist/ui/assets/app-D_nAPnHM.css +0 -1
- package/dist/ui/assets/app-DqBAtXSZ.js +0 -111
|
@@ -1,79 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { At as walkSummary, Br as WorkflowEditSchema, C as capsHere, Cn as liveStatus, Ct as explainWorkflowText, D as runningScript, Dr as placeFor, E as runningRunIds, En as runStatus, Er as placeFiles, H as isNodeEvent, Hn as END_KINDS, Hr as newWorkflowText, In as loadProject, Jn as planPost, Jr as parseWorkflow, Mn as nestItems, Mr as inside, N as triggersReport, O as detectInstaller, Ot as checkWorkflowText, Pr as LESSON_CAP_TOKENS, S as usageReport, Sn as tellLiveRun, Sr as loadAgents, T as releaseNotes, Tn as pausedOf, U as openStore, Ur as readDocument, V as activeTree, Vr as applyEdits, W as storePath, Xn as sendPost, Yn as runGh, Zr as EdgeInputSchema, _ as keyOf, _n as linkNodes, _t as followEvents, a as planRemove, b as stepPrunes, bn as requestPause, bt as limitsReport, d as planLine, ei as expandEdge, en as nodeSays, f as removeRefusal, g as cleanStep, gt as detachRun, h as applyClean, i as lostWork, jr as workflowDirOf, kn as processAlive, kr as runDirOf, kt as walkChecks, l as labelOf, ln as startFollowUpChecks, lt as answerDecision, mn as DEFAULT_FOLLOW_UPS_RULE, mt as resumable, ni as NodeSchema, o as projectHead, on as checkFollowUpsDue, or as readCondition, p as stateParts, pn as liveSessionOf, pt as detachResume, qn as DISCUSSIONS, qr as renderJsonSchema, r as applyRemove, s as readWorktrees, u as mergeStateOf, ut as pendingDecisions, v as planClean, vn as unlinkNodes, w as planUpgrade, xn as requestStop, y as stepActs, yn as requestContinue, zn as endOf, zr as skillsIn } from "./src-Dr_fTSu-.mjs";
|
|
2
|
+
import { a as acceptItem, c as feedbackActions, i as recordNote, l as openFixRun, n as previewPost, o as lessonPlaceOf, s as placeOf$1, t as runInstall } from "./install-DWtXTq4y.mjs";
|
|
3
|
+
import { _ as dueCause, a as registryShown, c as fetchLatest, d as readUpdateCache, f as refreshUpdateCache, g as changeFollowUp, h as nodeSession, i as registryOf, l as newerVersion, m as writeUpdateCache, o as updateSwitchOff, p as updateCachePath, s as checkDue, v as findFollowUp, y as followUpActions } from "./__build_info__-Bsb1kjgF.mjs";
|
|
4
|
+
import { t as postFollowUpMessage } from "./post-BzA6Qobq.mjs";
|
|
5
|
+
import { t as builtinProblem } from "./builtin-files-2bHf76x-.mjs";
|
|
6
|
+
import { n as newRunId, t as findRun } from "./find-BYLlszqj.mjs";
|
|
5
7
|
import path from "node:path";
|
|
6
8
|
import { z } from "zod";
|
|
7
9
|
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
8
10
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
9
11
|
import { homedir } from "node:os";
|
|
10
12
|
import { createServer } from "node:http";
|
|
11
|
-
// ../server/src/contract-builder.ts
|
|
12
|
-
/** A new workflow's name, as its file and its `name:` take it. */
|
|
13
|
-
const NewWorkflowSchema = z.strictObject({ name: z.string().min(1) });
|
|
14
|
-
/** The server checks each edit; this file imports only types of the schema. */
|
|
15
|
-
const WorkflowEditsSchema = z.strictObject({ edits: z.array(z.custom()).min(1) });
|
|
16
|
-
/** Earlier text, and the file it was based on, to ask before replacing it. */
|
|
17
|
-
const DraftTextSchema = z.strictObject({
|
|
18
|
-
text: z.string(),
|
|
19
|
-
baseHash: z.string().nullable()
|
|
20
|
-
});
|
|
21
|
-
const SaveWorkflowSchema = z.strictObject({
|
|
22
|
-
/** Write over a file that changed since this draft began. */
|
|
23
|
-
force: z.boolean().optional() });
|
|
24
|
-
const BUILDER_API = {
|
|
25
|
-
builderSchema: {
|
|
26
|
-
method: "GET",
|
|
27
|
-
path: "/api/workflow-schema"
|
|
28
|
-
},
|
|
29
|
-
builderCatalog: {
|
|
30
|
-
method: "GET",
|
|
31
|
-
path: "/api/projects/:id/catalog"
|
|
32
|
-
},
|
|
33
|
-
builderDrafts: {
|
|
34
|
-
method: "GET",
|
|
35
|
-
path: "/api/projects/:id/builder"
|
|
36
|
-
},
|
|
37
|
-
builderView: {
|
|
38
|
-
method: "GET",
|
|
39
|
-
path: "/api/projects/:id/builder/:name"
|
|
40
|
-
},
|
|
41
|
-
builderCreate: {
|
|
42
|
-
method: "POST",
|
|
43
|
-
path: "/api/projects/:id/builder",
|
|
44
|
-
body: NewWorkflowSchema
|
|
45
|
-
},
|
|
46
|
-
builderEdit: {
|
|
47
|
-
method: "POST",
|
|
48
|
-
path: "/api/projects/:id/builder/:name/edits",
|
|
49
|
-
body: WorkflowEditsSchema
|
|
50
|
-
},
|
|
51
|
-
builderRestore: {
|
|
52
|
-
method: "POST",
|
|
53
|
-
path: "/api/projects/:id/builder/:name/text",
|
|
54
|
-
body: DraftTextSchema
|
|
55
|
-
},
|
|
56
|
-
builderDiscard: {
|
|
57
|
-
method: "POST",
|
|
58
|
-
path: "/api/projects/:id/builder/:name/discard"
|
|
59
|
-
},
|
|
60
|
-
builderSave: {
|
|
61
|
-
method: "POST",
|
|
62
|
-
path: "/api/projects/:id/builder/:name/save",
|
|
63
|
-
body: SaveWorkflowSchema
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
// ../server/src/contract-context.ts
|
|
67
|
-
const CONTEXT_API = {
|
|
68
|
-
runContext: {
|
|
69
|
-
method: "GET",
|
|
70
|
-
path: "/api/runs/:id/nodes/:node/context"
|
|
71
|
-
},
|
|
72
|
-
builderContext: {
|
|
73
|
-
method: "GET",
|
|
74
|
-
path: "/api/projects/:id/builder/:name/nodes/:node/context"
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
13
|
// ../server/src/contract-feedback.ts
|
|
78
14
|
const NoteSchema = z.strictObject({
|
|
79
15
|
/** Its first line is the title. */
|
|
@@ -153,6 +89,133 @@ const FEEDBACK_API = {
|
|
|
153
89
|
path: "/api/feedback/:id/split"
|
|
154
90
|
}
|
|
155
91
|
};
|
|
92
|
+
// ../server/src/contract-follow-ups.ts
|
|
93
|
+
/** `open` is due and waiting, the default; `all` adds done and dropped. */
|
|
94
|
+
const FollowUpsQuerySchema = z.strictObject({
|
|
95
|
+
status: z.enum([
|
|
96
|
+
"open",
|
|
97
|
+
"all",
|
|
98
|
+
"due",
|
|
99
|
+
"waiting",
|
|
100
|
+
"done",
|
|
101
|
+
"dropped"
|
|
102
|
+
]).optional(),
|
|
103
|
+
/** Only those for this: `agent`, `me`, `project:<name>` or `person:<name>`. */
|
|
104
|
+
for: z.string().min(1).optional()
|
|
105
|
+
});
|
|
106
|
+
const FollowUpChangeSchema = z.strictObject({ action: z.enum([
|
|
107
|
+
"done",
|
|
108
|
+
"drop",
|
|
109
|
+
"reopen",
|
|
110
|
+
"due"
|
|
111
|
+
]) });
|
|
112
|
+
/**
|
|
113
|
+
* Posts a drafted GitHub comment through the person's own `gh`. `confirm` says
|
|
114
|
+
* yes, and `digest` is the detail's `draftDigest`, which stands for the
|
|
115
|
+
* recipient and text they saw: the route refuses when the draft is no longer
|
|
116
|
+
* that, so nothing else is sent.
|
|
117
|
+
*/
|
|
118
|
+
const FollowUpPostSchema = z.strictObject({
|
|
119
|
+
confirm: z.literal(true),
|
|
120
|
+
digest: z.string().min(1)
|
|
121
|
+
});
|
|
122
|
+
const FOLLOW_UPS_API = {
|
|
123
|
+
followUps: {
|
|
124
|
+
method: "GET",
|
|
125
|
+
path: "/api/projects/:id/follow-ups",
|
|
126
|
+
query: FollowUpsQuerySchema
|
|
127
|
+
},
|
|
128
|
+
followUp: {
|
|
129
|
+
method: "GET",
|
|
130
|
+
path: "/api/projects/:id/follow-ups/:followUp"
|
|
131
|
+
},
|
|
132
|
+
followUpChange: {
|
|
133
|
+
method: "POST",
|
|
134
|
+
path: "/api/projects/:id/follow-ups/:followUp",
|
|
135
|
+
body: FollowUpChangeSchema
|
|
136
|
+
},
|
|
137
|
+
followUpPost: {
|
|
138
|
+
method: "POST",
|
|
139
|
+
path: "/api/projects/:id/follow-ups/:followUp/post",
|
|
140
|
+
body: FollowUpPostSchema
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
// ../server/src/contract-after.ts
|
|
144
|
+
/**
|
|
145
|
+
* @file What the API offers after runs: the feedback loop's routes
|
|
146
|
+
* (contract-feedback.ts) and the follow-ups' (contract-follow-ups.ts), joined
|
|
147
|
+
* so the contract reads one part for both.
|
|
148
|
+
*/
|
|
149
|
+
const AFTER_API = {
|
|
150
|
+
...FEEDBACK_API,
|
|
151
|
+
...FOLLOW_UPS_API
|
|
152
|
+
};
|
|
153
|
+
// ../server/src/contract-builder.ts
|
|
154
|
+
/** A new workflow's name, as its file and its `name:` take it. */
|
|
155
|
+
const NewWorkflowSchema = z.strictObject({ name: z.string().min(1) });
|
|
156
|
+
/** The server checks each edit; this file imports only types of the schema. */
|
|
157
|
+
const WorkflowEditsSchema = z.strictObject({ edits: z.array(z.custom()).min(1) });
|
|
158
|
+
/** Earlier text, and the file it was based on, to ask before replacing it. */
|
|
159
|
+
const DraftTextSchema = z.strictObject({
|
|
160
|
+
text: z.string(),
|
|
161
|
+
baseHash: z.string().nullable()
|
|
162
|
+
});
|
|
163
|
+
const SaveWorkflowSchema = z.strictObject({
|
|
164
|
+
/** Write over a file that changed since this draft began. */
|
|
165
|
+
force: z.boolean().optional() });
|
|
166
|
+
const BUILDER_API = {
|
|
167
|
+
builderSchema: {
|
|
168
|
+
method: "GET",
|
|
169
|
+
path: "/api/workflow-schema"
|
|
170
|
+
},
|
|
171
|
+
builderCatalog: {
|
|
172
|
+
method: "GET",
|
|
173
|
+
path: "/api/projects/:id/catalog"
|
|
174
|
+
},
|
|
175
|
+
builderDrafts: {
|
|
176
|
+
method: "GET",
|
|
177
|
+
path: "/api/projects/:id/builder"
|
|
178
|
+
},
|
|
179
|
+
builderView: {
|
|
180
|
+
method: "GET",
|
|
181
|
+
path: "/api/projects/:id/builder/:name"
|
|
182
|
+
},
|
|
183
|
+
builderCreate: {
|
|
184
|
+
method: "POST",
|
|
185
|
+
path: "/api/projects/:id/builder",
|
|
186
|
+
body: NewWorkflowSchema
|
|
187
|
+
},
|
|
188
|
+
builderEdit: {
|
|
189
|
+
method: "POST",
|
|
190
|
+
path: "/api/projects/:id/builder/:name/edits",
|
|
191
|
+
body: WorkflowEditsSchema
|
|
192
|
+
},
|
|
193
|
+
builderRestore: {
|
|
194
|
+
method: "POST",
|
|
195
|
+
path: "/api/projects/:id/builder/:name/text",
|
|
196
|
+
body: DraftTextSchema
|
|
197
|
+
},
|
|
198
|
+
builderDiscard: {
|
|
199
|
+
method: "POST",
|
|
200
|
+
path: "/api/projects/:id/builder/:name/discard"
|
|
201
|
+
},
|
|
202
|
+
builderSave: {
|
|
203
|
+
method: "POST",
|
|
204
|
+
path: "/api/projects/:id/builder/:name/save",
|
|
205
|
+
body: SaveWorkflowSchema
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
// ../server/src/contract-context.ts
|
|
209
|
+
const CONTEXT_API = {
|
|
210
|
+
runContext: {
|
|
211
|
+
method: "GET",
|
|
212
|
+
path: "/api/runs/:id/nodes/:node/context"
|
|
213
|
+
},
|
|
214
|
+
builderContext: {
|
|
215
|
+
method: "GET",
|
|
216
|
+
path: "/api/projects/:id/builder/:name/nodes/:node/context"
|
|
217
|
+
}
|
|
218
|
+
};
|
|
156
219
|
// ../server/src/contract-links.ts
|
|
157
220
|
/**
|
|
158
221
|
* @file The routes that link two nodes of live runs (RFC-003): list, link and
|
|
@@ -320,7 +383,7 @@ const API = {
|
|
|
320
383
|
},
|
|
321
384
|
...BUILDER_API,
|
|
322
385
|
...CONTEXT_API,
|
|
323
|
-
...
|
|
386
|
+
...AFTER_API,
|
|
324
387
|
...WORKTREES_API,
|
|
325
388
|
...UPDATE_API,
|
|
326
389
|
projects: {
|
|
@@ -2021,7 +2084,7 @@ const applyRoute = async (context, item, driver) => {
|
|
|
2021
2084
|
* workflows would go and how big that file is, the project a fix would be
|
|
2022
2085
|
* proposed in, and the run proposing one now, if any.
|
|
2023
2086
|
*/
|
|
2024
|
-
const detailOf = (store, item) => {
|
|
2087
|
+
const detailOf$1 = (store, item) => {
|
|
2025
2088
|
const registered = store.projects();
|
|
2026
2089
|
const fixRun = openFixRun(store, item);
|
|
2027
2090
|
const actions = feedbackActions(item, fixRun);
|
|
@@ -2124,7 +2187,7 @@ const feedbackRoutes = (context) => {
|
|
|
2124
2187
|
feedbackItem: ({ params }) => {
|
|
2125
2188
|
const found = itemOf(store, params.id);
|
|
2126
2189
|
if (!found.ok) return found.refusal;
|
|
2127
|
-
return ok(detailOf(store, found.item));
|
|
2190
|
+
return ok(detailOf$1(store, found.item));
|
|
2128
2191
|
},
|
|
2129
2192
|
feedbackStatus: ({ params, body }) => {
|
|
2130
2193
|
const found = itemOf(store, params.id);
|
|
@@ -2173,6 +2236,172 @@ const feedbackRoutes = (context) => {
|
|
|
2173
2236
|
}
|
|
2174
2237
|
};
|
|
2175
2238
|
};
|
|
2239
|
+
// ../server/src/follow-up-routes.ts
|
|
2240
|
+
/**
|
|
2241
|
+
* @file The follow-ups' routes (specs/follow-ups.md), through the same core
|
|
2242
|
+
* functions as `ork follow-ups`: a project's list (after the due check, which
|
|
2243
|
+
* reads pull requests through the person's own `gh` and only reports a `gh`
|
|
2244
|
+
* that fails), one follow-up with what to copy and what can be done to it,
|
|
2245
|
+
* done, drop, reopen and due, and posting a drafted GitHub comment only with
|
|
2246
|
+
* the person's confirmation of the draft they saw (its digest). Ork never
|
|
2247
|
+
* runs a task's commands.
|
|
2248
|
+
*/
|
|
2249
|
+
const OPEN = ["due", "waiting"];
|
|
2250
|
+
/** Stands for what a person saw of a draft: its recipient and text. */
|
|
2251
|
+
const digestOf$1 = (f) => f.draft === void 0 ? void 0 : createHash("sha256").update(JSON.stringify([f.draft.to, f.draft.text])).digest("hex");
|
|
2252
|
+
/** The place a project's rule keeps follow-ups in. */
|
|
2253
|
+
const ruleOf = (project) => (loadProject(project.root, placeFiles(project).rules).project?.followUps ?? DEFAULT_FOLLOW_UPS_RULE).store;
|
|
2254
|
+
/** Why a follow-up isn't where the project's rule says, when it isn't. */
|
|
2255
|
+
const fallbackOf = (placed, rule) => {
|
|
2256
|
+
if (placed === rule) return void 0;
|
|
2257
|
+
return rule === "github" ? "GitHub couldn't be used when it was added (gh not signed in, or the issue failed), so Ork's store keeps it." : `It couldn't be written to ${rule} when it was added, so Ork's store keeps it.`;
|
|
2258
|
+
};
|
|
2259
|
+
const deliveryOf = (store, f) => {
|
|
2260
|
+
if (!f.for.startsWith("project:")) return void 0;
|
|
2261
|
+
const name = f.for.slice(8).trim();
|
|
2262
|
+
const target = store.projects().find((p) => p.id === name);
|
|
2263
|
+
if (target === void 0) return {
|
|
2264
|
+
project: name,
|
|
2265
|
+
registered: false
|
|
2266
|
+
};
|
|
2267
|
+
const live = liveSessionOf(store, target.root);
|
|
2268
|
+
return {
|
|
2269
|
+
project: name,
|
|
2270
|
+
registered: true,
|
|
2271
|
+
root: target.root,
|
|
2272
|
+
keptIn: ruleOf(target),
|
|
2273
|
+
...live === void 0 ? {} : { live }
|
|
2274
|
+
};
|
|
2275
|
+
};
|
|
2276
|
+
/** `f`, what can be done to it, where it is kept, and what to copy from it. */
|
|
2277
|
+
const detailOf = (context, project, f) => {
|
|
2278
|
+
const rule = ruleOf(project);
|
|
2279
|
+
const fallback = fallbackOf(f.place, rule);
|
|
2280
|
+
const cause = dueCause(f);
|
|
2281
|
+
const delivery = deliveryOf(context.store, f);
|
|
2282
|
+
const digest = digestOf$1(f);
|
|
2283
|
+
return {
|
|
2284
|
+
followUp: f,
|
|
2285
|
+
actions: followUpActions(f),
|
|
2286
|
+
...cause === void 0 ? {} : { cause },
|
|
2287
|
+
keptIn: {
|
|
2288
|
+
place: f.place,
|
|
2289
|
+
rule,
|
|
2290
|
+
...f.url === void 0 ? {} : { url: f.url },
|
|
2291
|
+
...fallback === void 0 ? {} : { fallback }
|
|
2292
|
+
},
|
|
2293
|
+
...delivery === void 0 ? {} : { delivery },
|
|
2294
|
+
...digest === void 0 ? {} : { draftDigest: digest },
|
|
2295
|
+
copy: {
|
|
2296
|
+
text: f.draft?.text ?? "",
|
|
2297
|
+
commands: (f.steps ?? []).flatMap((step) => step.command === void 0 ? [] : [step.command])
|
|
2298
|
+
}
|
|
2299
|
+
};
|
|
2300
|
+
};
|
|
2301
|
+
const toItem = (f) => ({
|
|
2302
|
+
id: f.id,
|
|
2303
|
+
project: f.project,
|
|
2304
|
+
title: f.title,
|
|
2305
|
+
for: f.for,
|
|
2306
|
+
kind: f.kind,
|
|
2307
|
+
...f.note === void 0 ? {} : { note: f.note }
|
|
2308
|
+
});
|
|
2309
|
+
/** The due follow-ups of `roots`, most recently changed first. */
|
|
2310
|
+
const dueOf = (store, roots) => {
|
|
2311
|
+
const due = roots.flatMap((root) => store.followUps(root)).filter((f) => f.status === "due").toSorted((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
2312
|
+
return {
|
|
2313
|
+
count: due.length,
|
|
2314
|
+
items: due.slice(0, 20).map((f) => toItem(f))
|
|
2315
|
+
};
|
|
2316
|
+
};
|
|
2317
|
+
const found = (context, params) => {
|
|
2318
|
+
const project = projectOf(context, params.id);
|
|
2319
|
+
if (project === void 0) return {
|
|
2320
|
+
ok: false,
|
|
2321
|
+
refusal: fail(404, `No registered project \`${params.id}\`.`)
|
|
2322
|
+
};
|
|
2323
|
+
if (params.followUp === void 0) return {
|
|
2324
|
+
ok: true,
|
|
2325
|
+
project
|
|
2326
|
+
};
|
|
2327
|
+
const one = findFollowUp(context.store, project.root, params.followUp);
|
|
2328
|
+
if (!one.ok) {
|
|
2329
|
+
const status = one.error.startsWith("No follow-up") ? 404 : 400;
|
|
2330
|
+
return {
|
|
2331
|
+
ok: false,
|
|
2332
|
+
refusal: fail(status, one.error)
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2335
|
+
return {
|
|
2336
|
+
ok: true,
|
|
2337
|
+
project,
|
|
2338
|
+
followUp: one.followUp
|
|
2339
|
+
};
|
|
2340
|
+
};
|
|
2341
|
+
const followUpRoutes = (context) => {
|
|
2342
|
+
const { store } = context;
|
|
2343
|
+
const gh = context.gh ?? runGh;
|
|
2344
|
+
return {
|
|
2345
|
+
followUps: async ({ params, query }) => {
|
|
2346
|
+
const one = found(context, params);
|
|
2347
|
+
if (!one.ok) return one.refusal;
|
|
2348
|
+
const { root } = one.project;
|
|
2349
|
+
const errors = await checkFollowUpsDue({
|
|
2350
|
+
rows: store,
|
|
2351
|
+
project: root,
|
|
2352
|
+
gh
|
|
2353
|
+
}).then((checked) => checked.errors).catch((error) => [error instanceof Error ? error.message : String(error)]);
|
|
2354
|
+
const all = store.followUps(root);
|
|
2355
|
+
const status = query.status ?? "open";
|
|
2356
|
+
const shown = all.filter((f) => {
|
|
2357
|
+
if (query.for !== void 0 && f.for !== query.for) return false;
|
|
2358
|
+
if (status === "all") return true;
|
|
2359
|
+
if (status === "open") return OPEN.some((s) => s === f.status);
|
|
2360
|
+
return f.status === status;
|
|
2361
|
+
});
|
|
2362
|
+
return ok({
|
|
2363
|
+
project: root,
|
|
2364
|
+
followUps: shown,
|
|
2365
|
+
due: all.filter((f) => f.status === "due").length,
|
|
2366
|
+
checker: {
|
|
2367
|
+
available: errors.length === 0,
|
|
2368
|
+
errors
|
|
2369
|
+
}
|
|
2370
|
+
});
|
|
2371
|
+
},
|
|
2372
|
+
followUp: ({ params }) => {
|
|
2373
|
+
const one = found(context, params);
|
|
2374
|
+
if (!one.ok) return one.refusal;
|
|
2375
|
+
return one.followUp === void 0 ? fail(404, "No such follow-up.") : ok(detailOf(context, one.project, one.followUp));
|
|
2376
|
+
},
|
|
2377
|
+
followUpChange: ({ params, body }) => {
|
|
2378
|
+
const one = found(context, params);
|
|
2379
|
+
if (!one.ok) return one.refusal;
|
|
2380
|
+
if (one.followUp === void 0) return fail(404, "No such follow-up.");
|
|
2381
|
+
const changed = changeFollowUp(store, one.followUp, body.action);
|
|
2382
|
+
return changed.ok ? ok(detailOf(context, one.project, changed.followUp)) : fail(409, changed.error);
|
|
2383
|
+
},
|
|
2384
|
+
followUpPost: async ({ params, body }) => {
|
|
2385
|
+
const one = found(context, params);
|
|
2386
|
+
if (!one.ok) return one.refusal;
|
|
2387
|
+
const { followUp } = one;
|
|
2388
|
+
if (followUp === void 0) return fail(404, "No such follow-up.");
|
|
2389
|
+
const check = followUpActions(followUp).post;
|
|
2390
|
+
if (!check.ok) return fail(409, check.error);
|
|
2391
|
+
if (digestOf$1(followUp) !== body.digest) return fail(409, "The draft is no longer the one you confirmed; open the follow-up again.");
|
|
2392
|
+
const posted = await postFollowUpMessage(followUp, {
|
|
2393
|
+
rows: store,
|
|
2394
|
+
gh,
|
|
2395
|
+
confirmed: body.confirm,
|
|
2396
|
+
home: context.home ?? homedir()
|
|
2397
|
+
});
|
|
2398
|
+
return posted.ok ? ok({
|
|
2399
|
+
...posted.url === void 0 ? {} : { url: posted.url },
|
|
2400
|
+
followUp: detailOf(context, one.project, posted.followUp)
|
|
2401
|
+
}) : fail(409, posted.error);
|
|
2402
|
+
}
|
|
2403
|
+
};
|
|
2404
|
+
};
|
|
2176
2405
|
const ANSI = /\u001B\[[0-?]*[ -/]*[@-~]|\u001B\][^\u0007\u001B]*(?:\u0007|\u001B\\)|\u001B[@-Z\\-_]/gu;
|
|
2177
2406
|
/** A line as a terminal would end up showing it. */
|
|
2178
2407
|
const plainLine = (raw) => (raw.replaceAll(ANSI, "").split("\r").findLast((part) => part !== "") ?? "").replaceAll(/\s+$/gu, "");
|
|
@@ -2727,6 +2956,7 @@ const apiRoutes = (context, port) => ({
|
|
|
2727
2956
|
...builderRoutes(context),
|
|
2728
2957
|
...contextRoutes(context),
|
|
2729
2958
|
...feedbackRoutes(context),
|
|
2959
|
+
...followUpRoutes(context),
|
|
2730
2960
|
...worktreesRoutes(context),
|
|
2731
2961
|
...updateRoutes(context, port)
|
|
2732
2962
|
});
|
|
@@ -2885,7 +3115,11 @@ const overviewStream = (context, res, url, shutdown) => {
|
|
|
2885
3115
|
const last = {
|
|
2886
3116
|
runs: "",
|
|
2887
3117
|
decisions: "",
|
|
2888
|
-
version: ""
|
|
3118
|
+
version: "",
|
|
3119
|
+
followUps: JSON.stringify({
|
|
3120
|
+
count: 0,
|
|
3121
|
+
items: []
|
|
3122
|
+
})
|
|
2889
3123
|
};
|
|
2890
3124
|
const tick = () => {
|
|
2891
3125
|
const filter = root === void 0 ? {} : { project: root };
|
|
@@ -2900,7 +3134,8 @@ const overviewStream = (context, res, url, shutdown) => {
|
|
|
2900
3134
|
for (const [name, value] of [
|
|
2901
3135
|
["runs", runs],
|
|
2902
3136
|
["decisions", decisions],
|
|
2903
|
-
["version", context.updates.info()]
|
|
3137
|
+
["version", context.updates.info()],
|
|
3138
|
+
["followUps", dueOf(context.store, root === void 0 ? context.store.projects().map((p) => p.root) : [root])]
|
|
2904
3139
|
]) {
|
|
2905
3140
|
const text = JSON.stringify(value);
|
|
2906
3141
|
if (text === last[name]) continue;
|
|
@@ -3058,6 +3293,8 @@ const runningServer = (file) => {
|
|
|
3058
3293
|
*/
|
|
3059
3294
|
/** The port `ork ui` serves on unless told otherwise. */
|
|
3060
3295
|
const DEFAULT_PORT = 4417;
|
|
3296
|
+
/** The overview stream sends the due follow-ups itself; nothing more here. */
|
|
3297
|
+
const noticed = () => {};
|
|
3061
3298
|
const listen = (server, port) => new Promise((resolve, reject) => {
|
|
3062
3299
|
server.once("error", (error) => {
|
|
3063
3300
|
reject(error.code === "EADDRINUSE" ? /* @__PURE__ */ new Error(`Port ${String(port)} is in use; start Ork's UI on another with \`--port <n>\`.`) : error);
|
|
@@ -3119,6 +3356,15 @@ const startServer = async (options) => {
|
|
|
3119
3356
|
token,
|
|
3120
3357
|
startedAt
|
|
3121
3358
|
});
|
|
3359
|
+
const stopChecks = startFollowUpChecks({
|
|
3360
|
+
rows: store,
|
|
3361
|
+
gh: options.gh ?? runGh,
|
|
3362
|
+
projects: () => store.projects().map((project) => project.root),
|
|
3363
|
+
onDue: noticed,
|
|
3364
|
+
onError: (error) => {
|
|
3365
|
+
log(`ork ui: follow-ups: ${error}`);
|
|
3366
|
+
}
|
|
3367
|
+
});
|
|
3122
3368
|
let closed;
|
|
3123
3369
|
return {
|
|
3124
3370
|
port,
|
|
@@ -3131,6 +3377,7 @@ const startServer = async (options) => {
|
|
|
3131
3377
|
close: () => {
|
|
3132
3378
|
closed ??= new Promise((resolve) => {
|
|
3133
3379
|
shutdown.abort();
|
|
3380
|
+
stopChecks();
|
|
3134
3381
|
updates.close();
|
|
3135
3382
|
server.close(() => {
|
|
3136
3383
|
store.close();
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { $t as
|
|
2
|
-
import { t as runOnce } from "./run-
|
|
1
|
+
import { $t as sessionDriver, Bn as outcomeEnd, Bt as stoppedEnd, Dt as reportSchemaFor, Ft as runScope, Gr as beforeOf, Ht as slotClock, It as calledWorkflows, Kr as programsRunBy, Kt as startAt, Nn as countedTokens, Pt as heldTimeout, Rt as endedWith, Tt as planNodeSession, Un as endFor, Vn as END_DETAIL_LIMIT, Vt as declaredProblem, Wt as lowerChild, Xr as markValue, Xt as envReadsOf, _i as AGENT_DRIVERS, ar as renderTemplate, ci as timeoutMs, di as integrationFor, ii as isToolNode, in as serversIn, ir as parseTemplate, li as INTEGRATIONS, nn as MCP_FILE, nt as sessionRefusals, ri as isClaudeNode, rn as mcpNotText, rr as evaluate, tn as declaredOutputOf, ui as TOOL_PREFIX, xt as planReason, zn as endOf, zt as failedWith } from "./src-Dr_fTSu-.mjs";
|
|
2
|
+
import { t as runOnce } from "./run-CiPsW9Kf.mjs";
|
|
3
|
+
import { n as holdGuard, r as orphanGuard, t as KILL_AFTER_MS } from "./orphan-guard-BFKg8VSd.mjs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { accessSync, constants, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
6
|
import { spawn } from "node:child_process";
|
|
7
|
+
import { Readable } from "node:stream";
|
|
6
8
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
7
9
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
8
10
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
9
|
-
import { Readable } from "node:stream";
|
|
10
11
|
// ../nodes/src/call.ts
|
|
11
12
|
/**
|
|
12
13
|
* @file The `workflow.call` node type (RFC-004): renders what the node asks for
|
|
@@ -1816,6 +1817,7 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1816
1817
|
if (context.mailbox !== void 0) ports.mailbox = context.mailbox;
|
|
1817
1818
|
if (context.claims !== void 0) ports.claims = context.claims;
|
|
1818
1819
|
if (context.feedback !== void 0) ports.feedback = context.feedback;
|
|
1820
|
+
if (context.followUps !== void 0) ports.followUps = context.followUps;
|
|
1819
1821
|
const whole = context.round > 1 ? wholeInput(context.input) : void 0;
|
|
1820
1822
|
if (whole !== void 0) ports.input = whole;
|
|
1821
1823
|
const watch = limitWatch(context);
|
|
@@ -2143,20 +2145,23 @@ const mcpCallExecutor = (options = {}) => async (context) => {
|
|
|
2143
2145
|
* whatever it started: SIGTERM, then SIGKILL for what ignores that. A stop or
|
|
2144
2146
|
* a timeout therefore leaves nothing running, and an escaped process that
|
|
2145
2147
|
* keeps the output pipes open cannot hold the node. Off Windows it runs under
|
|
2146
|
-
* `sh`, whose `times` says the CPU the program and its children used,
|
|
2147
|
-
* the
|
|
2148
|
+
* `sh`, whose `times` says the CPU the program and its children used, beside
|
|
2149
|
+
* the orphan guard, which ends the group when `ork` dies, and at the
|
|
2150
|
+
* project's priority: `low` starts it below Ork's own (nice, and on macOS
|
|
2148
2151
|
* utility QoS).
|
|
2149
2152
|
*/
|
|
2150
|
-
/** How long a program may take to end after SIGTERM. */
|
|
2151
|
-
const KILL_AFTER_MS = 2e3;
|
|
2152
2153
|
/** How long to wait for the pipes to close after SIGKILL. */
|
|
2153
2154
|
const CLOSE_AFTER_MS = 500;
|
|
2155
|
+
/** The fd of the orphan guard's pipe from `ork`. */
|
|
2156
|
+
const WATCH_FD = 4;
|
|
2154
2157
|
/**
|
|
2155
|
-
* Runs `$0 "$@"
|
|
2156
|
-
* and
|
|
2158
|
+
* Runs `$0 "$@"` beside the orphan guard, which ends the group if `ork` dies,
|
|
2159
|
+
* and stops the guard once the program ends, so its leftovers live on as
|
|
2160
|
+
* before. Then writes the shell's `times` to fd 3: its children's user and
|
|
2161
|
+
* system time, the program's whole tree that it waited for. A program that
|
|
2157
2162
|
* isn't there says so on fd 3, as spawn's ENOENT would.
|
|
2158
2163
|
*/
|
|
2159
|
-
const TIMED = String.raw`command -v "$0" >/dev/null 2>&1 || { echo ork-missing >&3; exit 127; }; "$0" "$@" 3
|
|
2164
|
+
const TIMED = String.raw`command -v "$0" >/dev/null 2>&1 || { echo ork-missing >&3; exit 127; }; ${orphanGuard(WATCH_FD)}w=$!; "$0" "$@" 3>&- ${String(WATCH_FD)}<&-; s=$?; kill -s KILL $w 2>/dev/null; times >&3; exit $s`;
|
|
2160
2165
|
const MISSING = "ork-missing";
|
|
2161
2166
|
/** The children's line of `times` (`0m1.250s 0m0.300s`), in milliseconds. */
|
|
2162
2167
|
const cpuOfTimes = (text) => {
|
|
@@ -2197,10 +2202,12 @@ const spawnTool = (program, args, { cwd, signal, env, priority }) => {
|
|
|
2197
2202
|
"ignore",
|
|
2198
2203
|
"pipe",
|
|
2199
2204
|
"pipe",
|
|
2205
|
+
"pipe",
|
|
2200
2206
|
"pipe"
|
|
2201
2207
|
]
|
|
2202
2208
|
});
|
|
2203
2209
|
lowerChild(priority, child.pid);
|
|
2210
|
+
holdGuard(child.stdio[WATCH_FD]);
|
|
2204
2211
|
const fd3 = child.stdio[3];
|
|
2205
2212
|
if (fd3 instanceof Readable) fd3.setEncoding("utf8").on("data", (chunk) => {
|
|
2206
2213
|
times.push(chunk);
|