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

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 (48) hide show
  1. package/dist/{__build_info__-C1Nm0hlJ.mjs → __build_info__-dPf4cEGL.mjs} +3 -134
  2. package/dist/{attach-EP374oMP.mjs → attach-BQl8nQz2.mjs} +5 -5
  3. package/dist/{attach-RQx__RzH.mjs → attach-DhZQ87Nz.mjs} +49 -224
  4. package/dist/bin.mjs +204 -154
  5. package/dist/{brief-Bs3cMQU0.mjs → brief-BQbeoPMc.mjs} +19 -9
  6. package/dist/{builtin-files-yYaNTQRU.mjs → builtin-files-CWL3JEo-.mjs} +1 -1
  7. package/dist/{command-tree-BkSYWmYJ.mjs → command-tree-B6uvMJq1.mjs} +1 -1
  8. package/dist/{completion-DIXWlnAl.mjs → completion-DKPuD_Rw.mjs} +47 -14
  9. package/dist/{context-Dq-VM_sq.mjs → context-Bw6R_EYq.mjs} +3 -3
  10. package/dist/detached-BQlbmqR0.mjs +38 -0
  11. package/dist/{find-k489laBa.mjs → find-B30-rd-u.mjs} +1 -1
  12. package/dist/flags-ByYBx-Xb.mjs +170 -0
  13. package/dist/{follow-ups-DD8NTPe6.mjs → follow-ups-Cxca1Jgg.mjs} +24 -18
  14. package/dist/{format-DQc9A_ei.mjs → format-C-nEZv-P.mjs} +27 -11
  15. package/dist/{help-groups-hB6kY34d.mjs → help-groups-BpRgBSTh.mjs} +13 -7
  16. package/dist/{in-a-run-D_9GlAlS.mjs → in-a-run-CZFzoT3R.mjs} +2 -2
  17. package/dist/{install-PVlV2QPq.mjs → install-CsqK1avz.mjs} +2 -183
  18. package/dist/{limits-CHqBO7wb.mjs → limits-CXh052II.mjs} +1 -1
  19. package/dist/{mcp-D38Ajb0b.mjs → mcp-B4wME9C4.mjs} +6 -6
  20. package/dist/{once-DuUzpzL2.mjs → once-BKn3pOtg.mjs} +3 -3
  21. package/dist/outputs-text-CNTJ7Qq_.mjs +19 -0
  22. package/dist/{pause-Bx3ePGrn.mjs → pause-B1grR1cl.mjs} +3 -3
  23. package/dist/{print-n2qetUHc.mjs → print-Bd8MWVJk.mjs} +1 -1
  24. package/dist/{project-records-Cune1l6I.mjs → project-records-BOEVs69i.mjs} +1 -1
  25. package/dist/{parse-BzWpMN-a.mjs → refusals-DQQX3AIb.mjs} +10 -1
  26. package/dist/{relay-D7RN4m68.mjs → relay-CeNiq3GT.mjs} +1 -1
  27. package/dist/{run-OOWQIKMJ.mjs → run-C0C54UiU.mjs} +116 -137
  28. package/dist/{run-BfxdsQJk.mjs → run-D6yU2rLf.mjs} +1 -1
  29. package/dist/{send-CKth_vgn.mjs → send-DqgF58hb.mjs} +2 -2
  30. package/dist/{src-DLsFsmOD.mjs → src-Ciy7i3se.mjs} +882 -71
  31. package/dist/{src-BHod38UQ.mjs → src-D2qpd-G7.mjs} +394 -247
  32. package/dist/{src-DmmrX2_C.mjs → src-DP02RP9O.mjs} +227 -180
  33. package/dist/{src-DOjTY2ET.mjs → src-n-u4TGev.mjs} +186 -43
  34. package/dist/{store-DACH768X.mjs → store-2KXzMCEN.mjs} +1 -1
  35. package/dist/ui/assets/app-C5vO1M-l.css +1 -0
  36. package/dist/ui/assets/{app-CN3acQ-1.js → app-ICEKpy_C.js} +21 -20
  37. package/dist/ui/assets/{index-B2uGxA4W.js → index-BGaix5wh.js} +2 -2
  38. package/dist/ui/index.html +1 -1
  39. package/dist/{ui-CJ-BX12n.mjs → ui-CAvygxTb.mjs} +53 -24
  40. package/dist/{usage-DxZ6JGd4.mjs → usage-BFBco5OS.mjs} +7 -7
  41. package/dist/{validate-BS0nCccW.mjs → validate-UrmC5AG1.mjs} +5 -5
  42. package/dist/{watch-Dp7IB4FR.mjs → watch-DTxkgB8R.mjs} +5 -5
  43. package/dist/{workflows-Djo1edlK.mjs → workflows-8GV-SeRm.mjs} +28 -4
  44. package/dist/{worktrees-Drof_Nyx.mjs → worktrees-CUdUvZlO.mjs} +9 -6
  45. package/package.json +1 -1
  46. package/dist/flags-B4ZZWspN.mjs +0 -125
  47. package/dist/post-2CaJz_mV.mjs +0 -46
  48. package/dist/ui/assets/app-9Q-62Ywz.css +0 -1
package/dist/bin.mjs CHANGED
@@ -1,29 +1,30 @@
1
1
  #!/usr/bin/env node
2
- import { $n as FEEDBACK_TARGETS, An as liveStatus, Ar as loadAgents, Bt as decisionListTable, Ci as AGENT_TOOL_LAYOUTS, Cr as linkTools, Dr as deleteAgent, Ei as DRIVER_IDS, Er as createAgent, F as activeTree, Fr as placeFor, H as listOrkWorktrees, Kt as applyClean, L as openStore, Mr as inRepoPlace, Nn as runStatus, On as requestStop, Or as AGENT_SOURCES, Pr as placeFiles, Qn as FEEDBACK_SEVERITIES, Qr as renameNodeTypes, Rr as shownPath, Si as readyDriver, Sr as planMoveInto, Tr as toolsInUse, Un as loadProject, Ut as runListTable, V as createdWorktrees, Vn as PROJECT_FILE, Vt as feedbackListTable, Yt as planClean, Zn as FEEDBACK_KINDS, b as runningRunIds, br as planAgentMigration, cr as normalizeTitle, kn as tellLiveRun, kr as catalogAgent, li as settingsOf, ni as parseWorkflow, nt as answerDecision, oi as WorkflowSchema, ot as detachResume, ri as serializeWorkflow, rn as modelDriver, rr as sendPost, rt as pendingDecisions, st as resumable, tn as clearGitLocalEnv, tr as planPost, v as planUpgrade, w as isNewer, wi as ORK_LAYOUT, wr as toolLinks, x as runningScript, xi as driverChecks, xr as applySteps, y as releaseNotes, zn as nestItems } from "./src-DLsFsmOD.mjs";
3
- import { a as unknownNode, i as logListTable, l as createTerminalHuman, n as askStored, r as followRun, u as readText } from "./attach-RQx__RzH.mjs";
4
- import { a as onInterrupt, c as runWorkflowFile, g as machineSlotLedger, h as sweepLocks, i as loadRuntime, m as machineLocksDir, n as flagValues, o as run, p as resumeChat, r as isDriver, s as terminalHuman, t as badDriver } from "./run-OOWQIKMJ.mjs";
5
- import { a as acceptItem, c as feedbackActions, i as recordNote, l as openFixRun, n as previewPost, r as checkNote, s as placeOf, t as runInstall } from "./install-PVlV2QPq.mjs";
6
- import { c as fetchLatest, d as readUpdateCache, h as nodeSession, i as registryOf, m as writeUpdateCache, n as ORK_VERSION, p as updateCachePath, t as ORK_NAME } from "./__build_info__-C1Nm0hlJ.mjs";
2
+ import { Ai as driverChecks, Ar as applySteps, Fi as DRIVER_IDS, Fr as createAgent, G as listOrkWorktrees, Hn as nestItems, I as activeTree, In as runStatus, Ir as deleteAgent, Kn as loadProject, Kt as runListTable, Lr as AGENT_SOURCES, Mi as AGENT_TOOL_LAYOUTS, Mn as tellLiveRun, Mr as linkTools, Ni as ORK_LAYOUT, Nn as liveStatus, Nr as toolLinks, Pr as toolsInUse, Qt as planClean, R as openStore, Rr as catalogAgent, S as runningScript, T as isNewer, Ur as placeFiles, Ut as decisionListTable, Vr as inRepoPlace, W as createdWorktrees, Wn as PROJECT_FILE, Wr as placeFor, Wt as feedbackListTable, Yt as applyClean, _r as feedbackActions, ar as previewPost, at as answerDecision, b as releaseNotes, cr as FEEDBACK_KINDS, di as parseWorkflow, fi as serializeWorkflow, fr as planPost, gr as normalizeTitle, hi as WorkflowSchema, in as clearGitLocalEnv, ji as readyDriver, jn as requestStop, jr as planMoveInto, kr as planAgentMigration, lr as FEEDBACK_SEVERITIES, lt as detachResume, mr as sendPost, on as modelDriver, or as checkNote, ot as pendingDecisions, qr as shownPath, si as renameNodeTypes, sr as recordNote, ur as FEEDBACK_TARGETS, ut as resumable, vi as settingsOf, vr as openFixRun, x as runningRunIds, y as planUpgrade, zr as loadAgents } from "./src-Ciy7i3se.mjs";
3
+ import { i as placeOf, n as acceptItem, t as runInstall } from "./install-CsqK1avz.mjs";
4
+ import { _ as machineSlotLedger, a as onInterrupt, c as runWorkflowFile, g as sweepLocks, h as machineLocksDir, i as loadRuntime, m as resumeChat, n as flagValues, o as run, r as isDriver, s as terminalHuman, t as badDriver } from "./run-C0C54UiU.mjs";
7
5
  import { t as applyFilters } from "./apply-Mb0fNpCX.mjs";
8
- import { n as builtinWorkflowFile, t as builtinProblem } from "./builtin-files-yYaNTQRU.mjs";
9
- import { t as findRun } from "./find-k489laBa.mjs";
10
- import { n as groupedEntries, t as groupOf } from "./help-groups-hB6kY34d.mjs";
11
- import { a as publicArgs, o as resolved, r as argsOf, s as subcommandsOf } from "./command-tree-BkSYWmYJ.mjs";
6
+ import { n as builtinWorkflowFile, t as builtinProblem } from "./builtin-files-CWL3JEo-.mjs";
7
+ import { p as scrubberOfRun } from "./src-DP02RP9O.mjs";
8
+ import { t as findRun } from "./find-B30-rd-u.mjs";
9
+ import { c as fetchLatest, d as readUpdateCache, h as nodeSession, i as registryOf, m as writeUpdateCache, n as ORK_VERSION, p as updateCachePath, t as ORK_NAME } from "./__build_info__-dPf4cEGL.mjs";
10
+ import { n as groupedEntries, t as groupOf } from "./help-groups-BpRgBSTh.mjs";
11
+ import { a as resolved, i as publicArgs, n as argsOf, o as subcommandsOf } from "./command-tree-B6uvMJq1.mjs";
12
12
  import { C as termOf, D as wrap, E as widthOf, S as takePlainFlag, T as hang, a as plain, b as canKey, c as write, h as paint, l as writeErr, m as bold, s as style, t as confirm, w as cut } from "./output-B1kwo0YU.mjs";
13
13
  import { n as chip, r as nodeChip, t as CHIP_LABELS } from "./chips-BqcT58qr.mjs";
14
- import { c as registeredProjects, n as WORKFLOW_SUFFIX, s as projectAt, t as WORKFLOW_DIR } from "./workflows-Djo1edlK.mjs";
15
- import { C as startUpdateCheck, S as showUpdateNotice, _ as runChecks, a as formatReport, c as checksHere, g as orkCheck, h as headWarning, m as experimentsCheck, n as validate, p as exec, r as validateFile, v as socketCheck, w as updateCheckOff, x as runUpdateChild, y as triggerChecks } from "./validate-BS0nCccW.mjs";
16
- import { a as decideRefusal, r as chatRefusal } from "./in-a-run-D_9GlAlS.mjs";
17
- import { t as context } from "./context-Dq-VM_sq.mjs";
18
- import { i as readListArgs, n as filterArgs, o as allAlias, r as projectScope, t as fail$1 } from "./flags-B4ZZWspN.mjs";
19
- import { t as printList } from "./print-n2qetUHc.mjs";
20
- import { a as formatRegistered, i as formatProjects, n as move, o as recordInRepo, r as withStore, s as registerProject, t as forget } from "./project-records-Cune1l6I.mjs";
21
- import { i as listedStatus, n as formatRuns, r as formatTreeView, t as ago } from "./format-DQc9A_ei.mjs";
22
- import { t as withStore$1 } from "./store-DACH768X.mjs";
14
+ import { a as unknownNode, i as logListTable, l as createTerminalHuman, n as askStored, r as followRun, u as readText } from "./attach-DhZQ87Nz.mjs";
15
+ import { c as projectAt, l as registeredProjects, n as WORKFLOW_SUFFIX, t as WORKFLOW_DIR } from "./workflows-8GV-SeRm.mjs";
16
+ import { C as startUpdateCheck, S as showUpdateNotice, _ as runChecks, a as formatReport, c as checksHere, g as orkCheck, h as headWarning, m as experimentsCheck, n as validate, p as exec, r as validateFile, v as socketCheck, w as updateCheckOff, x as runUpdateChild, y as triggerChecks } from "./validate-UrmC5AG1.mjs";
17
+ import { a as decideRefusal, r as chatRefusal } from "./in-a-run-CZFzoT3R.mjs";
18
+ import { t as context } from "./context-Bw6R_EYq.mjs";
19
+ import { i as readListArgs, n as filterArgs, o as resolveRun, r as projectScope, s as refuseUnknownFlags, t as fail$1 } from "./flags-ByYBx-Xb.mjs";
20
+ import { i as listedStatus, n as formatRuns, r as formatTreeView, t as ago } from "./format-C-nEZv-P.mjs";
21
+ import { t as printList } from "./print-Bd8MWVJk.mjs";
22
+ import { a as formatRegistered, i as formatProjects, n as move, o as recordInRepo, r as withStore, s as registerProject, t as forget } from "./project-records-BOEVs69i.mjs";
23
+ import { t as withStore$1 } from "./store-2KXzMCEN.mjs";
23
24
  import path from "node:path";
24
25
  import { stringify } from "yaml";
25
26
  import { z } from "zod";
26
- import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
27
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmdirSync, writeFileSync } from "node:fs";
27
28
  import { homedir } from "node:os";
28
29
  import { setTimeout } from "node:timers/promises";
29
30
  import { defineCommand, renderUsage, runCommand, runMain } from "citty";
@@ -280,11 +281,94 @@ const chat = defineCommand({
280
281
  }
281
282
  }
282
283
  });
284
+ // src/runs/feedback.ts
285
+ /**
286
+ * @file `ork feedback`'s helpers (specs/feedback.md): finding an item by a
287
+ * prefix of its fingerprint, the lines `list` and `show` print, and the
288
+ * writes a person makes: `restore` an item, `note` a run or node.
289
+ */
290
+ /** The item whose fingerprint starts with `prefix`, dismissed ones included. */
291
+ const findFeedbackItem = (store, prefix) => {
292
+ const found = store.findFeedback(prefix);
293
+ const [item, other] = found;
294
+ if (item === void 0) return {
295
+ ok: false,
296
+ error: `No feedback item ${prefix}; see ork feedback list.`
297
+ };
298
+ if (other !== void 0) return {
299
+ ok: false,
300
+ error: [`${prefix} matches ${String(found.length)} items:`, ...found.map((i) => ` ${i.id} ${i.title}`)].join("\n")
301
+ };
302
+ return {
303
+ ok: true,
304
+ item
305
+ };
306
+ };
307
+ const SEVERITY_STYLE = {
308
+ low: "dim",
309
+ medium: "yellow",
310
+ high: "red"
311
+ };
312
+ const about = (item) => `${item.target}/${item.kind}`;
313
+ /** One line per item, most recently seen first. */
314
+ const formatFeedbackItems = (items, now = Date.now(), term = termOf(process.stdout)) => {
315
+ if (items.length === 0) return ["No feedback yet."];
316
+ const width = Math.max(...items.map((i) => about(i).length));
317
+ return items.map((item) => {
318
+ const mark = item.status === "new" ? "" : term.rich ? ` ${chip(term, item.status.toUpperCase(), item.status === "dismissed" ? "muted" : "accent")}` : ` ${style("dim", `[${item.status}]`)}`;
319
+ const times = `${String(item.count)}×`.padStart(4);
320
+ const when = ` ${style("dim", `· ${ago(item.lastSeen, now)}`)}`;
321
+ const room = term.width - (item.id.length + 1 + times.length + 1 + width + 2) - widthOf(mark) - widthOf(when);
322
+ const title = term.rich ? cut(item.title, Math.max(8, room)) : item.title;
323
+ return `${style("dim", item.id)} ${times} ${style(SEVERITY_STYLE[item.severity], about(item).padEnd(width))} ${title}${mark}${when}`;
324
+ });
325
+ };
326
+ const plural = (n, word) => `${String(n)} ${word}${n === 1 ? "" : "s"}`;
327
+ /** An item and each of its records. */
328
+ const formatFeedbackItem = (item, records, now = Date.now()) => {
329
+ const lines = [
330
+ style("bold", item.title),
331
+ style("dim", `${item.id} · ${item.status} · ${about(item)} · ${item.severity} · from ${item.sources.join(", ")}`),
332
+ `Seen ${plural(item.count, "time")} in ${plural(item.runs.length, "run")}, first ${ago(item.firstSeen, now)}, last ${ago(item.lastSeen, now)}.`
333
+ ];
334
+ if (item.workflows.length > 0) lines.push(`Workflows: ${item.workflows.join(", ")}`);
335
+ if (item.models.length > 0) lines.push(`Models: ${item.models.join(", ")}`);
336
+ if (item.merged.length > 0) lines.push(`Merged into it: ${item.merged.map((id) => id.slice(0, 12)).join(", ")} (ork feedback split ${item.id.slice(0, 12)} takes them apart)`);
337
+ for (const record of records) {
338
+ const { feedback } = record;
339
+ const where = record.node === void 0 ? "" : ` · ${record.node}`;
340
+ lines.push("", style("dim", `${ago(record.at, now)} · run ${record.runId}${where} · ${feedback.source}`));
341
+ if (feedback.title !== item.title) lines.push(` ${feedback.title}`);
342
+ if (feedback.body !== "") lines.push(` ${feedback.body}`);
343
+ if (feedback.evidence.length > 0) lines.push(style("dim", ` evidence: ${feedback.evidence.join(", ")}`));
344
+ }
345
+ return lines;
346
+ };
347
+ /**
348
+ * `ork feedback note`: records a person's note on a run, or one of its nodes,
349
+ * as that run's feedback; returns the item it joins, or why it could not.
350
+ */
351
+ const noteRun = (store, cwd, args) => {
352
+ const found = findRun(store, args.run, cwd);
353
+ if (!found.ok) return found;
354
+ return noteOn(store, found.run, args);
355
+ };
356
+ /**
357
+ * Records a person's note on `run`, masked with the env values its workflow
358
+ * file names (by pattern only when the file is gone or no longer parses).
359
+ */
360
+ const noteOn = (store, run, ask) => recordNote(store, run, ask, "--", scrubberOfRun(run, store.projects()));
283
361
  // src/commands/decide-list.ts
284
362
  /**
285
363
  * @file The list `ork decide --list` prints: one line per open decision, and
286
364
  * the filters (RFC-017) that choose which.
287
365
  */
366
+ /** `ork decide`'s filter flags, with `--list`. */
367
+ const listArgs = filterArgs(decisionListTable, { extra: { list: {
368
+ type: "boolean",
369
+ description: "List them without answering",
370
+ default: false
371
+ } } });
288
372
  /**
289
373
  * One line per open decision, for `--list`: on a terminal an ASK chip and the
290
374
  * node's chip with the id and the question after, cut to the screen; plain, the
@@ -316,7 +400,7 @@ const asksForList = (args) => args["list"] === true || args["json"] === true ||
316
400
  * refused (said, exit code set).
317
401
  */
318
402
  const selectDecisions = (store, args) => {
319
- const request = readListArgs(decisionListTable, args, { all: "project" });
403
+ const request = readListArgs(decisionListTable, args);
320
404
  if (request === void 0) return void 0;
321
405
  const scope = projectScope(request.filter, store.projects());
322
406
  if (scope === void 0) return void 0;
@@ -324,15 +408,20 @@ const selectDecisions = (store, args) => {
324
408
  const { workflow } = request.filter;
325
409
  if (workflow !== void 0) filter.workflow = workflow;
326
410
  const positional = args["run-id"];
327
- const run = request.filter["run"] ?? (typeof positional === "string" ? positional : void 0);
328
- if (run !== void 0 && run !== "") {
329
- const found = findRun(store, run, process.cwd());
330
- if (!found.ok) {
331
- fail$1(found.error);
332
- return;
333
- }
334
- filter.runId = found.run.id;
335
- } else if (scope === "here") filter.project = placeFor(process.cwd(), store.projects()).root;
411
+ const named = request.filter["run"] ?? (typeof positional === "string" ? positional : void 0);
412
+ const hint = named !== void 0 && request.filter["run"] === void 0 ? decisionHint(store, named) : void 0;
413
+ if (hint !== void 0) {
414
+ fail$1(hint);
415
+ return;
416
+ }
417
+ const resolved = resolveRun(store, named === void 0 ? request.filter : {
418
+ ...request.filter,
419
+ run: named
420
+ });
421
+ if (resolved === void 0) return void 0;
422
+ const run = resolved["run"];
423
+ if (run !== void 0 && run !== "") filter.runId = run;
424
+ else if (scope === "here") filter.project = placeFor(process.cwd(), store.projects()).root;
336
425
  else if (scope !== "all") filter.project = scope.root;
337
426
  const pending = pendingDecisions(store, filter);
338
427
  return {
@@ -346,6 +435,16 @@ const printDecisions = (open, args, workflow) => {
346
435
  for (const line of formatDecisions(shown, workflow)) write(line);
347
436
  });
348
437
  };
438
+ /**
439
+ * What to say when the positional meant for a run is an open decision's id: the
440
+ * form that answers it (a run id is the positional; a decision answers with
441
+ * `--id` and `--choose`).
442
+ */
443
+ const decisionHint = (store, arg) => {
444
+ const decision = store.decision(arg);
445
+ if (decision === void 0 || decision.status !== "open") return void 0;
446
+ return `${arg} is a decision id, not a run: answer it with \`ork decide --id ${arg} --choose ${decision.recommended ?? decision.options[0]?.id ?? "<option>"}\``;
447
+ };
349
448
  // src/commands/decide.ts
350
449
  /**
351
450
  * @file `ork decide`: answer a live run's open decisions from any terminal (it
@@ -371,11 +470,11 @@ const noteDecision = (store, id, note, rating) => {
371
470
  ok: false,
372
471
  error: `No decision ${id} to note.`
373
472
  };
374
- return recordNote(store, run, {
473
+ return noteOn(store, run, {
375
474
  text: note ?? `Rated ${rating ?? ""} at ${decision.question}`,
376
475
  node: decision.node,
377
476
  rating
378
- }, "--");
477
+ });
379
478
  };
380
479
  /** Why a note given with an answer can't be recorded, before answering. */
381
480
  const noteProblem = (note, rating) => {
@@ -396,20 +495,14 @@ const decide = defineCommand({
396
495
  name: "decide",
397
496
  description: "Answer the open decisions of this project's live runs"
398
497
  },
498
+ plugins: [refuseUnknownFlags],
399
499
  args: {
400
500
  "run-id": {
401
501
  type: "positional",
402
502
  description: "Only this run's decisions (an id or a prefix)",
403
503
  required: false
404
504
  },
405
- ...filterArgs(decisionListTable, { extra: {
406
- ...allAlias,
407
- list: {
408
- type: "boolean",
409
- description: "List them without answering",
410
- default: false
411
- }
412
- } }),
505
+ ...listArgs,
413
506
  document: {
414
507
  type: "boolean",
415
508
  description: "Print the document of the decision --id names",
@@ -534,6 +627,8 @@ const failed$1 = (message) => {
534
627
  writeErr(message);
535
628
  process.exitCode = 1;
536
629
  };
630
+ /** The mark of how the run ended, as the run's own summary line has it. */
631
+ const endMark = (status) => status === "succeeded" ? style("green", "✓") : status === "failed" || status === "crashed" ? style("red", "✗") : style("yellow", "!");
537
632
  const stop = defineCommand({
538
633
  meta: {
539
634
  name: "stop",
@@ -571,7 +666,7 @@ const stop = defineCommand({
571
666
  for (let i = 0; i < 150; i += 1) {
572
667
  const [now] = store.lookup(run.id);
573
668
  if (now !== void 0 && liveStatus(now) !== "running") {
574
- write(`${style("green", "✓")} run ${run.id} ${liveStatus(now)}`);
669
+ write(`${endMark(liveStatus(now))} run ${run.id} ${liveStatus(now)}`);
575
670
  return;
576
671
  }
577
672
  await setTimeout(100);
@@ -727,7 +822,7 @@ const formatCheck = (result, term = termOf(process.stdout)) => {
727
822
  * folder. Says nothing when there were none. `bin` is the `cmd` program.
728
823
  */
729
824
  const leaseChecks = async (place, env = process.env, bin = "cmd") => {
730
- const { cleanStaleLeases, leaseLedger } = await import("./src-BHod38UQ.mjs");
825
+ const { cleanStaleLeases, leaseLedger } = await import("./src-D2qpd-G7.mjs");
731
826
  const { cleaned, failed } = await cleanStaleLeases({
732
827
  bin,
733
828
  ledger: leaseLedger(placeFiles(place).runs),
@@ -753,10 +848,22 @@ const leaseChecks = async (place, env = process.env, bin = "cmd") => {
753
848
  * nothing when there were none.
754
849
  */
755
850
  const named = (held) => held.map(({ run, node, pid }) => `${run}/${node} (pid ${String(pid)})`).join(", ");
756
- /** Sweeps the slots and locks in `home`'s `~/.ork`; one line per kind swept. */
851
+ /** Removes `dir`'s `queue` folder when sweeping left it empty (else it stays). */
852
+ const dropEmptyQueue = (dir) => {
853
+ try {
854
+ rmdirSync(path.join(dir, "queue"));
855
+ } catch {}
856
+ };
857
+ /**
858
+ * Sweeps the slots and locks in `home`'s `~/.ork`; one line per kind swept, and
859
+ * the empty `queue/` folders the sweep left are removed.
860
+ */
757
861
  const ledgerChecks = (home = homedir()) => {
758
862
  const slots = machineSlotLedger({ home }).sweep();
759
- const locks = sweepLocks(machineLocksDir(home));
863
+ const locksDir = machineLocksDir(home);
864
+ const locks = sweepLocks(locksDir);
865
+ if (slots.length > 0) dropEmptyQueue(path.join(home, ".ork", "slots"));
866
+ if (locks.length > 0) for (const folder of readdirSync(locksDir)) dropEmptyQueue(path.join(locksDir, folder));
760
867
  return [...slots.length === 0 ? [] : [{
761
868
  name: "check slots",
762
869
  status: "ok",
@@ -1559,6 +1666,7 @@ const projects = defineCommand({
1559
1666
  name: "projects",
1560
1667
  description: "List the registered projects, in-repo and attached"
1561
1668
  },
1669
+ plugins: [refuseUnknownFlags],
1562
1670
  args: filterArgs(projectListTable),
1563
1671
  subCommands: {
1564
1672
  forget,
@@ -1625,78 +1733,6 @@ const migrate = defineCommand({
1625
1733
  }, (file) => formatReport(validateFile(file, process.cwd())));
1626
1734
  }
1627
1735
  });
1628
- // src/runs/feedback.ts
1629
- /**
1630
- * @file `ork feedback`'s helpers (specs/feedback.md): finding an item by a
1631
- * prefix of its fingerprint, the lines `list` and `show` print, and the
1632
- * writes a person makes: `restore` an item, `note` a run or node.
1633
- */
1634
- /** The item whose fingerprint starts with `prefix`, dismissed ones included. */
1635
- const findFeedbackItem = (store, prefix) => {
1636
- const found = store.findFeedback(prefix);
1637
- const [item, other] = found;
1638
- if (item === void 0) return {
1639
- ok: false,
1640
- error: `No feedback item ${prefix}; see ork feedback list.`
1641
- };
1642
- if (other !== void 0) return {
1643
- ok: false,
1644
- error: [`${prefix} matches ${String(found.length)} items:`, ...found.map((i) => ` ${i.id} ${i.title}`)].join("\n")
1645
- };
1646
- return {
1647
- ok: true,
1648
- item
1649
- };
1650
- };
1651
- const SEVERITY_STYLE = {
1652
- low: "dim",
1653
- medium: "yellow",
1654
- high: "red"
1655
- };
1656
- const about = (item) => `${item.target}/${item.kind}`;
1657
- /** One line per item, most recently seen first. */
1658
- const formatFeedbackItems = (items, now = Date.now(), term = termOf(process.stdout)) => {
1659
- if (items.length === 0) return ["No feedback yet."];
1660
- const width = Math.max(...items.map((i) => about(i).length));
1661
- return items.map((item) => {
1662
- const mark = item.status === "new" ? "" : term.rich ? ` ${chip(term, item.status.toUpperCase(), item.status === "dismissed" ? "muted" : "accent")}` : ` ${style("dim", `[${item.status}]`)}`;
1663
- const times = `${String(item.count)}×`.padStart(4);
1664
- const when = ` ${style("dim", `· ${ago(item.lastSeen, now)}`)}`;
1665
- const room = term.width - (item.id.length + 1 + times.length + 1 + width + 2) - widthOf(mark) - widthOf(when);
1666
- const title = term.rich ? cut(item.title, Math.max(8, room)) : item.title;
1667
- return `${style("dim", item.id)} ${times} ${style(SEVERITY_STYLE[item.severity], about(item).padEnd(width))} ${title}${mark}${when}`;
1668
- });
1669
- };
1670
- const plural = (n, word) => `${String(n)} ${word}${n === 1 ? "" : "s"}`;
1671
- /** An item and each of its records. */
1672
- const formatFeedbackItem = (item, records, now = Date.now()) => {
1673
- const lines = [
1674
- style("bold", item.title),
1675
- style("dim", `${item.id} · ${item.status} · ${about(item)} · ${item.severity} · from ${item.sources.join(", ")}`),
1676
- `Seen ${plural(item.count, "time")} in ${plural(item.runs.length, "run")}, first ${ago(item.firstSeen, now)}, last ${ago(item.lastSeen, now)}.`
1677
- ];
1678
- if (item.workflows.length > 0) lines.push(`Workflows: ${item.workflows.join(", ")}`);
1679
- if (item.models.length > 0) lines.push(`Models: ${item.models.join(", ")}`);
1680
- if (item.merged.length > 0) lines.push(`Merged into it: ${item.merged.map((id) => id.slice(0, 12)).join(", ")} (ork feedback split ${item.id.slice(0, 12)} takes them apart)`);
1681
- for (const record of records) {
1682
- const { feedback } = record;
1683
- const where = record.node === void 0 ? "" : ` · ${record.node}`;
1684
- lines.push("", style("dim", `${ago(record.at, now)} · run ${record.runId}${where} · ${feedback.source}`));
1685
- if (feedback.title !== item.title) lines.push(` ${feedback.title}`);
1686
- if (feedback.body !== "") lines.push(` ${feedback.body}`);
1687
- if (feedback.evidence.length > 0) lines.push(style("dim", ` evidence: ${feedback.evidence.join(", ")}`));
1688
- }
1689
- return lines;
1690
- };
1691
- /**
1692
- * `ork feedback note`: records a person's note on a run, or one of its nodes,
1693
- * as that run's feedback; returns the item it joins, or why it could not.
1694
- */
1695
- const noteRun = (store, cwd, args) => {
1696
- const found = findRun(store, args.run, cwd);
1697
- if (!found.ok) return found;
1698
- return recordNote(store, found.run, args, "--");
1699
- };
1700
1736
  // src/commands/feedback-list.ts
1701
1737
  /**
1702
1738
  * @file `ork feedback list`: the items, newest first, filtered by the flags
@@ -1708,16 +1744,16 @@ const list = defineCommand({
1708
1744
  name: "list",
1709
1745
  description: "List feedback items, newest first"
1710
1746
  },
1711
- args: {
1712
- ...filterArgs(feedbackListTable),
1713
- ...allAlias
1714
- },
1747
+ plugins: [refuseUnknownFlags],
1748
+ args: filterArgs(feedbackListTable),
1715
1749
  run: async ({ args }) => {
1716
1750
  const given = args;
1717
- const asked = readListArgs(feedbackListTable, given, { all: "status" });
1751
+ const asked = readListArgs(feedbackListTable, given);
1718
1752
  if (asked === void 0) return;
1719
- const { filter, limit } = asked;
1753
+ const { limit } = asked;
1720
1754
  await withStore$1((store) => {
1755
+ const filter = resolveRun(store, asked.filter);
1756
+ if (filter === void 0) return;
1721
1757
  const items = applyFilters(feedbackListTable, store.feedbackItems({ all: filter["status"] !== void 0 }), filter).slice(0, limit);
1722
1758
  printList(items, feedbackListTable, given, (shown) => {
1723
1759
  for (const line of formatFeedbackItems(shown)) write(line);
@@ -2422,15 +2458,13 @@ const ps = defineCommand({
2422
2458
  name: "ps",
2423
2459
  description: "List this project's runs, newest first"
2424
2460
  },
2425
- args: {
2426
- ...filterArgs(runListTable, { extra: { limit: {
2427
- type: "string",
2428
- description: `Show at most this many, a positive whole number (default ${String(PS_LIMIT)})`
2429
- } } }),
2430
- ...allAlias
2431
- },
2461
+ plugins: [refuseUnknownFlags],
2462
+ args: { ...filterArgs(runListTable, { extra: { limit: {
2463
+ type: "string",
2464
+ description: `Show at most this many, a positive whole number (default ${String(PS_LIMIT)})`
2465
+ } } }) },
2432
2466
  run: ({ args }) => withStore$1((store) => {
2433
- const req = readListArgs(runListTable, args, { all: "project" });
2467
+ const req = readListArgs(runListTable, args);
2434
2468
  if (req === void 0) return;
2435
2469
  const scope = projectScope(req.filter, store.projects());
2436
2470
  if (scope === void 0) return;
@@ -2447,7 +2481,13 @@ const ps = defineCommand({
2447
2481
  json: args["json"]
2448
2482
  }, (runs) => {
2449
2483
  for (const line of formatRuns(runs, scope === "all", Date.now(), statusOf)) write(line);
2450
- }, (runs) => runs.map((run) => byId.get(run.id) ?? run));
2484
+ }, (runs) => runs.map((run) => {
2485
+ const record = byId.get(run.id) ?? run;
2486
+ return {
2487
+ ...record,
2488
+ live: statusOf(record)
2489
+ };
2490
+ }));
2451
2491
  })
2452
2492
  });
2453
2493
  const runArg = {
@@ -2458,8 +2498,9 @@ const runArg = {
2458
2498
  const logs = defineCommand({
2459
2499
  meta: {
2460
2500
  name: "logs",
2461
- description: "Print a run's transcript"
2501
+ description: "Print a run's transcript. A delegated task shows its task label: the lead's short description, whitespace folded, clipped to 80 characters, secrets masked"
2462
2502
  },
2503
+ plugins: [refuseUnknownFlags],
2463
2504
  args: {
2464
2505
  run: runArg,
2465
2506
  ...filterArgs(logListTable, {
@@ -2525,7 +2566,7 @@ const logs = defineCommand({
2525
2566
  const tree = defineCommand({
2526
2567
  meta: {
2527
2568
  name: "tree",
2528
- description: "Show a run's ownership tree with status, tokens and cost"
2569
+ description: "Show a run's ownership tree with status, tokens and cost. A delegated task shows its task label: the lead's short description, whitespace folded, clipped to 80 characters, secrets masked"
2529
2570
  },
2530
2571
  args: {
2531
2572
  run: runArg,
@@ -2695,6 +2736,7 @@ const issuesStep = async (root, options, checks = checksHere) => {
2695
2736
  return;
2696
2737
  }
2697
2738
  write(`${style("green", "created")} ${ISSUES_FILE}`);
2739
+ write(style("dim", `Commit it before \`ork run issues\`: the builders' worktrees come from your commits.`));
2698
2740
  const line = await issuesDriverLine(checks);
2699
2741
  if (line !== null) write(line);
2700
2742
  };
@@ -2886,6 +2928,7 @@ const agents = defineCommand({
2886
2928
  name: "list",
2887
2929
  description: "Every agent, and where it comes from"
2888
2930
  },
2931
+ plugins: [refuseUnknownFlags],
2889
2932
  args: agentListArgs,
2890
2933
  run: ({ args }) => {
2891
2934
  const catalog = catalogHere();
@@ -2992,31 +3035,31 @@ const main = defineCommand({
2992
3035
  run,
2993
3036
  ps,
2994
3037
  logs,
2995
- attach: () => import("./attach-EP374oMP.mjs").then((module) => module.attach),
3038
+ attach: () => import("./attach-BQl8nQz2.mjs").then((module) => module.attach),
2996
3039
  tree,
2997
- usage: () => import("./usage-DxZ6JGd4.mjs").then((module) => module.usage),
2998
- prune: () => import("./usage-DxZ6JGd4.mjs").then((module) => module.prune),
3040
+ usage: () => import("./usage-BFBco5OS.mjs").then((module) => module.usage),
3041
+ prune: () => import("./usage-BFBco5OS.mjs").then((module) => module.prune),
2999
3042
  decide,
3000
- relay: () => import("./relay-D7RN4m68.mjs").then((module) => module.relay),
3001
- pause: () => import("./pause-Bx3ePGrn.mjs").then((module) => module.pause),
3002
- continue: () => import("./pause-Bx3ePGrn.mjs").then((module) => module.continueRun),
3043
+ relay: () => import("./relay-CeNiq3GT.mjs").then((module) => module.relay),
3044
+ pause: () => import("./pause-B1grR1cl.mjs").then((module) => module.pause),
3045
+ continue: () => import("./pause-B1grR1cl.mjs").then((module) => module.continueRun),
3003
3046
  stop,
3004
3047
  chat,
3005
- once: () => import("./once-DuUzpzL2.mjs").then((module) => module.once),
3006
- send: () => import("./send-CKth_vgn.mjs").then((module) => module.send),
3048
+ once: () => import("./once-BKn3pOtg.mjs").then((module) => module.once),
3049
+ send: () => import("./send-DqgF58hb.mjs").then((module) => module.send),
3007
3050
  resume,
3008
3051
  feedback,
3009
- "follow-ups": () => import("./follow-ups-DD8NTPe6.mjs").then((module) => module.followUps),
3052
+ "follow-ups": () => import("./follow-ups-Cxca1Jgg.mjs").then((module) => module.followUps),
3010
3053
  context,
3011
- worktrees: () => import("./worktrees-Drof_Nyx.mjs").then((module) => module.worktrees),
3012
- wt: () => import("./worktrees-Drof_Nyx.mjs").then((module) => module.worktrees),
3013
- watch: () => import("./watch-Dp7IB4FR.mjs").then((module) => module.watch),
3014
- mcp: () => import("./mcp-D38Ajb0b.mjs").then((module) => module.mcp),
3015
- ui: () => import("./ui-CJ-BX12n.mjs").then((module) => module.ui),
3054
+ worktrees: () => import("./worktrees-CUdUvZlO.mjs").then((module) => module.worktrees),
3055
+ wt: () => import("./worktrees-CUdUvZlO.mjs").then((module) => module.worktrees),
3056
+ watch: () => import("./watch-DTxkgB8R.mjs").then((module) => module.watch),
3057
+ mcp: () => import("./mcp-B4wME9C4.mjs").then((module) => module.mcp),
3058
+ ui: () => import("./ui-CAvygxTb.mjs").then((module) => module.ui),
3016
3059
  doctor,
3017
3060
  upgrade,
3018
- completion: () => import("./completion-DIXWlnAl.mjs").then((module) => module.completion),
3019
- __complete: () => import("./completion-DIXWlnAl.mjs").then((module) => module.completeCommand(main))
3061
+ completion: () => import("./completion-DKPuD_Rw.mjs").then((module) => module.completion),
3062
+ __complete: () => import("./completion-DKPuD_Rw.mjs").then((module) => module.completeCommand(main))
3020
3063
  }
3021
3064
  });
3022
3065
  // src/bin.ts
@@ -3032,11 +3075,13 @@ const main = defineCommand({
3032
3075
  * completion runs on every Tab, goes first: no update check, and no citty, so
3033
3076
  * a typed `--help` is a word to complete. `ork once -- <command>` skips
3034
3077
  * citty's help scan, so a `--help` or `-h` of the command is the command's.
3078
+ * An argument error of a command with no subcommands prints its message
3079
+ * alone, without the help (specs/cli/list-filters.md).
3035
3080
  */
3036
3081
  clearGitLocalEnv();
3037
3082
  const argv = takePlainFlag(process.argv.slice(2));
3038
3083
  if (argv[0] === "__complete") {
3039
- const { printCompletions } = await import("./completion-DIXWlnAl.mjs");
3084
+ const { printCompletions } = await import("./completion-DKPuD_Rw.mjs");
3040
3085
  await printCompletions(main, argv.slice(1));
3041
3086
  } else if (process.env["ORK_UPDATE_CHECK_CHILD"] === "1") await runUpdateChild();
3042
3087
  else {
@@ -3049,15 +3094,20 @@ else {
3049
3094
  const dash = argv.indexOf("--");
3050
3095
  const askedHelp = argv.slice(1, dash === -1 ? 0 : dash).some((arg) => arg === "--help" || arg === "-h");
3051
3096
  if (argv[0] === "once" && dash !== -1 && !askedHelp) try {
3052
- const { once } = await import("./once-DuUzpzL2.mjs");
3097
+ const { once } = await import("./once-BKn3pOtg.mjs");
3053
3098
  await runCommand(once, { rawArgs: argv.slice(1) });
3054
3099
  } catch (error) {
3055
3100
  console.error(error);
3056
3101
  process.exitCode = 1;
3057
3102
  }
3058
- else await runMain(main, {
3059
- rawArgs: argv,
3060
- showUsage: showHelp
3061
- });
3103
+ else {
3104
+ const wantsHelp = argv.some((arg) => arg === "--help" || arg === "-h");
3105
+ await runMain(main, {
3106
+ rawArgs: argv,
3107
+ showUsage: async (cmd, parent) => {
3108
+ if (wantsHelp || cmd.subCommands !== void 0) await showHelp(cmd, parent);
3109
+ }
3110
+ });
3111
+ }
3062
3112
  }
3063
3113
  export {};
@@ -1,8 +1,8 @@
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";
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";
4
4
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
5
- import { t as loadWorkflow } from "./validate-BS0nCccW.mjs";
5
+ import { t as loadWorkflow } from "./validate-UrmC5AG1.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
@@ -56,9 +56,11 @@ const problemsOf = (loaded, inputs) => {
56
56
  /**
57
57
  * The inputs and run id `ork run` starts with: those it was given and, for
58
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.
59
+ * takes them. `undefined` after saying why it can't start. With `mark` false
60
+ * nothing is marked taken: a `--detach` parent checks before it makes the run
61
+ * folder, and the run it starts marks them.
60
62
  */
61
- const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh) => {
63
+ const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh, mark = true) => {
62
64
  const inputs = flagValues(rawArgs, "--input");
63
65
  const plain = {
64
66
  inputs,
@@ -72,9 +74,15 @@ const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh) => {
72
74
  const project = loaded.place.root;
73
75
  const named = values.filter((value) => value !== DUE);
74
76
  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) : [];
77
+ const isLive = runIsLive(store);
78
+ const { ids: due, held } = values.includes(DUE) ? availableDue(store, project, isLive, runId) : {
79
+ ids: [],
80
+ held: []
81
+ };
82
+ for (const f of held) writeErr(`${FLAG} ${DUE}: skipped ${f.id}, taken by run ${f.takenBy}, still running.`);
76
83
  if (named.length === 0 && due.length === 0) {
77
- writeErr(`${FLAG} ${DUE}: no agent follow-ups are due. \`ork follow-ups list\` shows them.`);
84
+ const reason = held.length > 0 ? ` ${held.length} due ${held.length === 1 ? "one is" : "ones are"} taken by a run still running.` : "";
85
+ writeErr(`${FLAG} ${DUE}: no agent follow-ups are due.${reason} \`ork follow-ups list\` shows them.`);
78
86
  process.exitCode = 1;
79
87
  return;
80
88
  }
@@ -86,11 +94,13 @@ const prepareFollowUps = async (store, rawArgs, runId, target, gh = runGh) => {
86
94
  return;
87
95
  }
88
96
  const followUps = [...new Map(takeable.followUps.map((f) => [f.id, f])).values()];
97
+ if (!mark) return plain;
89
98
  const taker = runId ?? newRunId(store);
90
99
  takeFollowUps(store, {
91
100
  project,
92
101
  run: taker,
93
- ids: followUps.map((f) => f.id)
102
+ ids: followUps.map((f) => f.id),
103
+ isLive
94
104
  });
95
105
  return {
96
106
  inputs: [...inputs, `brief=${briefOf(followUps)}`],
@@ -1,4 +1,4 @@
1
- import { Gr as plainPathInside, Kr as writePlainFile, Pr as placeFiles, Wr as guardedBase } from "./src-DLsFsmOD.mjs";
1
+ import { $r as guardedBase, Ur as placeFiles, ei as plainPathInside, ti as writePlainFile } from "./src-Ciy7i3se.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { createHash } from "node:crypto";
@@ -60,4 +60,4 @@ const subcommandsOf = async (cmd) => {
60
60
  };
61
61
  /** The subcommand `name` (or one of its aliases) of `entries`. */
62
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 };
63
+ export { resolved as a, publicArgs as i, argsOf as n, subcommandsOf as o, findEntry as r, argInfoOf as t };