@krapht/ork 1.0.0-alpha.15 → 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/README.md +10 -4
- package/dist/{__build_info__-Bsb1kjgF.mjs → __build_info__-C1Nm0hlJ.mjs} +25 -6
- package/dist/apply-Mb0fNpCX.mjs +17 -0
- package/dist/{attach-CPespxlQ.mjs → attach-EP374oMP.mjs} +5 -5
- package/dist/{attach-BHO3X3cf.mjs → attach-RQx__RzH.mjs} +46 -8
- package/dist/bin.mjs +238 -369
- package/dist/brief-Bs3cMQU0.mjs +100 -0
- package/dist/{builtin-files-2bHf76x-.mjs → builtin-files-yYaNTQRU.mjs} +1 -1
- package/dist/command-tree-BkSYWmYJ.mjs +63 -0
- package/dist/{completion-CQ2UYKuJ.mjs → completion-DIXWlnAl.mjs} +87 -6
- package/dist/{context-BNqDw9z1.mjs → context-Dq-VM_sq.mjs} +3 -3
- package/dist/{find-BYLlszqj.mjs → find-k489laBa.mjs} +2 -2
- package/dist/flags-B4ZZWspN.mjs +125 -0
- package/dist/{follow-ups-B4GJ3Vzw.mjs → follow-ups-DD8NTPe6.mjs} +59 -24
- package/dist/{format-C8MsFj8_.mjs → format-DQc9A_ei.mjs} +17 -4
- package/dist/{help-groups-CQ98mLjF.mjs → help-groups-hB6kY34d.mjs} +1 -63
- package/dist/in-a-run-D_9GlAlS.mjs +27 -0
- package/dist/{install-DWtXTq4y.mjs → install-PVlV2QPq.mjs} +1 -1
- package/dist/{limits-B1qzS4cX.mjs → limits-CHqBO7wb.mjs} +1 -1
- package/dist/{mcp-BOrVkyhN.mjs → mcp-D38Ajb0b.mjs} +6 -6
- package/dist/{once-C1fL3GVo.mjs → once-DuUzpzL2.mjs} +3 -3
- package/dist/parse-BzWpMN-a.mjs +107 -0
- package/dist/{pause-DOMK-R8V.mjs → pause-Bx3ePGrn.mjs} +3 -3
- package/dist/{post-BzA6Qobq.mjs → post-2CaJz_mV.mjs} +5 -3
- package/dist/print-n2qetUHc.mjs +19 -0
- package/dist/project-records-Cune1l6I.mjs +230 -0
- package/dist/{relay-OWuu4fib.mjs → relay-D7RN4m68.mjs} +1 -1
- package/dist/{run-CiPsW9Kf.mjs → run-BfxdsQJk.mjs} +1 -1
- package/dist/{run--4-1xAF2.mjs → run-OOWQIKMJ.mjs} +33 -20
- package/dist/{send-CnNNW-ot.mjs → send-CKth_vgn.mjs} +2 -2
- package/dist/{src-B9zWIVqo.mjs → src-BHod38UQ.mjs} +104 -72
- package/dist/{src-Dr_fTSu-.mjs → src-DLsFsmOD.mjs} +790 -502
- package/dist/{src-DQKz2eOH.mjs → src-DOjTY2ET.mjs} +238 -79
- package/dist/{src-DcrhgipG.mjs → src-DmmrX2_C.mjs} +162 -58
- package/dist/{store-oKJ-cCf3.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-BtwkftKe.js → index-B2uGxA4W.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-CzKlsCnm.mjs → ui-CJ-BX12n.mjs} +3 -3
- package/dist/{usage-DHGNk2JL.mjs → usage-DxZ6JGd4.mjs} +62 -107
- package/dist/{validate-Bs_gg22g.mjs → validate-BS0nCccW.mjs} +35 -8
- package/dist/{watch-CCCfw3n7.mjs → watch-Dp7IB4FR.mjs} +5 -5
- package/dist/{workflows-CW28ZU-z.mjs → workflows-Djo1edlK.mjs} +2 -2
- package/dist/{worktrees-CyE8aF6j.mjs → worktrees-Drof_Nyx.mjs} +49 -20
- package/package.json +8 -4
- package/dist/brief-za0ozN_E.mjs +0 -58
- package/dist/in-a-run-Bp0k0J09.mjs +0 -24
- package/dist/ui/assets/app-Bdc6OBeZ.css +0 -1
- package/dist/ui/assets/app-Drp8Dm9y.js +0 -111
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @krapht/ork
|
|
2
2
|
|
|
3
|
-
The `ork` command: orchestrate
|
|
4
|
-
serializable workflows.
|
|
3
|
+
The `ork` command: orchestrate coding agents (Claude Code, OpenCode, Command
|
|
4
|
+
Code) on your machine with hierarchical, serializable workflows.
|
|
5
5
|
|
|
6
|
-
> **Alpha.** Workflows of
|
|
6
|
+
> **Alpha.** Workflows of coding agents and tools, run from the terminal or the
|
|
7
7
|
> browser (`ork ui`). Expect changes until 1.0.0. See the
|
|
8
8
|
> [project README](https://github.com/mimshins/ork#readme), the
|
|
9
9
|
> [guides](https://github.com/mimshins/ork/tree/main/docs#readme) and
|
|
@@ -28,7 +28,13 @@ ork upgrade # a newer version? upgrade the way you installed Ork
|
|
|
28
28
|
|
|
29
29
|
A workflow that names no agent driver runs on the one that's ready. Today that
|
|
30
30
|
is `claude-code`: your own `claude`, logged in or with `ANTHROPIC_API_KEY` or a
|
|
31
|
-
cloud provider set.
|
|
31
|
+
cloud provider set. Your own `opencode` (`open-code`) and Command Code's `cmd`
|
|
32
|
+
(`command-code`) work too: `--driver <id>`, or a driver per node
|
|
33
|
+
([Drivers](https://github.com/mimshins/ork/blob/main/docs/guides/drivers.md)).
|
|
34
|
+
|
|
35
|
+
Ork is built with Ork: its own workflows plan, build, review and document its
|
|
36
|
+
features, and each run is measured against a manual session in
|
|
37
|
+
[Benchmarks: Ork building Ork](https://github.com/mimshins/ork/blob/main/benchmarks/README.md).
|
|
32
38
|
|
|
33
39
|
Ork never stores or asks for credentials: it uses the tools you already have,
|
|
34
40
|
signed in with your own accounts. Once a day it asks the npm registry whether a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as compareVersions, T as parseVersion, w as isNewer } from "./src-DLsFsmOD.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -57,19 +57,38 @@ const check = (f, action) => {
|
|
|
57
57
|
const error = refusal(f, action);
|
|
58
58
|
return error === void 0 ? { ok: true } : {
|
|
59
59
|
ok: false,
|
|
60
|
+
kind: "status",
|
|
60
61
|
why: `it is ${f.status}`,
|
|
61
62
|
error
|
|
62
63
|
};
|
|
63
64
|
};
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
/** Whether `to` names one GitHub issue or pull request by its URL. */
|
|
66
|
+
const isGithubIssueUrl = (to) => /^https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(?:issues|pull)\/\d+$/u.test(to);
|
|
67
|
+
/**
|
|
68
|
+
* Why `f`'s draft can't be posted to GitHub whatever its status, or
|
|
69
|
+
* `undefined`.
|
|
70
|
+
*/
|
|
71
|
+
const githubDraftRefusal = (f) => {
|
|
66
72
|
if (f.kind !== "message" || f.draft?.channel !== "github") return {
|
|
67
|
-
ok: false,
|
|
68
73
|
why: "not drafted for the github channel",
|
|
69
74
|
error: "only a message drafted for the github channel is posted; send the others yourself"
|
|
70
75
|
};
|
|
76
|
+
return isGithubIssueUrl(f.draft.to) ? void 0 : {
|
|
77
|
+
why: "its `to` isn't a GitHub issue or pull request URL",
|
|
78
|
+
error: `${f.id}'s \`to\` (${f.draft.to}) isn't a GitHub issue or pull request URL, so it is not posted; copy the text and send it yourself.`
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
const postCheck = (f) => {
|
|
82
|
+
const open = f.status === "waiting" || f.status === "due";
|
|
83
|
+
const refused = githubDraftRefusal(f);
|
|
84
|
+
if (refused !== void 0) return {
|
|
85
|
+
ok: false,
|
|
86
|
+
kind: "draft",
|
|
87
|
+
...refused
|
|
88
|
+
};
|
|
71
89
|
return open ? { ok: true } : {
|
|
72
90
|
ok: false,
|
|
91
|
+
kind: "status",
|
|
73
92
|
why: `it is ${f.status}`,
|
|
74
93
|
error: `${f.id} is ${f.status}, so it is not posted.`
|
|
75
94
|
};
|
|
@@ -336,5 +355,5 @@ const registryShown = (registry) => {
|
|
|
336
355
|
* fails when it is stale.
|
|
337
356
|
*/
|
|
338
357
|
const ORK_NAME = "@krapht/ork";
|
|
339
|
-
const ORK_VERSION = "1.0.0-alpha.
|
|
340
|
-
export { dueCause as _, registryShown as a, fetchLatest as c, readUpdateCache as d, refreshUpdateCache as f, changeFollowUp as g, nodeSession as h, registryOf as i, newerVersion as l, writeUpdateCache as m, ORK_VERSION as n, updateSwitchOff as o, updateCachePath as p, isSwitchedOn as r, checkDue as s, ORK_NAME as t, pendingNotice as u, findFollowUp as v, followUpActions as y };
|
|
358
|
+
const ORK_VERSION = "1.0.0-alpha.17";
|
|
359
|
+
export { dueCause as _, registryShown as a, githubDraftRefusal as b, fetchLatest as c, readUpdateCache as d, refreshUpdateCache as f, changeFollowUp as g, nodeSession as h, registryOf as i, newerVersion as l, writeUpdateCache as m, ORK_VERSION as n, updateSwitchOff as o, updateCachePath as p, isSwitchedOn as r, checkDue as s, ORK_NAME as t, pendingNotice as u, findFollowUp as v, isGithubIssueUrl as x, followUpActions as y };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// ../core/src/list-filters/apply.ts
|
|
2
|
+
/**
|
|
3
|
+
* @file Keeps the rows a list's filter matches (RFC-017). The list's own order
|
|
4
|
+
* and `--limit` stay the caller's: filter, then order, then limit.
|
|
5
|
+
*/
|
|
6
|
+
const fieldMatches = (field, row, wanted) => {
|
|
7
|
+
if (wanted === void 0 || wanted === "all" || field.get === void 0) return true;
|
|
8
|
+
const got = field.get(row);
|
|
9
|
+
if (got === void 0) return false;
|
|
10
|
+
const values = typeof got === "string" ? [got] : got;
|
|
11
|
+
if (field.type === "since") return values.some((value) => Date.parse(value) >= Date.parse(wanted));
|
|
12
|
+
if (field.type === "until") return values.some((value) => Date.parse(value) < Date.parse(wanted));
|
|
13
|
+
return values.includes(wanted);
|
|
14
|
+
};
|
|
15
|
+
/** The rows of `rows` every field of `filter` matches, in their order. */
|
|
16
|
+
const applyFilters = (table, rows, filter) => rows.filter((row) => table.fields.every((field) => fieldMatches(field, row, filter[field.name])));
|
|
17
|
+
export { applyFilters as t };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./src-
|
|
2
|
-
import {
|
|
3
|
-
import { t as findRun } from "./find-
|
|
1
|
+
import "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { l as createTerminalHuman, t as attachRun } from "./attach-RQx__RzH.mjs";
|
|
3
|
+
import { t as findRun } from "./find-k489laBa.mjs";
|
|
4
4
|
import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
|
|
5
|
-
import { n as attachRefusal } from "./in-a-run-
|
|
6
|
-
import { t as withStore } from "./store-
|
|
5
|
+
import { n as attachRefusal } from "./in-a-run-D_9GlAlS.mjs";
|
|
6
|
+
import { t as withStore } from "./store-DACH768X.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
// src/commands/attach.ts
|
|
9
9
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ft as slotWaitLine, I as isNodeEvent, Kn as endOf, Yn as END_KINDS, kt as lockWaitLine, nt as answerDecision, qn as outcomeEnd, rt as pendingDecisions, tt as followRunTree, ut as followEvents, yr as maskSecrets } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { t as applyFilters } from "./apply-Mb0fNpCX.mjs";
|
|
2
3
|
import { C as termOf, D as wrap, E as widthOf, O as readKeys, _ as interrupt, a as plain, b as canKey, g as createRegion, h as paint, m as bold, n as cost, p as apply, r as costOf, s as style, u as confirmOrStop, v as readLine, w as cut, x as plainEnv, y as withdrawn } from "./output-B1kwo0YU.mjs";
|
|
3
4
|
import { n as chip, r as nodeChip, t as CHIP_LABELS } from "./chips-BqcT58qr.mjs";
|
|
4
5
|
import { a as createView, i as formatBusEvent, n as nodeVerdict, o as styler, r as firstLine, t as hasConflict } from "./verdict-CMvPCpWC.mjs";
|
|
@@ -1038,7 +1039,8 @@ const formatRunEvent = (event, width, tools, terminal = false, verbose = false,
|
|
|
1038
1039
|
if (event.type === "node.started") {
|
|
1039
1040
|
const round = event.round > 1 ? ` (round ${String(event.round)})` : "";
|
|
1040
1041
|
const owner = event.owner === void 0 ? "" : `, for ${event.owner}`;
|
|
1041
|
-
|
|
1042
|
+
const named = event.description === void 0 ? "" : ` · ${event.description}`;
|
|
1043
|
+
return [`${tag(event.id)} ${style("dim", `${event.nodeType}${round}${owner}${named}`)}`];
|
|
1042
1044
|
}
|
|
1043
1045
|
if (event.type === "node.event") {
|
|
1044
1046
|
const inner = event.event;
|
|
@@ -1121,7 +1123,7 @@ const formatRunEvent = (event, width, tools, terminal = false, verbose = false,
|
|
|
1121
1123
|
/** Turns stored events into lines, keeping the state a transcript needs. */
|
|
1122
1124
|
const createLogPrinter = (options) => {
|
|
1123
1125
|
const tools = /* @__PURE__ */ new Map();
|
|
1124
|
-
const view = createView();
|
|
1126
|
+
const view = options.view ?? createView();
|
|
1125
1127
|
let width = 8;
|
|
1126
1128
|
return (stored) => {
|
|
1127
1129
|
const { event } = stored;
|
|
@@ -1141,6 +1143,19 @@ const unknownNode = (stored, node, live) => {
|
|
|
1141
1143
|
const declared = stored.some(({ event }) => event.type === "run.started" && event.nodes.some((n) => n.id === node));
|
|
1142
1144
|
return named || declared || live ? null : `Run has no node ${node}.`;
|
|
1143
1145
|
};
|
|
1146
|
+
/** `ork logs`'s filter flags (RFC-017): an event's time; no ids. */
|
|
1147
|
+
const logListTable = { fields: [{
|
|
1148
|
+
name: "since",
|
|
1149
|
+
description: "Only events since an age (24h, 30d, 12w), a day (2026-11-01), or all",
|
|
1150
|
+
type: "since",
|
|
1151
|
+
all: true,
|
|
1152
|
+
get: (stored) => stored.at
|
|
1153
|
+
}, {
|
|
1154
|
+
name: "until",
|
|
1155
|
+
description: "Only events on or before this day (2026-11-01)",
|
|
1156
|
+
type: "until",
|
|
1157
|
+
get: (stored) => stored.at
|
|
1158
|
+
}] };
|
|
1144
1159
|
/**
|
|
1145
1160
|
* Prints a run's events; with `follow`, then each new one as it is stored:
|
|
1146
1161
|
* pushed over the run's socket, or polled from the store when there is none.
|
|
@@ -1149,8 +1164,13 @@ const unknownNode = (stored, node, live) => {
|
|
|
1149
1164
|
*/
|
|
1150
1165
|
const followRun = async (store, run, out, options) => {
|
|
1151
1166
|
const print = createLogPrinter(options);
|
|
1167
|
+
const matches = (stored) => applyFilters(logListTable, [stored], options.filter ?? {}).length > 0 && (options.node === void 0 || isNodeEvent(stored.event, options.node));
|
|
1168
|
+
const replayed = options.limit === void 0 ? [] : store.events(run.id, options.after ?? 0).filter((stored) => matches(stored)).slice(0, -options.limit);
|
|
1169
|
+
const dropped = new Set(replayed.map((stored) => stored.seq));
|
|
1152
1170
|
if (await followEvents(store, run.id, (stored) => {
|
|
1153
|
-
|
|
1171
|
+
const lines = print(stored);
|
|
1172
|
+
if (!matches(stored) || dropped.has(stored.seq)) return;
|
|
1173
|
+
for (const line of lines) out(line);
|
|
1154
1174
|
}, {
|
|
1155
1175
|
follow: options.follow,
|
|
1156
1176
|
...options.after === void 0 ? {} : { after: options.after },
|
|
@@ -1208,13 +1228,15 @@ const askStored = async (store, human, decision, { place, by, signal, home }) =>
|
|
|
1208
1228
|
* asked through one `TerminalHuman`, withdrawn when it closes elsewhere.
|
|
1209
1229
|
*/
|
|
1210
1230
|
const where = (path) => path.join(" › ");
|
|
1231
|
+
/** The gutter before a called run's lines: its call path, then ` › `. */
|
|
1232
|
+
const gutterOf = (path) => path.length === 0 ? "" : `${where(path)} › `;
|
|
1211
1233
|
/**
|
|
1212
1234
|
* Prints the events of `root` and of the runs it called until the root ends or
|
|
1213
1235
|
* `signal` aborts, and asks each open decision with `options.human`.
|
|
1214
1236
|
*/
|
|
1215
1237
|
const attachRun = async (store, root, out, options = {}) => {
|
|
1216
1238
|
const { human, basePath = [] } = options;
|
|
1217
|
-
const { term } = createView();
|
|
1239
|
+
const { term } = options.view ?? createView();
|
|
1218
1240
|
const say = styler(term);
|
|
1219
1241
|
const printers = /* @__PURE__ */ new Map();
|
|
1220
1242
|
const prompts = /* @__PURE__ */ new Map();
|
|
@@ -1226,9 +1248,25 @@ const attachRun = async (store, root, out, options = {}) => {
|
|
|
1226
1248
|
succeeded: false
|
|
1227
1249
|
};
|
|
1228
1250
|
const show = (path, lines) => {
|
|
1229
|
-
const
|
|
1251
|
+
const gutter = gutterOf(path);
|
|
1252
|
+
const prefix = gutter === "" ? "" : paint(term, "muted", gutter);
|
|
1230
1253
|
for (const line of lines) out(line === "" ? line : `${prefix}${line}`);
|
|
1231
1254
|
};
|
|
1255
|
+
/**
|
|
1256
|
+
* A run's printer, laid out in the columns its gutter leaves, so a line fits
|
|
1257
|
+
* the terminal with the gutter before it and a wrapped line goes on under its
|
|
1258
|
+
* own text, not at the terminal's first column.
|
|
1259
|
+
*/
|
|
1260
|
+
const printerFor = (path) => createLogPrinter({
|
|
1261
|
+
json: false,
|
|
1262
|
+
view: {
|
|
1263
|
+
term: {
|
|
1264
|
+
...term,
|
|
1265
|
+
width: Math.max(20, term.width - widthOf(gutterOf(path)))
|
|
1266
|
+
},
|
|
1267
|
+
roots: /* @__PURE__ */ new Map()
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1232
1270
|
const ask = (run, path, id) => {
|
|
1233
1271
|
const decision = store.decision(id);
|
|
1234
1272
|
if (human === void 0 || decision === void 0) return;
|
|
@@ -1288,7 +1326,7 @@ const attachRun = async (store, root, out, options = {}) => {
|
|
|
1288
1326
|
}
|
|
1289
1327
|
let print = printers.get(run);
|
|
1290
1328
|
if (print === void 0) {
|
|
1291
|
-
print =
|
|
1329
|
+
print = printerFor(path);
|
|
1292
1330
|
printers.set(run, print);
|
|
1293
1331
|
}
|
|
1294
1332
|
show(path, print(stored));
|
|
@@ -1307,4 +1345,4 @@ const attachRun = async (store, root, out, options = {}) => {
|
|
|
1307
1345
|
exitCode: end === "aborted" || seen.succeeded ? 0 : 1
|
|
1308
1346
|
};
|
|
1309
1347
|
};
|
|
1310
|
-
export {
|
|
1348
|
+
export { unknownNode as a, callsShown as c, createDecisionQueue as d, logListTable as i, createTerminalHuman as l, askStored as n, formatEvent as o, followRun as r, formatRunEvent as s, attachRun as t, readText as u };
|