@krapht/ork 1.0.0-alpha.7 → 1.0.0-alpha.9

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 (33) hide show
  1. package/dist/{__build_info__-BGoaUwLd.mjs → __build_info__-y1TPvZvp.mjs} +2 -2
  2. package/dist/bin.mjs +598 -51
  3. package/dist/{clean-BPITM-6p.mjs → clean-BRUXyk87.mjs} +5 -2
  4. package/dist/{completion-CCn8xWmO.mjs → completion-cpZHtv50.mjs} +5 -5
  5. package/dist/{context-CZNM454F.mjs → context-Dbay8l7P.mjs} +8 -7
  6. package/dist/{decide-DsA6kOT7.mjs → decide-BphP3ONM.mjs} +1 -1
  7. package/dist/{find-ntyniv2E.mjs → find-BXZjliwr.mjs} +1 -1
  8. package/dist/format-DeT7vL-8.mjs +191 -0
  9. package/dist/{in-a-run-D_fnj1Mw.mjs → in-a-run-C4E9HfED.mjs} +1 -1
  10. package/dist/{limits-BKzVMwkt.mjs → limits-CBeoYrUH.mjs} +1 -1
  11. package/dist/{list-D9HPWLPH.mjs → list-BmxgNyd3.mjs} +11 -4
  12. package/dist/{mcp-BFl3cIDp.mjs → mcp-DTreb7Nq.mjs} +6 -6
  13. package/dist/{output-CwqlG1Le.mjs → output-BVkI6ZVv.mjs} +1 -1
  14. package/dist/{pause-DhgKQORW.mjs → pause-h66SC4rV.mjs} +4 -4
  15. package/dist/{relay-Cp8JGrdv.mjs → relay-BxRhxL6n.mjs} +2 -2
  16. package/dist/{remove-CSpT_nJH.mjs → remove-CYGd9Csj.mjs} +14 -7
  17. package/dist/{send-CHiYkM6X.mjs → send-BskOwN4p.mjs} +3 -3
  18. package/dist/{src-BsLHKQRc.mjs → src-BwFxTank.mjs} +335 -107
  19. package/dist/{src-CUeMUVwW.mjs → src-W1i5Bl6N.mjs} +23 -9
  20. package/dist/{src-DhGLtYR-.mjs → src-bOImrq43.mjs} +30 -11
  21. package/dist/{src-BwnitlJh.mjs → src-xd9DbQw8.mjs} +8 -8
  22. package/dist/ui/assets/{app-D4CoH-lh.js → app-BMg0OOv4.js} +19 -19
  23. package/dist/ui/assets/app-C8uhHVYp.css +1 -0
  24. package/dist/ui/assets/{index-DxDGdEwz.js → index-DY1q4SDl.js} +2 -2
  25. package/dist/ui/index.html +1 -1
  26. package/dist/{ui-BxE0L7V0.mjs → ui-B46Z3e9E.mjs} +4 -4
  27. package/dist/{usage-BuzDsEhq.mjs → usage-DpHXbQEu.mjs} +5 -5
  28. package/dist/{watch-CCj0vU3B.mjs → watch-CJO1ee6Y.mjs} +6 -6
  29. package/dist/{workflows-BNCDD6J-.mjs → workflows-BJdSHnkr.mjs} +4 -3
  30. package/dist/{worktrees-DBBcaimX.mjs → worktrees-Ccf2lUhE.mjs} +72 -19
  31. package/package.json +1 -1
  32. package/dist/format-DaROJUgG.mjs +0 -662
  33. package/dist/ui/assets/app-Dt_tjFj6.css +0 -1
@@ -19,7 +19,7 @@
19
19
  href="/favicon.svg"
20
20
  type="image/svg+xml"
21
21
  />
22
- <script type="module" crossorigin src="/assets/index-DxDGdEwz.js"></script>
22
+ <script type="module" crossorigin src="/assets/index-DY1q4SDl.js"></script>
23
23
  <link rel="modulepreload" crossorigin href="/assets/theme-CdXvqTQ6.js">
24
24
  <link rel="stylesheet" crossorigin href="/assets/index-BPIbqRRb.css">
25
25
  </head>
@@ -1,7 +1,7 @@
1
- import { n as ORK_VERSION, t as ORK_NAME } from "./__build_info__-BGoaUwLd.mjs";
2
- import { a as write, i as style, o as writeErr } from "./output-CwqlG1Le.mjs";
3
- import { a as mayShowSignIn } from "./in-a-run-D_fnj1Mw.mjs";
4
- import { i as uiFilePath, l as newToken, n as startServer, r as runningServer, t as DEFAULT_PORT } from "./src-BwnitlJh.mjs";
1
+ import { n as ORK_VERSION, t as ORK_NAME } from "./__build_info__-y1TPvZvp.mjs";
2
+ import { a as write, i as style, o as writeErr } from "./output-BVkI6ZVv.mjs";
3
+ import { a as mayShowSignIn } from "./in-a-run-C4E9HfED.mjs";
4
+ import { i as uiFilePath, l as newToken, n as startServer, r as runningServer, t as DEFAULT_PORT } from "./src-xd9DbQw8.mjs";
5
5
  import path from "node:path";
6
6
  import { constants } from "node:os";
7
7
  import { spawn } from "node:child_process";
@@ -1,9 +1,9 @@
1
- import { En as runDirOf, bt as liveStatus, c as usd, wn as placeFor } from "./src-BsLHKQRc.mjs";
2
- import "./format-DaROJUgG.mjs";
3
- import { a as write, c as openStore, i as style, n as cost, o as writeErr, t as confirm } from "./output-CwqlG1Le.mjs";
4
- import { n as listOrkWorktrees, t as createdWorktrees } from "./list-D9HPWLPH.mjs";
1
+ import { En as placeFor, On as runDirOf, bt as liveStatus, c as usd } from "./src-BwFxTank.mjs";
2
+ import { a as write, c as openStore, i as style, n as cost, o as writeErr, t as confirm } from "./output-BVkI6ZVv.mjs";
3
+ import { n as listOrkWorktrees, t as createdWorktrees } from "./list-BmxgNyd3.mjs";
5
4
  import { n as usageReport, t as USAGE_DIMENSIONS } from "./report-DK4LGqwF.mjs";
6
- import { n as limitsHere } from "./limits-BKzVMwkt.mjs";
5
+ import "./format-DeT7vL-8.mjs";
6
+ import { n as limitsHere } from "./limits-CBeoYrUH.mjs";
7
7
  import { existsSync, rmSync } from "node:fs";
8
8
  import { defineCommand } from "citty";
9
9
  // ../core/src/store/prune.ts
@@ -1,9 +1,9 @@
1
- import { Cn as placeFiles, Dt as stillTheSameProcess, S as readProjectTriggers, T as watchingPid, Yn as CheckReportSchema, b as triggerStanding, bt as liveStatus, er as isToolNode, it as detachRun, nr as timeoutMs, v as triggersReport, w as takeWatchLock, x as declaredTriggers, y as createWatcher } from "./src-BsLHKQRc.mjs";
2
- import { n as newRunId } from "./find-ntyniv2E.mjs";
3
- import { a as write, c as openStore, i as style, o as writeErr, r as plain, t as confirm } from "./output-CwqlG1Le.mjs";
4
- import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-CUeMUVwW.mjs";
5
- import { i as runLimits, r as limitsRefusal } from "./limits-BKzVMwkt.mjs";
6
- import { t as acceptRefusal } from "./in-a-run-D_fnj1Mw.mjs";
1
+ import { Dt as stillTheSameProcess, S as readProjectTriggers, T as watchingPid, Tn as placeFiles, Zn as CheckReportSchema, b as triggerStanding, bt as liveStatus, ir as timeoutMs, it as detachRun, nr as isToolNode, v as triggersReport, w as takeWatchLock, x as declaredTriggers, y as createWatcher } from "./src-BwFxTank.mjs";
2
+ import { n as newRunId } from "./find-BXZjliwr.mjs";
3
+ import { a as write, c as openStore, i as style, o as writeErr, r as plain, t as confirm } from "./output-BVkI6ZVv.mjs";
4
+ import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-W1i5Bl6N.mjs";
5
+ import { i as runLimits, r as limitsRefusal } from "./limits-CBeoYrUH.mjs";
6
+ import { t as acceptRefusal } from "./in-a-run-C4E9HfED.mjs";
7
7
  import path from "node:path";
8
8
  import { mkdirSync } from "node:fs";
9
9
  import { homedir } from "node:os";
@@ -1,6 +1,6 @@
1
- import { Cn as placeFiles, En as runDirOf, kn as inside, wn as placeFor } from "./src-BsLHKQRc.mjs";
2
- import { i as builtinWorkflowFile, r as builtinProblem, s as isBuiltinArg } from "./decide-DsA6kOT7.mjs";
3
- import { c as openStore, l as storePath, o as writeErr } from "./output-CwqlG1Le.mjs";
1
+ import { En as placeFor, On as runDirOf, Tn as placeFiles, jn as inside } from "./src-BwFxTank.mjs";
2
+ import { i as builtinWorkflowFile, r as builtinProblem, s as isBuiltinArg } from "./decide-BphP3ONM.mjs";
3
+ import { c as openStore, l as storePath, o as writeErr } from "./output-BVkI6ZVv.mjs";
4
4
  import path from "node:path";
5
5
  import { existsSync, readdirSync, statSync } from "node:fs";
6
6
  // src/project/place.ts
@@ -40,6 +40,7 @@ const WORKFLOW_SUFFIX = ".ork.yaml";
40
40
  * that folder.
41
41
  */
42
42
  const findWorkflowFiles = (paths, cwd, workflows = path.join(cwd, WORKFLOW_DIR)) => {
43
+ if (paths.length === 0 && !existsSync(workflows)) return [];
43
44
  return (paths.length > 0 ? paths : [fromCwd(workflows, cwd)]).flatMap((target) => {
44
45
  const absolute = path.resolve(cwd, target);
45
46
  if (existsSync(absolute) && statSync(absolute).isDirectory()) return readdirSync(absolute).filter((name) => name.endsWith(WORKFLOW_SUFFIX)).toSorted().map((name) => path.join(target, name));
@@ -1,9 +1,28 @@
1
- import { D as inspectProject } from "./src-BsLHKQRc.mjs";
2
- import { a as write, c as openStore, i as style, o as writeErr, t as confirm } from "./output-CwqlG1Le.mjs";
3
- import { a as planClean, i as keyOf, o as stepActs, t as applyClean } from "./clean-BPITM-6p.mjs";
4
- import { a as readWorktrees, c as planLine, n as lostWork, o as labelOf, r as planRemove, s as mergeStateOf, t as applyRemove, u as stateParts } from "./remove-CSpT_nJH.mjs";
1
+ import { D as inspectProject } from "./src-BwFxTank.mjs";
2
+ import { a as write, c as openStore, i as style, o as writeErr, t as confirm } from "./output-BVkI6ZVv.mjs";
3
+ import { a as planClean, i as keyOf, o as stepActs, t as applyClean } from "./clean-BRUXyk87.mjs";
4
+ import { a as readWorktrees, c as mergeStateOf, d as stateParts, l as planLine, n as lostWork, o as repoRoot, r as planRemove, s as labelOf, t as applyRemove } from "./remove-CYGd9Csj.mjs";
5
5
  import path from "node:path";
6
+ import { realpathSync } from "node:fs";
6
7
  import { defineCommand } from "citty";
8
+ // src/project/go-ahead.ts
9
+ /**
10
+ * @file The question `ork worktrees clean` and `remove` ask before they act:
11
+ * skipped with `--yes`, impossible without a terminal (so `--yes` is needed),
12
+ * and a no says so rather than leaving the command silent.
13
+ */
14
+ /** Whether to carry on; says why not when it won't. */
15
+ const goAhead = async (yes, verb, terminal = process.stdin.isTTY, ask = confirm) => {
16
+ if (yes) return true;
17
+ if (!terminal) {
18
+ writeErr(`Pass --yes to ${verb} without a terminal.`);
19
+ process.exitCode = 1;
20
+ return false;
21
+ }
22
+ if (await ask("Go ahead? [y/N] ")) return true;
23
+ write("Cancelled.");
24
+ return false;
25
+ };
7
26
  // src/project/worktrees.ts
8
27
  /**
9
28
  * @file What `ork worktrees` prints: each worktree or branch a run left, with
@@ -32,6 +51,11 @@ const formatPlan = (steps) => steps.map((step) => {
32
51
  });
33
52
  /** What a forced remove loses, as git prints it, under a heading each. */
34
53
  const formatLost = (lost) => [...lost.changes.length === 0 ? [] : ["Uncommitted changes:", ...lost.changes.map((line) => ` ${line}`)], ...lost.commits.length === 0 ? [] : [lost.commitsOn === "no branch" ? "Commits on no branch:" : "Commits not merged:", ...lost.commits.map((line) => ` ${line}`)]];
54
+ /** What a forced clean loses, item by item: the same lines `remove` prints. */
55
+ const formatLosses = (losses) => losses.flatMap(({ item, lost }) => {
56
+ const lines = formatLost(lost);
57
+ return lines.length === 0 ? [] : [`Loses in ${labelOf(item)}:`, ...lines];
58
+ });
35
59
  // src/commands/worktrees.ts
36
60
  /**
37
61
  * @file `ork worktrees` (or `ork wt`): lists the worktrees and branches runs
@@ -41,10 +65,22 @@ const formatLost = (lost) => [...lost.changes.length === 0 ? [] : ["Uncommitted
41
65
  * the twin of the Worktrees panel's Remove…. The plans are core's, so the
42
66
  * panel keeps and removes exactly what these do.
43
67
  */
44
- /** The repo this folder is in, and what Ork created there; null outside one. */
45
- const here = async () => {
46
- const root = (await inspectProject(process.cwd()))?.root ?? null;
68
+ /**
69
+ * The repo this folder is in, and what Ork created there; null outside one. A
70
+ * repo with no commit has nothing of Ork's, which only a read says as an empty
71
+ * list.
72
+ */
73
+ const here = async (emptyWithoutCommit = false) => {
74
+ const cwd = process.cwd();
75
+ const root = (await inspectProject(cwd))?.root ?? null;
47
76
  if (root === null) {
77
+ const bare = emptyWithoutCommit ? await repoRoot(cwd) : null;
78
+ if (bare !== null) return {
79
+ root: bare,
80
+ items: [],
81
+ live: /* @__PURE__ */ new Set(),
82
+ runs: []
83
+ };
48
84
  writeErr("Not in a git repository with a commit.");
49
85
  process.exitCode = 1;
50
86
  return null;
@@ -53,27 +89,25 @@ const here = async () => {
53
89
  try {
54
90
  return {
55
91
  root,
92
+ runs: store.runs({ project: root }).map((run) => run.id),
56
93
  ...await readWorktrees(store, root)
57
94
  };
58
95
  } finally {
59
96
  store.close();
60
97
  }
61
98
  };
62
- /** Asks before acting, unless `--yes`; without a terminal `--yes` is needed. */
63
- const goAhead = (yes, verb) => {
64
- if (yes) return Promise.resolve(true);
65
- if (!process.stdin.isTTY) {
66
- writeErr(`Pass --yes to ${verb} without a terminal.`);
67
- process.exitCode = 1;
68
- return Promise.resolve(false);
99
+ const realOr = (target) => {
100
+ try {
101
+ return realpathSync(target);
102
+ } catch {
103
+ return target;
69
104
  }
70
- return confirm("Go ahead? [y/N] ");
71
105
  };
72
106
  const done = (lines) => {
73
107
  for (const line of lines) write(`${style("green", "✓")} ${line}`);
74
108
  };
75
109
  const show = async (json) => {
76
- const found = await here();
110
+ const found = await here(true);
77
111
  if (found === null) return;
78
112
  if (json) write(JSON.stringify(found.items, void 0, 2));
79
113
  else for (const line of formatWorktrees(found.items)) write(line);
@@ -132,7 +166,15 @@ const clean = defineCommand({
132
166
  const found = await here();
133
167
  if (found === null) return;
134
168
  const filter = { merged: !args.all };
135
- if (args.run !== void 0) filter.runId = args.run;
169
+ if (args.run !== void 0) {
170
+ const runId = found.runs.find((id) => id === args.run);
171
+ if (runId === void 0) {
172
+ writeErr(`No run ${args.run} in this project.`);
173
+ process.exitCode = 1;
174
+ return;
175
+ }
176
+ filter.runId = runId;
177
+ }
136
178
  const steps = planClean(found.items, filter, {
137
179
  branches: args.branches,
138
180
  force: args.force,
@@ -141,11 +183,21 @@ const clean = defineCommand({
141
183
  const acting = steps.filter((s) => stepActs(s));
142
184
  if (acting.length === 0) {
143
185
  for (const line of formatPlan(steps)) write(line);
144
- write("Nothing to clean.");
186
+ if (steps.length === 0) write("Nothing to clean.");
145
187
  return;
146
188
  }
147
189
  write("Plan:");
148
190
  for (const line of formatPlan(steps)) write(line);
191
+ if (args.force) {
192
+ const losses = await Promise.all(acting.map(async (step) => ({
193
+ item: step.item,
194
+ lost: await lostWork(found.root, {
195
+ step,
196
+ force: true
197
+ })
198
+ })));
199
+ for (const line of formatLosses(losses)) write(line);
200
+ }
149
201
  if (!await goAhead(args.yes, "clean")) return;
150
202
  done(await applyClean(found.root, acting, args.force));
151
203
  }
@@ -177,7 +229,8 @@ const remove = defineCommand({
177
229
  const found = await here();
178
230
  if (found === null) return;
179
231
  const byPath = path.resolve(args.target);
180
- const item = found.items.find((i) => keyOf(i) === args.target || labelOf(i) === args.target || i.path === byPath);
232
+ const paths = /* @__PURE__ */ new Set([byPath, realOr(byPath)]);
233
+ const item = found.items.find((i) => keyOf(i) === args.target || labelOf(i) === args.target || i.path !== null && paths.has(i.path));
181
234
  const planned = planRemove(found, item === void 0 ? args.target : keyOf(item), args.branch);
182
235
  if (!planned.ok) {
183
236
  writeErr(planned.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krapht/ork",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.9",
4
4
  "description": "Orchestrate Claude agents on your machine: hierarchical, serializable workflows with a CLI and a localhost UI.",
5
5
  "keywords": [
6
6
  "claude",