@krapht/ork 1.0.0-alpha.16 → 1.0.0-alpha.17
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__-DcRdK0Du.mjs → __build_info__-C1Nm0hlJ.mjs} +2 -2
- package/dist/{attach-7lB5_jpr.mjs → attach-EP374oMP.mjs} +5 -5
- package/dist/{attach-B-FeE1dJ.mjs → attach-RQx__RzH.mjs} +1 -1
- package/dist/bin.mjs +35 -35
- package/dist/brief-Bs3cMQU0.mjs +100 -0
- package/dist/{builtin-files-BRSOObAv.mjs → builtin-files-yYaNTQRU.mjs} +1 -1
- package/dist/{completion-Cgb2qPPh.mjs → completion-DIXWlnAl.mjs} +46 -4
- package/dist/{context-BN9A2Nnu.mjs → context-Dq-VM_sq.mjs} +3 -3
- package/dist/{find-mLYsR0uC.mjs → find-k489laBa.mjs} +1 -1
- package/dist/{flags-CdgIH1L6.mjs → flags-B4ZZWspN.mjs} +3 -108
- package/dist/{follow-ups-DxCsOby1.mjs → follow-ups-DD8NTPe6.mjs} +8 -8
- package/dist/{format-hiDvtNGM.mjs → format-DQc9A_ei.mjs} +1 -1
- package/dist/in-a-run-D_9GlAlS.mjs +27 -0
- package/dist/{install-23g_1ngs.mjs → install-PVlV2QPq.mjs} +1 -1
- package/dist/{limits-C_Xz_t3C.mjs → limits-CHqBO7wb.mjs} +1 -1
- package/dist/{mcp-CWng9I9n.mjs → mcp-D38Ajb0b.mjs} +6 -6
- package/dist/{once-lvwcWfVf.mjs → once-DuUzpzL2.mjs} +3 -3
- package/dist/parse-BzWpMN-a.mjs +107 -0
- package/dist/{pause-Cy11KrXK.mjs → pause-Bx3ePGrn.mjs} +3 -3
- package/dist/{post-C9soCx7i.mjs → post-2CaJz_mV.mjs} +2 -2
- package/dist/{print-BaWiWf4v.mjs → print-n2qetUHc.mjs} +1 -1
- package/dist/{project-records-BRiyQzUo.mjs → project-records-Cune1l6I.mjs} +1 -1
- package/dist/{relay-C0M1TWMB.mjs → relay-D7RN4m68.mjs} +1 -1
- package/dist/{run-D_u9V_Ve.mjs → run-BfxdsQJk.mjs} +1 -1
- package/dist/{run-B-j3Qxqc.mjs → run-OOWQIKMJ.mjs} +17 -17
- package/dist/{send-qBxj0JbJ.mjs → send-CKth_vgn.mjs} +2 -2
- package/dist/{src-CXBmaGwS.mjs → src-BHod38UQ.mjs} +12 -1
- package/dist/{src-DN-RPsil.mjs → src-DLsFsmOD.mjs} +10 -1
- package/dist/{src-nXLIwDrt.mjs → src-DOjTY2ET.mjs} +235 -73
- package/dist/{src-DHDQ0itC.mjs → src-DmmrX2_C.mjs} +73 -18
- package/dist/{store-Dyr1mP8K.mjs → store-DACH768X.mjs} +1 -1
- package/dist/ui/assets/app-9Q-62Ywz.css +1 -0
- package/dist/ui/assets/app-CN3acQ-1.js +111 -0
- package/dist/ui/assets/{index-CVzwYlz3.js → index-B2uGxA4W.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-DLrSt5ny.mjs → ui-CJ-BX12n.mjs} +3 -3
- package/dist/{usage-CxmpYYO4.mjs → usage-DxZ6JGd4.mjs} +5 -4
- package/dist/{validate-BVrT43GO.mjs → validate-BS0nCccW.mjs} +3 -3
- package/dist/{watch-mkLm4t9D.mjs → watch-Dp7IB4FR.mjs} +5 -5
- package/dist/{workflows-Bvl2Fquu.mjs → workflows-Djo1edlK.mjs} +2 -2
- package/dist/{worktrees-DOOCoS2w.mjs → worktrees-Drof_Nyx.mjs} +4 -4
- package/package.json +1 -1
- package/dist/brief-BvMtIFio.mjs +0 -58
- package/dist/in-a-run-a447hxq8.mjs +0 -24
- package/dist/ui/assets/app-BPSCxb_l.css +0 -1
- package/dist/ui/assets/app-CnNRowFn.js +0 -111
|
@@ -1,15 +1,87 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
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__-
|
|
4
|
-
import { t as postFollowUpMessage } from "./post-
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
1
|
+
import { An as liveStatus, Ar as loadAgents, Br as inside, Bt as decisionListTable, D as triggersReport, Dn as requestPause, En as requestContinue, F as activeTree, Fr as placeFor, Gt as worktreeListTable, Hr as LESSON_CAP_TOKENS, Ht as followUpListTable, I as isNodeEvent, In as processAlive, Jr as WorkflowEditSchema, Jt as keyOf, Kn as endOf, Kt as applyClean, L as openStore, Lr as runDirOf, Mn as pausedOf, Nn as runStatus, On as requestStop, Pr as placeFiles, R as storePath, S as detectInstaller, St as walkSummary, Tn as unlinkNodes, Un as loadProject, Ut as runListTable, Vt as feedbackListTable, Wt as usageListTable, Xr as newWorkflowText, Xt as stepActs, Yn as END_KINDS, Yr as applyEdits, Yt as planClean, Zr as readDocument, Zt as stepPrunes, _ as capsHere, a as planRemove, ai as EdgeInputSchema, b as runningRunIds, bn as liveSessionOf, bt as checkWorkflowText, ci as expandEdge, d as planLine, er as DISCUSSIONS, f as removeRefusal, g as usageReport, gn as startFollowUpChecks, ht as explainWorkflowText, i as lostWork, kn as tellLiveRun, l as labelOf, lt as detachRun, ni as parseWorkflow, nr as runGh, nt as answerDecision, o as projectHead, on as nodeSays, ot as detachResume, p as stateParts, pn as checkFollowUpsDue, pr as readCondition, pt as limitsReport, qr as skillsIn, qt as cleanStep, r as applyRemove, rr as sendPost, rt as pendingDecisions, s as readWorktrees, st as resumable, ti as renderJsonSchema, tr as planPost, u as mergeStateOf, ui as NodeSchema, ut as followEvents, v as planUpgrade, wn as linkNodes, x as runningScript, xn as DEFAULT_FOLLOW_UPS_RULE, xt as walkChecks, y as releaseNotes, zn as nestItems, zr as workflowDirOf, zt as LIST_TABLES } from "./src-DLsFsmOD.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-PVlV2QPq.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__-C1Nm0hlJ.mjs";
|
|
4
|
+
import { t as postFollowUpMessage } from "./post-2CaJz_mV.mjs";
|
|
5
|
+
import { t as applyFilters } from "./apply-Mb0fNpCX.mjs";
|
|
6
|
+
import { t as parseFilters } from "./parse-BzWpMN-a.mjs";
|
|
7
|
+
import { t as builtinProblem } from "./builtin-files-yYaNTQRU.mjs";
|
|
8
|
+
import { n as newRunId, t as findRun } from "./find-k489laBa.mjs";
|
|
7
9
|
import path from "node:path";
|
|
8
10
|
import { z } from "zod";
|
|
9
11
|
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
10
12
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
11
13
|
import { homedir } from "node:os";
|
|
12
14
|
import { createServer } from "node:http";
|
|
15
|
+
// ../server/src/contract-lists.ts
|
|
16
|
+
/** A filter's value: any text; the handler checks it with core. */
|
|
17
|
+
const text = () => z.string().min(1).optional();
|
|
18
|
+
/**
|
|
19
|
+
* A `since` or `until`: `all`, an age (`24h`), a day, or an ISO time. Read with
|
|
20
|
+
* core by the handler, so a bad one is refused in the CLI's words.
|
|
21
|
+
*/
|
|
22
|
+
const time = text;
|
|
23
|
+
/** Each list's filter fields, by flag name, in its core table's order. */
|
|
24
|
+
const LIST_SHAPES = {
|
|
25
|
+
runs: {
|
|
26
|
+
status: text(),
|
|
27
|
+
workflow: text(),
|
|
28
|
+
project: text(),
|
|
29
|
+
since: time(),
|
|
30
|
+
until: time()
|
|
31
|
+
},
|
|
32
|
+
feedback: {
|
|
33
|
+
status: text(),
|
|
34
|
+
kind: text(),
|
|
35
|
+
severity: text(),
|
|
36
|
+
workflow: text(),
|
|
37
|
+
run: text()
|
|
38
|
+
},
|
|
39
|
+
"follow-ups": {
|
|
40
|
+
status: text(),
|
|
41
|
+
for: text(),
|
|
42
|
+
kind: text(),
|
|
43
|
+
due: text(),
|
|
44
|
+
project: text()
|
|
45
|
+
},
|
|
46
|
+
decisions: {
|
|
47
|
+
workflow: text(),
|
|
48
|
+
run: text(),
|
|
49
|
+
project: text()
|
|
50
|
+
},
|
|
51
|
+
worktrees: {
|
|
52
|
+
run: text(),
|
|
53
|
+
project: text()
|
|
54
|
+
},
|
|
55
|
+
usage: {
|
|
56
|
+
workflow: text(),
|
|
57
|
+
project: text(),
|
|
58
|
+
since: time(),
|
|
59
|
+
until: time()
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
/** A list's filter fields as query params: its core table's, each optional. */
|
|
63
|
+
const listShape = (list) => LIST_SHAPES[list];
|
|
64
|
+
Object.keys(LIST_SHAPES.runs), Object.keys(LIST_SHAPES.feedback), Object.keys(LIST_SHAPES["follow-ups"]), Object.keys(LIST_SHAPES.decisions), Object.keys(LIST_SHAPES.worktrees), Object.keys(LIST_SHAPES.usage);
|
|
65
|
+
const Count$1 = z.coerce.number().int().positive();
|
|
66
|
+
/** `GET /api/runs`: `runListTable`'s fields, and the newest `limit`. */
|
|
67
|
+
const RunsQuerySchema = z.strictObject({
|
|
68
|
+
limit: Count$1.optional(),
|
|
69
|
+
...LIST_SHAPES.runs
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* `GET /api/usage`: `usageListTable`'s fields; `since` and `until` also take
|
|
73
|
+
* ISO times (`since` included, `until` not), as before.
|
|
74
|
+
*/
|
|
75
|
+
const UsageQuerySchema = z.strictObject(LIST_SHAPES.usage);
|
|
76
|
+
/**
|
|
77
|
+
* `GET /api/decisions`: `decisionListTable`'s fields; `workflow` is ANDed with
|
|
78
|
+
* `run` or `project`.
|
|
79
|
+
*/
|
|
80
|
+
const DecisionsQuerySchema = z.strictObject(LIST_SHAPES.decisions);
|
|
81
|
+
const LISTS_API = { listFields: {
|
|
82
|
+
method: "GET",
|
|
83
|
+
path: "/api/list-fields"
|
|
84
|
+
} };
|
|
13
85
|
// ../server/src/contract-feedback.ts
|
|
14
86
|
const NoteSchema = z.strictObject({
|
|
15
87
|
/** Its first line is the title. */
|
|
@@ -45,6 +117,11 @@ const PublishSchema = z.strictObject({
|
|
|
45
117
|
/** The preview's digest: what the person saw, so nothing else is sent. */
|
|
46
118
|
digest: z.string().min(1)
|
|
47
119
|
});
|
|
120
|
+
/**
|
|
121
|
+
* The filters are core's `feedbackListTable` fields; with none, every item
|
|
122
|
+
* comes, dismissed too (the panel hides them itself).
|
|
123
|
+
*/
|
|
124
|
+
const FeedbackItemsQuerySchema = z.strictObject(listShape("feedback"));
|
|
48
125
|
const FEEDBACK_API = {
|
|
49
126
|
note: {
|
|
50
127
|
method: "POST",
|
|
@@ -53,7 +130,8 @@ const FEEDBACK_API = {
|
|
|
53
130
|
},
|
|
54
131
|
feedbackItems: {
|
|
55
132
|
method: "GET",
|
|
56
|
-
path: "/api/feedback"
|
|
133
|
+
path: "/api/feedback",
|
|
134
|
+
query: FeedbackItemsQuerySchema
|
|
57
135
|
},
|
|
58
136
|
feedbackItem: {
|
|
59
137
|
method: "GET",
|
|
@@ -90,19 +168,11 @@ const FEEDBACK_API = {
|
|
|
90
168
|
}
|
|
91
169
|
};
|
|
92
170
|
// ../server/src/contract-follow-ups.ts
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
});
|
|
171
|
+
/**
|
|
172
|
+
* The filters are core's `followUpListTable` fields. `status` is `open` (due
|
|
173
|
+
* and waiting, the default), `all` (adds done and dropped), or the table's.
|
|
174
|
+
*/
|
|
175
|
+
const FollowUpsQuerySchema = z.strictObject(listShape("follow-ups"));
|
|
106
176
|
const FollowUpChangeSchema = z.strictObject({ action: z.enum([
|
|
107
177
|
"done",
|
|
108
178
|
"drop",
|
|
@@ -271,9 +341,11 @@ planId: z.string().min(1) })
|
|
|
271
341
|
};
|
|
272
342
|
// ../server/src/contract-worktrees.ts
|
|
273
343
|
const Root = z.string().min(1);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
project
|
|
344
|
+
/**
|
|
345
|
+
* The filters are core's `worktreeListTable` fields (`project`: a root; every
|
|
346
|
+
* project without one).
|
|
347
|
+
*/
|
|
348
|
+
const WorktreesQuerySchema = z.strictObject(listShape("worktrees"));
|
|
277
349
|
const RemovePlanSchema = z.strictObject({
|
|
278
350
|
project: Root,
|
|
279
351
|
/** The item's branch, or a detached worktree's path. */
|
|
@@ -323,17 +395,6 @@ const WORKTREES_API = {
|
|
|
323
395
|
// ../server/src/contract.ts
|
|
324
396
|
const Count = z.coerce.number().int().positive();
|
|
325
397
|
const Seq = z.coerce.number().int().nonnegative();
|
|
326
|
-
const RunsQuerySchema = z.strictObject({
|
|
327
|
-
project: z.string().min(1).optional(),
|
|
328
|
-
limit: Count.optional()
|
|
329
|
-
});
|
|
330
|
-
const UsageQuerySchema = z.strictObject({
|
|
331
|
-
project: z.string().min(1).optional(),
|
|
332
|
-
workflow: z.string().min(1).optional(),
|
|
333
|
-
/** ISO times: `since` included, `until` not. */
|
|
334
|
-
since: z.iso.datetime().optional(),
|
|
335
|
-
until: z.iso.datetime().optional()
|
|
336
|
-
});
|
|
337
398
|
const EventsQuerySchema = z.strictObject({
|
|
338
399
|
after: Seq.optional(),
|
|
339
400
|
node: z.string().min(1).optional(),
|
|
@@ -342,12 +403,6 @@ const EventsQuerySchema = z.strictObject({
|
|
|
342
403
|
/** Only the newest this many, still oldest first. */
|
|
343
404
|
last: Count.optional()
|
|
344
405
|
});
|
|
345
|
-
const DecisionsQuerySchema = z.strictObject({
|
|
346
|
-
run: z.string().min(1).optional(),
|
|
347
|
-
project: z.string().min(1).optional(),
|
|
348
|
-
/** Only runs of this workflow, by name; ANDed with `run` or `project`. */
|
|
349
|
-
workflow: z.string().min(1).optional()
|
|
350
|
-
});
|
|
351
406
|
/** An answer: the option, and what the person said with it, if anything. */
|
|
352
407
|
const AnswerSchema = z.strictObject({
|
|
353
408
|
choose: z.string().min(1),
|
|
@@ -385,6 +440,7 @@ const API = {
|
|
|
385
440
|
...CONTEXT_API,
|
|
386
441
|
...AFTER_API,
|
|
387
442
|
...WORKTREES_API,
|
|
443
|
+
...LISTS_API,
|
|
388
444
|
...UPDATE_API,
|
|
389
445
|
projects: {
|
|
390
446
|
method: "GET",
|
|
@@ -1575,6 +1631,76 @@ const treeWithEnds = (roots, stored) => {
|
|
|
1575
1631
|
};
|
|
1576
1632
|
return roots.map((node) => dress(node));
|
|
1577
1633
|
};
|
|
1634
|
+
// ../server/src/list-fields-routes.ts
|
|
1635
|
+
/**
|
|
1636
|
+
* @file `GET /api/list-fields`: the filter fields of each list, from core's
|
|
1637
|
+
* tables (RFC-017), as text without their functions, so the UI builds its
|
|
1638
|
+
* filter bar without importing core.
|
|
1639
|
+
*/
|
|
1640
|
+
const infoOf = (field) => ({
|
|
1641
|
+
name: field.name,
|
|
1642
|
+
description: field.description,
|
|
1643
|
+
type: field.type,
|
|
1644
|
+
...field.values === void 0 ? {} : { values: [...field.values] },
|
|
1645
|
+
...field.all === true ? { all: true } : {}
|
|
1646
|
+
});
|
|
1647
|
+
/** The answer, built once: the tables do not change while the server runs. */
|
|
1648
|
+
const listFields = () => ({
|
|
1649
|
+
runs: LIST_TABLES.ps.fields.map(infoOf),
|
|
1650
|
+
feedback: LIST_TABLES["feedback list"].fields.map(infoOf),
|
|
1651
|
+
"follow-ups": LIST_TABLES["follow-ups list"].fields.map(infoOf),
|
|
1652
|
+
decisions: LIST_TABLES["decide --list"].fields.map(infoOf),
|
|
1653
|
+
worktrees: LIST_TABLES["worktrees list"].fields.map(infoOf),
|
|
1654
|
+
usage: LIST_TABLES.usage.fields.map(infoOf)
|
|
1655
|
+
});
|
|
1656
|
+
const listFieldsRoutes = () => ({ listFields: () => ok(listFields()) });
|
|
1657
|
+
// ../server/src/list-query.ts
|
|
1658
|
+
/**
|
|
1659
|
+
* @file Reads a list route's filter fields the way the CLI reads its flags
|
|
1660
|
+
* (RFC-017, ADR-088): each value checked by core's `parseFilters` against the
|
|
1661
|
+
* list's table, a refused one answered as 400 in the CLI's words. A full ISO
|
|
1662
|
+
* time in `since` or `until` is taken as given (the form `usage` had before
|
|
1663
|
+
* the tables), the rest are an age, a day or `all`.
|
|
1664
|
+
*/
|
|
1665
|
+
/** A `2026-11-01T10:00:00Z`-style time, as an ISO time; else `undefined`. */
|
|
1666
|
+
const isoTime = (value) => {
|
|
1667
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T/u.test(value)) return;
|
|
1668
|
+
const time = Date.parse(value);
|
|
1669
|
+
return Number.isNaN(time) ? void 0 : new Date(time).toISOString();
|
|
1670
|
+
};
|
|
1671
|
+
/**
|
|
1672
|
+
* The filter `query` asks for, checked against `table`; a value the table
|
|
1673
|
+
* refuses is a 400.
|
|
1674
|
+
*/
|
|
1675
|
+
const filterOf = (table, query) => {
|
|
1676
|
+
const times = {};
|
|
1677
|
+
const rest = { ...query };
|
|
1678
|
+
for (const name of ["since", "until"]) {
|
|
1679
|
+
const iso = isoTime(query[name]);
|
|
1680
|
+
if (iso === void 0) continue;
|
|
1681
|
+
times[name] = iso;
|
|
1682
|
+
delete rest[name];
|
|
1683
|
+
}
|
|
1684
|
+
const parsed = parseFilters(table, rest, Date.now());
|
|
1685
|
+
return parsed.ok ? {
|
|
1686
|
+
ok: true,
|
|
1687
|
+
filter: {
|
|
1688
|
+
...parsed.filter,
|
|
1689
|
+
...times
|
|
1690
|
+
}
|
|
1691
|
+
} : {
|
|
1692
|
+
ok: false,
|
|
1693
|
+
refusal: fail(400, parsed.error)
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1696
|
+
/**
|
|
1697
|
+
* The root a filter's `project` names (a registered project's id or root, else
|
|
1698
|
+
* the value as a root); `undefined` without one or for `all`.
|
|
1699
|
+
*/
|
|
1700
|
+
const projectRootOf = (context, filter) => {
|
|
1701
|
+
const key = filter["project"];
|
|
1702
|
+
return key === void 0 || key === "all" ? void 0 : projectOf(context, key)?.root ?? key;
|
|
1703
|
+
};
|
|
1578
1704
|
// ../server/src/workflows.ts
|
|
1579
1705
|
/**
|
|
1580
1706
|
* @file A project's workflows, for the UI's Run workflow dialog: each
|
|
@@ -1633,14 +1759,18 @@ const projectWorkflows = (project) => {
|
|
|
1633
1759
|
* decisions, and usage. Each reads the store as the matching CLI command does
|
|
1634
1760
|
* (`ork projects`, `ps`, `tree`, `logs`, `decide --list`, `usage`).
|
|
1635
1761
|
*/
|
|
1636
|
-
/** A project filter's root: a registered project's, or the value as a root. */
|
|
1637
1762
|
/** A registered project's place; caps are only known for one. */
|
|
1638
1763
|
const placeOf = (context, key) => {
|
|
1639
1764
|
const known = key === void 0 ? void 0 : projectOf(context, key);
|
|
1640
1765
|
return known === void 0 ? void 0 : placeFor(known.root, context.store.projects());
|
|
1641
1766
|
};
|
|
1642
|
-
|
|
1767
|
+
/** `ork ps`'s table, matching `--status` on the live status the API shows. */
|
|
1768
|
+
const liveRunTable = {
|
|
1769
|
+
...runListTable,
|
|
1770
|
+
fields: runListTable.fields.map((field) => field.name === "status" ? Object.assign({}, field, { get: (run) => run.live }) : field)
|
|
1771
|
+
};
|
|
1643
1772
|
const readRoutes = (context) => ({
|
|
1773
|
+
...listFieldsRoutes(),
|
|
1644
1774
|
health: () => ok({
|
|
1645
1775
|
version: context.version,
|
|
1646
1776
|
pid: context.pid,
|
|
@@ -1649,23 +1779,38 @@ const readRoutes = (context) => ({
|
|
|
1649
1779
|
projects: () => ok(context.store.projects()),
|
|
1650
1780
|
triggers: () => ok(triggersReport(context.store, context.store.projects(), context.home)),
|
|
1651
1781
|
links: ({ query }) => ok(context.store.links(query.run === void 0 ? {} : { run: query.run })),
|
|
1652
|
-
usage: ({ query }) =>
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1782
|
+
usage: ({ query }) => {
|
|
1783
|
+
const read = filterOf(usageListTable, query);
|
|
1784
|
+
if (!read.ok) return read.refusal;
|
|
1785
|
+
const { filter } = read;
|
|
1786
|
+
const { workflow, since, until } = filter;
|
|
1787
|
+
const root = projectRootOf(context, filter);
|
|
1788
|
+
return ok({
|
|
1789
|
+
...usageReport(context.store.usage({
|
|
1790
|
+
...root === void 0 ? {} : { project: root },
|
|
1791
|
+
...workflow === void 0 ? {} : { workflow },
|
|
1792
|
+
...since === void 0 || since === "all" ? {} : { since },
|
|
1793
|
+
...until === void 0 ? {} : { until }
|
|
1794
|
+
})),
|
|
1795
|
+
limits: limitsReport(context.store, capsHere(context.home, placeOf(context, root)), /* @__PURE__ */ new Date())
|
|
1796
|
+
});
|
|
1797
|
+
},
|
|
1661
1798
|
workflows: ({ params }) => {
|
|
1662
1799
|
const project = projectOf(context, params.id);
|
|
1663
1800
|
return project === void 0 ? fail(404, `No registered project \`${params.id}\`.`) : ok(projectWorkflows(project));
|
|
1664
1801
|
},
|
|
1665
|
-
runs: ({ query }) =>
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1802
|
+
runs: ({ query }) => {
|
|
1803
|
+
const read = filterOf(liveRunTable, query);
|
|
1804
|
+
if (!read.ok) return read.refusal;
|
|
1805
|
+
const root = projectRootOf(context, read.filter);
|
|
1806
|
+
const limit = query.limit ?? 20;
|
|
1807
|
+
const narrowed = Object.keys(read.filter).some((name) => name !== "project");
|
|
1808
|
+
const views = context.store.runs({
|
|
1809
|
+
...root === void 0 ? {} : { project: root },
|
|
1810
|
+
...narrowed ? {} : { limit }
|
|
1811
|
+
}).map((run) => viewOf$2(context, run));
|
|
1812
|
+
return ok(applyFilters(liveRunTable, views, read.filter).slice(0, limit));
|
|
1813
|
+
},
|
|
1669
1814
|
run: ({ params }) => {
|
|
1670
1815
|
const found = runOf(context, params.id);
|
|
1671
1816
|
return found.ok ? ok(viewOf$2(context, found.run)) : found.refusal;
|
|
@@ -1689,12 +1834,18 @@ const readRoutes = (context) => ({
|
|
|
1689
1834
|
return ok((query.limit === void 0 ? newest : newest.slice(0, query.limit)).map((stored) => servedEvent(stored)));
|
|
1690
1835
|
},
|
|
1691
1836
|
decisions: ({ query }) => {
|
|
1692
|
-
const
|
|
1693
|
-
if (
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1837
|
+
const read = filterOf(decisionListTable, query);
|
|
1838
|
+
if (!read.ok) return read.refusal;
|
|
1839
|
+
const { run, workflow: named } = read.filter;
|
|
1840
|
+
const workflow = named === void 0 ? {} : { workflow: named };
|
|
1841
|
+
if (run === void 0) {
|
|
1842
|
+
const root = projectRootOf(context, read.filter);
|
|
1843
|
+
return ok(pendingDecisions(context.store, {
|
|
1844
|
+
...workflow,
|
|
1845
|
+
...root === void 0 ? {} : { project: root }
|
|
1846
|
+
}));
|
|
1847
|
+
}
|
|
1848
|
+
const found = runOf(context, run);
|
|
1698
1849
|
if (!found.ok) return found.refusal;
|
|
1699
1850
|
return ok(pendingDecisions(context.store, {
|
|
1700
1851
|
...workflow,
|
|
@@ -1739,7 +1890,7 @@ const mcpTools = (context) => {
|
|
|
1739
1890
|
...NO_QUERY,
|
|
1740
1891
|
params: { id: args.project }
|
|
1741
1892
|
}))),
|
|
1742
|
-
tool("runs", "Runs, newest first, with their live status and cost. 10 unless a limit is given.", RunsQuerySchema.shape, (args) => fromReply(read.runs({
|
|
1893
|
+
tool("runs", "Runs, newest first, with their live status and cost. 10 unless a limit is given. Narrow them with `status` (running, paused, crashed, succeeded, failed, … or all), `workflow`, `project` (or all), `since` (24h, 30d, 2026-11-01, all) and `until` (a day).", RunsQuerySchema.shape, (args) => fromReply(read.runs({
|
|
1743
1894
|
...NO_QUERY,
|
|
1744
1895
|
query: {
|
|
1745
1896
|
limit: 10,
|
|
@@ -1775,11 +1926,11 @@ const mcpTools = (context) => {
|
|
|
1775
1926
|
}
|
|
1776
1927
|
}));
|
|
1777
1928
|
}),
|
|
1778
|
-
tool("usage", "What runs spent, by workflow and model, and how close the limits are. `since` and `until
|
|
1929
|
+
tool("usage", "What runs spent, by workflow and model, and how close the limits are. Narrow it with `workflow`, `project` (or all), `since` and `until`: an age (24h, 30d), a day (2026-11-01) or an ISO time; `since` also takes all.", UsageQuerySchema.shape, (args) => fromReply(read.usage({
|
|
1779
1930
|
...NO_QUERY,
|
|
1780
1931
|
query: args
|
|
1781
1932
|
}))),
|
|
1782
|
-
tool("decisions", "The decisions open in live runs, waiting on a person. This server can't answer them.", DecisionsQuerySchema.shape, (args) => fromReply(read.decisions({
|
|
1933
|
+
tool("decisions", "The decisions open in live runs, waiting on a person. This server can't answer them. Narrow them with `workflow`, `run` (an id or a start of one) and `project` (or all).", DecisionsQuerySchema.shape, (args) => fromReply(read.decisions({
|
|
1783
1934
|
...NO_QUERY,
|
|
1784
1935
|
query: args
|
|
1785
1936
|
}), (open) => ({
|
|
@@ -2180,7 +2331,10 @@ const feedbackRoutes = (context) => {
|
|
|
2180
2331
|
const noted = recordNote(store, found.run, body);
|
|
2181
2332
|
return noted.ok ? ok({ item: noted.item }) : fail(400, noted.error);
|
|
2182
2333
|
},
|
|
2183
|
-
feedbackItems: () =>
|
|
2334
|
+
feedbackItems: ({ query }) => {
|
|
2335
|
+
const read = filterOf(feedbackListTable, query);
|
|
2336
|
+
return read.ok ? ok(applyFilters(feedbackListTable, store.feedbackItems({ all: true }), read.filter)) : read.refusal;
|
|
2337
|
+
},
|
|
2184
2338
|
feedbackItem: ({ params }) => {
|
|
2185
2339
|
const found = itemOf(store, params.id);
|
|
2186
2340
|
if (!found.ok) return found.refusal;
|
|
@@ -2349,13 +2503,15 @@ const followUpRoutes = (context) => {
|
|
|
2349
2503
|
gh
|
|
2350
2504
|
}).then((checked) => checked.errors).catch((error) => [error instanceof Error ? error.message : String(error)]);
|
|
2351
2505
|
const all = store.followUps(root);
|
|
2352
|
-
const
|
|
2353
|
-
const
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
if (status === "open") return OPEN.some((s) => s === f.status);
|
|
2357
|
-
return f.status === status;
|
|
2506
|
+
const open = (query.status ?? "open") === "open";
|
|
2507
|
+
const read = filterOf(followUpListTable, {
|
|
2508
|
+
...query,
|
|
2509
|
+
...open ? { status: "all" } : {}
|
|
2358
2510
|
});
|
|
2511
|
+
if (!read.ok) return read.refusal;
|
|
2512
|
+
const other = projectRootOf(context, read.filter);
|
|
2513
|
+
const matched = other === void 0 || other === root ? applyFilters(followUpListTable, all, read.filter) : [];
|
|
2514
|
+
const shown = open ? matched.filter((f) => OPEN.some((s) => s === f.status)) : matched;
|
|
2359
2515
|
return ok({
|
|
2360
2516
|
project: root,
|
|
2361
2517
|
followUps: shown,
|
|
@@ -2905,9 +3061,15 @@ const worktreesRoutes = (context) => {
|
|
|
2905
3061
|
};
|
|
2906
3062
|
return {
|
|
2907
3063
|
worktrees: async ({ query }) => {
|
|
2908
|
-
const
|
|
3064
|
+
const filtered = filterOf(worktreeListTable, query);
|
|
3065
|
+
if (!filtered.ok) return filtered.refusal;
|
|
3066
|
+
const all = await readAll(projectRootOf(context, filtered.filter));
|
|
2909
3067
|
if (!all.ok) return all.refusal;
|
|
2910
|
-
return ok({ projects: all.reads.map((read) =>
|
|
3068
|
+
return ok({ projects: all.reads.map((read) => {
|
|
3069
|
+
const project = listed(context, read);
|
|
3070
|
+
project.items = applyFilters(worktreeListTable, project.items, filtered.filter);
|
|
3071
|
+
return project;
|
|
3072
|
+
}) });
|
|
2911
3073
|
},
|
|
2912
3074
|
worktreeRemovePlan: async ({ body }) => {
|
|
2913
3075
|
const planned = await removePlanOf(context, body);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $r as
|
|
2
|
-
import { t as runOnce } from "./run-
|
|
1
|
+
import { $r as beforeOf, At as endedWith, Bn as countedTokens, Dt as runScope, Et as heldTimeout, It as lowerChild, Jn as END_DETAIL_LIMIT, Kn as endOf, Mt as stoppedEnd, Nt as declaredProblem, Ot as calledWorkflows, Pt as slotClock, R as storePath, Rt as startAt, Ti as AGENT_DRIVERS, Xn as endFor, Y as sessionRefusals, _i as INTEGRATIONS, _t as planNodeSession, an as sessionDriver, cn as MCP_FILE, di as isClaudeNode, dr as parseTemplate, ei as programsRunBy, fi as isToolNode, fr as renderTemplate, gi as timeoutMs, ii as markValue, jt as failedWith, ln as mcpNotText, mt as planReason, nn as envReadsOf, qn as outcomeEnd, sn as declaredOutputOf, un as serversIn, ur as evaluate, vi as TOOL_PREFIX, yi as integrationFor, yt as reportSchemaFor } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { t as runOnce } from "./run-BfxdsQJk.mjs";
|
|
3
3
|
import { n as holdGuard, r as orphanGuard, t as KILL_AFTER_MS } from "./orphan-guard-BFKg8VSd.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { accessSync, constants, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { accessSync, constants, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { Readable } from "node:stream";
|
|
8
8
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -1100,6 +1100,62 @@ const skippedCheck = (outputFile) => {
|
|
|
1100
1100
|
}
|
|
1101
1101
|
}, endFor("done"));
|
|
1102
1102
|
};
|
|
1103
|
+
// ../nodes/src/run-marker.ts
|
|
1104
|
+
/**
|
|
1105
|
+
* @file The marker a run leaves on its sessions and programs (ADR-047), and the
|
|
1106
|
+
* stores it guards: the commands that act as the user refuse in the stores of
|
|
1107
|
+
* the runs that started a process, and everywhere under a marker that lists
|
|
1108
|
+
* none, which an older `ork` sets.
|
|
1109
|
+
*/
|
|
1110
|
+
/** Set for a program in a run. */
|
|
1111
|
+
const RUN_ENV = "ORK_RUN";
|
|
1112
|
+
/** Set for a Claude session. It says no more than that: no run, no node. */
|
|
1113
|
+
const SESSION_ENV = "ORK_SESSION";
|
|
1114
|
+
/**
|
|
1115
|
+
* The stores whose runs started a session or program, as a JSON array of real
|
|
1116
|
+
* paths: the commands that act as the user refuse only in these.
|
|
1117
|
+
*/
|
|
1118
|
+
const GUARDED_STORES_ENV = "ORK_GUARDED_STORES";
|
|
1119
|
+
/**
|
|
1120
|
+
* The variable that says a program in a run or a session started this process,
|
|
1121
|
+
* or `null` when none does.
|
|
1122
|
+
*/
|
|
1123
|
+
const runMarkerIn = (env) => ["ORK_RUN", "ORK_SESSION"].find((name) => env[name] !== void 0) ?? null;
|
|
1124
|
+
/** The stores `env` lists, or `undefined` when it lists none or garbles it. */
|
|
1125
|
+
const listIn = (env) => {
|
|
1126
|
+
const text = env[GUARDED_STORES_ENV];
|
|
1127
|
+
if (text === void 0) return void 0;
|
|
1128
|
+
try {
|
|
1129
|
+
const value = JSON.parse(text);
|
|
1130
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
|
|
1131
|
+
} catch {
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
/** A store file's real path, so a symlinked `~/.ork` is the same store. */
|
|
1136
|
+
const realStore = (store) => {
|
|
1137
|
+
try {
|
|
1138
|
+
return realpathSync(store);
|
|
1139
|
+
} catch {
|
|
1140
|
+
return path.resolve(store);
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
/**
|
|
1144
|
+
* The stores a run that started this process is in: `null` when no run did, and
|
|
1145
|
+
* `"all"` when one did but listed none (an older `ork`), which fails closed.
|
|
1146
|
+
*/
|
|
1147
|
+
const guardedStoresIn = (env) => runMarkerIn(env) === null ? null : listIn(env) ?? "all";
|
|
1148
|
+
/** Whether a run in `store` (a store file) started this process. */
|
|
1149
|
+
const storeGuarded = (env, store) => {
|
|
1150
|
+
const guarded = guardedStoresIn(env);
|
|
1151
|
+
return guarded === "all" || guarded !== null && guarded.includes(realStore(store));
|
|
1152
|
+
};
|
|
1153
|
+
/**
|
|
1154
|
+
* What a run in `store` (default: the user's) tells its sessions and programs:
|
|
1155
|
+
* the stores it inherited, and its own. Nothing when it inherited "all", so
|
|
1156
|
+
* that holds.
|
|
1157
|
+
*/
|
|
1158
|
+
const guardOf = (env, store = storePath()) => guardedStoresIn(env) === "all" ? {} : { [GUARDED_STORES_ENV]: JSON.stringify([.../* @__PURE__ */ new Set([...listIn(env) ?? [], realStore(store)])]) };
|
|
1103
1159
|
// ../nodes/src/tool-scrub.ts
|
|
1104
1160
|
/**
|
|
1105
1161
|
* @file Masking a secret in what a program prints. A plain search, so a value
|
|
@@ -1263,16 +1319,13 @@ const scrubberOf = (values) => {
|
|
|
1263
1319
|
const OUTPUT_ENV = "ORK_OUTPUT";
|
|
1264
1320
|
/** A file a `watch:` node's program keeps between looks (RFC-011). */
|
|
1265
1321
|
const STATE_ENV = "ORK_STATE";
|
|
1266
|
-
/** Set for a program in a run. */
|
|
1267
|
-
const RUN_ENV = "ORK_RUN";
|
|
1268
|
-
/** Set for a Claude session. It says no more than that: no run, no node. */
|
|
1269
|
-
const SESSION_ENV = "ORK_SESSION";
|
|
1270
1322
|
/** The variables a caller's run reads, for a run it calls to mask too. */
|
|
1271
1323
|
const MASKED_ENV = "ORK_MASKED";
|
|
1272
1324
|
/** Every variable Ork sets itself; a workflow's `env:` cannot set them. */
|
|
1273
1325
|
const IDENTITY_KEYS = /* @__PURE__ */ new Set([
|
|
1274
1326
|
RUN_ENV,
|
|
1275
1327
|
SESSION_ENV,
|
|
1328
|
+
GUARDED_STORES_ENV,
|
|
1276
1329
|
MASKED_ENV,
|
|
1277
1330
|
"ORK_NODE",
|
|
1278
1331
|
"ORK_ROUND",
|
|
@@ -1291,20 +1344,21 @@ const IDENTITY_KEYS = /* @__PURE__ */ new Set([
|
|
|
1291
1344
|
*/
|
|
1292
1345
|
const withoutIdentity = (env) => Object.fromEntries(Object.entries(env).flatMap(([key, value]) => value === void 0 || IDENTITY_KEYS.has(key) ? [] : [[key, value]]));
|
|
1293
1346
|
/**
|
|
1294
|
-
* What a Claude session
|
|
1295
|
-
* Bash from speaking as the user
|
|
1347
|
+
* What a Claude session of a run in `store` (default: the user's) runs with: no
|
|
1348
|
+
* identity, only the marker that stops its Bash from speaking as the user
|
|
1349
|
+
* through `ork chat`, and the stores it must not do that in.
|
|
1296
1350
|
*/
|
|
1297
|
-
const sessionEnv = (env) => ({
|
|
1351
|
+
const sessionEnv = (env, store) => ({
|
|
1298
1352
|
...withoutIdentity(env),
|
|
1299
|
-
[SESSION_ENV]: "1"
|
|
1353
|
+
[SESSION_ENV]: "1",
|
|
1354
|
+
...guardOf(env, store)
|
|
1300
1355
|
});
|
|
1301
1356
|
/**
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1357
|
+
* Who a node's program is, and the stores its run guards (none listed without
|
|
1358
|
+
* `store`, which guards every one). It is attribution, not a boundary.
|
|
1304
1359
|
*/
|
|
1305
|
-
const
|
|
1306
|
-
|
|
1307
|
-
const identityOf = (context, orkBin) => ({
|
|
1360
|
+
const identityOf = (context, orkBin, environ = {}, store) => ({
|
|
1361
|
+
...store === void 0 ? {} : guardOf(environ, store),
|
|
1308
1362
|
[RUN_ENV]: context.runId,
|
|
1309
1363
|
ORK_NODE: context.id,
|
|
1310
1364
|
ORK_ROUND: String(context.round),
|
|
@@ -1526,7 +1580,7 @@ const toolExecutor = (given, options = {}) => async (context) => {
|
|
|
1526
1580
|
const outputFile = node.output?.format === "json" ? prepareOutputFile(context.runDir, context.id, context.round) : void 0;
|
|
1527
1581
|
const env = {
|
|
1528
1582
|
...nodeEnv.values,
|
|
1529
|
-
...identityOf(context, options.orkBin),
|
|
1583
|
+
...identityOf(context, options.orkBin, environ, options.store),
|
|
1530
1584
|
...maskedEnv(namesToMask(context.workflow, environ, options.maskedNames)),
|
|
1531
1585
|
...outputFile === void 0 ? {} : { [OUTPUT_ENV]: outputFile },
|
|
1532
1586
|
...node.watch === void 0 ? {} : { [STATE_ENV]: prepareStateFile(context.runDir, context.id) }
|
|
@@ -2320,6 +2374,7 @@ const spawnTool = (program, args, { cwd, signal, env, priority }) => {
|
|
|
2320
2374
|
const builtinExecutors = (options) => {
|
|
2321
2375
|
const tool = toolExecutor(options.tools ?? spawnTool, {
|
|
2322
2376
|
...options.orkBin === void 0 ? {} : { orkBin: options.orkBin },
|
|
2377
|
+
...options.store === void 0 ? {} : { store: options.store },
|
|
2323
2378
|
...options.maskedNames === void 0 ? {} : { maskedNames: options.maskedNames }
|
|
2324
2379
|
});
|
|
2325
2380
|
const claude = claudeExecutor({
|
|
@@ -2460,4 +2515,4 @@ const missingPrograms = (workflow, installed = (program) => onPath(program)) =>
|
|
|
2460
2515
|
}
|
|
2461
2516
|
return [...missing.values()];
|
|
2462
2517
|
};
|
|
2463
|
-
export {
|
|
2518
|
+
export { clearOutputFiles as _, builtinExecutors as a, toolExecutor as c, maskedEnv as d, maskedNamesOfRun as f, storeGuarded as g, runMarkerIn as h, onPath as i, clearStateFiles as l, sessionEnv as m, missingProgramMessage as n, spawnTool as o, runScrubber as p, missingPrograms as r, mcpCallExecutor as s, envProblems as t, inheritedScrubber as u, namedMcpEntries as v, resultOf as y };
|