@krapht/ork 0.4.0 → 1.0.0-alpha.0

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 (37) hide show
  1. package/README.md +16 -12
  2. package/dist/{__build_info__-CtSVVuZE.mjs → __build_info__-DdTVd2p5.mjs} +36 -112
  3. package/dist/bin.mjs +663 -300
  4. package/dist/{clean-Dcr807be.mjs → clean-NnboOuz6.mjs} +1 -1
  5. package/dist/completion-snnYGjgK.mjs +405 -0
  6. package/dist/{context-C_bksb0C.mjs → context-DO3sBy9v.mjs} +11 -88
  7. package/dist/decide-B81wCZQg.mjs +113 -0
  8. package/dist/{find-DptmbhGd.mjs → find-BKW-uGey.mjs} +1 -1
  9. package/dist/{format-J-a21Yvn.mjs → format-CmTlTOjT.mjs} +71 -37
  10. package/dist/help-groups-BwYoAWsh.mjs +354 -0
  11. package/dist/{in-a-run-D1Qc5Mit.mjs → in-a-run-BPXX09Bs.mjs} +1 -1
  12. package/dist/{limits-BDZCmGEu.mjs → limits-JCve2QpI.mjs} +1 -1
  13. package/dist/{list-ZvY2OcLq.mjs → list-C7UEgmtd.mjs} +1 -1
  14. package/dist/{mcp-CHVKKg3B.mjs → mcp-CKPyNaKD.mjs} +7 -7
  15. package/dist/{output-CXSJO00X.mjs → output-B1V6ZJSx.mjs} +67 -17
  16. package/dist/{pause-BPSmg4yz.mjs → pause-B_SL_yDz.mjs} +4 -4
  17. package/dist/{relay-Do-aNbSD.mjs → relay-o-Luee1c.mjs} +2 -2
  18. package/dist/{remove-AwaMMaHf.mjs → remove-DAZ7ZCzt.mjs} +3 -3
  19. package/dist/{send-DhGBkowy.mjs → send-3B64fBNB.mjs} +3 -3
  20. package/dist/{src-CpDKIulI.mjs → src-BJTegEzY.mjs} +23 -13
  21. package/dist/{src-UWkk1sl9.mjs → src-C38BPzit.mjs} +251 -18
  22. package/dist/{src-CGqMati3.mjs → src-DHvWU4tX.mjs} +636 -217
  23. package/dist/{src-BHnxpJyH.mjs → src-Dyz_Gy1q.mjs} +35 -8
  24. package/dist/ui/THIRD_PARTY_LICENSES.txt +2 -2
  25. package/dist/ui/assets/app-C8nJ6NpT.js +67 -0
  26. package/dist/ui/assets/app-CH7YC3in.css +1 -0
  27. package/dist/ui/assets/{index-BiO54L90.css → index-BPIbqRRb.css} +1 -1
  28. package/dist/ui/assets/{index-MQNNgsyT.js → index-D83F2OKZ.js} +2 -2
  29. package/dist/ui/index.html +2 -3
  30. package/dist/{ui-DhutUMgQ.mjs → ui-CY4xxJUu.mjs} +5 -5
  31. package/dist/{usage-CT7Z-yjr.mjs → usage-CJnytoe4.mjs} +6 -6
  32. package/dist/{watch-0Qr2UfCQ.mjs → watch-BJB82ZJ7.mjs} +7 -7
  33. package/dist/workflows-CiM7S3l0.mjs +88 -0
  34. package/dist/{worktrees-DHl80k96.mjs → worktrees-86ySXxR6.mjs} +5 -5
  35. package/package.json +3 -3
  36. package/dist/ui/assets/app-BgVDC_5l.js +0 -67
  37. package/dist/ui/assets/app-DVf68fj5.css +0 -1
@@ -1,9 +1,9 @@
1
- import { At as FEEDBACK_KINDS, Ht as maskReplacer, J as eventOf, K as backfillUsage, Mt as FEEDBACK_TARGETS, Ut as maskSecrets, X as text, Y as inTransaction, jt as FEEDBACK_SEVERITIES, pt as ownProcessStart, q as usageQueries, sn as PROJECT_MODES } from "./src-CGqMati3.mjs";
2
- import { createInterface } from "node:readline/promises";
1
+ import { $ as text, Bt as FEEDBACK_TARGETS, Q as inTransaction, Rt as FEEDBACK_KINDS, X as usageQueries, Xt as maskReplacer, Y as backfillUsage, Z as eventOf, Zt as maskSecrets, gn as PROJECT_MODES, yt as ownProcessStart, zt as FEEDBACK_SEVERITIES } from "./src-DHvWU4tX.mjs";
3
2
  import path from "node:path";
4
3
  import { mkdirSync } from "node:fs";
5
4
  import { homedir } from "node:os";
6
5
  import { DatabaseSync } from "node:sqlite";
6
+ import { createInterface } from "node:readline/promises";
7
7
  import { stripVTControlCharacters, styleText } from "node:util";
8
8
  // ../core/src/store/drafts.ts
9
9
  const rowOf = (row) => {
@@ -49,6 +49,11 @@ const choicesOf = (json) => {
49
49
  return [choice];
50
50
  });
51
51
  };
52
+ /** A note as stored: masked, or null when blank. */
53
+ const noteOf = (note) => {
54
+ const trimmed = note?.trim() ?? "";
55
+ return trimmed === "" ? null : maskSecrets(trimmed);
56
+ };
52
57
  const kindOf = (value) => value === "permission" ? "permission" : "question";
53
58
  const statusOf$1 = (value) => value === "answered" || value === "withdrawn" ? value : "open";
54
59
  const decisionOf = (row) => {
@@ -66,17 +71,19 @@ const decisionOf = (row) => {
66
71
  recommended: text(row, "recommended"),
67
72
  context: text(row, "context"),
68
73
  answer: text(row, "answer"),
69
- answeredAt: text(row, "answered_at")
74
+ answeredAt: text(row, "answered_at"),
75
+ note: text(row, "note"),
76
+ owner: text(row, "owner")
70
77
  };
71
78
  for (const [key, value] of Object.entries(optional)) if (value !== "") Object.assign(record, { [key]: value });
72
79
  const by = text(row, "answered_by");
73
- if (by === "terminal" || by === "decide" || by === "ui") record.answeredBy = by;
80
+ if (by === "terminal" || by === "decide" || by === "ui" || by === "owner") record.answeredBy = by;
74
81
  return record;
75
82
  };
76
83
  const decisionQueries = (db) => {
77
- const insert = db.prepare(`INSERT INTO decisions (id, run_id, node, kind, question, options, recommended, context, opened_at, status)
78
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'open')`);
79
- const answer = db.prepare(`UPDATE decisions SET status = 'answered', answer = ?, answered_by = ?, answered_at = ?
84
+ const insert = db.prepare(`INSERT INTO decisions (id, run_id, node, kind, question, options, recommended, context, owner, opened_at, status)
85
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'open')`);
86
+ const answer = db.prepare(`UPDATE decisions SET status = 'answered', answer = ?, answered_by = ?, answered_at = ?, note = ?
80
87
  WHERE id = ? AND status = 'open'`);
81
88
  const withdraw = db.prepare("UPDATE decisions SET status = 'withdrawn', answered_at = ? WHERE id = ? AND status = 'open'");
82
89
  const byId = db.prepare("SELECT * FROM decisions WHERE id = ?");
@@ -97,14 +104,14 @@ const decisionQueries = (db) => {
97
104
  question: maskSecrets(decision.question),
98
105
  ...decision.context === void 0 ? {} : { context: maskSecrets(decision.context) }
99
106
  };
100
- insert.run(masked.id, masked.runId, masked.node, masked.kind, masked.question, JSON.stringify(masked.options), masked.recommended ?? null, masked.context ?? null, openedAt);
107
+ insert.run(masked.id, masked.runId, masked.node, masked.kind, masked.question, JSON.stringify(masked.options), masked.recommended ?? null, masked.context ?? null, masked.owner ?? null, openedAt);
101
108
  return {
102
109
  ...masked,
103
110
  openedAt,
104
111
  status: "open"
105
112
  };
106
113
  },
107
- answerDecision: (id, choice, by) => Number(answer.run(choice, by, (/* @__PURE__ */ new Date()).toISOString(), id).changes) === 1,
114
+ answerDecision: (id, choice, by, note) => Number(answer.run(choice, by, (/* @__PURE__ */ new Date()).toISOString(), noteOf(note), id).changes) === 1,
108
115
  withdrawDecision: (id) => {
109
116
  withdraw.run((/* @__PURE__ */ new Date()).toISOString(), id);
110
117
  },
@@ -720,9 +727,21 @@ const MIGRATIONS = [
720
727
  );`,
721
728
  `ALTER TABLE feedback_items ADD COLUMN merged_into TEXT;
722
729
  CREATE INDEX feedback_items_merged ON feedback_items (merged_into);`,
723
- `ALTER TABLE runs ADD COLUMN process_start TEXT;`
730
+ `ALTER TABLE runs ADD COLUMN process_start TEXT;`,
731
+ `ALTER TABLE runs ADD COLUMN skipped INTEGER;
732
+ ALTER TABLE runs ADD COLUMN failures_handled INTEGER;`,
733
+ `ALTER TABLE decisions ADD COLUMN note TEXT;`,
734
+ `ALTER TABLE decisions ADD COLUMN owner TEXT;`
724
735
  ];
725
736
  const versionOf = (db) => Number(db.prepare("PRAGMA user_version").get()?.["user_version"] ?? 0);
737
+ /**
738
+ * Refuses a database that is not at this Ork's schema version, newer or older,
739
+ * for a reader that may not migrate it (a read-only open).
740
+ */
741
+ const requireCurrent = (db, migrations = MIGRATIONS) => {
742
+ const version = versionOf(db);
743
+ if (version !== migrations.length) throw new Error(`The store is at schema version ${String(version)}; this Ork reads ${String(migrations.length)}.`);
744
+ };
726
745
  /** Applies the migrations the database has not had yet. */
727
746
  const migrate = (db, migrations = MIGRATIONS) => {
728
747
  for (const [index, step] of migrations.entries()) {
@@ -741,7 +760,9 @@ const migrate = (db, migrations = MIGRATIONS) => {
741
760
  * project, `~/.ork/state.db`, in WAL mode so other `ork` processes read while
742
761
  * a run writes. Events are stored with secrets masked, feedback records
743
762
  * beside them, and the registered projects; the schema is versioned with
744
- * `user_version`.
763
+ * `user_version`. Tab completion opens it read-only: no store created, no
764
+ * migration, a store at another version refused, and the database never
765
+ * changed (SQLite may still add the `-wal` and `-shm` files beside it).
745
766
  */
746
767
  /** `~/.ork/state.db`; `home` is `~` (tests pass a folder). */
747
768
  const storePath = (home = homedir()) => path.join(home, ".ork", "state.db");
@@ -773,6 +794,10 @@ const recordOf = (row) => {
773
794
  if (parent !== "") record.parent = parent;
774
795
  const finished = text(row, "finished_at");
775
796
  if (finished !== "") record.finishedAt = finished;
797
+ const skipped = row?.["skipped"];
798
+ if (typeof skipped === "number") record.skipped = skipped;
799
+ const handled = row?.["failures_handled"];
800
+ if (typeof handled === "number") record.failuresHandled = handled;
776
801
  return record;
777
802
  };
778
803
  /** The node an event is about, for filtering. */
@@ -781,9 +806,20 @@ const nodeOf = (event) => {
781
806
  if ("node" in event && typeof event.node === "string") return event.node;
782
807
  return null;
783
808
  };
784
- /** Opens (and creates) the store at `file`; `:memory:` for tests. */
785
- const openStore = (file = storePath(), options = {}) => {
786
- const ownStart = options.processStart ?? ownProcessStart;
809
+ /** A database opened for reading only, refused unless it is current. */
810
+ const openReadOnly = (file) => {
811
+ const db = new DatabaseSync(file, { readOnly: true });
812
+ try {
813
+ db.exec("PRAGMA busy_timeout = 5000");
814
+ requireCurrent(db);
815
+ return db;
816
+ } catch (error) {
817
+ db.close();
818
+ throw error;
819
+ }
820
+ };
821
+ /** A database opened for writing: created, in WAL mode, migrated. */
822
+ const openWritable = (file) => {
787
823
  if (file !== ":memory:") mkdirSync(path.dirname(file), { recursive: true });
788
824
  const db = new DatabaseSync(file);
789
825
  db.exec("PRAGMA busy_timeout = 5000");
@@ -791,18 +827,28 @@ const openStore = (file = storePath(), options = {}) => {
791
827
  db.exec("PRAGMA synchronous = NORMAL");
792
828
  db.exec("PRAGMA foreign_keys = ON");
793
829
  migrate(db);
830
+ return db;
831
+ };
832
+ /**
833
+ * Opens (and creates) the store at `file`; `:memory:` for tests. With
834
+ * `readOnly`, it neither creates nor migrates, and throws when it can't read.
835
+ */
836
+ const openStore = (file = storePath(), options = {}) => {
837
+ const ownStart = options.processStart ?? ownProcessStart;
838
+ const db = options.readOnly === true ? openReadOnly(file) : openWritable(file);
794
839
  const insertRun = db.prepare(`INSERT INTO runs (id, workflow, file, project, status, pid, process_start, started_at, parent, depth)
795
840
  VALUES (?, ?, ?, ?, 'running', ?, ?, ?, ?, ?)`);
796
841
  const lastSeq = db.prepare("SELECT COALESCE(MAX(seq), 0) AS seq FROM events WHERE run_id = ?");
797
842
  const insertEvent = db.prepare("INSERT INTO events (run_id, seq, at, type, node, data) VALUES (?, ?, ?, ?, ?, ?)");
798
- const finishRun = db.prepare("UPDATE runs SET status = ?, finished_at = ?, cost_usd = ? WHERE id = ?");
799
- const reopenRun = db.prepare("UPDATE runs SET status = 'running', pid = ?, process_start = ?, finished_at = NULL WHERE id = ?");
843
+ const finishRun = db.prepare("UPDATE runs SET status = ?, finished_at = ?, cost_usd = ?, skipped = ?, failures_handled = ? WHERE id = ?");
844
+ const reopenRun = db.prepare("UPDATE runs SET status = 'running', pid = ?, process_start = ?, finished_at = NULL, skipped = NULL, failures_handled = NULL WHERE id = ?");
800
845
  const addCost = db.prepare("UPDATE runs SET cost_usd = cost_usd + ? WHERE id = ?");
801
846
  const byId = db.prepare("SELECT * FROM runs WHERE id = ?");
802
847
  const byPrefix = db.prepare("SELECT * FROM runs WHERE substr(id, 1, ?) = ? ORDER BY started_at DESC, rowid DESC");
803
848
  const allRuns = db.prepare("SELECT * FROM runs ORDER BY started_at DESC, rowid DESC LIMIT ?");
804
849
  const projectRuns = db.prepare("SELECT * FROM runs WHERE project = ? ORDER BY started_at DESC, rowid DESC LIMIT ?");
805
850
  const eventsAfter = db.prepare("SELECT seq, at, data FROM events WHERE run_id = ? AND seq > ? ORDER BY seq");
851
+ const runNodes = db.prepare("SELECT node FROM events WHERE run_id = ? AND node IS NOT NULL GROUP BY node ORDER BY MIN(seq)");
806
852
  const { insertFeedback, recordUsage, recordPlanLimit, ...queries } = storeQueries(db);
807
853
  return {
808
854
  ...queries,
@@ -832,7 +878,10 @@ const openStore = (file = storePath(), options = {}) => {
832
878
  if (event.type === "node.event" && event.event.type === "session.finished") recordUsage(runId);
833
879
  if (event.type === "node.event" && event.event.type === "plan.limit") recordPlanLimit(event.event, at);
834
880
  if (event.type === "feedback.recorded") insertFeedback(runId, seq, at, event.node, event.feedback);
835
- if (event.type === "run.finished") finishRun.run(event.result.status, at, event.result.costUsd, runId);
881
+ if (event.type === "run.finished") {
882
+ const { status, costUsd, skipped, failuresHandled } = event.result;
883
+ finishRun.run(status, at, costUsd, skipped ?? null, failuresHandled ?? null, runId);
884
+ }
836
885
  return {
837
886
  runId,
838
887
  seq,
@@ -855,6 +904,7 @@ const openStore = (file = storePath(), options = {}) => {
855
904
  at: text(r, "at"),
856
905
  event: eventOf(text(r, "data"))
857
906
  })),
907
+ nodes: (runId) => runNodes.all(runId).map((r) => text(r, "node")),
858
908
  close: () => {
859
909
  db.close();
860
910
  }
@@ -1,7 +1,7 @@
1
- import { H as requestContinue, U as requestPause } from "./src-CGqMati3.mjs";
2
- import { t as findRun } from "./find-DptmbhGd.mjs";
3
- import { a as write, c as openStore, i as style, o as writeErr } from "./output-CXSJO00X.mjs";
4
- import { r as continueRefusal } from "./in-a-run-D1Qc5Mit.mjs";
1
+ import { G as requestContinue, K as requestPause } from "./src-DHvWU4tX.mjs";
2
+ import { t as findRun } from "./find-BKW-uGey.mjs";
3
+ import { a as write, c as openStore, i as style, o as writeErr } from "./output-B1V6ZJSx.mjs";
4
+ import { r as continueRefusal } from "./in-a-run-BPXX09Bs.mjs";
5
5
  import { defineCommand } from "citty";
6
6
  // src/commands/pause.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
- import { B as unlinkNodes, L as linkNodes, P as addressOf } from "./src-CGqMati3.mjs";
2
- import { a as write, c as openStore, i as style, o as writeErr } from "./output-CXSJO00X.mjs";
1
+ import { B as linkNodes, L as addressOf, U as unlinkNodes } from "./src-DHvWU4tX.mjs";
2
+ import { a as write, c as openStore, i as style, o as writeErr } from "./output-B1V6ZJSx.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  // src/commands/relay.ts
5
5
  /**
@@ -1,6 +1,6 @@
1
- import { D as git, k as lines, lt as liveStatus } from "./src-CGqMati3.mjs";
2
- import { n as listOrkWorktrees, t as createdWorktrees } from "./list-ZvY2OcLq.mjs";
3
- import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-Dcr807be.mjs";
1
+ import { ht as liveStatus, j as lines, k as git } from "./src-DHvWU4tX.mjs";
2
+ import { n as listOrkWorktrees, t as createdWorktrees } from "./list-C7UEgmtd.mjs";
3
+ import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-NnboOuz6.mjs";
4
4
  // ../core/src/worktree/words.ts
5
5
  /**
6
6
  * @file The plain words for what `ork worktrees` shows, in one place, so the
@@ -1,6 +1,6 @@
1
- import { Xt as wakeRun, Yt as socketPath, lt as liveStatus, wt as scriptContactsOf } from "./src-CGqMati3.mjs";
2
- import { c as openStore, o as writeErr } from "./output-CXSJO00X.mjs";
3
- import { u as inheritedScrubber } from "./src-UWkk1sl9.mjs";
1
+ import { an as wakeRun, ht as liveStatus, kt as scriptContactsOf, rn as socketPath } from "./src-DHvWU4tX.mjs";
2
+ import { c as openStore, o as writeErr } from "./output-B1V6ZJSx.mjs";
3
+ import { u as inheritedScrubber } from "./src-C38BPzit.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  // ../core/src/remote/send.ts
6
6
  /**
@@ -1,10 +1,11 @@
1
- import { $ as resumable, An as parseWorkflow, B as unlinkNodes, Dn as newWorkflowText, Dt as nodeSays, En as applyEdits, Ft as runGh, G as tellLiveRun, H as requestContinue, In as expandEdge, It as sendPost, L as linkNodes, Nt as DISCUSSIONS, On as readDocument, Pn as EdgeInputSchema, Pt as planPost, Q as detachResume, Rn as NodeSchema, Tn as WorkflowEditSchema, U as requestPause, W as requestStop, _n as inside, _t as walkChecks, at as explainWorkflowText, d as runningRunIds, dn as placeFiles, dt as runStatus, f as runningScript, fn as placeFor, ft as runTree, g as triggersReport, gn as workflowDirOf, gt as checkWorkflowText, it as followEvents, kn as renderJsonSchema, l as planUpgrade, lt as liveStatus, mn as runDirOf, mt as processAlive, o as limitsReport, on as loadAgents, p as detectInstaller, qt as readCondition, r as capsHere, rt as detachRun, u as releaseNotes, ut as pausedOf, vt as walkSummary, wn as skillsIn, yn as LESSON_CAP_TOKENS } from "./src-CGqMati3.mjs";
2
- import { D as placeOf$1, E as lessonPlaceOf, O as feedbackActions, S as previewPost, T as acceptItem, _ as answerDecision, a as registryShown, c as checkDue, f as readUpdateCache, g as nodeSession, h as writeUpdateCache, i as registryOf, k as openFixRun, l as fetchLatest, m as updateCachePath, o as updateSwitchOff, p as refreshUpdateCache, s as runInstall, u as newerVersion, v as pendingDecisions, w as recordNote, y as builtinProblem } from "./__build_info__-CtSVVuZE.mjs";
3
- import { n as newRunId, t as findRun } from "./find-DptmbhGd.mjs";
4
- import { c as openStore, l as storePath, s as nodeOf } from "./output-CXSJO00X.mjs";
1
+ import { B as linkNodes, Cn as runDirOf, Ct as walkChecks, En as inside, Fn as applyEdits, G as requestContinue, Gn as expandEdge, Hn as EdgeInputSchema, Ht as planPost, In as newWorkflowText, J as tellLiveRun, K as requestPause, Ln as readDocument, Nn as skillsIn, Nt as nodeSays, On as LESSON_CAP_TOKENS, Pn as WorkflowEditSchema, Rn as renderJsonSchema, St as checkWorkflowText, Tn as workflowDirOf, U as unlinkNodes, Ut as runGh, Vt as DISCUSSIONS, Wt as sendPost, _t as runStatus, bn as placeFiles, bt as processAlive, ct as explainWorkflowText, d as runningRunIds, f as runningScript, gt as pausedOf, hn as loadAgents, ht as liveStatus, l as planUpgrade, nt as resumable, o as limitsReport, ot as detachRun, p as detectInstaller, q as requestStop, qn as NodeSchema, r as capsHere, st as followEvents, tn as readCondition, tt as detachResume, u as releaseNotes, v as triggersReport, vt as runTree, wt as walkSummary, xn as placeFor, zn as parseWorkflow } from "./src-DHvWU4tX.mjs";
2
+ import { C as feedbackActions, S as placeOf$1, _ as previewPost, a as registryShown, b as acceptItem, c as checkDue, f as readUpdateCache, g as nodeSession, h as writeUpdateCache, i as registryOf, l as fetchLatest, m as updateCachePath, o as updateSwitchOff, p as refreshUpdateCache, s as runInstall, u as newerVersion, w as openFixRun, x as lessonPlaceOf, y as recordNote } from "./__build_info__-DdTVd2p5.mjs";
3
+ import { n as pendingDecisions, r as builtinProblem, t as answerDecision } from "./decide-B81wCZQg.mjs";
4
+ import { n as newRunId, t as findRun } from "./find-BKW-uGey.mjs";
5
+ import { c as openStore, l as storePath, s as nodeOf } from "./output-B1V6ZJSx.mjs";
5
6
  import { n as usageReport } from "./report-DK4LGqwF.mjs";
6
- import { a as planClean, i as keyOf, o as stepActs, r as cleanStep, s as stepPrunes, t as applyClean } from "./clean-Dcr807be.mjs";
7
- import { a as readWorktrees, c as planLine, i as projectHead, l as removeRefusal, n as lostWork, o as labelOf, r as planRemove, s as mergeStateOf, t as applyRemove, u as stateParts } from "./remove-AwaMMaHf.mjs";
7
+ import { a as planClean, i as keyOf, o as stepActs, r as cleanStep, s as stepPrunes, t as applyClean } from "./clean-NnboOuz6.mjs";
8
+ import { a as readWorktrees, c as planLine, i as projectHead, l as removeRefusal, n as lostWork, o as labelOf, r as planRemove, s as mergeStateOf, t as applyRemove, u as stateParts } from "./remove-DAZ7ZCzt.mjs";
8
9
  import path from "node:path";
9
10
  import { z } from "zod";
10
11
  import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
@@ -350,7 +351,11 @@ const DecisionsQuerySchema = z.strictObject({
350
351
  run: z.string().min(1).optional(),
351
352
  project: z.string().min(1).optional()
352
353
  });
353
- const AnswerSchema = z.strictObject({ choose: z.string().min(1) });
354
+ /** An answer: the option, and what the person said with it, if anything. */
355
+ const AnswerSchema = z.strictObject({
356
+ choose: z.string().min(1),
357
+ note: z.string().optional()
358
+ });
354
359
  const RunFlags = {
355
360
  inputs: z.record(z.string(), z.string()).optional(),
356
361
  driver: Driver.optional(),
@@ -955,7 +960,7 @@ const writeRoutes = (context) => {
955
960
  const script = context.script === void 0 ? {} : { script: context.script };
956
961
  return {
957
962
  answer: async ({ params, body }) => {
958
- const answered = await answerDecision(context.store, params.id, body.choose, context.home, "ui");
963
+ const answered = await answerDecision(context.store, params.id, body.choose, context.home, "ui", body.note);
959
964
  return answered.ok ? ok({
960
965
  decision: params.id,
961
966
  answer: body.choose
@@ -1710,8 +1715,11 @@ const mcpTools = (context) => {
1710
1715
  ];
1711
1716
  };
1712
1717
  const NOT_HERE = "This server was not started by `ork ui`.";
1713
- /** Asks the registry when the daily check is due; never throws. */
1714
- const checkIfDue = async (file, options) => {
1718
+ /**
1719
+ * Asks the registry when the daily check is due; never throws. `current` is the
1720
+ * running version, which says whether the `canary` tag counts.
1721
+ */
1722
+ const checkIfDue = async (file, options, current) => {
1715
1723
  try {
1716
1724
  const now = /* @__PURE__ */ new Date();
1717
1725
  const cache = readUpdateCache(file);
@@ -1723,7 +1731,8 @@ const checkIfDue = async (file, options) => {
1723
1731
  const registry = registryOf(options.env ?? process.env);
1724
1732
  await refreshUpdateCache(file, options.name, now, {
1725
1733
  ...registry === void 0 ? {} : { registry },
1726
- ...options.fetch === void 0 ? {} : { fetch: options.fetch }
1734
+ ...options.fetch === void 0 ? {} : { fetch: options.fetch },
1735
+ current
1727
1736
  });
1728
1737
  return true;
1729
1738
  } catch {
@@ -1750,7 +1759,7 @@ const createUpdates = (input) => {
1750
1759
  let timer;
1751
1760
  if (options !== void 0 && reason === null) {
1752
1761
  const due = () => {
1753
- checkIfDue(file, options).then((asked) => {
1762
+ checkIfDue(file, options, version).then((asked) => {
1754
1763
  if (asked) record = null;
1755
1764
  return asked;
1756
1765
  });
@@ -2276,7 +2285,8 @@ const askPlan = async (context) => {
2276
2285
  const latest = await fetchLatest(options.name, {
2277
2286
  ...registry === void 0 ? {} : { registry },
2278
2287
  ...options.fetch === void 0 ? {} : { fetch: options.fetch },
2279
- timeoutMs: ASK_TIMEOUT_MS
2288
+ timeoutMs: ASK_TIMEOUT_MS,
2289
+ current
2280
2290
  });
2281
2291
  const script = options.script ?? runningScript();
2282
2292
  const plan = planUpgrade({