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

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 (40) hide show
  1. package/dist/{__build_info__-CIchF6nr.mjs → __build_info__-Da73_nBs.mjs} +4 -3
  2. package/dist/attach-E6NNyA3T.mjs +89 -0
  3. package/dist/bin.mjs +213 -1230
  4. package/dist/{decide-B6PnKeqo.mjs → builtin-files-n6o6oWpB.mjs} +3 -51
  5. package/dist/{chips-BA7SrrH5.mjs → chips-CyeB_rhR.mjs} +1 -1
  6. package/dist/{clean-Di-KT7Mf.mjs → clean-Bh4KZgzc.mjs} +1 -1
  7. package/dist/{completion-C5D0sEs5.mjs → completion-SNNNxnv9.mjs} +7 -6
  8. package/dist/{context-BaNshWr9.mjs → context-DHudLA5e.mjs} +6 -6
  9. package/dist/decide-DuIHACvH.mjs +50 -0
  10. package/dist/{find-BicBbGMg.mjs → find-CjsNYAAf.mjs} +1 -1
  11. package/dist/{format-lWhN-jYR.mjs → format-C60TFpRe.mjs} +5 -85
  12. package/dist/{help-groups-BwYoAWsh.mjs → help-groups-CyfPWlST.mjs} +8 -0
  13. package/dist/{in-a-run-CgkVouyG.mjs → in-a-run-BYjTXaST.mjs} +4 -2
  14. package/dist/{limits-jZQp9ZJC.mjs → limits-C5QKZNLT.mjs} +2 -2
  15. package/dist/{list-CEaJ07jd.mjs → list-BUb5Uc3H.mjs} +1 -1
  16. package/dist/{mcp-DYgVA9f5.mjs → mcp-bcctR-wc.mjs} +6 -6
  17. package/dist/once-DPQu5Q3H.mjs +76 -0
  18. package/dist/{output-CM95njYt.mjs → output-CnRzrbUM.mjs} +3 -1
  19. package/dist/{pause-D6PuSlNl.mjs → pause-BPvlDIvz.mjs} +4 -4
  20. package/dist/{relay-DNx7be9k.mjs → relay-C8W0t_zc.mjs} +2 -2
  21. package/dist/{remove-CpMb4NDl.mjs → remove-BkFWGVYo.mjs} +3 -3
  22. package/dist/run-CQIfq918.mjs +192 -0
  23. package/dist/{send-CLs_fyg7.mjs → send-CaZlGG5a.mjs} +3 -3
  24. package/dist/{src-D6_xjm-x.mjs → src-BeR6f70A.mjs} +595 -228
  25. package/dist/{src-B6KvTm7B.mjs → src-CGJGL1sZ.mjs} +7 -6
  26. package/dist/{src-BnZgZGrf.mjs → src-CqRqsb2t.mjs} +44 -7
  27. package/dist/{src-9iGkjnsy.mjs → src-D93tHZ5B.mjs} +110 -35
  28. package/dist/store-CM3cERGl.mjs +1365 -0
  29. package/dist/ui/THIRD_PARTY_LICENSES.txt +18 -0
  30. package/dist/ui/assets/app-DYRC0V4p.js +111 -0
  31. package/dist/ui/assets/{index-By_8KKG6.js → index-CWwm8HTG.js} +2 -2
  32. package/dist/ui/index.html +1 -1
  33. package/dist/{ui-CIci4UBW.mjs → ui-D2Ydofq0.mjs} +4 -4
  34. package/dist/{usage-GceBGMjU.mjs → usage-6WIowblz.mjs} +6 -6
  35. package/dist/verdict-CIy8tAyX.mjs +84 -0
  36. package/dist/{watch-BmoybMQg.mjs → watch-uOU_WeBI.mjs} +7 -7
  37. package/dist/{workflows-DZvW3i1e.mjs → workflows-7tQdMnrA.mjs} +3 -3
  38. package/dist/{worktrees-Be51E2rB.mjs → worktrees-ZCII298F.mjs} +5 -5
  39. package/package.json +1 -1
  40. package/dist/ui/assets/app-CxURph7a.js +0 -75
@@ -0,0 +1,192 @@
1
+ import { Rt as git, zt as gitOk } from "./src-BeR6f70A.mjs";
2
+ import path from "node:path";
3
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ import { tmpdir } from "node:os";
6
+ // ../core/src/once/key.ts
7
+ /**
8
+ * @file The key of a check run once (`ork once`, `verify: { once: true }`): the
9
+ * working tree's files as a git tree (tracked and untracked, not ignored),
10
+ * written through a temporary index so the real one is untouched, with `HEAD`
11
+ * and the repository's common git folder, where passes are kept for every
12
+ * worktree. The key is the files, not the commit: a commit or a no-op rebase
13
+ * keeps it.
14
+ */
15
+ /**
16
+ * The key of the files in the worktree at `cwd`. Rejects outside a git
17
+ * repository. Starts from a copy of the real index, so git hashes only the
18
+ * files whose stat changed.
19
+ */
20
+ const treeKeyOf = async (cwd) => {
21
+ const [commonDir = "", index = ""] = (await gitOk(cwd, [
22
+ "rev-parse",
23
+ "--git-common-dir",
24
+ "--git-path",
25
+ "index"
26
+ ])).split("\n").map((line) => path.resolve(cwd, line.trim()));
27
+ const scratch = mkdtempSync(path.join(tmpdir(), "ork-once-"));
28
+ const env = { GIT_INDEX_FILE: path.join(scratch, "index") };
29
+ try {
30
+ if (existsSync(index)) copyFileSync(index, env.GIT_INDEX_FILE);
31
+ await gitOk(cwd, ["add", "-A"], env);
32
+ const tree = (await gitOk(cwd, ["write-tree"], env)).trim();
33
+ const head = await git(cwd, [
34
+ "rev-parse",
35
+ "--verify",
36
+ "-q",
37
+ "HEAD"
38
+ ]);
39
+ return {
40
+ tree,
41
+ head: head.code === 0 ? head.stdout.trim() : null,
42
+ commonDir
43
+ };
44
+ } finally {
45
+ rmSync(scratch, {
46
+ recursive: true,
47
+ force: true
48
+ });
49
+ }
50
+ };
51
+ // ../core/src/once/store.ts
52
+ /**
53
+ * @file The passes of checks run once, kept in `<git-common-dir>/ork-once/`,
54
+ * outside every worktree and shared by all of them. A pass is one JSON file
55
+ * per check name, files and Node version; it holds the tree, `HEAD`, the time
56
+ * and who ran it, nothing else. Only a passing run writes one (Ork's process
57
+ * or the check's own, never an agent's edit). Pruned past 7 days or 500
58
+ * entries.
59
+ */
60
+ const ONCE_MAX_AGE_MS = 6048e5;
61
+ /** The folder of passes for a repository's common git folder. */
62
+ const onceDirOf = (commonDir) => path.join(commonDir, "ork-once");
63
+ const fileOf = (dir, name, tree, node) => path.join(dir, `${createHash("sha256").update(JSON.stringify([
64
+ name,
65
+ tree,
66
+ node
67
+ ])).digest("hex")}.json`);
68
+ const read = (file) => {
69
+ try {
70
+ const value = JSON.parse(readFileSync(file, "utf8"));
71
+ if (typeof value !== "object" || value === null || !("name" in value && "tree" in value && "head" in value && "node" in value && "at" in value && "who" in value)) return null;
72
+ const { name, tree, head, node, at, who } = value;
73
+ return typeof name === "string" && typeof tree === "string" && (typeof head === "string" || head === null) && typeof node === "string" && typeof at === "string" && typeof who === "string" ? {
74
+ name,
75
+ tree,
76
+ head,
77
+ node,
78
+ at,
79
+ who
80
+ } : null;
81
+ } catch {
82
+ return null;
83
+ }
84
+ };
85
+ /** The pass of `name` on these files, or `null`. */
86
+ const findPass = ({ key, name, withHead = false, node = process.version }) => {
87
+ const pass = read(fileOf(onceDirOf(key.commonDir), name, key.tree, node));
88
+ if (pass === null || pass.tree !== key.tree || pass.node !== node) return null;
89
+ return withHead && pass.head !== key.head ? null : pass;
90
+ };
91
+ /** Records a pass under `name` and each covered name, then prunes. */
92
+ const recordPass = ({ key, name, covers = [], who, node = process.version, at = /* @__PURE__ */ new Date() }) => {
93
+ const dir = onceDirOf(key.commonDir);
94
+ mkdirSync(dir, { recursive: true });
95
+ const pass = {
96
+ name,
97
+ tree: key.tree,
98
+ head: key.head,
99
+ node,
100
+ at: at.toISOString(),
101
+ who
102
+ };
103
+ for (const each of [name, ...covers]) {
104
+ const temp = path.join(dir, `.${randomUUID()}.tmp`);
105
+ writeFileSync(temp, `${JSON.stringify({
106
+ ...pass,
107
+ name: each
108
+ })}\n`);
109
+ renameSync(temp, fileOf(dir, each, pass.tree, node));
110
+ }
111
+ prunePasses(key.commonDir, { now: at });
112
+ return pass;
113
+ };
114
+ /**
115
+ * Removes passes older than `maxAgeMs` or past the newest `maxEntries`, and
116
+ * files that don't read as a pass. Returns how many it removed.
117
+ */
118
+ const prunePasses = (commonDir, { now = /* @__PURE__ */ new Date(), maxAgeMs = ONCE_MAX_AGE_MS, maxEntries = 500 } = {}) => {
119
+ const dir = onceDirOf(commonDir);
120
+ let names;
121
+ try {
122
+ names = readdirSync(dir).filter((name) => name.endsWith(".json"));
123
+ } catch {
124
+ return 0;
125
+ }
126
+ const kept = [];
127
+ const stale = [];
128
+ for (const name of names) {
129
+ const file = path.join(dir, name);
130
+ const at = Date.parse(read(file)?.at ?? "");
131
+ if (Number.isNaN(at) || now.getTime() - at > maxAgeMs) stale.push(file);
132
+ else kept.push({
133
+ file,
134
+ at
135
+ });
136
+ }
137
+ kept.sort((a, b) => b.at - a.at);
138
+ stale.push(...kept.slice(maxEntries).map((entry) => entry.file));
139
+ for (const file of stale) rmSync(file, { force: true });
140
+ return stale.length;
141
+ };
142
+ // ../core/src/once/run.ts
143
+ /**
144
+ * @file Runs a check once per set of files, for `ork once` and for
145
+ * `verify:`/tool commands with `once: true`: skip it when the same check
146
+ * already passed on identical files, else run it and record a pass when it
147
+ * exits 0 and the files didn't change while it ran. `force` and
148
+ * `ORK_ONCE=off` run it anyway; outside a git repository it always runs.
149
+ */
150
+ /** `null` outside a git repository: nothing to key the files by. */
151
+ const keyOf = (cwd) => treeKeyOf(cwd).catch(() => null);
152
+ /** Runs `run` unless the check already passed on these files. */
153
+ const runOnce = async ({ cwd, name, covers = [], withHead = false, force = false, who = "you", run, env = process.env, node = process.version }) => {
154
+ if (env["ORK_ONCE"] === "off") return {
155
+ skipped: false,
156
+ code: await run()
157
+ };
158
+ const before = await keyOf(cwd);
159
+ const earlier = before === null || force ? null : findPass({
160
+ key: before,
161
+ name,
162
+ withHead,
163
+ node
164
+ });
165
+ if (earlier !== null) return {
166
+ skipped: true,
167
+ pass: earlier,
168
+ code: 0
169
+ };
170
+ const code = await run();
171
+ if (code !== 0 || before === null) return {
172
+ skipped: false,
173
+ code
174
+ };
175
+ const after = await keyOf(cwd);
176
+ if (after?.tree !== before.tree || after.head !== before.head) return {
177
+ skipped: false,
178
+ code
179
+ };
180
+ return {
181
+ skipped: false,
182
+ pass: recordPass({
183
+ key: before,
184
+ name,
185
+ covers,
186
+ who,
187
+ node
188
+ }),
189
+ code
190
+ };
191
+ };
192
+ export { runOnce as t };
@@ -1,6 +1,6 @@
1
- import { C as openStore, Cn as wakeRun, jt as scriptContactsOf, xn as socketPath, xt as liveStatus } from "./src-D6_xjm-x.mjs";
2
- import { o as writeErr } from "./output-CM95njYt.mjs";
3
- import { u as inheritedScrubber } from "./src-9iGkjnsy.mjs";
1
+ import { Cn as socketPath, Dt as scriptContactsOf, Tn as wakeRun, _t as liveStatus, w as openStore } from "./src-BeR6f70A.mjs";
2
+ import { s as writeErr } from "./output-CnRzrbUM.mjs";
3
+ import { u as inheritedScrubber } from "./src-D93tHZ5B.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  // ../core/src/remote/send.ts
6
6
  /**