@krapht/ork 1.0.0-alpha.15 → 1.0.0-alpha.16

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 (46) hide show
  1. package/README.md +10 -4
  2. package/dist/{__build_info__-Bsb1kjgF.mjs → __build_info__-DcRdK0Du.mjs} +25 -6
  3. package/dist/apply-Mb0fNpCX.mjs +17 -0
  4. package/dist/{attach-CPespxlQ.mjs → attach-7lB5_jpr.mjs} +5 -5
  5. package/dist/{attach-BHO3X3cf.mjs → attach-B-FeE1dJ.mjs} +46 -8
  6. package/dist/bin.mjs +238 -369
  7. package/dist/{brief-za0ozN_E.mjs → brief-BvMtIFio.mjs} +4 -4
  8. package/dist/{builtin-files-2bHf76x-.mjs → builtin-files-BRSOObAv.mjs} +1 -1
  9. package/dist/command-tree-BkSYWmYJ.mjs +63 -0
  10. package/dist/{completion-CQ2UYKuJ.mjs → completion-Cgb2qPPh.mjs} +45 -6
  11. package/dist/{context-BNqDw9z1.mjs → context-BN9A2Nnu.mjs} +3 -3
  12. package/dist/{find-BYLlszqj.mjs → find-mLYsR0uC.mjs} +2 -2
  13. package/dist/flags-CdgIH1L6.mjs +230 -0
  14. package/dist/{follow-ups-B4GJ3Vzw.mjs → follow-ups-DxCsOby1.mjs} +59 -24
  15. package/dist/{format-C8MsFj8_.mjs → format-hiDvtNGM.mjs} +17 -4
  16. package/dist/{help-groups-CQ98mLjF.mjs → help-groups-hB6kY34d.mjs} +1 -63
  17. package/dist/{in-a-run-Bp0k0J09.mjs → in-a-run-a447hxq8.mjs} +1 -1
  18. package/dist/{install-DWtXTq4y.mjs → install-23g_1ngs.mjs} +1 -1
  19. package/dist/{limits-B1qzS4cX.mjs → limits-C_Xz_t3C.mjs} +1 -1
  20. package/dist/{mcp-BOrVkyhN.mjs → mcp-CWng9I9n.mjs} +6 -6
  21. package/dist/{once-C1fL3GVo.mjs → once-lvwcWfVf.mjs} +3 -3
  22. package/dist/{pause-DOMK-R8V.mjs → pause-Cy11KrXK.mjs} +3 -3
  23. package/dist/{post-BzA6Qobq.mjs → post-C9soCx7i.mjs} +5 -3
  24. package/dist/print-BaWiWf4v.mjs +19 -0
  25. package/dist/project-records-BRiyQzUo.mjs +230 -0
  26. package/dist/{relay-OWuu4fib.mjs → relay-C0M1TWMB.mjs} +1 -1
  27. package/dist/{run--4-1xAF2.mjs → run-B-j3Qxqc.mjs} +26 -13
  28. package/dist/{run-CiPsW9Kf.mjs → run-D_u9V_Ve.mjs} +1 -1
  29. package/dist/{send-CnNNW-ot.mjs → send-qBxj0JbJ.mjs} +2 -2
  30. package/dist/{src-B9zWIVqo.mjs → src-CXBmaGwS.mjs} +93 -72
  31. package/dist/{src-DcrhgipG.mjs → src-DHDQ0itC.mjs} +91 -42
  32. package/dist/{src-Dr_fTSu-.mjs → src-DN-RPsil.mjs} +781 -502
  33. package/dist/{src-DQKz2eOH.mjs → src-nXLIwDrt.mjs} +9 -12
  34. package/dist/{store-oKJ-cCf3.mjs → store-Dyr1mP8K.mjs} +1 -1
  35. package/dist/ui/assets/app-BPSCxb_l.css +1 -0
  36. package/dist/ui/assets/{app-Drp8Dm9y.js → app-CnNRowFn.js} +40 -40
  37. package/dist/ui/assets/{index-BtwkftKe.js → index-CVzwYlz3.js} +2 -2
  38. package/dist/ui/index.html +1 -1
  39. package/dist/{ui-CzKlsCnm.mjs → ui-DLrSt5ny.mjs} +3 -3
  40. package/dist/{usage-DHGNk2JL.mjs → usage-CxmpYYO4.mjs} +61 -107
  41. package/dist/{validate-Bs_gg22g.mjs → validate-BVrT43GO.mjs} +35 -8
  42. package/dist/{watch-CCCfw3n7.mjs → watch-mkLm4t9D.mjs} +5 -5
  43. package/dist/{workflows-CW28ZU-z.mjs → workflows-Bvl2Fquu.mjs} +2 -2
  44. package/dist/{worktrees-CyE8aF6j.mjs → worktrees-DOOCoS2w.mjs} +49 -20
  45. package/package.json +8 -4
  46. package/dist/ui/assets/app-Bdc6OBeZ.css +0 -1
@@ -113,68 +113,6 @@ complete -c ork -f -a '(__ork_complete)'
113
113
  };
114
114
  /** The shells there is a script for. */
115
115
  const SHELLS = Object.keys(SHELL_SCRIPTS);
116
- // src/command-tree.ts
117
- /** How a flag that only Ork passes to itself starts its description. */
118
- const INTERNAL = "Internal:";
119
- /** Whether citty was given a function that gives the value. */
120
- const isThunk = (value) => typeof value === "function";
121
- /** A value citty lets be given as is, as a promise, or as a function. */
122
- const resolved = (value) => Promise.resolve(isThunk(value) ? value() : value);
123
- /** `args` without the flags only Ork passes to itself. */
124
- const publicArgs = (args) => Object.fromEntries(Object.entries(args).filter(([, def]) => !(def.description ?? "").startsWith(INTERNAL)));
125
- /** A command's flags and positionals, which citty lets be given lazily. */
126
- const argsOf = (cmd) => cmd.args === void 0 ? Promise.resolve({}) : resolved(cmd.args);
127
- const listOf = (value) => value === void 0 ? [] : [value].flat();
128
- const flagOf = (name, def) => ({
129
- name,
130
- description: def.description ?? "",
131
- takesValue: def.type === "string" || def.type === "enum",
132
- aliases: "alias" in def ? listOf(def.alias) : [],
133
- options: def.type === "enum" ? def.options ?? [] : [],
134
- negatable: def.type === "boolean" && def.default === true
135
- });
136
- /** A command's public flags and positionals, in the order it defines them. */
137
- const argInfoOf = async (cmd) => {
138
- const entries = Object.entries(publicArgs(await argsOf(cmd)));
139
- return {
140
- flags: entries.filter(([, def]) => def.type !== "positional").map(([name, def]) => flagOf(name, def)),
141
- positionals: entries.filter(([, def]) => def.type === "positional").map(([name, def]) => ({
142
- name,
143
- description: def.description ?? ""
144
- }))
145
- };
146
- };
147
- /**
148
- * A command's subcommands, in order, loaded ones resolved. A name whose
149
- * definition is one listed before it (`wt`, `worktrees`'s) is an alias of that
150
- * one, not an entry of its own.
151
- */
152
- const subcommandsOf = async (cmd) => {
153
- const subs = cmd.subCommands === void 0 ? {} : await resolved(cmd.subCommands);
154
- const loaded = await Promise.all(Object.entries(subs).map(async ([name, sub]) => {
155
- const def = await resolved(sub);
156
- return {
157
- name,
158
- def,
159
- meta: def.meta === void 0 ? {} : await resolved(def.meta)
160
- };
161
- }));
162
- const entries = [];
163
- for (const { name, def, meta } of loaded) {
164
- const same = entries.find((entry) => entry.def === def);
165
- if (same === void 0) entries.push({
166
- name,
167
- aliases: listOf(meta.alias),
168
- description: meta.description ?? "",
169
- hidden: meta.hidden === true,
170
- def
171
- });
172
- else same.aliases.push(name);
173
- }
174
- return entries;
175
- };
176
- /** The subcommand `name` (or one of its aliases) of `entries`. */
177
- const findEntry = (entries, name) => entries.find((entry) => entry.name === name || entry.aliases.includes(name));
178
116
  // src/help-groups.ts
179
117
  const HELP_GROUPS = [
180
118
  {
@@ -373,4 +311,4 @@ const groupedEntries = (entries) => {
373
311
  entries: other
374
312
  }].filter((group) => group.entries.length > 0);
375
313
  };
376
- export { findEntry as a, subcommandsOf as c, SHELL_SCRIPTS as d, argsOf as i, COMPLETE_COMMAND as l, groupedEntries as n, publicArgs as o, argInfoOf as r, resolved as s, groupOf as t, SHELLS as u };
314
+ export { SHELL_SCRIPTS as a, SHELLS as i, groupedEntries as n, COMPLETE_COMMAND as r, groupOf as t };
@@ -1,4 +1,4 @@
1
- import { p as runMarkerIn } from "./src-DcrhgipG.mjs";
1
+ import { p as runMarkerIn } from "./src-DHDQ0itC.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 { Dr as placeFor, Er as placeFiles, Fr as estimateTokens, Gn as FEEDBACK_SEVERITIES, Ir as guardedBase, Lr as plainPathInside, Mr as inside, Pr as LESSON_CAP_TOKENS, Rr as writePlainFile, Wn as FEEDBACK_KINDS, Zn as publishPost, er as fingerprint, fr as maskSecrets, nr as targetOf } from "./src-Dr_fTSu-.mjs";
1
+ import { Gr as writePlainFile, Hr as estimateTokens, Nr as placeFiles, Pr as placeFor, Ur as guardedBase, Vr as LESSON_CAP_TOKENS, Wr as plainPathInside, Xn as FEEDBACK_KINDS, Zn as FEEDBACK_SEVERITIES, cr as targetOf, or as fingerprint, rr as publishPost, vr as maskSecrets, zr as inside } from "./src-DN-RPsil.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync, readFileSync, realpathSync } from "node:fs";
4
4
  import { spawn } from "node:child_process";
@@ -1,4 +1,4 @@
1
- import { C as capsHere, bt as limitsReport, vt as NOT_STARTED, yt as limitsNow } from "./src-Dr_fTSu-.mjs";
1
+ import { _ as capsHere, dt as NOT_STARTED, ft as limitsNow, pt as limitsReport } from "./src-DN-RPsil.mjs";
2
2
  // src/run/limits.ts
3
3
  /**
4
4
  * @file The limits across runs that apply here (RFC-007): the user's settings
@@ -1,8 +1,8 @@
1
- import { A as isNewer } from "./src-Dr_fTSu-.mjs";
2
- import { n as ORK_VERSION } from "./__build_info__-Bsb1kjgF.mjs";
3
- import { p as runMarkerIn } from "./src-DcrhgipG.mjs";
4
- import { n as explainNode } from "./context-BNqDw9z1.mjs";
5
- import { a as openMcp, c as refused, o as tool, s as answer } from "./src-DQKz2eOH.mjs";
1
+ import { w as isNewer } from "./src-DN-RPsil.mjs";
2
+ import { n as ORK_VERSION } from "./__build_info__-DcRdK0Du.mjs";
3
+ import { p as runMarkerIn } from "./src-DHDQ0itC.mjs";
4
+ import { n as explainNode } from "./context-BN9A2Nnu.mjs";
5
+ import { a as openMcp, c as refused, o as tool, s as answer } from "./src-nXLIwDrt.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.15") ? tooOld(all, options.expects) : all;
46
+ const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.16") ? tooOld(all, options.expects) : all;
47
47
  const server = new McpServer({
48
48
  name: "ork",
49
49
  version: ORK_VERSION
@@ -1,7 +1,7 @@
1
- import "./src-Dr_fTSu-.mjs";
2
- import { t as runOnce } from "./run-CiPsW9Kf.mjs";
1
+ import "./src-DN-RPsil.mjs";
2
+ import { t as runOnce } from "./run-D_u9V_Ve.mjs";
3
3
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
4
- import { t as ago } from "./format-C8MsFj8_.mjs";
4
+ import { t as ago } from "./format-hiDvtNGM.mjs";
5
5
  import { spawn } from "node:child_process";
6
6
  import { defineCommand, parseArgs } from "citty";
7
7
  // src/commands/once.ts
@@ -1,7 +1,7 @@
1
- import { U as openStore, bn as requestPause, yn as requestContinue } from "./src-Dr_fTSu-.mjs";
2
- import { t as findRun } from "./find-BYLlszqj.mjs";
1
+ import { En as requestPause, L as openStore, Tn as requestContinue } from "./src-DN-RPsil.mjs";
2
+ import { t as findRun } from "./find-mLYsR0uC.mjs";
3
3
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
4
- import { i as continueRefusal } from "./in-a-run-Bp0k0J09.mjs";
4
+ import { i as continueRefusal } from "./in-a-run-a447hxq8.mjs";
5
5
  import { defineCommand } from "citty";
6
6
  // src/commands/pause.ts
7
7
  /**
@@ -1,11 +1,13 @@
1
- import { Qn as redact } from "./src-Dr_fTSu-.mjs";
1
+ import { ir as redact } from "./src-DN-RPsil.mjs";
2
+ import { b as githubDraftRefusal } from "./__build_info__-DcRdK0Du.mjs";
2
3
  // ../core/src/follow-ups/post.ts
3
4
  /** Posts `f`'s draft as a GitHub comment once `confirmed`, and marks it done. */
4
5
  const postFollowUpMessage = async (f, options) => {
5
6
  const draft = f.draft;
6
- if (f.kind !== "message" || draft?.channel !== "github") return {
7
+ const refused = githubDraftRefusal(f);
8
+ if (refused !== void 0 || draft === void 0) return {
7
9
  ok: false,
8
- error: "only a message drafted for the github channel is posted; send the others yourself"
10
+ error: refused?.error ?? "it has no draft"
9
11
  };
10
12
  if (!options.confirmed) return {
11
13
  ok: false,
@@ -0,0 +1,19 @@
1
+ import { a as refuseIdsWithJson } from "./flags-CdgIH1L6.mjs";
2
+ import { c as write } from "./output-B1kwo0YU.mjs";
3
+ // src/list/print.ts
4
+ /**
5
+ * Prints `rows`: `--ids` their ids (`table.id`) comma-separated; `--json` the
6
+ * rows (or `json(rows)`); else `human(rows)`, which also says what an empty
7
+ * list is. `--ids` with `--json` is refused (said, exit code set).
8
+ */
9
+ const printList = (rows, table, args, human, json = (shown) => shown) => {
10
+ if (refuseIdsWithJson(args)) return;
11
+ if (args.ids === true) {
12
+ const id = table.id;
13
+ if (id !== void 0 && rows.length > 0) write(rows.map((row) => id(row)).join(","));
14
+ return;
15
+ }
16
+ if (args.json === true) write(JSON.stringify(json(rows), void 0, 2));
17
+ else human(rows);
18
+ };
19
+ export { printList as t };
@@ -0,0 +1,230 @@
1
+ import { Ar as hasInRepoFiles, Br as projectRootOf, Fr as projectsHome, L as openStore, Lr as shownPath, Mr as newProjectId, Nr as placeFiles, jr as inRepoPlace } from "./src-DN-RPsil.mjs";
2
+ import { C as termOf, c as write, l as writeErr, s as style, w as cut } from "./output-B1kwo0YU.mjs";
3
+ import { n as chip } from "./chips-BqcT58qr.mjs";
4
+ import path from "node:path";
5
+ import { existsSync, mkdirSync, realpathSync, statSync } from "node:fs";
6
+ import { defineCommand } from "citty";
7
+ // src/project/register.ts
8
+ /**
9
+ * @file Registering projects (ADR-035): `ork register` attaches a repository
10
+ * from outside it, with its workflows, rules and runs in
11
+ * `~/.ork/projects/<id>/` and nothing written into the repository; `ork init`
12
+ * records an in-repo project, whose files are its `.ork/`.
13
+ */
14
+ const ID = /^[a-z0-9][a-z0-9._-]*$/u;
15
+ /** The git root of `target`'s main clone, or why there is none. */
16
+ const cloneOf = (target) => {
17
+ if (!existsSync(target)) return {
18
+ ok: false,
19
+ error: `${target} does not exist`
20
+ };
21
+ const root = projectRootOf(realpathSync(target));
22
+ const dotGit = path.join(root, ".git");
23
+ if (!existsSync(dotGit)) return {
24
+ ok: false,
25
+ error: `${target} is not in a git repository`
26
+ };
27
+ if (statSync(dotGit).isFile()) return {
28
+ ok: false,
29
+ error: `${root} is a git worktree; register the main clone instead`
30
+ };
31
+ return {
32
+ ok: true,
33
+ root
34
+ };
35
+ };
36
+ /**
37
+ * Attaches the repository at `target`: creates `~/.ork/projects/<id>/workflows`
38
+ * and records the project. Registering it again returns the same project.
39
+ */
40
+ const registerProject = (store, target, options = {}) => {
41
+ const clone = cloneOf(target);
42
+ if (!clone.ok) return clone;
43
+ const { root } = clone;
44
+ const projects = store.projects();
45
+ const existing = projects.find((p) => p.root === root);
46
+ if (existing?.mode === "attached") return {
47
+ ok: true,
48
+ project: existing,
49
+ created: false
50
+ };
51
+ if (existing !== void 0 || hasInRepoFiles(root)) return {
52
+ ok: false,
53
+ error: `${root} keeps Ork's files in its own .ork/ (in-repo), so it is not attached`
54
+ };
55
+ const taken = projects.map((p) => p.id);
56
+ if (options.id !== void 0) {
57
+ if (!ID.test(options.id)) return {
58
+ ok: false,
59
+ error: `--id \`${options.id}\` must be lowercase letters, digits, ".", "_" or "-"`
60
+ };
61
+ if (taken.includes(options.id)) return {
62
+ ok: false,
63
+ error: `a project is already registered as ${options.id}`
64
+ };
65
+ }
66
+ const id = options.id ?? newProjectId(root, taken);
67
+ const project = {
68
+ id,
69
+ root,
70
+ mode: "attached",
71
+ dir: path.join(projectsHome(options.home), id)
72
+ };
73
+ mkdirSync(placeFiles(project).workflows, { recursive: true });
74
+ return {
75
+ ok: true,
76
+ project: store.addProject(project),
77
+ created: true
78
+ };
79
+ };
80
+ /**
81
+ * Records the in-repo project at `cwd`'s git root, if it is not registered yet;
82
+ * an attached one stays attached (`ork init` must not take it over).
83
+ */
84
+ const recordInRepo = (store, cwd) => {
85
+ const root = projectRootOf(realpathSync(cwd));
86
+ const projects = store.projects();
87
+ const existing = projects.find((p) => p.root === root);
88
+ if (existing?.mode === "attached") return {
89
+ ok: false,
90
+ error: `${root} is attached: its workflows are in ${shownPath(existing.dir, root)}, and Ork writes nothing into the repository`
91
+ };
92
+ if (existing !== void 0) return {
93
+ ok: true,
94
+ project: existing,
95
+ created: false
96
+ };
97
+ const project = {
98
+ ...inRepoPlace(root),
99
+ id: newProjectId(root, projects.map((p) => p.id))
100
+ };
101
+ return {
102
+ ok: true,
103
+ project: store.addProject(project),
104
+ created: true
105
+ };
106
+ };
107
+ /**
108
+ * Points a registered project at its clone's new place, after the clone was
109
+ * moved or renamed; its runs follow, and an in-repo project's `.ork/` with it.
110
+ */
111
+ const relocateProject = (store, id, target) => {
112
+ const projects = store.projects();
113
+ const project = projects.find((p) => p.id === id);
114
+ if (project === void 0) return {
115
+ ok: false,
116
+ error: `No project is registered as ${id}.`
117
+ };
118
+ const clone = cloneOf(target);
119
+ if (!clone.ok) return clone;
120
+ const { root } = clone;
121
+ const other = projects.find((p) => p.root === root && p.id !== id);
122
+ if (other !== void 0) return {
123
+ ok: false,
124
+ error: `${root} is already registered as ${other.id}`
125
+ };
126
+ const dir = project.mode === "in-repo" ? inRepoPlace(root).dir : project.dir;
127
+ store.moveProject(id, {
128
+ root,
129
+ mode: project.mode,
130
+ dir
131
+ });
132
+ return {
133
+ ok: true,
134
+ project: {
135
+ ...project,
136
+ root,
137
+ dir
138
+ },
139
+ created: false
140
+ };
141
+ };
142
+ /**
143
+ * One project's lines for `ork projects`; rich, its mode and a missing clone
144
+ * are chips, its id is padded to `idWidth` and its root is cut to the screen.
145
+ */
146
+ const formatProject = (project, term = termOf(process.stdout), idWidth = 0) => {
147
+ const missing = !existsSync(project.root);
148
+ if (!term.rich) {
149
+ const gone = missing ? style("yellow", " (missing)") : "";
150
+ return [`${style("bold", project.id)} ${style("dim", project.mode)} ${project.root}${gone}`, style("dim", ` files: ${shownPath(project.dir, project.root)}`)];
151
+ }
152
+ const mode = chip(term, project.mode.toUpperCase(), "muted");
153
+ const gone = missing ? ` ${chip(term, "MISSING", "warn")}` : "";
154
+ const room = term.width - (idWidth + 2 + project.mode.length + 2 + 2) - (missing ? 10 : 0);
155
+ return [`${style("bold", project.id.padEnd(idWidth))} ${mode} ${cut(project.root, Math.max(8, room))}${gone}`, style("dim", cut(` files: ${shownPath(project.dir, project.root)}`, term.width))];
156
+ };
157
+ /** Every project's lines, their ids aligned when rich. */
158
+ const formatProjects = (projects, term = termOf(process.stdout)) => {
159
+ const idWidth = term.rich ? Math.max(0, ...projects.map((p) => p.id.length)) : 0;
160
+ return projects.flatMap((p) => formatProject(p, term, idWidth));
161
+ };
162
+ /** What `ork register` prints: the project, and where its files go. */
163
+ const formatRegistered = (project, created) => {
164
+ const files = placeFiles(project);
165
+ const shown = (file) => shownPath(file, project.root);
166
+ return [
167
+ `${style("green", created ? "registered" : "already registered")} ${project.id} → ${project.root}`,
168
+ `\nWorkflows: ${shown(files.workflows)}/ · rules: ${shown(files.rules)} · runs: ${shown(files.runs)}/`,
169
+ `Nothing is written into ${project.root}. In it, ${style("bold", "ork run <name>")} finds the workflows above.`
170
+ ];
171
+ };
172
+ // src/commands/project-records.ts
173
+ /**
174
+ * @file `ork projects`' subcommands on one project's record (ADR-035): `forget`
175
+ * drops it and keeps its files and runs; `move` points it at its clone's new
176
+ * place after the clone was moved or renamed, and its runs follow.
177
+ */
178
+ /** Runs `use` with the store open, and closes it. */
179
+ const withStore = (use) => {
180
+ const store = openStore();
181
+ try {
182
+ return use(store);
183
+ } finally {
184
+ store.close();
185
+ }
186
+ };
187
+ const id = {
188
+ type: "positional",
189
+ description: "The project's id",
190
+ required: true
191
+ };
192
+ const forget = defineCommand({
193
+ meta: {
194
+ name: "forget",
195
+ description: "Forget a registered project; its files and runs are kept"
196
+ },
197
+ args: { id },
198
+ run: ({ args }) => {
199
+ if (withStore((store) => store.forgetProject(args.id))) {
200
+ write(`${style("green", "forgot")} ${args.id} (its files are kept)`);
201
+ return;
202
+ }
203
+ writeErr(`No project is registered as ${args.id}.`);
204
+ process.exitCode = 1;
205
+ }
206
+ });
207
+ const move = defineCommand({
208
+ meta: {
209
+ name: "move",
210
+ description: "Point a registered project at its clone's new place, after moving or renaming it"
211
+ },
212
+ args: {
213
+ id,
214
+ path: {
215
+ type: "positional",
216
+ description: "Where the clone is now",
217
+ required: true
218
+ }
219
+ },
220
+ run: ({ args }) => {
221
+ const result = withStore((store) => relocateProject(store, args.id, args.path));
222
+ if (result.ok) {
223
+ write(`${style("green", "moved")} ${args.id} → ${result.project.root}`);
224
+ return;
225
+ }
226
+ writeErr(result.error);
227
+ process.exitCode = 1;
228
+ }
229
+ });
230
+ export { formatRegistered as a, formatProjects as i, move as n, recordInRepo as o, withStore as r, registerProject as s, forget as t };
@@ -1,4 +1,4 @@
1
- import { U as openStore, _n as linkNodes, hn as addressOf, vn as unlinkNodes } from "./src-Dr_fTSu-.mjs";
1
+ import { Cn as linkNodes, L as openStore, wn as unlinkNodes, xn as addressOf } from "./src-DN-RPsil.mjs";
2
2
  import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  // src/commands/relay.ts
@@ -1,13 +1,13 @@
1
- import { $ as resolveInputs, $n as createFeedback, $t as sessionDriver, At as walkSummary, Cn as liveStatus, Er as placeFiles, Fn as gitRulesOf, Gr as beforeOf, In as loadProject, Ln as machineRulesOf, Mr as inside, Nt as userMessageText, On as templateOf, Q as parseInputPairs, Rn as createSignals, Tt as planNodeSession, U as openStore, X as createReplay, Y as inspectProject, Yn as runGh, Z as replayLoopAnswers, _i as AGENT_DRIVERS, an as createFollowUps, ar as renderTemplate, cr as socketPath, dn as deliverFollowUp, dr as maskReplacer, dt as createCalls, ft as adoptedCalls, gn as endLinksOf, gt as detachRun, ht as DETACHED_ENV, ir as parseTemplate, jt as startRun, kr as runDirOf, m as resolveBase, mi as readyDriver, n as resumedOptions, on as checkFollowUpsDue, qt as git, ri as isClaudeNode, si as retiredDriverHint, sr as serveRun, st as createRelay, t as createWorkspace, un as takeFollowUps, vt as NOT_STARTED, zn as endOf } from "./src-Dr_fTSu-.mjs";
2
- import { a as formatEvent, c as createTerminalHuman, o as formatRunEvent, s as callsShown, t as attachRun, u as createDecisionQueue } from "./attach-BHO3X3cf.mjs";
3
- import { h as nodeSession, n as ORK_VERSION, v as findFollowUp } from "./__build_info__-Bsb1kjgF.mjs";
4
- import { n as newRunId } from "./find-BYLlszqj.mjs";
1
+ import { Ct as startRun, G as parseInputPairs, Gn as endOf, Hn as loadProject, Ir as runDirOf, K as resolveInputs, L as openStore, Nr as placeFiles, Pn as templateOf, Qr as beforeOf, Qt as git, Sn as endLinksOf, St as walkSummary, Ti as DRIVER_IDS, Tt as userMessageText, U as createReplay, Un as machineRulesOf, Vn as gitRulesOf, W as replayLoopAnswers, Wn as createSignals, Zt as inspectProject, _n as deliverFollowUp, _r as maskReplacer, _t as planNodeSession, ar as createFeedback, at as adoptedCalls, ct as DETACHED_ENV, dn as createFollowUps, dr as renderTemplate, dt as NOT_STARTED, et as createRelay, fn as checkFollowUpsDue, gn as takeFollowUps, in as sessionDriver, it as createCalls, kn as liveStatus, lt as detachRun, m as resolveBase, mi as retiredDriverHint, mr as socketPath, n as resumedOptions, pr as serveRun, t as createWorkspace, tr as runGh, ui as isClaudeNode, ur as parseTemplate, wi as AGENT_DRIVERS, xi as readyDriver, zr as inside } from "./src-DN-RPsil.mjs";
2
+ import { c as callsShown, d as createDecisionQueue, l as createTerminalHuman, o as formatEvent, s as formatRunEvent, t as attachRun } from "./attach-B-FeE1dJ.mjs";
3
+ import { h as nodeSession, n as ORK_VERSION, v as findFollowUp } from "./__build_info__-DcRdK0Du.mjs";
4
+ import { n as newRunId } from "./find-mLYsR0uC.mjs";
5
5
  import { c as write, i as detachHint, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
6
- import { _ as namedMcpEntries, a as builtinExecutors, d as maskedEnv, f as maskedNamesOfRun, g as clearOutputFiles, h as sessionEnv, i as onPath, l as clearStateFiles, m as runScrubber, n as missingProgramMessage, r as missingPrograms, t as envProblems, v as resultOf } from "./src-DcrhgipG.mjs";
7
- import { i as refusedBuiltin, o as workflowArg } from "./workflows-CW28ZU-z.mjs";
8
- import { a as formatReport, c as checksHere, d as unfitLines, i as walkLoaded, l as chooseReadyDriver, o as warningLines, s as budgetWarningLines, t as loadWorkflow, u as runReadyDriver } from "./validate-Bs_gg22g.mjs";
6
+ import { _ as namedMcpEntries, a as builtinExecutors, d as maskedEnv, f as maskedNamesOfRun, g as clearOutputFiles, h as sessionEnv, i as onPath, l as clearStateFiles, m as runScrubber, n as missingProgramMessage, r as missingPrograms, t as envProblems, v as resultOf } from "./src-DHDQ0itC.mjs";
7
+ import { i as refusedBuiltin, o as workflowArg } from "./workflows-Bvl2Fquu.mjs";
8
+ import { a as formatReport, c as checksHere, d as runReadyDriver, f as unfitLines, i as walkLoaded, l as chooseReadyDriver, o as warningLines, s as budgetWarningLines, t as loadWorkflow, u as overrideRefusal } from "./validate-BVrT43GO.mjs";
9
9
  import { a as createView, o as styler } from "./verdict-CMvPCpWC.mjs";
10
- import { i as runLimits, r as limitsRefusal, t as chatNotice } from "./limits-B1qzS4cX.mjs";
10
+ import { i as runLimits, r as limitsRefusal, t as chatNotice } from "./limits-C_Xz_t3C.mjs";
11
11
  import path from "node:path";
12
12
  import { appendFileSync, existsSync, linkSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
13
13
  import { createHash, randomUUID } from "node:crypto";
@@ -478,9 +478,17 @@ const followUpSink = (options) => (input, at) => {
478
478
  ...options.gh === void 0 ? {} : { gh: options.gh }
479
479
  });
480
480
  };
481
+ /** Gh's own words when it has no login. */
482
+ const SIGNED_OUT = /not logged in|gh auth login/iu;
483
+ /**
484
+ * A gh error's first line, without a trailing period, so the notice is one
485
+ * line.
486
+ */
487
+ const oneLine = (error) => (error.trim().split("\n")[0] ?? "").trim().replace(/\.$/u, "");
481
488
  /**
482
489
  * Moves the project's follow-ups whose time has come to due, as every `ork
483
- * follow-ups` call does first. `gh` failing only warns, through `warn`.
490
+ * follow-ups` call does first. `gh` failing only warns, through `warn`: one
491
+ * line per call, however many refs failed.
484
492
  */
485
493
  const refreshDue = async (store, project, warn, gh = runGh) => {
486
494
  try {
@@ -489,7 +497,8 @@ const refreshDue = async (store, project, warn, gh = runGh) => {
489
497
  project,
490
498
  gh
491
499
  });
492
- for (const error of checked.errors) warn(`couldn't check a ref: ${error}`);
500
+ const [first] = checked.errors;
501
+ if (first !== void 0) warn(checked.errors.some((error) => SIGNED_OUT.test(error)) ? "Can't check PRs: `gh` isn't signed in. After-merge follow-ups stay waiting; run `gh auth login` yourself." : `Can't check PRs: ${oneLine(first)}. After-merge follow-ups stay waiting.`);
493
502
  return checked.due;
494
503
  } catch (error) {
495
504
  warn(`couldn't check what is due: ${error instanceof Error ? error.message : String(error)}`);
@@ -610,6 +619,10 @@ const runNode = async (options) => {
610
619
  named: plan.driver,
611
620
  pinned: plan.pinned
612
621
  });
622
+ if (options.driver !== void 0 && named === options.driver) {
623
+ const refusal = await overrideRefusal(options.driver, options.driverChecks);
624
+ if (refusal.length > 0) return failed(refusal);
625
+ }
613
626
  const ready = named === void 0 ? chooseReadyDriver([options.nodeId], true, await (options.driverChecks ?? checksHere)()) : null;
614
627
  if (ready?.ok === false) return failed(ready.lines);
615
628
  if (ready?.line !== void 0) options.err(ready.line);
@@ -1238,7 +1251,7 @@ const isDriver = (value) => AGENT_DRIVERS.some((d) => d.id === value);
1238
1251
  /** Why `--driver` refuses a value: a retired id names its replacement. */
1239
1252
  const badDriver = (value) => `--${retiredDriverHint(value) ?? `driver must be one of ${AGENT_DRIVERS.map((d) => d.id).join(", ")}, got \`${value}\``}`;
1240
1253
  /** Loads the drivers only when a run starts, so other commands stay fast. */
1241
- const loadRuntime = async (driver, runs) => (await import("./src-B9zWIVqo.mjs")).createRuntime(driver, sessionEnv(process.env), runs);
1254
+ const loadRuntime = async (driver, runs) => (await import("./src-CXBmaGwS.mjs")).createRuntime(driver, sessionEnv(process.env), runs);
1242
1255
  /**
1243
1256
  * Ctrl-C asks the run to stop, and so does a terminal closing or a polite kill,
1244
1257
  * so that the run ends tidily and leaves no result unscrubbed.
@@ -1293,7 +1306,7 @@ const run = defineCommand({
1293
1306
  },
1294
1307
  driver: {
1295
1308
  type: "string",
1296
- description: "claude-code (default: the driver ready here)"
1309
+ description: `${DRIVER_IDS.join(", ")} (default: the driver ready here)`
1297
1310
  },
1298
1311
  "in-place": {
1299
1312
  type: "boolean",
@@ -1393,7 +1406,7 @@ const run = defineCommand({
1393
1406
  }
1394
1407
  return;
1395
1408
  }
1396
- const { prepareFollowUps } = await import("./brief-za0ozN_E.mjs");
1409
+ const { prepareFollowUps } = await import("./brief-BvMtIFio.mjs");
1397
1410
  const taking = prepareFollowUps(store, rawArgs, args["run-id"], target);
1398
1411
  if (taking === void 0) {
1399
1412
  store.close();
@@ -1,4 +1,4 @@
1
- import { Jt as gitOk, qt as git } from "./src-Dr_fTSu-.mjs";
1
+ import { $t as gitOk, Qt as git } from "./src-DN-RPsil.mjs";
2
2
  import path from "node:path";
3
3
  import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { createHash, randomUUID } from "node:crypto";
@@ -1,6 +1,6 @@
1
- import { U as openStore, at as scriptRefusal, it as TOO_LONG, ot as sendFromScript } from "./src-Dr_fTSu-.mjs";
1
+ import { $ as sendFromScript, L as openStore, Q as scriptRefusal, Z as TOO_LONG } from "./src-DN-RPsil.mjs";
2
2
  import { l as writeErr } from "./output-B1kwo0YU.mjs";
3
- import { u as inheritedScrubber } from "./src-DcrhgipG.mjs";
3
+ import { u as inheritedScrubber } from "./src-DHDQ0itC.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  // src/commands/send.ts
6
6
  /**