@krapht/ork 1.0.0-alpha.10 → 1.0.0-alpha.11

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 (35) hide show
  1. package/dist/{__build_info__-DFF18K8y.mjs → __build_info__-CIchF6nr.mjs} +3 -72
  2. package/dist/bin.mjs +1066 -387
  3. package/dist/chips-BA7SrrH5.mjs +43 -0
  4. package/dist/{clean-DVaEH9e7.mjs → clean-Di-KT7Mf.mjs} +1 -1
  5. package/dist/{completion-Dv5kf598.mjs → completion-C5D0sEs5.mjs} +22 -15
  6. package/dist/{context-CEaKOVmG.mjs → context-BaNshWr9.mjs} +43 -31
  7. package/dist/{decide-3l9q8UtX.mjs → decide-B6PnKeqo.mjs} +1 -1
  8. package/dist/{find-DEjjOlTG.mjs → find-BicBbGMg.mjs} +1 -1
  9. package/dist/{format-Cb5_m-Qd.mjs → format-lWhN-jYR.mjs} +130 -35
  10. package/dist/{in-a-run-BS9Nc-JW.mjs → in-a-run-CgkVouyG.mjs} +1 -1
  11. package/dist/{limits-BSwEjQST.mjs → limits-jZQp9ZJC.mjs} +1 -1
  12. package/dist/{list-Qxr6rwsY.mjs → list-CEaJ07jd.mjs} +1 -1
  13. package/dist/{mcp-CslnG5wf.mjs → mcp-DYgVA9f5.mjs} +6 -6
  14. package/dist/output-CM95njYt.mjs +421 -0
  15. package/dist/{pause-D7OVB5Ac.mjs → pause-D6PuSlNl.mjs} +4 -4
  16. package/dist/{relay-EceRIebO.mjs → relay-DNx7be9k.mjs} +2 -2
  17. package/dist/{remove-0IQZVWmI.mjs → remove-CpMb4NDl.mjs} +3 -3
  18. package/dist/{report-DK4LGqwF.mjs → report-CEN8VoUb.mjs} +31 -20
  19. package/dist/{send-C0uwfUYi.mjs → send-CLs_fyg7.mjs} +3 -3
  20. package/dist/{src-cmmXKHn1.mjs → src-9iGkjnsy.mjs} +234 -150
  21. package/dist/{src-i5k2Y-kf.mjs → src-B6KvTm7B.mjs} +78 -11
  22. package/dist/{src-oaJYIddp.mjs → src-BnZgZGrf.mjs} +523 -81
  23. package/dist/{src-Df6KOIDC.mjs → src-D6_xjm-x.mjs} +1722 -825
  24. package/dist/ui/assets/{app-qs8Lofv6.js → app-CxURph7a.js} +16 -16
  25. package/dist/ui/assets/app-QoHVi-mb.css +1 -0
  26. package/dist/ui/assets/{index-DV1ZaOk-.js → index-By_8KKG6.js} +2 -2
  27. package/dist/ui/index.html +1 -1
  28. package/dist/{ui-CBkHJdqk.mjs → ui-CIci4UBW.mjs} +4 -4
  29. package/dist/{usage-Cd8pEYyK.mjs → usage-GceBGMjU.mjs} +43 -32
  30. package/dist/{watch-DW5R2OPO.mjs → watch-BmoybMQg.mjs} +28 -16
  31. package/dist/{workflows-BT1gDRIV.mjs → workflows-DZvW3i1e.mjs} +3 -3
  32. package/dist/{worktrees-g1MQMGie.mjs → worktrees-Be51E2rB.mjs} +11 -10
  33. package/package.json +1 -1
  34. package/dist/output-Bqljtmp_.mjs +0 -40
  35. package/dist/ui/assets/app-C8uhHVYp.css +0 -1
@@ -0,0 +1,43 @@
1
+ import { c as CHIP, l as NODE_PALETTE, u as apply } from "./output-CM95njYt.mjs";
2
+ // src/term/chips.ts
3
+ /** The chip words the kit's commands use. */
4
+ const CHIP_LABELS = {
5
+ ask: "ASK",
6
+ run: "RUN",
7
+ ok: "OK",
8
+ fail: "FAIL",
9
+ wait: "WAIT",
10
+ warn: "WARN",
11
+ skip: "SKIP",
12
+ error: "ERROR"
13
+ };
14
+ /** A run's or trigger's state word as a chip: its label and role. */
15
+ const statusChip = (status) => {
16
+ const role = status === "running" ? "accent" : status === "succeeded" ? "ok" : status === "failed" || status === "crashed" ? "danger" : [
17
+ "paused",
18
+ "budget_exhausted",
19
+ "quota_exhausted",
20
+ "timed_out",
21
+ "interrupted"
22
+ ].includes(status) ? "warn" : "muted";
23
+ return {
24
+ label: status === "running" ? CHIP_LABELS.run : status === "succeeded" ? CHIP_LABELS.ok : status === "failed" ? CHIP_LABELS.fail : status.replaceAll("_", " ").toUpperCase(),
25
+ role
26
+ };
27
+ };
28
+ /** A chip: ` LABEL ` on the role's background; `[LABEL]` when plain. */
29
+ const chip = (term, label, role) => term.rich ? apply(term, CHIP[role], ` ${label} `) : `[${label}]`;
30
+ /** A stable non-negative number for `text` (FNV-1a). */
31
+ const hash = (text) => {
32
+ let h = 2166136261;
33
+ for (const char of text) h = Math.imul(h ^ (char.codePointAt(0) ?? 0), 16777619);
34
+ return h >>> 0;
35
+ };
36
+ /** The palette slot of a node id, 0 to 5, the same on every call. */
37
+ const nodeSlot = (id) => hash(id) % NODE_PALETTE.length;
38
+ /** A node's chip: its id on the color its id picks; `[id]` when plain. */
39
+ const nodeChip = (term, id) => {
40
+ const format = NODE_PALETTE[nodeSlot(id)] ?? CHIP.muted;
41
+ return term.rich ? apply(term, format, ` ${id} `) : `[${id}]`;
42
+ };
43
+ export { statusChip as i, chip as n, nodeChip as r, CHIP_LABELS as t };
@@ -1,4 +1,4 @@
1
- import { N as gitOk, j as removeWorktree } from "./src-Df6KOIDC.mjs";
1
+ import { D as removeWorktree, k as gitOk } from "./src-D6_xjm-x.mjs";
2
2
  // ../core/src/worktree/clean.ts
3
3
  /**
4
4
  * @file What `ork worktrees clean` and `ork worktrees remove` do with what
@@ -1,9 +1,9 @@
1
- import { D as openStore, O as storePath, Tn as placeFor, bt as liveStatus, mr as AGENT_DRIVERS, rr as NodeIdSchema, wn as placeFiles } from "./src-Df6KOIDC.mjs";
2
- import { a as builtinWorkflowNames, n as pendingDecisions, o as builtinWorkflowText, s as isBuiltinArg } from "./decide-3l9q8UtX.mjs";
3
- import { t as findRun } from "./find-DEjjOlTG.mjs";
1
+ import { Ar as AGENT_DRIVERS, Bn as placeFiles, C as openStore, Vn as placeFor, w as storePath, xt as liveStatus, yr as NodeIdSchema } from "./src-D6_xjm-x.mjs";
2
+ import { a as builtinWorkflowNames, n as pendingDecisions, o as builtinWorkflowText, s as isBuiltinArg } from "./decide-B6PnKeqo.mjs";
3
+ import { t as findRun } from "./find-BicBbGMg.mjs";
4
4
  import { a as findEntry, c as subcommandsOf, d as SHELL_SCRIPTS, l as COMPLETE_COMMAND, n as groupedEntries, r as argInfoOf, t as groupOf, u as SHELLS } from "./help-groups-BwYoAWsh.mjs";
5
- import { o as writeErr } from "./output-Bqljtmp_.mjs";
6
- import { a as resolveWorkflowArg, n as WORKFLOW_SUFFIX } from "./workflows-BT1gDRIV.mjs";
5
+ import { o as writeErr } from "./output-CM95njYt.mjs";
6
+ import { a as resolveWorkflowArg, n as WORKFLOW_SUFFIX } from "./workflows-DZvW3i1e.mjs";
7
7
  import path from "node:path";
8
8
  import { parse } from "yaml";
9
9
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
@@ -184,16 +184,23 @@ const subcommandSections = (position) => {
184
184
  };
185
185
  const flagSection = (position) => ({
186
186
  title: "flags",
187
- candidates: [...position.flags.flatMap((flag) => [{
188
- value: `--${flag.name}`,
189
- description: brief(flag.description)
190
- }, ...flag.negatable ? [{
191
- value: `--no-${flag.name}`,
192
- description: `Turn off --${flag.name}`
193
- }] : []]), {
194
- value: "--help",
195
- description: "Show this command's help"
196
- }]
187
+ candidates: [
188
+ ...position.flags.flatMap((flag) => [{
189
+ value: `--${flag.name}`,
190
+ description: brief(flag.description)
191
+ }, ...flag.negatable ? [{
192
+ value: `--no-${flag.name}`,
193
+ description: `Turn off --${flag.name}`
194
+ }] : []]),
195
+ {
196
+ value: "--plain",
197
+ description: "Plain output, no color or redraw"
198
+ },
199
+ {
200
+ value: "--help",
201
+ description: "Show this command's help"
202
+ }
203
+ ]
197
204
  });
198
205
  const fromProvider = (provider, context) => provider === void 0 ? NONE : {
199
206
  sections: [{
@@ -1,7 +1,8 @@
1
- import { C as workflowTextHash, D as openStore, Mn as LESSON_CAP_TOKENS, O as storePath, R as driverRefusals, Rt as loadProject, S as readProjectTriggers, Tn as placeFor, _ as lateTriggers, _r as EXPERIMENTS, dr as readyDriver, gr as firstLine, hr as DRIVER_IDS, ht as walkSummary, ir as retiredDriverHint, kn as workflowDirOf, lt as namingNoDriver, mr as AGENT_DRIVERS, mt as walkChecks, nr as DriverSchema, on as socketRoom, or as INTEGRATIONS, pt as checkWorkflowText, st as explainSession, ur as driverChecks, v as triggersReport, vr as experimentsOn, wn as placeFiles, yr as knownExperiments, z as driverQueues } from "./src-Df6KOIDC.mjs";
2
- import { c as checkDue, d as pendingNotice, f as readUpdateCache, h as writeUpdateCache, i as registryOf, m as updateCachePath, n as ORK_VERSION, o as updateSwitchOff, p as refreshUpdateCache, r as isSwitchedOn, t as ORK_NAME, u as newerVersion } from "./__build_info__-DFF18K8y.mjs";
3
- import { a as write, i as style, o as writeErr, r as plain } from "./output-Bqljtmp_.mjs";
4
- import { c as registeredProjects, i as refusedBuiltin, o as workflowArg, r as findWorkflowFiles, s as projectAt } from "./workflows-BT1gDRIV.mjs";
1
+ import { Ar as AGENT_DRIVERS, Bn as placeFiles, C as openStore, Dr as readyDriver, Er as driverChecks, F as driverQueues, Fr as knownExperiments, Gn as workflowDirOf, Jn as LESSON_CAP_TOKENS, Mr as firstLine, Nr as EXPERIMENTS, P as driverRefusals, Pr as experimentsOn, Sn as socketRoom, Sr as INTEGRATIONS, Vn as placeFor, _ as readProjectTriggers, br as retiredDriverHint, ct as explainSession, f as lateTriggers, gt as walkSummary, ht as walkChecks, jr as DRIVER_IDS, mt as checkWorkflowText, p as triggersReport, qt as loadProject, ut as namingNoDriver, v as workflowTextHash, vr as DriverSchema, w as storePath } from "./src-D6_xjm-x.mjs";
2
+ import { c as checkDue, d as pendingNotice, f as readUpdateCache, h as writeUpdateCache, i as registryOf, m as updateCachePath, n as ORK_VERSION, o as updateSwitchOff, p as refreshUpdateCache, r as isSwitchedOn, t as ORK_NAME, u as newerVersion } from "./__build_info__-CIchF6nr.mjs";
3
+ import { C as widthOf, a as write, b as termOf, f as paint, i as style, o as writeErr, r as plain, v as plainEnv, w as wrap, x as cut } from "./output-CM95njYt.mjs";
4
+ import { n as chip, t as CHIP_LABELS } from "./chips-BA7SrrH5.mjs";
5
+ import { c as registeredProjects, i as refusedBuiltin, o as workflowArg, r as findWorkflowFiles, s as projectAt } from "./workflows-DZvW3i1e.mjs";
5
6
  import path from "node:path";
6
7
  import { readFileSync } from "node:fs";
7
8
  import { execFile, spawn } from "node:child_process";
@@ -73,7 +74,7 @@ const showUpdateNotice = (file = updateCachePath(), now = /* @__PURE__ */ new Da
73
74
  const latest = pendingNotice(cache, ORK_VERSION, now);
74
75
  if (cache === null || latest === null) return;
75
76
  const text = updateNotice(latest, ORK_VERSION);
76
- process.stderr.write(`\n${styleText("yellow", text, { stream: process.stderr })}\n`);
77
+ process.stderr.write(`\n${plainEnv() ? text : styleText("yellow", text, { stream: process.stderr })}\n`);
77
78
  writeUpdateCache(file, {
78
79
  ...cache,
79
80
  notified: {
@@ -417,6 +418,41 @@ const pathLines = (walk) => {
417
418
  const endings = walk?.endings ?? [];
418
419
  return [...endings.filter(({ status }) => status === "succeeded"), ...endings.filter(({ status }) => status !== "succeeded")].flatMap((ending) => endingLines(ending));
419
420
  };
421
+ // src/commands/validate-report.ts
422
+ const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
423
+ const diagnosticLine = (file, d, term) => {
424
+ const where = d.line === void 0 ? file : `${file}:${d.line}:${d.column ?? 1}`;
425
+ if (term.rich) return [
426
+ `${d.severity === "error" ? chip(term, CHIP_LABELS.error, "danger") : chip(term, CHIP_LABELS.warn, "warn")} ${paint(term, "muted", cut(where, term.width - 9))}`,
427
+ ...wrap(d.message, term.width - 2).map((line) => ` ${line}`),
428
+ ` ${paint(term, "muted", `(${d.code})`)}`
429
+ ];
430
+ const severity = d.severity === "error" ? style(["red", "bold"], "error") : style(["yellow", "bold"], "warning");
431
+ return [`${style("dim", where)} ${severity} ${d.message} ${style("dim", `(${d.code})`)}`];
432
+ };
433
+ /** The warnings alone, for a run that goes ahead despite them. */
434
+ const warningLines = (report, term = termOf(process.stderr)) => report.diagnostics.filter((d) => d.severity === "warning").flatMap((d) => diagnosticLine(report.file, d, term));
435
+ /** The verdict line: `OK` or `FAIL` chip when rich, else `✓` or `✗`. */
436
+ const verdictLine = (term, ok, file, note) => {
437
+ const mark = term.rich ? chip(term, ok ? CHIP_LABELS.ok : CHIP_LABELS.fail, ok ? "ok" : "danger") : style(ok ? "green" : "red", ok ? "✓" : "✗");
438
+ const room = term.rich ? Math.max(8, term.width - widthOf(file) - 8) : Infinity;
439
+ return `${mark} ${file}${note === "" ? "" : ` ${style("dim", cut(note, room))}`}`;
440
+ };
441
+ /** Human-readable report, one line per diagnostic, compiler style. */
442
+ const formatReport = (report, showsPaths = false, term = termOf(process.stdout)) => {
443
+ const lines = report.diagnostics.flatMap((d) => diagnosticLine(report.file, d, term));
444
+ const errors = report.diagnostics.filter((d) => d.severity === "error").length;
445
+ const warnings = report.diagnostics.length - errors;
446
+ if (report.summary === void 0 && errors === 0) lines.push(verdictLine(term, true, report.file, warnings === 0 ? "" : `(${plural(warnings, "warning")})`));
447
+ else if (report.summary !== void 0 && errors === 0) {
448
+ const { nodes, edges, entries } = report.summary;
449
+ const extra = warnings > 0 ? `, ${plural(warnings, "warning")}` : "";
450
+ lines.push(verdictLine(term, true, report.file, `(${plural(nodes, "node")}, ${plural(edges, "edge")}, starts at ${entries.join(", ")}${extra})`));
451
+ } else lines.push(verdictLine(term, false, report.file, `(${plural(errors, "error")}, ${plural(warnings, "warning")})`));
452
+ return [...lines, ...walkLine(report.walk, showsPaths)];
453
+ };
454
+ /** A report's lines, and with `showsPaths` each path the walk found. */
455
+ const reportLines = (report, showsPaths) => [...formatReport(report, showsPaths), ...showsPaths ? pathLines(report.walk) : []];
420
456
  // src/commands/validate.ts
421
457
  /**
422
458
  * @file `ork validate`: loads, parses and compiles workflow files with the
@@ -494,27 +530,6 @@ const walkLoaded = async (loaded) => {
494
530
  }
495
531
  };
496
532
  };
497
- const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
498
- const diagnosticLine = (file, d) => {
499
- const where = d.line === void 0 ? file : `${file}:${d.line}:${d.column ?? 1}`;
500
- const severity = d.severity === "error" ? style(["red", "bold"], "error") : style(["yellow", "bold"], "warning");
501
- return `${style("dim", where)} ${severity} ${d.message} ${style("dim", `(${d.code})`)}`;
502
- };
503
- /** The warnings alone, for a run that goes ahead despite them. */
504
- const warningLines = (report) => report.diagnostics.filter((d) => d.severity === "warning").map((d) => diagnosticLine(report.file, d));
505
- /** Human-readable report, one line per diagnostic, compiler style. */
506
- const formatReport = (report, showsPaths = false) => {
507
- const lines = report.diagnostics.map((d) => diagnosticLine(report.file, d));
508
- const errors = report.diagnostics.filter((d) => d.severity === "error").length;
509
- const warnings = report.diagnostics.length - errors;
510
- if (report.summary === void 0 && errors === 0) lines.push(`${style("green", "✓")} ${report.file}${warnings === 0 ? "" : style("dim", ` (${plural(warnings, "warning")})`)}`);
511
- else if (report.summary !== void 0 && errors === 0) {
512
- const { nodes, edges, entries } = report.summary;
513
- const extra = warnings > 0 ? `, ${plural(warnings, "warning")}` : "";
514
- lines.push(`${style("green", "✓")} ${report.file} ${style("dim", `(${plural(nodes, "node")}, ${plural(edges, "edge")}, starts at ${entries.join(", ")}${extra})`)}`);
515
- } else lines.push(`${style("red", "✗")} ${report.file} ${style("dim", `(${plural(errors, "error")}, ${plural(warnings, "warning")})`)}`);
516
- return [...lines, ...walkLine(report.walk, showsPaths)];
517
- };
518
533
  const validate = defineCommand({
519
534
  meta: {
520
535
  name: "validate",
@@ -573,10 +588,7 @@ const validate = defineCommand({
573
588
  diagnostics: [...triggers.diagnostics, ...triggers.triggers.flatMap((item) => item.diagnostics)]
574
589
  }] : []];
575
590
  if (args.json) write(JSON.stringify(reports, void 0, 2));
576
- else for (const report of reports) {
577
- for (const line of formatReport(report, args.paths)) write(line);
578
- if (args.paths) for (const line of pathLines(report.walk)) write(line);
579
- }
591
+ else for (const report of reports) for (const line of reportLines(report, args.paths)) write(line);
580
592
  if (reports.some((r) => hasErrors(r.diagnostics))) process.exitCode = 1;
581
593
  }
582
594
  });
@@ -680,4 +692,4 @@ const context = defineCommand({
680
692
  },
681
693
  subCommands: { explain }
682
694
  });
683
- export { startUpdateCheck as C, showUpdateNotice as S, runChecks as _, validate as a, UPDATE_CHILD_ENV as b, warningLines as c, runReadyDriver as d, unfitLines as f, orkCheck as g, headWarning as h, loadWorkflow as i, checksHere as l, experimentsCheck as m, explainNode as n, validateFile as o, exec as p, formatReport as r, walkLoaded as s, context as t, chooseReadyDriver as u, socketCheck as v, updateCheckOff as w, runUpdateChild as x, triggerChecks as y };
695
+ export { startUpdateCheck as C, showUpdateNotice as S, runChecks as _, validateFile as a, UPDATE_CHILD_ENV as b, warningLines as c, runReadyDriver as d, unfitLines as f, orkCheck as g, headWarning as h, validate as i, checksHere as l, experimentsCheck as m, explainNode as n, walkLoaded as o, exec as p, loadWorkflow as r, formatReport as s, context as t, chooseReadyDriver as u, socketCheck as v, updateCheckOff as w, runUpdateChild as x, triggerChecks as y };
@@ -1,4 +1,4 @@
1
- import { Fn as plainPathInside, In as writePlainFile, Pn as guardedBase, an as socketPath, bt as liveStatus, sn as wakeRun, wn as placeFiles } from "./src-Df6KOIDC.mjs";
1
+ import { Bn as placeFiles, Cn as wakeRun, Qn as writePlainFile, Xn as guardedBase, Zn as plainPathInside, xn as socketPath, xt as liveStatus } from "./src-D6_xjm-x.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { createHash } from "node:crypto";
@@ -1,4 +1,4 @@
1
- import { Tn as placeFor } from "./src-Df6KOIDC.mjs";
1
+ import { Vn as placeFor } from "./src-D6_xjm-x.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  // ../core/src/remote/find.ts
4
4
  /**
@@ -1,5 +1,20 @@
1
- import { Dt as isItem, bt as liveStatus } from "./src-Df6KOIDC.mjs";
2
- import { i as style, n as cost } from "./output-Bqljtmp_.mjs";
1
+ import { Ct as runStatus, Tt as slotWaitsOf, kt as isItem, xt as liveStatus } from "./src-D6_xjm-x.mjs";
2
+ import { C as widthOf, b as termOf, i as style, n as cost, u as apply, x as cut } from "./output-CM95njYt.mjs";
3
+ import { i as statusChip, n as chip, t as CHIP_LABELS } from "./chips-BA7SrrH5.mjs";
4
+ // src/run/view.ts
5
+ /**
6
+ * @file How a run's lines are drawn: the terminal kit's {@link Term} for the
7
+ * stream they go to, and what a transcript has to remember between events (a
8
+ * node's worktree, to show its paths relative to it). Plain, a view draws
9
+ * today's line-based transcript; rich, it draws chips and cuts to the width.
10
+ */
11
+ /** A view for `stream` (stdout when not given), as `env` sets it. */
12
+ const createView = (stream = process.stdout, env = process.env) => ({
13
+ term: termOf(stream, env),
14
+ roots: /* @__PURE__ */ new Map()
15
+ });
16
+ /** Styles text for `term`: no escape codes when it is plain. */
17
+ const styler = (term) => (format, text) => apply(term, format, text);
3
18
  // src/run/format-bus.ts
4
19
  /** The first line of a message body, cut to fit one terminal line. */
5
20
  const firstLine = (body) => {
@@ -7,7 +22,8 @@ const firstLine = (body) => {
7
22
  return line.length > 100 ? `${line.slice(0, 99)}…` : line;
8
23
  };
9
24
  /** Messages, owner questions and claims, without the node prefix. */
10
- const formatBusEvent = (event) => {
25
+ const formatBusEvent = (event, term = createView().term) => {
26
+ const style = styler(term);
11
27
  if (event.type === "claim.taken") return [style("dim", `⚑ claimed ${event.resource}`)];
12
28
  if (event.type === "claim.refused") {
13
29
  const held = event.held === event.resource ? "" : ` (it holds ${event.held})`;
@@ -25,7 +41,7 @@ const formatBusEvent = (event) => {
25
41
  if (event.type === "call.started") return [style("dim", `↳ started ${event.workflow} as run ${event.run}`)];
26
42
  if (event.type === "link.notice") return [style("dim", `↔ ${event.text}`)];
27
43
  if (event.type === "message.read") return [];
28
- if (event.type === "owner.asked") return [`${style(["yellow", "bold"], "?")} asked as the owner of ${event.about}: ${event.text} ${style("dim", `(${event.question})`)}`];
44
+ if (event.type === "owner.asked") return [`${term.rich ? chip(term, CHIP_LABELS.ask, "accent") : style(["yellow", "bold"], "?")} asked as the owner of ${event.about}: ${event.text} ${style("dim", `(${event.question})`)}`];
29
45
  if (event.type === "owner.answered") return [style("dim", `→ ${event.answer} (owner)`)];
30
46
  return [style("dim", "→ its session ended first; asking you")];
31
47
  };
@@ -66,6 +82,54 @@ const nodeVerdict = (output, ok = true, error) => {
66
82
  if (typeof count === "number") return itemsRan(count, output["statuses"]);
67
83
  return "done";
68
84
  };
85
+ // src/term/table.ts
86
+ /**
87
+ * @file Aligned columns for the listing commands: each column as wide as its
88
+ * widest cell, a two-space gap, the last column left unpadded. Rich, a cell
89
+ * may be a chip and a table wider than the screen cuts its flexible columns
90
+ * with `…`; plain, nothing is cut or styled, as the listings always printed.
91
+ */
92
+ /** A dimmed header cell. */
93
+ const header = (text) => ({
94
+ text,
95
+ look: (s) => style("dim", s)
96
+ });
97
+ const GAP = " ";
98
+ /** A flexible column is never cut under this many columns. */
99
+ const MIN_FLEX = 8;
100
+ /** The text a cell shows, and its columns. */
101
+ const shown = (term, cell) => term.rich && cell.chip !== void 0 ? cell.chip.label : cell.text;
102
+ const widthOfCell = (term, cell) => widthOf(shown(term, cell)) + (term.rich && cell.chip !== void 0 ? 2 : 0);
103
+ /** The lines of a table, one per row (a header is a row the caller passes). */
104
+ const table = (term, columns, rows, indent = "") => {
105
+ const widths = columns.map((_, c) => Math.max(0, ...rows.map((row) => widthOfCell(term, row[c] ?? { text: "" }))));
106
+ if (term.rich) {
107
+ const gaps = 2 * (columns.length - 1);
108
+ let over = indent.length + widths.reduce((a, b) => a + b, 0) + gaps - term.width;
109
+ columns.forEach((column, c) => {
110
+ const width = widths[c] ?? 0;
111
+ if (over <= 0 || column.flex !== true || width <= MIN_FLEX) return;
112
+ const next = Math.max(MIN_FLEX, width - over);
113
+ over -= width - next;
114
+ widths[c] = next;
115
+ });
116
+ }
117
+ const last = columns.length - 1;
118
+ return rows.map((row) => indent + columns.map((column, c) => {
119
+ const cell = row[c] ?? { text: "" };
120
+ const width = widths[c] ?? 0;
121
+ const look = cell.look ?? ((s) => s);
122
+ if (term.rich && cell.chip !== void 0) {
123
+ const used = widthOfCell(term, cell);
124
+ const pad = " ".repeat(Math.max(0, width - used));
125
+ return column.align === "right" ? pad + chip(term, cell.chip.label, cell.chip.role) : chip(term, cell.chip.label, cell.chip.role) + (c === last ? "" : pad);
126
+ }
127
+ const text = cut(shown(term, cell), width);
128
+ const pad = " ".repeat(Math.max(0, width - widthOf(text)));
129
+ if (column.align === "right") return look(pad + text);
130
+ return c === last ? look(text) : look(text + pad);
131
+ }).join(GAP));
132
+ };
69
133
  // src/runs/format.ts
70
134
  /**
71
135
  * @file How stored runs read on the terminal: the `ork ps` table and the `ork
@@ -99,11 +163,21 @@ const duration = (ms) => {
99
163
  if (s < 3600) return `${String(Math.floor(s / 60))}m${String(s % 60).padStart(2, "0")}s`;
100
164
  return `${String(Math.floor(s / 3600))}h${String(Math.floor(s % 3600 / 60)).padStart(2, "0")}m`;
101
165
  };
166
+ const dim = (s) => style("dim", s);
167
+ /**
168
+ * A run's status as `ork ps` reads it: `waiting for slot` for a running run
169
+ * with a command waiting for a machine-wide slot; `events` are a running
170
+ * run's.
171
+ */
172
+ const listedStatus = (run, events) => {
173
+ const status = runStatus(run, events);
174
+ return status === "running" && slotWaitsOf(events).length > 0 ? "waiting for slot" : status;
175
+ };
102
176
  /**
103
177
  * The `ork ps` table; `withProject` adds each run's project. A called run's
104
178
  * cost is dimmed and says its caller's, whose cost already counts it.
105
179
  */
106
- const formatRuns = (runs, withProject, now = Date.now(), statusOf = liveStatus) => {
180
+ const formatRuns = (runs, withProject, now = Date.now(), statusOf = liveStatus, term = termOf(process.stdout)) => {
107
181
  if (runs.length === 0) return ["No runs."];
108
182
  const rows = runs.map((run) => {
109
183
  const status = statusOf(run);
@@ -118,37 +192,58 @@ const formatRuns = (runs, withProject, now = Date.now(), statusOf = liveStatus)
118
192
  project: run.project
119
193
  };
120
194
  });
121
- const width = (pick, title) => Math.max(title.length, ...rows.map((r) => pick(r).length));
122
- const w = {
123
- id: width((r) => r.id, "RUN"),
124
- workflow: width((r) => r.workflow, "WORKFLOW"),
125
- status: width((r) => r.status, "STATUS"),
126
- when: width((r) => r.when, "STARTED"),
127
- cost: width((r) => r.cost, "COST")
195
+ const rowOf = (r) => {
196
+ const cells = [
197
+ {
198
+ text: r.id,
199
+ look: (s) => style("bold", s)
200
+ },
201
+ { text: r.workflow },
202
+ {
203
+ text: r.status,
204
+ chip: statusChip(r.status),
205
+ look: (s) => style(STATUS_STYLE[r.status] ?? "reset", s)
206
+ },
207
+ {
208
+ text: r.when,
209
+ look: dim
210
+ },
211
+ r.called ? {
212
+ text: r.cost,
213
+ look: dim
214
+ } : { text: r.cost }
215
+ ];
216
+ if (withProject) cells.push({
217
+ text: r.project,
218
+ look: dim
219
+ });
220
+ return cells;
128
221
  };
129
- const header = [
130
- "RUN".padEnd(w.id),
131
- "WORKFLOW".padEnd(w.workflow),
132
- "STATUS".padEnd(w.status),
133
- "STARTED".padEnd(w.when),
134
- "COST".padStart(w.cost),
135
- ...withProject ? ["PROJECT"] : []
136
- ].join(" ");
137
- return [style("dim", header), ...rows.map((r) => [
138
- style("bold", r.id.padEnd(w.id)),
139
- r.workflow.padEnd(w.workflow),
140
- style(STATUS_STYLE[r.status] ?? "reset", r.status.padEnd(w.status)),
141
- style("dim", r.when.padEnd(w.when)),
142
- r.called ? style("dim", r.cost.padStart(w.cost)) : r.cost.padStart(w.cost),
143
- ...withProject ? [style("dim", r.project)] : []
144
- ].join(" "))];
222
+ const heads = [
223
+ "RUN",
224
+ "WORKFLOW",
225
+ "STATUS",
226
+ "STARTED",
227
+ "COST"
228
+ ].map((text) => header(text));
229
+ if (withProject) heads.push(header("PROJECT"));
230
+ const columns = [
231
+ {},
232
+ { flex: true },
233
+ {},
234
+ {},
235
+ { align: "right" }
236
+ ];
237
+ if (withProject) columns.push({ flex: true });
238
+ return table(term, columns, [heads, ...rows.map((row) => rowOf(row))]);
145
239
  };
240
+ /** Marks are made when used, so `--plain` (set after load) is read. */
146
241
  const STATE_MARK = {
147
- waiting: style("dim", "·"),
148
- running: style("cyan", "●"),
149
- ok: style("green", "✓"),
150
- failed: style("red", "✗"),
151
- skipped: style("dim", "-")
242
+ waiting: () => style("dim", "·"),
243
+ running: () => style("cyan", "●"),
244
+ ok: () => style("green", "✓"),
245
+ failed: () => style("red", "✗"),
246
+ skipped: () => style("dim", "-")
152
247
  };
153
248
  /** `950`, `12.3k`, `1.2M`. */
154
249
  const count = (n) => {
@@ -183,9 +278,9 @@ const formatTree = (roots, now = Date.now()) => {
183
278
  const type = Math.max(...lines.map((l) => l.node.type.length));
184
279
  return lines.map(({ label: text, node }) => {
185
280
  const usage = node.inputTokens + node.outputTokens === 0 ? "" : style("dim", ` ${count(node.inputTokens)} in / ${count(node.outputTokens)} out · ${cost(node.costUsd)}`);
186
- const state = node.held === true ? `${style("yellow", "‖")} paused` : `${STATE_MARK[node.state]} ${stateText(node)}`;
281
+ const state = node.held === true ? `${style("yellow", "‖")} paused` : `${STATE_MARK[node.state]()} ${stateText(node)}`;
187
282
  const spent = isItem(node) && node.startedAt !== void 0 ? style("dim", ` ${duration((node.finishedAt === void 0 ? now : Date.parse(node.finishedAt)) - Date.parse(node.startedAt))}`) : "";
188
283
  return `${text.padEnd(label)} ${style("dim", node.type.padEnd(type))} ${state}${spent}${usage}`;
189
284
  });
190
285
  };
191
- export { nodeVerdict as a, hasConflict as i, formatRuns as n, firstLine as o, formatTree as r, formatBusEvent as s, ago as t };
286
+ export { header as a, nodeVerdict as c, createView as d, styler as f, listedStatus as i, firstLine as l, formatRuns as n, table as o, formatTree as r, hasConflict as s, ago as t, formatBusEvent as u };
@@ -1,4 +1,4 @@
1
- import { p as runMarkerIn } from "./src-cmmXKHn1.mjs";
1
+ import { p as runMarkerIn } from "./src-9iGkjnsy.mjs";
2
2
  // src/commands/in-a-run.ts
3
3
  /**
4
4
  * @file The commands that act as the user refuse a program or an agent in a run
@@ -1,4 +1,4 @@
1
- import { a as limitsNow, i as NOT_STARTED, o as limitsReport, r as capsHere } from "./src-Df6KOIDC.mjs";
1
+ import { it as limitsReport, nt as NOT_STARTED, r as capsHere, rt as limitsNow } from "./src-D6_xjm-x.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,4 +1,4 @@
1
- import { M as git, N as gitOk, P as lines } from "./src-Df6KOIDC.mjs";
1
+ import { A as lines, O as git, k as gitOk } from "./src-D6_xjm-x.mjs";
2
2
  import { existsSync } from "node:fs";
3
3
  // ../core/src/worktree/list.ts
4
4
  /**
@@ -1,8 +1,8 @@
1
- import { h as isNewer } from "./src-Df6KOIDC.mjs";
2
- import { n as ORK_VERSION } from "./__build_info__-DFF18K8y.mjs";
3
- import { p as runMarkerIn } from "./src-cmmXKHn1.mjs";
4
- import { n as explainNode } from "./context-CEaKOVmG.mjs";
5
- import { a as openMcp, c as refused, o as tool, s as answer } from "./src-i5k2Y-kf.mjs";
1
+ import { u as isNewer } from "./src-D6_xjm-x.mjs";
2
+ import { n as ORK_VERSION } from "./__build_info__-CIchF6nr.mjs";
3
+ import { p as runMarkerIn } from "./src-9iGkjnsy.mjs";
4
+ import { n as explainNode } from "./context-BaNshWr9.mjs";
5
+ import { a as openMcp, c as refused, o as tool, s as answer } from "./src-B6KvTm7B.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.10") ? tooOld(all, options.expects) : all;
46
+ const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.11") ? tooOld(all, options.expects) : all;
47
47
  const server = new McpServer({
48
48
  name: "ork",
49
49
  version: ORK_VERSION