@krapht/ork 1.0.0-alpha.19 → 1.0.0-alpha.20

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.
Files changed (45) hide show
  1. package/dist/{__build_info__-dPf4cEGL.mjs → __build_info__-D6mXC4cD.mjs} +2 -2
  2. package/dist/argument-error-CihH46Le.mjs +27 -0
  3. package/dist/{attach-BQl8nQz2.mjs → attach-C1OnxyMh.mjs} +7 -5
  4. package/dist/{attach-DhZQ87Nz.mjs → attach-CEGbRg1D.mjs} +126 -69
  5. package/dist/bin.mjs +556 -119
  6. package/dist/{brief-BQbeoPMc.mjs → brief-DH66xmj8.mjs} +11 -6
  7. package/dist/{builtin-files-CWL3JEo-.mjs → builtin-files-Cf-NZDqM.mjs} +1 -1
  8. package/dist/{command-tree-B6uvMJq1.mjs → command-tree-CEkzWNy6.mjs} +1 -1
  9. package/dist/{completion-DKPuD_Rw.mjs → completion-DS0gCZRm.mjs} +19 -12
  10. package/dist/{context-Bw6R_EYq.mjs → context-CGPh12HV.mjs} +3 -3
  11. package/dist/{detached-BQlbmqR0.mjs → detached-Dakw5RZj.mjs} +3 -3
  12. package/dist/extra-arguments-BxQMXARO.mjs +13 -0
  13. package/dist/{find-B30-rd-u.mjs → find-BTikxc54.mjs} +1 -1
  14. package/dist/{flags-ByYBx-Xb.mjs → flags-C8yCq0j5.mjs} +7 -32
  15. package/dist/{follow-ups-Cxca1Jgg.mjs → follow-ups-CtlhHbwe.mjs} +87 -26
  16. package/dist/{format-C-nEZv-P.mjs → format-BB4E-T6x.mjs} +1 -1
  17. package/dist/{in-a-run-CZFzoT3R.mjs → in-a-run-CbnKjO7t.mjs} +2 -2
  18. package/dist/{install-CsqK1avz.mjs → install-CWcpX5g4.mjs} +1 -1
  19. package/dist/{limits-CXh052II.mjs → limits-VQqsBoQk.mjs} +1 -1
  20. package/dist/{mcp-B4wME9C4.mjs → mcp-wGfkMCVF.mjs} +6 -6
  21. package/dist/{once-BKn3pOtg.mjs → once-BHxSdZz_.mjs} +43 -7
  22. package/dist/{pause-B1grR1cl.mjs → pause-C_Wxh-KM.mjs} +6 -3
  23. package/dist/{print-Bd8MWVJk.mjs → print-DNYzq4Rr.mjs} +1 -1
  24. package/dist/{project-records-BOEVs69i.mjs → project-records-XY3ku95x.mjs} +4 -1
  25. package/dist/{relay-CeNiq3GT.mjs → relay-BA6tsnpc.mjs} +1 -1
  26. package/dist/{run-D6yU2rLf.mjs → run-Bvvg-fiF.mjs} +61 -19
  27. package/dist/{run-C0C54UiU.mjs → run-DBUAq-Uu.mjs} +29 -20
  28. package/dist/{send-DqgF58hb.mjs → send-nrKtak5F.mjs} +2 -2
  29. package/dist/{src-Ciy7i3se.mjs → src-8cOPOgrT.mjs} +155 -32
  30. package/dist/{src-n-u4TGev.mjs → src-CmEvHdju.mjs} +28 -28
  31. package/dist/{src-D2qpd-G7.mjs → src-D4JSymhK.mjs} +11 -2
  32. package/dist/{src-DP02RP9O.mjs → src-I_RyKu6_.mjs} +2 -2
  33. package/dist/{store-2KXzMCEN.mjs → store-CDpk8Wtz.mjs} +1 -1
  34. package/dist/ui/assets/app--FijEXiJ.css +1 -0
  35. package/dist/ui/assets/{app-ICEKpy_C.js → app-BowhjEAe.js} +12 -12
  36. package/dist/ui/assets/{index-BGaix5wh.js → index-CrMa2oHB.js} +2 -2
  37. package/dist/ui/index.html +1 -1
  38. package/dist/{ui-CAvygxTb.mjs → ui-DY3Dnpho.mjs} +4 -4
  39. package/dist/{usage-BFBco5OS.mjs → usage-1VwSg_Qt.mjs} +4 -4
  40. package/dist/{validate-UrmC5AG1.mjs → validate-BxayjjkV.mjs} +3 -3
  41. package/dist/{watch-DTxkgB8R.mjs → watch-CT0EtLPZ.mjs} +5 -5
  42. package/dist/{workflows-8GV-SeRm.mjs → workflows-DHHi-APg.mjs} +2 -2
  43. package/dist/{worktrees-CUdUvZlO.mjs → worktrees-CZvbHzbN.mjs} +4 -4
  44. package/package.json +1 -1
  45. package/dist/ui/assets/app-C5vO1M-l.css +0 -1
@@ -1,8 +1,8 @@
1
- import { pr as runGh } from "./src-Ciy7i3se.mjs";
2
- import { f as refreshDue, l as briefOf, n as flagValues, p as runIsLive, u as checkTakeable, v as availableDue, y as takeFollowUps } from "./run-C0C54UiU.mjs";
3
- import { n as newRunId } from "./find-B30-rd-u.mjs";
1
+ import { mr as runGh } from "./src-8cOPOgrT.mjs";
2
+ import { b as takeFollowUps, f as refreshDue, l as briefOf, n as flagValues, p as runIsLive, u as checkTakeable, v as availableDue, y as heldNote } from "./run-DBUAq-Uu.mjs";
3
+ import { n as newRunId } from "./find-BTikxc54.mjs";
4
4
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
5
- import { t as loadWorkflow } from "./validate-UrmC5AG1.mjs";
5
+ import { t as loadWorkflow } from "./validate-BxayjjkV.mjs";
6
6
  // src/follow-ups/brief.ts
7
7
  /**
8
8
  * @file `ork run --follow-ups <ids>`: the `agent` follow-ups become the run's
@@ -75,11 +75,16 @@ const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh, mark
75
75
  const named = values.filter((value) => value !== DUE);
76
76
  if (values.includes(DUE)) await refreshDue(store, project, writeErr, gh);
77
77
  const isLive = runIsLive(store);
78
- const { ids: due, held } = values.includes(DUE) ? availableDue(store, project, isLive, runId) : {
78
+ const stamp = (/* @__PURE__ */ new Date()).toISOString();
79
+ const { ids: due, held } = values.includes(DUE) ? availableDue(store, project, isLive, runId, () => stamp) : {
79
80
  ids: [],
80
81
  held: []
81
82
  };
82
- for (const f of held) writeErr(`${FLAG} ${DUE}: skipped ${f.id}, taken by run ${f.takenBy}, still running.`);
83
+ const at = Date.parse(stamp);
84
+ for (const f of held) {
85
+ const note = heldNote(f, isLive, at) ?? "still running";
86
+ writeErr(`${FLAG} ${DUE}: skipped ${f.id}, taken by run ${f.takenBy}, ${note}.`);
87
+ }
83
88
  if (named.length === 0 && due.length === 0) {
84
89
  const reason = held.length > 0 ? ` ${held.length} due ${held.length === 1 ? "one is" : "ones are"} taken by a run still running.` : "";
85
90
  writeErr(`${FLAG} ${DUE}: no agent follow-ups are due.${reason} \`ork follow-ups list\` shows them.`);
@@ -1,4 +1,4 @@
1
- import { $r as guardedBase, Ur as placeFiles, ei as plainPathInside, ti as writePlainFile } from "./src-Ciy7i3se.mjs";
1
+ import { Wr as placeFiles, ei as guardedBase, ni as writePlainFile, ti as plainPathInside } from "./src-8cOPOgrT.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { createHash } from "node:crypto";
@@ -16,7 +16,7 @@ const flagOf = (name, def) => ({
16
16
  takesValue: def.type === "string" || def.type === "enum",
17
17
  aliases: "alias" in def ? listOf(def.alias) : [],
18
18
  options: def.type === "enum" ? def.options ?? [] : [],
19
- negatable: def.type === "boolean" && def.default === true
19
+ negatable: def.type === "boolean" && (def.default === true || def.negativeDescription !== void 0)
20
20
  });
21
21
  /** A command's public flags and positionals, in the order it defines them. */
22
22
  const argInfoOf = async (cmd) => {
@@ -1,10 +1,10 @@
1
- import { Ci as NodeIdSchema, Nn as liveStatus, Pi as AGENT_DRIVERS, R as openStore, Ur as placeFiles, Wr as placeFor, ot as pendingDecisions, z as storePath } from "./src-Ciy7i3se.mjs";
2
- import { a as isBuiltinArg, i as builtinWorkflowText, r as builtinWorkflowNames } from "./builtin-files-CWL3JEo-.mjs";
3
- import { t as findRun } from "./find-B30-rd-u.mjs";
1
+ import { Fi as AGENT_DRIVERS, Gr as placeFor, Pn as liveStatus, R as openStore, Wr as placeFiles, st as pendingDecisions, wi as NodeIdSchema, z as storePath } from "./src-8cOPOgrT.mjs";
2
+ import { a as isBuiltinArg, i as builtinWorkflowText, r as builtinWorkflowNames } from "./builtin-files-Cf-NZDqM.mjs";
3
+ import { t as findRun } from "./find-BTikxc54.mjs";
4
4
  import { a as SHELL_SCRIPTS, i as SHELLS, n as groupedEntries, r as COMPLETE_COMMAND, t as groupOf } from "./help-groups-BpRgBSTh.mjs";
5
- import { o as subcommandsOf, r as findEntry, t as argInfoOf } from "./command-tree-B6uvMJq1.mjs";
5
+ import { o as subcommandsOf, r as findEntry, t as argInfoOf } from "./command-tree-CEkzWNy6.mjs";
6
6
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
7
- import { n as WORKFLOW_SUFFIX, o as resolveWorkflowArg } from "./workflows-8GV-SeRm.mjs";
7
+ import { n as WORKFLOW_SUFFIX, o as resolveWorkflowArg } from "./workflows-DHHi-APg.mjs";
8
8
  import path from "node:path";
9
9
  import { parse } from "yaml";
10
10
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
@@ -309,13 +309,20 @@ const subcommandSections = (position) => {
309
309
  const flagSection = (position) => ({
310
310
  title: "flags",
311
311
  candidates: [
312
- ...position.flags.flatMap((flag) => [{
313
- value: `--${flag.name}`,
314
- description: brief(flag.description)
315
- }, ...flag.negatable ? [{
316
- value: `--no-${flag.name}`,
317
- description: `Turn off --${flag.name}`
318
- }] : []]),
312
+ ...position.flags.flatMap((flag) => [
313
+ {
314
+ value: `--${flag.name}`,
315
+ description: brief(flag.description)
316
+ },
317
+ ...flag.aliases.filter((alias) => alias.length > 1).map((alias) => ({
318
+ value: `--${alias}`,
319
+ description: `Same as --${flag.name}`
320
+ })),
321
+ ...flag.negatable ? [{
322
+ value: `--no-${flag.name}`,
323
+ description: `Turn off --${flag.name}`
324
+ }] : []
325
+ ]),
319
326
  {
320
327
  value: "--plain",
321
328
  description: "Plain output, no color or redraw"
@@ -1,7 +1,7 @@
1
- import { Zr as LESSON_CAP_TOKENS, yt as explainSession } from "./src-Ciy7i3se.mjs";
1
+ import { Qr as LESSON_CAP_TOKENS, bt as explainSession } from "./src-8cOPOgrT.mjs";
2
2
  import { c as write, s as style } from "./output-B1kwo0YU.mjs";
3
- import { a as refusedBuiltin, s as workflowArg } from "./workflows-8GV-SeRm.mjs";
4
- import { a as formatReport, t as loadWorkflow } from "./validate-UrmC5AG1.mjs";
3
+ import { a as refusedBuiltin, s as workflowArg } from "./workflows-DHHi-APg.mjs";
4
+ import { a as formatReport, t as loadWorkflow } from "./validate-BxayjjkV.mjs";
5
5
  import { defineCommand } from "citty";
6
6
  // src/commands/context.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
- import { ft as detachRun } from "./src-Ciy7i3se.mjs";
2
- import { n as newRunId } from "./find-B30-rd-u.mjs";
1
+ import { pt as detachRun } from "./src-8cOPOgrT.mjs";
2
+ import { n as newRunId } from "./find-BTikxc54.mjs";
3
3
  import { c as write, i as detachHint, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
4
4
  // src/run/detached.ts
5
5
  /**
@@ -10,7 +10,7 @@ import { c as write, i as detachHint, l as writeErr, s as style } from "./output
10
10
  /** Starts the run in the background; `rawArgs` are `ork run`'s own, as typed. */
11
11
  const startDetached = async (store, options) => {
12
12
  const { rawArgs, cwd, target } = options;
13
- const { prepareFollowUps } = await import("./brief-BQbeoPMc.mjs");
13
+ const { prepareFollowUps } = await import("./brief-DH66xmj8.mjs");
14
14
  if (await prepareFollowUps(store, rawArgs, void 0, target, void 0, false) === void 0) return;
15
15
  const single = options.node !== void 0 && options.node !== "";
16
16
  const runId = newRunId(store, single ? "node-" : "");
@@ -0,0 +1,13 @@
1
+ import { n as argsOf } from "./command-tree-CEkzWNy6.mjs";
2
+ import { t as argumentError } from "./argument-error-CihH46Le.mjs";
3
+ // src/extra-arguments.ts
4
+ /** Refuses the first word beyond the positionals the command declares. */
5
+ const refuseExtraArguments = {
6
+ name: "refuse-extra-arguments",
7
+ setup: async ({ cmd, args }) => {
8
+ const declared = Object.values(await argsOf(cmd)).filter((def) => def.type === "positional").length;
9
+ const extra = args._[declared];
10
+ if (extra !== void 0) throw argumentError(`Unexpected argument \`${extra}\`.`);
11
+ }
12
+ };
13
+ export { refuseExtraArguments as t };
@@ -1,4 +1,4 @@
1
- import { Wr as placeFor } from "./src-Ciy7i3se.mjs";
1
+ import { Gr as placeFor } from "./src-8cOPOgrT.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  // ../core/src/remote/find.ts
4
4
  /**
@@ -1,19 +1,10 @@
1
- import "./src-Ciy7i3se.mjs";
1
+ import { Gr as placeFor } from "./src-8cOPOgrT.mjs";
2
2
  import { i as parseLimit, n as unknownProjectRefusal, r as parseFilters, t as limitRefusal } from "./refusals-DQQX3AIb.mjs";
3
- import { t as findRun } from "./find-B30-rd-u.mjs";
4
- import { a as resolved, n as argsOf } from "./command-tree-B6uvMJq1.mjs";
3
+ import { t as findRun } from "./find-BTikxc54.mjs";
4
+ import { a as resolved, n as argsOf } from "./command-tree-CEkzWNy6.mjs";
5
5
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
6
- import { parseArgs } from "citty";
6
+ import { t as argumentError } from "./argument-error-CihH46Le.mjs";
7
7
  // src/list/known-flags.ts
8
- /**
9
- * @file The citty plugin that refuses a flag a list command does not have (`ork
10
- * ps --bogus`, `ork decide --list --since 24h`). citty's parser is not
11
- * strict: it puts an unknown `--since 24h` into the arguments as `since:
12
- * true` plus a positional, which `decide` would read as a run id. The plugin
13
- * runs before the command, on the nine list commands only (specs/cli/
14
- * list-filters.md), and refuses with citty's own argument error, so the
15
- * one-line message and exit code 1 are the same as for a wrong enum value.
16
- */
17
8
  /** Names citty reads without the command declaring them. */
18
9
  const BUILT_IN = /* @__PURE__ */ new Set([
19
10
  "_",
@@ -22,24 +13,6 @@ const BUILT_IN = /* @__PURE__ */ new Set([
22
13
  ]);
23
14
  /** A flag's name without its spelling: `run-id`, `runId` and `run_id` agree. */
24
15
  const spelling = (name) => name.replaceAll(/[-_]/gu, "").toLowerCase();
25
- /**
26
- * An error citty's `runMain` takes for an argument error (its `CLIError`, which
27
- * it does not export): a failed parse gives one, and it takes `message`.
28
- */
29
- const argumentError = (message) => {
30
- try {
31
- parseArgs([], { x: {
32
- type: "string",
33
- required: true
34
- } });
35
- } catch (error) {
36
- if (error instanceof Error) {
37
- error.message = message;
38
- return error;
39
- }
40
- }
41
- return new Error(message);
42
- };
43
16
  /** How the flag is typed: `--since`, or `-x` for a one-letter name. */
44
17
  const written = (name) => name.length === 1 ? `-${name}` : `--${name}`;
45
18
  /** Refuses the first flag the command does not declare. */
@@ -134,6 +107,8 @@ const readListArgs = (table, args, options = {}) => {
134
107
  limit
135
108
  };
136
109
  };
110
+ /** The project root a scope other than `all` names. */
111
+ const rootOf = (scope, projects) => scope === "here" ? placeFor(process.cwd(), projects).root : scope.root;
137
112
  /**
138
113
  * The scope the filter's `project` names, checked against the registered
139
114
  * projects (core does not know them): an id or a root, or `all`; none given is
@@ -167,4 +142,4 @@ const resolveRun = (store, filter) => {
167
142
  run: found.run.id
168
143
  };
169
144
  };
170
- export { refuseIdsWithJson as a, readListArgs as i, filterArgs as n, resolveRun as o, projectScope as r, refuseUnknownFlags as s, fail as t };
145
+ export { refuseIdsWithJson as a, refuseUnknownFlags as c, readListArgs as i, filterArgs as n, resolveRun as o, projectScope as r, rootOf as s, fail as t };
@@ -1,12 +1,13 @@
1
- import { Gt as followUpListTable, Jn as changeFollowUp, Qn as isGithubIssueUrl, Sn as followUpProblem, Wr as placeFor, Xn as findFollowUp, Zn as followUpActions, gn as postFollowUpMessage, pr as runGh, vn as markDue, xn as deliverFollowUp, yn as recordPublished } from "./src-Ciy7i3se.mjs";
2
- import { d as followUpsRule, f as refreshDue, n as flagValues } from "./run-C0C54UiU.mjs";
1
+ import { $n as isGithubIssueUrl, Cn as followUpProblem, Gr as placeFor, Kt as followUpListTable, Qn as followUpActions, Sn as deliverFollowUp, Yn as changeFollowUp, Zn as findFollowUp, _n as postFollowUpMessage, bn as recordPublished, mr as runGh, yn as markDue } from "./src-8cOPOgrT.mjs";
2
+ import { d as followUpsRule, f as refreshDue, n as flagValues } from "./run-DBUAq-Uu.mjs";
3
3
  import { t as applyFilters } from "./apply-Mb0fNpCX.mjs";
4
4
  import { n as unknownProjectRefusal } from "./refusals-DQQX3AIb.mjs";
5
- import { t as findRun } from "./find-B30-rd-u.mjs";
5
+ import { t as findRun } from "./find-BTikxc54.mjs";
6
6
  import { a as plain, c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
7
- import { i as readListArgs, n as filterArgs, s as refuseUnknownFlags } from "./flags-ByYBx-Xb.mjs";
8
- import { t as printList } from "./print-Bd8MWVJk.mjs";
9
- import { t as withStore } from "./store-2KXzMCEN.mjs";
7
+ import { t as refuseExtraArguments } from "./extra-arguments-BxQMXARO.mjs";
8
+ import { c as refuseUnknownFlags, i as readListArgs, n as filterArgs } from "./flags-C8yCq0j5.mjs";
9
+ import { t as printList } from "./print-DNYzq4Rr.mjs";
10
+ import { t as withStore } from "./store-CDpk8Wtz.mjs";
10
11
  import { homedir } from "node:os";
11
12
  import { defineCommand } from "citty";
12
13
  // src/follow-ups/command.ts
@@ -77,6 +78,48 @@ const withFollowUp = (args, body) => inProject(args.project, async (store, place
77
78
  }
78
79
  await body(store, place, found.followUp);
79
80
  });
81
+ /**
82
+ * The follow-ups several words name (`done a b`, `drop a,b`: a comma splits a
83
+ * word too), each once, or `undefined` after saying every word that failed and
84
+ * making the command exit 1; the caller then changes nothing.
85
+ */
86
+ const eachTarget = (words, resolve) => {
87
+ const named = [...new Set(words.flatMap((word) => word.split(",")).map((word) => word.trim()).filter((word) => word !== ""))];
88
+ if (named.length === 0) {
89
+ fail("Give a follow-up id.");
90
+ return;
91
+ }
92
+ const found = /* @__PURE__ */ new Map();
93
+ let failed = false;
94
+ for (const word of named) {
95
+ const one = resolve(word);
96
+ if (one.ok) for (const f of one.followUps) found.set(f.id, f);
97
+ else {
98
+ fail(one.error);
99
+ failed = true;
100
+ }
101
+ }
102
+ return failed ? void 0 : [...found.values()];
103
+ };
104
+ /**
105
+ * Like `withFollowUp`, for every id in `args._` (space or comma separated):
106
+ * `refused` says why one may not be changed, and any refusal stops the call.
107
+ */
108
+ const withFollowUps = (args, refused, body) => inProject(args.project, async (store, place) => {
109
+ const followUps = eachTarget(args._, (word) => {
110
+ const found = findFollowUp(store, place.root, word);
111
+ if (!found.ok) return found;
112
+ const why = refused(found.followUp);
113
+ return why === void 0 ? {
114
+ ok: true,
115
+ followUps: [found.followUp]
116
+ } : {
117
+ ok: false,
118
+ error: why
119
+ };
120
+ });
121
+ if (followUps !== void 0) await body(store, place, followUps);
122
+ });
80
123
  // src/follow-ups/format.ts
81
124
  /** The groups of the list, in the order they are shown. */
82
125
  const GROUPS = [
@@ -163,23 +206,34 @@ const formatFollowUp = (f) => [
163
206
  * the person's own `gh` and only with `--confirm`, after showing the exact
164
207
  * text; Ork never runs a task's commands.
165
208
  */
166
- /** `done`, `drop` or `reopen`: one change of status, or why it can't be. */
209
+ /**
210
+ * `done`, `drop` or `reopen`: one change of status for each id given (space or
211
+ * comma separated), or why one can't be; any refusal changes none.
212
+ */
167
213
  const closing = (action, description, verb) => defineCommand({
168
214
  meta: {
169
215
  name: action,
170
216
  description
171
217
  },
172
218
  args: {
173
- id: idArg,
219
+ id: {
220
+ ...idArg,
221
+ description: "A follow-up's id, or a prefix of one; several allowed, space or comma separated"
222
+ },
174
223
  project
175
224
  },
176
- run: ({ args }) => withFollowUp(args, (store, _place, followUp) => {
177
- const changed = changeFollowUp(store, followUp, action);
178
- if (!changed.ok) {
179
- fail(changed.error);
180
- return;
225
+ run: ({ args }) => withFollowUps(args, (followUp) => {
226
+ const allowed = followUpActions(followUp)[action];
227
+ return allowed.ok ? void 0 : allowed.error;
228
+ }, (store, _place, followUps) => {
229
+ for (const followUp of followUps) {
230
+ const changed = changeFollowUp(store, followUp, action);
231
+ if (!changed.ok) {
232
+ fail(changed.error);
233
+ continue;
234
+ }
235
+ write(`${style("green", "✓")} ${verb} ${changed.followUp.id}: ${plain(changed.followUp.title)}`);
181
236
  }
182
- write(`${style("green", "✓")} ${verb} ${changed.followUp.id}: ${plain(changed.followUp.title)}`);
183
237
  })
184
238
  });
185
239
  const due = defineCommand({
@@ -190,22 +244,26 @@ const due = defineCommand({
190
244
  args: {
191
245
  target: {
192
246
  type: "positional",
193
- description: "A follow-up's id (or a prefix), or a run id",
247
+ description: "A follow-up's id (or a prefix), or a run id; several allowed, space or comma separated",
194
248
  required: true
195
249
  },
196
250
  project
197
251
  },
198
252
  run: ({ args }) => inProject(args.project, (store, place) => {
199
- const one = findFollowUp(store, place.root, args.target);
200
- const run = findRun(store, args.target, "");
201
- const runId = run.ok ? run.run.id : args.target;
202
- const key = one.ok ? one.followUp.id : runId;
203
- const marked = markDue(store, place.root, key);
204
- if (marked.length === 0) {
205
- fail(`Nothing waiting under \`${args.target}\`: give a waiting follow-up's id, or a run that left some.`);
206
- return;
207
- }
208
- for (const f of marked) write(`${style("green", "✓")} due ${f.id}: ${plain(f.title)}`);
253
+ const waiting = eachTarget(args._, (target) => {
254
+ const one = findFollowUp(store, place.root, target);
255
+ const run = findRun(store, target, "");
256
+ const runId = run.ok ? run.run.id : target;
257
+ const ready = (one.ok ? [one.followUp] : store.followUps(place.root).filter((f) => f.from.run === runId)).filter((f) => f.status === "waiting");
258
+ return ready.length === 0 ? {
259
+ ok: false,
260
+ error: `Nothing waiting under \`${target}\`: give a waiting follow-up's id, or a run that left some.`
261
+ } : {
262
+ ok: true,
263
+ followUps: ready
264
+ };
265
+ });
266
+ for (const f of waiting ?? []) for (const marked of markDue(store, place.root, f.id)) write(`${style("green", "✓")} due ${marked.id}: ${plain(marked.title)}`);
209
267
  })
210
268
  });
211
269
  const post = defineCommand({
@@ -213,6 +271,7 @@ const post = defineCommand({
213
271
  name: "post",
214
272
  description: "Post a message drafted for GitHub, as a comment through your own gh, with --confirm; without it, show what would be posted"
215
273
  },
274
+ plugins: [refuseExtraArguments],
216
275
  args: {
217
276
  id: idArg,
218
277
  confirm: {
@@ -253,6 +312,7 @@ const published = defineCommand({
253
312
  name: "published",
254
313
  description: "Record that this run published a pull request or branch (a workflow step calls it): its follow-ups wait on it, and the ones it took are done"
255
314
  },
315
+ plugins: [refuseExtraArguments],
256
316
  args: { ref: {
257
317
  type: "positional",
258
318
  description: "The pull request URL or the branch",
@@ -452,7 +512,7 @@ const followUps = defineCommand({
452
512
  name: "list",
453
513
  description: "List the follow-ups, due first, then by who they are for"
454
514
  },
455
- plugins: [refuseUnknownFlags],
515
+ plugins: [refuseUnknownFlags, refuseExtraArguments],
456
516
  args: filterArgs(followUpListTable),
457
517
  run: async ({ args }) => {
458
518
  const given = args;
@@ -480,6 +540,7 @@ const followUps = defineCommand({
480
540
  name: "show",
481
541
  description: "Show a follow-up whole, with its draft and its steps to copy"
482
542
  },
543
+ plugins: [refuseExtraArguments],
483
544
  args: {
484
545
  id: idArg,
485
546
  project,
@@ -1,4 +1,4 @@
1
- import { In as runStatus, Ln as slotWaitsOf, Mt as lockWaitLine, Nn as liveStatus, Or as maskSecrets, Pn as lockWaitsOf, Vn as isItem } from "./src-Ciy7i3se.mjs";
1
+ import { Fn as lockWaitsOf, Hn as isItem, Ln as runStatus, Nt as lockWaitLine, Pn as liveStatus, Rn as slotWaitsOf, kr as maskSecrets } from "./src-8cOPOgrT.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";
@@ -1,5 +1,5 @@
1
- import { z as storePath } from "./src-Ciy7i3se.mjs";
2
- import { g as storeGuarded, h as runMarkerIn } from "./src-DP02RP9O.mjs";
1
+ import { z as storePath } from "./src-8cOPOgrT.mjs";
2
+ import { g as storeGuarded, h as runMarkerIn } from "./src-I_RyKu6_.mjs";
3
3
  // src/commands/in-a-run.ts
4
4
  /**
5
5
  * @file The commands that act as the user refuse a program or an agent in a run
@@ -1,4 +1,4 @@
1
- import { $r as guardedBase, Qr as estimateTokens, Ur as placeFiles, Wr as placeFor, Yr as inside, Zr as LESSON_CAP_TOKENS, _r as feedbackActions, ei as plainPathInside, ti as writePlainFile } from "./src-Ciy7i3se.mjs";
1
+ import { $r as estimateTokens, Gr as placeFor, Qr as LESSON_CAP_TOKENS, Wr as placeFiles, Xr as inside, ei as guardedBase, ni as writePlainFile, ti as plainPathInside, vr as feedbackActions } from "./src-8cOPOgrT.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync, realpathSync } from "node:fs";
4
4
  import { spawn } from "node:child_process";
@@ -1,4 +1,4 @@
1
- import { gt as limitsReport, ht as limitsNow, mt as NOT_STARTED, v as capsHere } from "./src-Ciy7i3se.mjs";
1
+ import { _t as limitsReport, gt as limitsNow, ht as NOT_STARTED, v as capsHere } from "./src-8cOPOgrT.mjs";
2
2
  // src/run/limits.ts
3
3
  /**
4
4
  * @file The limits across runs that apply here (RFC-007): the user's settings
@@ -1,8 +1,8 @@
1
- import { T as isNewer } from "./src-Ciy7i3se.mjs";
2
- import { h as runMarkerIn } from "./src-DP02RP9O.mjs";
3
- import { n as ORK_VERSION } from "./__build_info__-dPf4cEGL.mjs";
4
- import { n as explainNode } from "./context-Bw6R_EYq.mjs";
5
- import { a as openMcp, c as refused, o as tool, s as answer } from "./src-n-u4TGev.mjs";
1
+ import { T as isNewer } from "./src-8cOPOgrT.mjs";
2
+ import { h as runMarkerIn } from "./src-I_RyKu6_.mjs";
3
+ import { n as ORK_VERSION } from "./__build_info__-D6mXC4cD.mjs";
4
+ import { n as explainNode } from "./context-CGPh12HV.mjs";
5
+ import { a as openMcp, c as refused, o as tool, s as answer } from "./src-CmEvHdju.mjs";
6
6
  import { z } from "zod";
7
7
  import { defineCommand } from "citty";
8
8
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -43,7 +43,7 @@ const orkMcpServer = (options = {}) => {
43
43
  ...options.script === void 0 ? {} : { script: options.script }
44
44
  });
45
45
  const all = [...opened.tools, explainTool(opened, options.home)];
46
- const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.19") ? tooOld(all, options.expects) : all;
46
+ const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.20") ? tooOld(all, options.expects) : all;
47
47
  const server = new McpServer({
48
48
  name: "ork",
49
49
  version: ORK_VERSION
@@ -1,7 +1,7 @@
1
- import "./src-Ciy7i3se.mjs";
2
- import { t as runOnce } from "./run-D6yU2rLf.mjs";
1
+ import "./src-8cOPOgrT.mjs";
2
+ import { n as OncePathspecError, t as runOnce } from "./run-Bvvg-fiF.mjs";
3
3
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
4
- import { t as ago } from "./format-C-nEZv-P.mjs";
4
+ import { t as ago } from "./format-BB4E-T6x.mjs";
5
5
  import { spawn } from "node:child_process";
6
6
  import { defineCommand, parseArgs } from "citty";
7
7
  // src/commands/once.ts
@@ -21,6 +21,10 @@ const args = {
21
21
  type: "string",
22
22
  description: "Also record the pass for this name (repeat for more)"
23
23
  },
24
+ on: {
25
+ type: "string",
26
+ description: "A git pathspec the check depends on; only matching files key it (repeat for more)"
27
+ },
24
28
  "with-head": {
25
29
  type: "boolean",
26
30
  description: "Key the check by HEAD too (for checks relative to it)"
@@ -42,7 +46,22 @@ const exitCodeOf = (command) => new Promise((resolve) => {
42
46
  resolve(code ?? 1);
43
47
  });
44
48
  });
45
- const listOf = (value) => [value].flat().filter((item) => typeof item === "string" && item !== "");
49
+ /**
50
+ * Every use of a repeatable flag, `--flag v` or `--flag=v`: citty keeps only
51
+ * the last. Not `run.ts`'s `flagValues`, which would load the run command's
52
+ * imports on every `ork once`.
53
+ */
54
+ const valuesOf = (before, flag) => before.flatMap((arg, index) => {
55
+ if (arg.startsWith(`${flag}=`)) return [arg.slice(flag.length + 1)];
56
+ if (arg !== flag) return [];
57
+ const next = before[index + 1];
58
+ return [next === void 0 || next.startsWith("--") ? void 0 : next];
59
+ });
60
+ /** The values of `flag`, or `undefined` when one of its uses has none. */
61
+ const listOf = (before, flag) => {
62
+ const values = valuesOf(before, flag);
63
+ return values.every((value) => value !== void 0 && value !== "") ? values.filter((value) => value !== void 0) : void 0;
64
+ };
46
65
  const once = defineCommand({
47
66
  meta: {
48
67
  name: "once",
@@ -53,22 +72,39 @@ const once = defineCommand({
53
72
  const split = rawArgs.indexOf("--");
54
73
  const command = split === -1 ? [] : rawArgs.slice(split + 1);
55
74
  if (command.length === 0) {
56
- writeErr("Say what to run after --: ork once [--as <name>] [--covers <name>] [--with-head] [--force] -- <command…>");
75
+ writeErr("Say what to run after --: ork once [--as <name>] [--covers <name>]… [--on <pathspec>]… [--with-head] [--force] -- <command…>");
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+ const before = rawArgs.slice(0, split);
80
+ const given = parseArgs(before, args);
81
+ const covers = listOf(before, "--covers");
82
+ const on = listOf(before, "--on");
83
+ if (covers === void 0 || on === void 0) {
84
+ writeErr(`${covers === void 0 ? "--covers needs a name" : "--on needs a pathspec"}: ork once [--covers <name>]… [--on <pathspec>]… -- <command…>`);
57
85
  process.exitCode = 1;
58
86
  return;
59
87
  }
60
- const given = parseArgs(rawArgs.slice(0, split), args);
61
88
  const run = process.env["ORK_RUN"];
62
89
  const node = process.env["ORK_NODE"];
63
90
  const result = await runOnce({
64
91
  cwd: process.cwd(),
65
92
  name: given["as"] ?? command.join(" "),
66
- covers: listOf(given["covers"]),
93
+ covers,
94
+ on,
67
95
  withHead: given["with-head"] === true,
68
96
  force: given["force"] === true,
69
97
  ...run === void 0 || node === void 0 ? {} : { who: `${run}/${node}` },
70
98
  run: () => exitCodeOf(command)
99
+ }).catch((error) => {
100
+ if (!(error instanceof OncePathspecError)) throw error;
101
+ writeErr(error.message);
102
+ return null;
71
103
  });
104
+ if (result === null) {
105
+ process.exitCode = 1;
106
+ return;
107
+ }
72
108
  if (result.skipped) write(`${style("green", "✓")} check already passed on these files · ${ago(result.pass.at)} · ${result.pass.who}`);
73
109
  process.exitCode = result.code;
74
110
  }
@@ -1,7 +1,8 @@
1
- import { An as requestPause, R as openStore, kn as requestContinue } from "./src-Ciy7i3se.mjs";
2
- import { t as findRun } from "./find-B30-rd-u.mjs";
1
+ import { An as requestContinue, R as openStore, jn as requestPause } from "./src-8cOPOgrT.mjs";
2
+ import { t as findRun } from "./find-BTikxc54.mjs";
3
3
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
4
- import { i as continueRefusal } from "./in-a-run-CZFzoT3R.mjs";
4
+ import { i as continueRefusal } from "./in-a-run-CbnKjO7t.mjs";
5
+ import { t as refuseExtraArguments } from "./extra-arguments-BxQMXARO.mjs";
5
6
  import { defineCommand } from "citty";
6
7
  // src/commands/pause.ts
7
8
  /**
@@ -43,6 +44,7 @@ const pause = defineCommand({
43
44
  name: "pause",
44
45
  description: "Pause a live run, or one node, before its next tool call"
45
46
  },
47
+ plugins: [refuseExtraArguments],
46
48
  args,
47
49
  run: ({ args: given }) => ask(given.run, (store, run) => requestPause(store, run, void 0, given.node), (run) => given.node === void 0 ? `Run ${run.id} pauses: nothing new starts, and running sessions wait before their next tool call. Go on with: ork continue ${run.id}` : `${given.node} in run ${run.id} pauses before its next tool call. Go on with: ork continue ${run.id} --node ${given.node}`)
48
50
  });
@@ -51,6 +53,7 @@ const continueRun = defineCommand({
51
53
  name: "continue",
52
54
  description: "Let a paused run, or one paused node, go on"
53
55
  },
56
+ plugins: [refuseExtraArguments],
54
57
  args,
55
58
  run: async ({ args: given }) => {
56
59
  const refused = continueRefusal();
@@ -1,5 +1,5 @@
1
1
  import { c as write } from "./output-B1kwo0YU.mjs";
2
- import { a as refuseIdsWithJson } from "./flags-ByYBx-Xb.mjs";
2
+ import { a as refuseIdsWithJson } from "./flags-C8yCq0j5.mjs";
3
3
  // src/list/print.ts
4
4
  /**
5
5
  * Prints `rows`: `--ids` their ids (`table.id`) comma-separated; `--json` the
@@ -1,6 +1,7 @@
1
- import { Br as hasInRepoFiles, Gr as projectsHome, Hr as newProjectId, R as openStore, Ur as placeFiles, Vr as inRepoPlace, Xr as projectRootOf, qr as shownPath } from "./src-Ciy7i3se.mjs";
1
+ import { Hr as inRepoPlace, Jr as shownPath, Kr as projectsHome, R as openStore, Ur as newProjectId, Vr as hasInRepoFiles, Wr as placeFiles, Zr as projectRootOf } from "./src-8cOPOgrT.mjs";
2
2
  import { C as termOf, c as write, l as writeErr, s as style, w as cut } from "./output-B1kwo0YU.mjs";
3
3
  import { n as chip } from "./chips-BqcT58qr.mjs";
4
+ import { t as refuseExtraArguments } from "./extra-arguments-BxQMXARO.mjs";
4
5
  import path from "node:path";
5
6
  import { existsSync, mkdirSync, realpathSync, statSync } from "node:fs";
6
7
  import { defineCommand } from "citty";
@@ -194,6 +195,7 @@ const forget = defineCommand({
194
195
  name: "forget",
195
196
  description: "Forget a registered project; its files and runs are kept"
196
197
  },
198
+ plugins: [refuseExtraArguments],
197
199
  args: { id },
198
200
  run: ({ args }) => {
199
201
  if (withStore((store) => store.forgetProject(args.id))) {
@@ -209,6 +211,7 @@ const move = defineCommand({
209
211
  name: "move",
210
212
  description: "Point a registered project at its clone's new place, after moving or renaming it"
211
213
  },
214
+ plugins: [refuseExtraArguments],
212
215
  args: {
213
216
  id,
214
217
  path: {
@@ -1,4 +1,4 @@
1
- import { Dn as linkNodes, On as unlinkNodes, R as openStore, Tn as addressOf } from "./src-Ciy7i3se.mjs";
1
+ import { En as addressOf, On as linkNodes, R as openStore, kn as unlinkNodes } from "./src-8cOPOgrT.mjs";
2
2
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  // src/commands/relay.ts