@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
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { _n as takeFollowUps, nr as runGh } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { f as refreshDue, l as briefOf, n as flagValues, u as checkTakeable } from "./run-OOWQIKMJ.mjs";
|
|
3
|
+
import { n as newRunId } from "./find-k489laBa.mjs";
|
|
4
|
+
import { l as writeErr } from "./output-B1kwo0YU.mjs";
|
|
5
|
+
import { t as loadWorkflow } from "./validate-BS0nCccW.mjs";
|
|
6
|
+
// src/follow-ups/brief.ts
|
|
7
|
+
/**
|
|
8
|
+
* @file `ork run --follow-ups <ids>`: the `agent` follow-ups become the run's
|
|
9
|
+
* `brief` input, and are marked taken by the run, which finishes them when it
|
|
10
|
+
* publishes (`ork follow-ups published`). Everything that could refuse them
|
|
11
|
+
* (an unknown id, one for someone else, a workflow with no `brief` input) is
|
|
12
|
+
* checked before any is marked, so a run that doesn't start leaves them be.
|
|
13
|
+
*/
|
|
14
|
+
const FLAG = "--follow-ups";
|
|
15
|
+
/** What `--follow-ups` takes besides ids: every due agent follow-up. */
|
|
16
|
+
const DUE = "due";
|
|
17
|
+
/**
|
|
18
|
+
* Each `--follow-ups` value as typed (one per use, still comma-joined), and
|
|
19
|
+
* whether one is missing: no value, an empty one, or a next argument that is
|
|
20
|
+
* another flag.
|
|
21
|
+
*/
|
|
22
|
+
const given = (rawArgs) => {
|
|
23
|
+
const values = [];
|
|
24
|
+
let empty = false;
|
|
25
|
+
for (const [index, arg] of rawArgs.entries()) {
|
|
26
|
+
if (arg !== FLAG && !arg.startsWith(`${FLAG}=`)) continue;
|
|
27
|
+
const next = rawArgs[index + 1];
|
|
28
|
+
const parts = (arg === FLAG ? next === void 0 || next.startsWith("--") ? "" : next : arg.slice(13)).split(",").map((part) => part.trim()).filter((part) => part !== "");
|
|
29
|
+
if (parts.length === 0) empty = true;
|
|
30
|
+
values.push(...parts);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
values,
|
|
34
|
+
empty
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Says what `--follow-ups` needs when it is given with nothing after it, and
|
|
39
|
+
* fails the command; true when it is fine (or not given).
|
|
40
|
+
*/
|
|
41
|
+
const followUpsFlagFine = (rawArgs) => {
|
|
42
|
+
if (!given(rawArgs).empty) return true;
|
|
43
|
+
writeErr(`${FLAG} needs follow-up ids, or \`${DUE}\` for every due agent follow-up. \`ork follow-ups list\` shows them.`);
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return false;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* What stops `--follow-ups` from starting a run, one line each; none when
|
|
49
|
+
* nothing does.
|
|
50
|
+
*/
|
|
51
|
+
const problemsOf = (loaded, inputs) => {
|
|
52
|
+
const name = loaded.workflow?.name ?? "";
|
|
53
|
+
if (loaded.workflow?.inputs?.["brief"] === void 0) return [`--follow-ups fills a workflow's \`brief\` input, and ${name} has none.`];
|
|
54
|
+
return inputs.some((input) => input.startsWith("brief=")) ? ["--follow-ups and --input brief=… both set the brief."] : [];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The inputs and run id `ork run` starts with: those it was given and, for
|
|
58
|
+
* `--follow-ups`, a `brief` made of the follow-ups with the id of the run that
|
|
59
|
+
* takes them. `undefined` after saying why it can't start.
|
|
60
|
+
*/
|
|
61
|
+
const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh) => {
|
|
62
|
+
const inputs = flagValues(rawArgs, "--input");
|
|
63
|
+
const plain = {
|
|
64
|
+
inputs,
|
|
65
|
+
...runId === void 0 ? {} : { runId }
|
|
66
|
+
};
|
|
67
|
+
if (!followUpsFlagFine(rawArgs)) return void 0;
|
|
68
|
+
const { values } = given(rawArgs);
|
|
69
|
+
if (values.length === 0) return plain;
|
|
70
|
+
const loaded = loadWorkflow(target.file, process.cwd(), void 0, store.projects());
|
|
71
|
+
if (loaded.workflow === null) return plain;
|
|
72
|
+
const project = loaded.place.root;
|
|
73
|
+
const named = values.filter((value) => value !== DUE);
|
|
74
|
+
if (values.includes(DUE)) await refreshDue(store, project, writeErr, gh);
|
|
75
|
+
const due = values.includes(DUE) ? store.followUps(project).filter((f) => f.for === "agent" && f.status === "due").map((f) => f.id) : [];
|
|
76
|
+
if (named.length === 0 && due.length === 0) {
|
|
77
|
+
writeErr(`${FLAG} ${DUE}: no agent follow-ups are due. \`ork follow-ups list\` shows them.`);
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const takeable = checkTakeable(store, project, [...named, ...due]);
|
|
82
|
+
const problems = [...problemsOf(loaded, inputs), ...takeable.ok ? [] : takeable.lines];
|
|
83
|
+
if (!takeable.ok || problems.length > 0) {
|
|
84
|
+
for (const line of problems) writeErr(line);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const followUps = [...new Map(takeable.followUps.map((f) => [f.id, f])).values()];
|
|
89
|
+
const taker = runId ?? newRunId(store);
|
|
90
|
+
takeFollowUps(store, {
|
|
91
|
+
project,
|
|
92
|
+
run: taker,
|
|
93
|
+
ids: followUps.map((f) => f.id)
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
inputs: [...inputs, `brief=${briefOf(followUps)}`],
|
|
97
|
+
runId: taker
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export { followUpsFlagFine, prepareFollowUps };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Gr as plainPathInside, Kr as writePlainFile, Pr as placeFiles, Wr as guardedBase } from "./src-DLsFsmOD.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/command-tree.ts
|
|
2
|
+
/** How a flag that only Ork passes to itself starts its description. */
|
|
3
|
+
const INTERNAL = "Internal:";
|
|
4
|
+
/** Whether citty was given a function that gives the value. */
|
|
5
|
+
const isThunk = (value) => typeof value === "function";
|
|
6
|
+
/** A value citty lets be given as is, as a promise, or as a function. */
|
|
7
|
+
const resolved = (value) => Promise.resolve(isThunk(value) ? value() : value);
|
|
8
|
+
/** `args` without the flags only Ork passes to itself. */
|
|
9
|
+
const publicArgs = (args) => Object.fromEntries(Object.entries(args).filter(([, def]) => !(def.description ?? "").startsWith(INTERNAL)));
|
|
10
|
+
/** A command's flags and positionals, which citty lets be given lazily. */
|
|
11
|
+
const argsOf = (cmd) => cmd.args === void 0 ? Promise.resolve({}) : resolved(cmd.args);
|
|
12
|
+
const listOf = (value) => value === void 0 ? [] : [value].flat();
|
|
13
|
+
const flagOf = (name, def) => ({
|
|
14
|
+
name,
|
|
15
|
+
description: def.description ?? "",
|
|
16
|
+
takesValue: def.type === "string" || def.type === "enum",
|
|
17
|
+
aliases: "alias" in def ? listOf(def.alias) : [],
|
|
18
|
+
options: def.type === "enum" ? def.options ?? [] : [],
|
|
19
|
+
negatable: def.type === "boolean" && def.default === true
|
|
20
|
+
});
|
|
21
|
+
/** A command's public flags and positionals, in the order it defines them. */
|
|
22
|
+
const argInfoOf = async (cmd) => {
|
|
23
|
+
const entries = Object.entries(publicArgs(await argsOf(cmd)));
|
|
24
|
+
return {
|
|
25
|
+
flags: entries.filter(([, def]) => def.type !== "positional").map(([name, def]) => flagOf(name, def)),
|
|
26
|
+
positionals: entries.filter(([, def]) => def.type === "positional").map(([name, def]) => ({
|
|
27
|
+
name,
|
|
28
|
+
description: def.description ?? ""
|
|
29
|
+
}))
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* A command's subcommands, in order, loaded ones resolved. A name whose
|
|
34
|
+
* definition is one listed before it (`wt`, `worktrees`'s) is an alias of that
|
|
35
|
+
* one, not an entry of its own.
|
|
36
|
+
*/
|
|
37
|
+
const subcommandsOf = async (cmd) => {
|
|
38
|
+
const subs = cmd.subCommands === void 0 ? {} : await resolved(cmd.subCommands);
|
|
39
|
+
const loaded = await Promise.all(Object.entries(subs).map(async ([name, sub]) => {
|
|
40
|
+
const def = await resolved(sub);
|
|
41
|
+
return {
|
|
42
|
+
name,
|
|
43
|
+
def,
|
|
44
|
+
meta: def.meta === void 0 ? {} : await resolved(def.meta)
|
|
45
|
+
};
|
|
46
|
+
}));
|
|
47
|
+
const entries = [];
|
|
48
|
+
for (const { name, def, meta } of loaded) {
|
|
49
|
+
const same = entries.find((entry) => entry.def === def);
|
|
50
|
+
if (same === void 0) entries.push({
|
|
51
|
+
name,
|
|
52
|
+
aliases: listOf(meta.alias),
|
|
53
|
+
description: meta.description ?? "",
|
|
54
|
+
hidden: meta.hidden === true,
|
|
55
|
+
def
|
|
56
|
+
});
|
|
57
|
+
else same.aliases.push(name);
|
|
58
|
+
}
|
|
59
|
+
return entries;
|
|
60
|
+
};
|
|
61
|
+
/** The subcommand `name` (or one of its aliases) of `entries`. */
|
|
62
|
+
const findEntry = (entries, name) => entries.find((entry) => entry.name === name || entry.aliases.includes(name));
|
|
63
|
+
export { publicArgs as a, findEntry as i, argInfoOf as n, resolved as o, argsOf as r, subcommandsOf as s, INTERNAL as t };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as isBuiltinArg, i as builtinWorkflowText, r as builtinWorkflowNames } from "./builtin-files-
|
|
3
|
-
import { t as findRun } from "./find-
|
|
4
|
-
import { a as
|
|
1
|
+
import { An as liveStatus, Fr as placeFor, L as openStore, Pr as placeFiles, R as storePath, Ti as AGENT_DRIVERS, mi as NodeIdSchema, rt as pendingDecisions } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { a as isBuiltinArg, i as builtinWorkflowText, r as builtinWorkflowNames } from "./builtin-files-yYaNTQRU.mjs";
|
|
3
|
+
import { t as findRun } from "./find-k489laBa.mjs";
|
|
4
|
+
import { a as SHELL_SCRIPTS, i as SHELLS, n as groupedEntries, r as COMPLETE_COMMAND, t as groupOf } from "./help-groups-hB6kY34d.mjs";
|
|
5
|
+
import { i as findEntry, n as argInfoOf, s as subcommandsOf } from "./command-tree-BkSYWmYJ.mjs";
|
|
5
6
|
import { l as writeErr } from "./output-B1kwo0YU.mjs";
|
|
6
|
-
import { a as resolveWorkflowArg, n as WORKFLOW_SUFFIX } from "./workflows-
|
|
7
|
+
import { a as resolveWorkflowArg, n as WORKFLOW_SUFFIX } from "./workflows-Djo1edlK.mjs";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import { parse } from "yaml";
|
|
9
10
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
@@ -118,6 +119,62 @@ const decisionCandidates = (store, arg, cwd, place) => {
|
|
|
118
119
|
description: `${decision.kind} of ${decision.runId}/${decision.node}`
|
|
119
120
|
}));
|
|
120
121
|
};
|
|
122
|
+
/** The registered projects, by id, with their root. */
|
|
123
|
+
const projectCandidates = (store) => store.projects().map((p) => ({
|
|
124
|
+
value: p.id,
|
|
125
|
+
description: p.root
|
|
126
|
+
}));
|
|
127
|
+
/**
|
|
128
|
+
* Whom a follow-up is for (`--for`): `agent`, `me`, a registered project as
|
|
129
|
+
* `project:<id>`; a person has no list, so `person:` is left to be typed.
|
|
130
|
+
*/
|
|
131
|
+
const forCandidates = (store) => [
|
|
132
|
+
{
|
|
133
|
+
value: "agent",
|
|
134
|
+
description: "an agent picks it up"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
value: "me",
|
|
138
|
+
description: "you do"
|
|
139
|
+
},
|
|
140
|
+
...(store?.projects() ?? []).map((p) => ({
|
|
141
|
+
value: `project:${p.id}`,
|
|
142
|
+
description: p.root
|
|
143
|
+
}))
|
|
144
|
+
];
|
|
145
|
+
/** The longest title a menu shows. */
|
|
146
|
+
const TITLE_LIMIT = 60;
|
|
147
|
+
/** A title as one short line: first line only, cut with an ellipsis. */
|
|
148
|
+
const shortTitle = (title) => {
|
|
149
|
+
const line = (title.split("\n")[0] ?? "").trim();
|
|
150
|
+
return line.length > TITLE_LIMIT ? `${line.slice(0, 59)}…` : line;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* What `ork run --follow-ups` takes: `due` (every due agent follow-up), then
|
|
154
|
+
* the project's open agent follow-ups, due before waiting, each described by
|
|
155
|
+
* its title. Closed and other people's follow-ups are left out; an unreadable
|
|
156
|
+
* store gives `due` only.
|
|
157
|
+
*/
|
|
158
|
+
const followUpCandidates = (store, place) => {
|
|
159
|
+
const open = (status) => {
|
|
160
|
+
try {
|
|
161
|
+
return (store?.followUps(place.root) ?? []).filter((f) => f.for === "agent" && f.status === status).map((f) => ({
|
|
162
|
+
value: f.id,
|
|
163
|
+
description: shortTitle(f.title)
|
|
164
|
+
}));
|
|
165
|
+
} catch {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
value: "due",
|
|
172
|
+
description: "every due agent follow-up"
|
|
173
|
+
},
|
|
174
|
+
...open("due"),
|
|
175
|
+
...open("waiting")
|
|
176
|
+
];
|
|
177
|
+
};
|
|
121
178
|
// src/completion/values.ts
|
|
122
179
|
const withStore = (context, read) => {
|
|
123
180
|
const store = context.store();
|
|
@@ -154,7 +211,27 @@ const inputs = {
|
|
|
154
211
|
};
|
|
155
212
|
const decisions = {
|
|
156
213
|
group: "decisions",
|
|
157
|
-
values: (context) => withStore(context, (store) => decisionCandidates(store, context.given["run"], context.cwd, placeOf(context.cwd, store)))
|
|
214
|
+
values: (context) => withStore(context, (store) => decisionCandidates(store, context.given["run"] ?? context.given["run-id"], context.cwd, placeOf(context.cwd, store)))
|
|
215
|
+
};
|
|
216
|
+
/** A registered project's id, for `--project`; `all` too (RFC-017). */
|
|
217
|
+
const projects = {
|
|
218
|
+
group: "projects",
|
|
219
|
+
values: (context) => [{
|
|
220
|
+
value: "all",
|
|
221
|
+
description: "every project"
|
|
222
|
+
}, ...withStore(context, projectCandidates)]
|
|
223
|
+
};
|
|
224
|
+
const forWhom = {
|
|
225
|
+
group: "for",
|
|
226
|
+
values: (context) => forCandidates(context.store())
|
|
227
|
+
};
|
|
228
|
+
/** `ork run --follow-ups`: `due`, then the project's open agent follow-ups. */
|
|
229
|
+
const followUps = {
|
|
230
|
+
group: "follow-ups",
|
|
231
|
+
values: (context) => {
|
|
232
|
+
const store = context.store();
|
|
233
|
+
return followUpCandidates(store, placeOf(context.cwd, store));
|
|
234
|
+
}
|
|
158
235
|
};
|
|
159
236
|
const drivers = {
|
|
160
237
|
group: "drivers",
|
|
@@ -178,6 +255,7 @@ const shells = {
|
|
|
178
255
|
/** Providers by argument name, or by command path and name. */
|
|
179
256
|
const VALUE_PROVIDERS = {
|
|
180
257
|
run: runs,
|
|
258
|
+
"decide run-id": runs,
|
|
181
259
|
workflow: workflows,
|
|
182
260
|
files: {
|
|
183
261
|
...workflows,
|
|
@@ -186,8 +264,11 @@ const VALUE_PROVIDERS = {
|
|
|
186
264
|
node: nodes,
|
|
187
265
|
input: inputs,
|
|
188
266
|
"decide id": decisions,
|
|
267
|
+
"run follow-ups": followUps,
|
|
189
268
|
"completion shell": shells,
|
|
190
269
|
driver: drivers,
|
|
270
|
+
project: projects,
|
|
271
|
+
for: forWhom,
|
|
191
272
|
path: files,
|
|
192
273
|
file: files,
|
|
193
274
|
output: files
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Hr as LESSON_CAP_TOKENS, gt as explainSession } from "./src-DLsFsmOD.mjs";
|
|
2
2
|
import { c as write, s as style } from "./output-B1kwo0YU.mjs";
|
|
3
|
-
import { i as refusedBuiltin, o as workflowArg } from "./workflows-
|
|
4
|
-
import { a as formatReport, t as loadWorkflow } from "./validate-
|
|
3
|
+
import { i as refusedBuiltin, o as workflowArg } from "./workflows-Djo1edlK.mjs";
|
|
4
|
+
import { a as formatReport, t as loadWorkflow } from "./validate-BS0nCccW.mjs";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
// src/commands/context.ts
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fr as placeFor } from "./src-DLsFsmOD.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
// ../core/src/remote/find.ts
|
|
4
4
|
/**
|
|
@@ -16,7 +16,7 @@ const findRun = (store, arg, cwd) => {
|
|
|
16
16
|
});
|
|
17
17
|
return latest === void 0 ? {
|
|
18
18
|
ok: false,
|
|
19
|
-
error: "No runs in this project yet; see `ork ps --all`."
|
|
19
|
+
error: "No runs in this project yet; see `ork ps --project all`."
|
|
20
20
|
} : {
|
|
21
21
|
ok: true,
|
|
22
22
|
run: latest
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { n as parseLimit, t as parseFilters } from "./parse-BzWpMN-a.mjs";
|
|
3
|
+
import { t as INTERNAL } from "./command-tree-BkSYWmYJ.mjs";
|
|
4
|
+
import { l as writeErr } from "./output-B1kwo0YU.mjs";
|
|
5
|
+
// src/list/all-alias.ts
|
|
6
|
+
/**
|
|
7
|
+
* @file The deprecated `--all` of `ps`, `usage`, `decide`, `follow-ups list`
|
|
8
|
+
* and `feedback list` (RFC-017): it stands for `--project all` or `--status
|
|
9
|
+
* all`, is left out of `--help` and Tab completion (an `Internal:` flag), and
|
|
10
|
+
* warns once on stderr. `prune --all` is not this one.
|
|
11
|
+
*/
|
|
12
|
+
/** The hidden `--all` flag, for a command's `args`. */
|
|
13
|
+
const allAlias = { all: {
|
|
14
|
+
type: "boolean",
|
|
15
|
+
description: `${INTERNAL} deprecated, use --project all or --status all`,
|
|
16
|
+
default: false
|
|
17
|
+
} };
|
|
18
|
+
/**
|
|
19
|
+
* `args` with `all` in `--all`'s place when `--all` was given and that flag was
|
|
20
|
+
* not (a given one wins); the warning prints either way. `args` as is when
|
|
21
|
+
* `--all` was not given.
|
|
22
|
+
*/
|
|
23
|
+
const warnAll = (args, flag) => {
|
|
24
|
+
if (args["all"] !== true) return args;
|
|
25
|
+
writeErr(`--all is deprecated; use --${flag} all.`);
|
|
26
|
+
return args[flag] === void 0 ? {
|
|
27
|
+
...args,
|
|
28
|
+
[flag]: "all"
|
|
29
|
+
} : args;
|
|
30
|
+
};
|
|
31
|
+
// src/list/flags.ts
|
|
32
|
+
/**
|
|
33
|
+
* @file The flags every list command shares (RFC-017), made from its field
|
|
34
|
+
* table: one flag per field (an enum field's values as citty `options`, so
|
|
35
|
+
* `--help` and Tab completion read them), `--ids`, `--limit` and `--json`;
|
|
36
|
+
* and reading them back: each value checked by core's `parseFilters`,
|
|
37
|
+
* `--limit` a positive whole number, `--project` a registered one. A refusal
|
|
38
|
+
* says why on stderr and sets the exit code; the command then returns.
|
|
39
|
+
*/
|
|
40
|
+
const fieldArg = (field) => {
|
|
41
|
+
if (field.type !== "enum") return {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: field.description
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
type: "enum",
|
|
47
|
+
options: [...field.values ?? [], ...field.all === true ? ["all"] : []],
|
|
48
|
+
description: field.description
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/** The citty flags of `table`, then `--ids`, `--limit`, `--json`, `extra`. */
|
|
52
|
+
const filterArgs = (table, options = {}) => ({
|
|
53
|
+
...Object.fromEntries(table.fields.map((field) => [field.name, fieldArg(field)])),
|
|
54
|
+
...options.ids ?? table.id !== void 0 ? { ids: {
|
|
55
|
+
type: "boolean",
|
|
56
|
+
description: "Print only the ids, comma-separated, on one line",
|
|
57
|
+
default: false
|
|
58
|
+
} } : {},
|
|
59
|
+
...options.limit ?? true ? { limit: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "Show at most this many (a positive whole number)"
|
|
62
|
+
} } : {},
|
|
63
|
+
...options.json ?? true ? { json: {
|
|
64
|
+
type: "boolean",
|
|
65
|
+
description: "Print JSON",
|
|
66
|
+
default: false
|
|
67
|
+
} } : {},
|
|
68
|
+
...options.extra
|
|
69
|
+
});
|
|
70
|
+
/** Says why, and makes the command exit 1. */
|
|
71
|
+
const fail = (message) => {
|
|
72
|
+
writeErr(message);
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
};
|
|
75
|
+
/** The `--ids` with `--json` refusal; `true` when `args` has both. */
|
|
76
|
+
const refuseIdsWithJson = (args) => {
|
|
77
|
+
if (args.ids !== true || args.json !== true) return false;
|
|
78
|
+
fail("--ids and --json can't be used together.");
|
|
79
|
+
return true;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* `args` (a command's parsed flags) read against `table`: the filter, and the
|
|
83
|
+
* limit. `all` names the flag `--all` stands for (`project` or `status`):
|
|
84
|
+
* `--all` fills it when it is not given, with one warning. `undefined` when
|
|
85
|
+
* something was refused (already said, exit code set).
|
|
86
|
+
*/
|
|
87
|
+
const readListArgs = (table, args, options = {}) => {
|
|
88
|
+
if (refuseIdsWithJson(args)) return void 0;
|
|
89
|
+
const given = options.all === void 0 ? args : warnAll(args, options.all);
|
|
90
|
+
const parsed = parseFilters(table, given, options.now ?? Date.now());
|
|
91
|
+
if (!parsed.ok) {
|
|
92
|
+
fail(parsed.error);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const text = args["limit"];
|
|
96
|
+
if (typeof text !== "string") return {
|
|
97
|
+
filter: parsed.filter,
|
|
98
|
+
limit: void 0
|
|
99
|
+
};
|
|
100
|
+
const limit = parseLimit(text);
|
|
101
|
+
if (limit === null) {
|
|
102
|
+
fail(`--limit takes a positive whole number, not \`${text}\`.`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
filter: parsed.filter,
|
|
107
|
+
limit
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The scope the filter's `project` names, checked against the registered
|
|
112
|
+
* projects (core does not know them): an id or a root, or `all`; none given is
|
|
113
|
+
* `here`. A project not registered is refused, listing the registered ones
|
|
114
|
+
* (said, exit code set, `undefined`).
|
|
115
|
+
*/
|
|
116
|
+
const projectScope = (filter, projects) => {
|
|
117
|
+
const key = filter["project"];
|
|
118
|
+
if (key === void 0) return "here";
|
|
119
|
+
if (key === "all") return "all";
|
|
120
|
+
const found = projects.find((p) => p.id === key || p.root === key);
|
|
121
|
+
if (found !== void 0) return { root: found.root };
|
|
122
|
+
const names = projects.map((p) => p.id);
|
|
123
|
+
fail(`No registered project \`${key}\`; registered: ${names.length === 0 ? "none" : names.join(", ")}.`);
|
|
124
|
+
};
|
|
125
|
+
export { refuseIdsWithJson as a, readListArgs as i, filterArgs as n, allAlias as o, projectScope as r, fail as t };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as followUpsRule, f as refreshDue, n as flagValues } from "./run
|
|
3
|
-
import { g as changeFollowUp, v as findFollowUp, y as followUpActions } from "./__build_info__-
|
|
4
|
-
import { t as postFollowUpMessage } from "./post-
|
|
5
|
-
import { t as
|
|
1
|
+
import { Fr as placeFor, Ht as followUpListTable, hn as recordPublished, mn as markDue, nr as runGh, vn as deliverFollowUp, yn as followUpProblem } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { d as followUpsRule, f as refreshDue, n as flagValues } from "./run-OOWQIKMJ.mjs";
|
|
3
|
+
import { g as changeFollowUp, v as findFollowUp, x as isGithubIssueUrl, 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 findRun } from "./find-k489laBa.mjs";
|
|
6
7
|
import { a as plain, c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
|
|
7
|
-
import {
|
|
8
|
+
import { i as readListArgs, n as filterArgs, o as allAlias } from "./flags-B4ZZWspN.mjs";
|
|
9
|
+
import { t as printList } from "./print-n2qetUHc.mjs";
|
|
10
|
+
import { t as withStore } from "./store-DACH768X.mjs";
|
|
8
11
|
import { homedir } from "node:os";
|
|
9
12
|
import { defineCommand } from "citty";
|
|
10
13
|
// src/follow-ups/command.ts
|
|
@@ -53,6 +56,20 @@ const inProject = (key, body) => withStore(async (store) => {
|
|
|
53
56
|
});
|
|
54
57
|
await body(store, place);
|
|
55
58
|
});
|
|
59
|
+
/**
|
|
60
|
+
* Like `inProject`, for a list: `key` may be `all`, which gives every
|
|
61
|
+
* registered project's place. The due check runs for each.
|
|
62
|
+
*/
|
|
63
|
+
const inProjects = (key, body) => withStore(async (store) => {
|
|
64
|
+
const projects = store.projects();
|
|
65
|
+
const places = key === "all" ? projects.map((p) => placeFor(p.root, projects)) : [placeOf(store, key)];
|
|
66
|
+
if (places.includes(void 0)) return;
|
|
67
|
+
const found = places.filter((place) => place !== void 0);
|
|
68
|
+
await Promise.all(found.map((place) => refreshDue(store, place.root, (line) => {
|
|
69
|
+
writeErr(style("dim", line));
|
|
70
|
+
})));
|
|
71
|
+
await body(store, found);
|
|
72
|
+
});
|
|
56
73
|
/** Runs `body` on the follow-up `id` names, or says why there is none. */
|
|
57
74
|
const withFollowUp = (args, body) => inProject(args.project, async (store, place) => {
|
|
58
75
|
const found = findFollowUp(store, place.root, args.id);
|
|
@@ -90,6 +107,7 @@ const FOR_ORDER = [
|
|
|
90
107
|
"person:"
|
|
91
108
|
];
|
|
92
109
|
const forOrder = (value) => FOR_ORDER.findIndex((prefix) => value.startsWith(prefix));
|
|
110
|
+
/** The list's order within a status: by who it is for. */
|
|
93
111
|
const byFor = (a, b) => forOrder(a.for) - forOrder(b.for) || a.for.localeCompare(b.for);
|
|
94
112
|
/** A multi-line text, each line safe to print. */
|
|
95
113
|
const linesOf = (text) => text.split("\n").map((line) => plain(line));
|
|
@@ -213,7 +231,7 @@ const post = defineCommand({
|
|
|
213
231
|
if (!args.confirm && draft !== void 0) {
|
|
214
232
|
write(`Would post to ${plain(draft.to)} through your gh:`);
|
|
215
233
|
for (const line of draft.text.split("\n")) write(` ${plain(line)}`);
|
|
216
|
-
|
|
234
|
+
writeErr("Run again with --confirm to post it.");
|
|
217
235
|
return;
|
|
218
236
|
}
|
|
219
237
|
const posted = await postFollowUpMessage(followUp, {
|
|
@@ -325,7 +343,7 @@ const add = defineCommand({
|
|
|
325
343
|
},
|
|
326
344
|
to: {
|
|
327
345
|
type: "string",
|
|
328
|
-
description: "A message: who it is to"
|
|
346
|
+
description: "A message: who it is to (default: the person); for --channel github, the issue or PR URL"
|
|
329
347
|
},
|
|
330
348
|
channel: {
|
|
331
349
|
type: "string",
|
|
@@ -354,6 +372,14 @@ const add = defineCommand({
|
|
|
354
372
|
fail(isFor(recipient) ? "--due is now, after-merge, after-deploy or a YYYY-MM-DD date." : "--for is agent, me, project:<name> or person:<name>.");
|
|
355
373
|
return;
|
|
356
374
|
}
|
|
375
|
+
if (kind === "message" && args.text === void 0) {
|
|
376
|
+
fail("a message needs --text.");
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (args.channel === "github" && !isGithubIssueUrl(args.to ?? "")) {
|
|
380
|
+
fail("--channel github needs --to <the issue or pull request URL>, https://github.com/<owner>/<repo>/(issues|pull)/<n>.");
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
357
383
|
const steps = flagValues(rawArgs, "--step").map((raw) => stepOf(raw));
|
|
358
384
|
const input = {
|
|
359
385
|
title: args.title,
|
|
@@ -404,6 +430,15 @@ const add = defineCommand({
|
|
|
404
430
|
* `follow-ups-act.ts`). Every call first moves what has come due, reading
|
|
405
431
|
* pull requests through the person's own `gh`; a `gh` that fails only warns.
|
|
406
432
|
*/
|
|
433
|
+
/** What a list with no `--status` shows. */
|
|
434
|
+
const OPEN = /* @__PURE__ */ new Set(["due", "waiting"]);
|
|
435
|
+
/** The list's own order: due first, then waiting, done, dropped; then `byFor`. */
|
|
436
|
+
const RANK = {
|
|
437
|
+
due: 0,
|
|
438
|
+
waiting: 1,
|
|
439
|
+
done: 2,
|
|
440
|
+
dropped: 3
|
|
441
|
+
};
|
|
407
442
|
const followUps = defineCommand({
|
|
408
443
|
meta: {
|
|
409
444
|
name: "follow-ups",
|
|
@@ -416,23 +451,23 @@ const followUps = defineCommand({
|
|
|
416
451
|
description: "List the follow-ups, due first, then by who they are for"
|
|
417
452
|
},
|
|
418
453
|
args: {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
description: "Done and dropped ones too",
|
|
422
|
-
default: false
|
|
423
|
-
},
|
|
424
|
-
for: {
|
|
425
|
-
type: "string",
|
|
426
|
-
description: "Only those for agent, me, project:<name> or person:<name>"
|
|
427
|
-
},
|
|
428
|
-
project,
|
|
429
|
-
json
|
|
454
|
+
...filterArgs(followUpListTable),
|
|
455
|
+
...allAlias
|
|
430
456
|
},
|
|
431
|
-
run: ({ args }) =>
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
457
|
+
run: async ({ args }) => {
|
|
458
|
+
const given = args;
|
|
459
|
+
const asked = readListArgs(followUpListTable, given, { all: "status" });
|
|
460
|
+
if (asked === void 0) return;
|
|
461
|
+
const { filter, limit } = asked;
|
|
462
|
+
const status = filter["status"];
|
|
463
|
+
await inProjects(filter["project"], (store, places) => {
|
|
464
|
+
const stored = places.flatMap((place) => store.followUps(place.root));
|
|
465
|
+
const shown = applyFilters(followUpListTable, stored, filter).filter((f) => status !== void 0 || OPEN.has(f.status)).toSorted((a, b) => RANK[a.status] - RANK[b.status] || byFor(a, b)).slice(0, limit);
|
|
466
|
+
printList(shown, followUpListTable, given, (rows) => {
|
|
467
|
+
for (const line of formatFollowUps(rows, status !== void 0)) write(line);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
}
|
|
436
471
|
}),
|
|
437
472
|
show: defineCommand({
|
|
438
473
|
meta: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { An as liveStatus, Nn as runStatus, Pn as slotWaitsOf, Rn as isItem, jn as lockWaitsOf, kt as lockWaitLine } from "./src-DLsFsmOD.mjs";
|
|
2
2
|
import { C as termOf, E as widthOf, n as cost, o as shortCount, r as costOf, s as style, w as cut } from "./output-B1kwo0YU.mjs";
|
|
3
3
|
import { i as statusChip, n as chip } from "./chips-BqcT58qr.mjs";
|
|
4
4
|
import { n as nodeVerdict } from "./verdict-CMvPCpWC.mjs";
|
|
@@ -180,6 +180,18 @@ const stateText = (node) => {
|
|
|
180
180
|
}
|
|
181
181
|
return node.state;
|
|
182
182
|
};
|
|
183
|
+
/** A node's counted tokens: input, output and cache write. */
|
|
184
|
+
const countedOf = (node) => node.inputTokens + node.outputTokens + (node.cacheWriteTokens ?? 0);
|
|
185
|
+
/**
|
|
186
|
+
* What a node spent: its counted tokens, then dollars unless its driver reports
|
|
187
|
+
* none, where `$0.00` would be false. Blank with no tokens.
|
|
188
|
+
*/
|
|
189
|
+
const worth = (node) => {
|
|
190
|
+
const counted = countedOf(node);
|
|
191
|
+
if (counted === 0) return "";
|
|
192
|
+
const tok = `${count(counted)} tok`;
|
|
193
|
+
return style("dim", ` ${node.unpriced === true ? tok : `${tok} · ${cost(node.costUsd)}`}`);
|
|
194
|
+
};
|
|
183
195
|
/**
|
|
184
196
|
* The ownership tree, one line per node, children under their owner. A node in
|
|
185
197
|
* `waits` (a live run's `lockWaitsOf`) reads `waiting for <lock>`, an item
|
|
@@ -188,8 +200,9 @@ const stateText = (node) => {
|
|
|
188
200
|
const formatTree = (roots, now = Date.now(), waits = []) => {
|
|
189
201
|
const lines = [];
|
|
190
202
|
const walk = (node, lead, branch) => {
|
|
203
|
+
const named = node.description === void 0 ? "" : ` ${node.description}`;
|
|
191
204
|
lines.push({
|
|
192
|
-
label: `${lead}${branch}${node.id}`,
|
|
205
|
+
label: `${lead}${branch}${node.id}${named}`,
|
|
193
206
|
node
|
|
194
207
|
});
|
|
195
208
|
const next = lead + (branch === "├─ " ? "│ " : branch === "" ? "" : " ");
|
|
@@ -201,11 +214,11 @@ const formatTree = (roots, now = Date.now(), waits = []) => {
|
|
|
201
214
|
const label = Math.max(...lines.map((l) => l.label.length));
|
|
202
215
|
const type = Math.max(...lines.map((l) => l.node.type.length));
|
|
203
216
|
return lines.map(({ label: text, node }) => {
|
|
204
|
-
const usage =
|
|
217
|
+
const usage = worth(node);
|
|
205
218
|
const lock = waits.find((wait) => wait.id === node.id)?.lock;
|
|
206
219
|
const state = node.held === true ? `${style("yellow", "‖")} paused` : lock === void 0 ? `${STATE_MARK[node.state]()} ${stateText(node)}` : `${STATE_MARK.waiting()} waiting for ${lock}`;
|
|
207
220
|
const spent = isItem(node) && node.startedAt !== void 0 ? style("dim", ` ${duration((node.finishedAt === void 0 ? now : Date.parse(node.finishedAt)) - Date.parse(node.startedAt))}`) : "";
|
|
208
|
-
return `${text.
|
|
221
|
+
return `${node.description === void 0 ? text : `${text.slice(0, text.length - node.description.length)}${dim(node.description)}`}${" ".repeat(label - text.length)} ${style("dim", node.type.padEnd(type))} ${state}${spent}${usage}`;
|
|
209
222
|
});
|
|
210
223
|
};
|
|
211
224
|
/**
|