@krapht/ork 1.0.0-alpha.12 → 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.
- package/dist/{__build_info__-BJbE3Zvp.mjs → __build_info__-Da73_nBs.mjs} +3 -3
- package/dist/{attach-BmV5ckb9.mjs → attach-E6NNyA3T.mjs} +4 -4
- package/dist/bin.mjs +114 -55
- package/dist/{builtin-files-w0YULJ4c.mjs → builtin-files-n6o6oWpB.mjs} +2 -2
- package/dist/{clean-D8GI_2K-.mjs → clean-Bh4KZgzc.mjs} +1 -1
- package/dist/{completion-CzElB8nS.mjs → completion-SNNNxnv9.mjs} +6 -6
- package/dist/{context-BAwgVSX5.mjs → context-DHudLA5e.mjs} +4 -4
- package/dist/{decide-DlbyctOE.mjs → decide-DuIHACvH.mjs} +1 -1
- package/dist/{find-p05wlbmu.mjs → find-CjsNYAAf.mjs} +1 -1
- package/dist/{format-Dni98cbh.mjs → format-C60TFpRe.mjs} +1 -1
- package/dist/{help-groups-DYP_zMRP.mjs → help-groups-CyfPWlST.mjs} +4 -0
- package/dist/{in-a-run-BI-hLIl_.mjs → in-a-run-BYjTXaST.mjs} +1 -1
- package/dist/{limits-CElmhowV.mjs → limits-C5QKZNLT.mjs} +2 -2
- package/dist/{list-zW2xKuGr.mjs → list-BUb5Uc3H.mjs} +1 -1
- package/dist/{mcp-CM3b65AZ.mjs → mcp-bcctR-wc.mjs} +6 -6
- package/dist/once-DPQu5Q3H.mjs +76 -0
- package/dist/{pause-BuS83WAI.mjs → pause-BPvlDIvz.mjs} +3 -3
- package/dist/{relay-DAsJA8wF.mjs → relay-C8W0t_zc.mjs} +1 -1
- package/dist/{remove-Dh7D_hVn.mjs → remove-BkFWGVYo.mjs} +3 -3
- package/dist/run-CQIfq918.mjs +192 -0
- package/dist/{send-MFEQZH31.mjs → send-CaZlGG5a.mjs} +2 -2
- package/dist/{src-CdDTQLdQ.mjs → src-BeR6f70A.mjs} +424 -206
- package/dist/{src-S9yK2OHU.mjs → src-CGJGL1sZ.mjs} +7 -7
- package/dist/{src-D1QedD5y.mjs → src-CqRqsb2t.mjs} +44 -7
- package/dist/{src-BfxkJOYm.mjs → src-D93tHZ5B.mjs} +110 -35
- package/dist/{store-B2OaE4ID.mjs → store-CM3cERGl.mjs} +14 -5
- package/dist/ui/THIRD_PARTY_LICENSES.txt +18 -0
- package/dist/ui/assets/app-DYRC0V4p.js +111 -0
- package/dist/ui/assets/{index-BL7Ad0OA.js → index-CWwm8HTG.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-C4Ys26oO.mjs → ui-D2Ydofq0.mjs} +3 -3
- package/dist/{usage-C2zx-X6q.mjs → usage-6WIowblz.mjs} +4 -4
- package/dist/{watch-DzCeqM05.mjs → watch-uOU_WeBI.mjs} +5 -5
- package/dist/{workflows-Rr5w90A0.mjs → workflows-7tQdMnrA.mjs} +2 -2
- package/dist/{worktrees-f6SAbum5.mjs → worktrees-ZCII298F.mjs} +3 -3
- package/package.json +1 -1
- package/dist/ui/assets/app-CAoZtku5.js +0 -75
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as ORK_VERSION } from "./__build_info__-
|
|
3
|
-
import { p as runMarkerIn } from "./src-
|
|
4
|
-
import { n as explainNode } from "./context-
|
|
5
|
-
import { a as openMcp, c as refused, o as tool, s as answer } from "./src-
|
|
1
|
+
import { d as isNewer } from "./src-BeR6f70A.mjs";
|
|
2
|
+
import { n as ORK_VERSION } from "./__build_info__-Da73_nBs.mjs";
|
|
3
|
+
import { p as runMarkerIn } from "./src-D93tHZ5B.mjs";
|
|
4
|
+
import { n as explainNode } from "./context-DHudLA5e.mjs";
|
|
5
|
+
import { a as openMcp, c as refused, o as tool, s as answer } from "./src-CGJGL1sZ.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.
|
|
46
|
+
const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.13") ? tooOld(all, options.expects) : all;
|
|
47
47
|
const server = new McpServer({
|
|
48
48
|
name: "ork",
|
|
49
49
|
version: ORK_VERSION
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import "./src-BeR6f70A.mjs";
|
|
2
|
+
import { t as runOnce } from "./run-CQIfq918.mjs";
|
|
3
|
+
import { a as style, o as write, s as writeErr } from "./output-CnRzrbUM.mjs";
|
|
4
|
+
import { t as ago } from "./format-C60TFpRe.mjs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { defineCommand, parseArgs } from "citty";
|
|
7
|
+
// src/commands/once.ts
|
|
8
|
+
/**
|
|
9
|
+
* @file `ork once -- <command>`: runs a command unless the same check already
|
|
10
|
+
* passed on identical files, and records a pass (specs/check-once.md). The
|
|
11
|
+
* command's own output and exit code are `ork once`'s; a hit prints one line
|
|
12
|
+
* and exits 0. Everything after `--` is the command, so its flags are never
|
|
13
|
+
* Ork's.
|
|
14
|
+
*/
|
|
15
|
+
const args = {
|
|
16
|
+
as: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "The check's name (default: the command's text)"
|
|
19
|
+
},
|
|
20
|
+
covers: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Also record the pass for this name (repeat for more)"
|
|
23
|
+
},
|
|
24
|
+
"with-head": {
|
|
25
|
+
type: "boolean",
|
|
26
|
+
description: "Key the check by HEAD too (for checks relative to it)"
|
|
27
|
+
},
|
|
28
|
+
force: {
|
|
29
|
+
type: "boolean",
|
|
30
|
+
description: "Run even after a pass"
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** The command's exit code: a signal or a program that can't start is 1. */
|
|
34
|
+
const exitCodeOf = (command) => new Promise((resolve) => {
|
|
35
|
+
const [program = "", ...rest] = command;
|
|
36
|
+
const child = spawn(program, rest, { stdio: "inherit" });
|
|
37
|
+
child.on("error", (error) => {
|
|
38
|
+
writeErr(`Cannot run ${program}: ${error.message}`);
|
|
39
|
+
resolve(1);
|
|
40
|
+
});
|
|
41
|
+
child.on("close", (code) => {
|
|
42
|
+
resolve(code ?? 1);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
const listOf = (value) => [value].flat().filter((item) => typeof item === "string" && item !== "");
|
|
46
|
+
const once = defineCommand({
|
|
47
|
+
meta: {
|
|
48
|
+
name: "once",
|
|
49
|
+
description: "Run a command unless the same check already passed on these files: ork once [flags] -- <command…>"
|
|
50
|
+
},
|
|
51
|
+
args,
|
|
52
|
+
run: async ({ rawArgs }) => {
|
|
53
|
+
const split = rawArgs.indexOf("--");
|
|
54
|
+
const command = split === -1 ? [] : rawArgs.slice(split + 1);
|
|
55
|
+
if (command.length === 0) {
|
|
56
|
+
writeErr("Say what to run after --: ork once [--as <name>] [--covers <name>] [--with-head] [--force] -- <command…>");
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const given = parseArgs(rawArgs.slice(0, split), args);
|
|
61
|
+
const run = process.env["ORK_RUN"];
|
|
62
|
+
const node = process.env["ORK_NODE"];
|
|
63
|
+
const result = await runOnce({
|
|
64
|
+
cwd: process.cwd(),
|
|
65
|
+
name: given["as"] ?? command.join(" "),
|
|
66
|
+
covers: listOf(given["covers"]),
|
|
67
|
+
withHead: given["with-head"] === true,
|
|
68
|
+
force: given["force"] === true,
|
|
69
|
+
...run === void 0 || node === void 0 ? {} : { who: `${run}/${node}` },
|
|
70
|
+
run: () => exitCodeOf(command)
|
|
71
|
+
});
|
|
72
|
+
if (result.skipped) write(`${style("green", "✓")} check already passed on these files · ${ago(result.pass.at)} · ${result.pass.who}`);
|
|
73
|
+
process.exitCode = result.code;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
export { once };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as findRun } from "./find-
|
|
1
|
+
import { U as requestContinue, W as requestPause, w as openStore } from "./src-BeR6f70A.mjs";
|
|
2
|
+
import { t as findRun } from "./find-CjsNYAAf.mjs";
|
|
3
3
|
import { a as style, o as write, s as writeErr } from "./output-CnRzrbUM.mjs";
|
|
4
|
-
import { i as continueRefusal } from "./in-a-run-
|
|
4
|
+
import { i as continueRefusal } from "./in-a-run-BYjTXaST.mjs";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
// src/commands/pause.ts
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as addressOf, R as linkNodes, V as unlinkNodes, w as openStore } from "./src-BeR6f70A.mjs";
|
|
2
2
|
import { a as style, o as write, s as writeErr } from "./output-CnRzrbUM.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
// src/commands/relay.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as listOrkWorktrees, t as createdWorktrees } from "./list-
|
|
3
|
-
import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-
|
|
1
|
+
import { Bt as lines, Rt as git, _t as liveStatus } from "./src-BeR6f70A.mjs";
|
|
2
|
+
import { n as listOrkWorktrees, t as createdWorktrees } from "./list-BUb5Uc3H.mjs";
|
|
3
|
+
import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-Bh4KZgzc.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
|
|
@@ -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 {
|
|
1
|
+
import { Cn as socketPath, Dt as scriptContactsOf, Tn as wakeRun, _t as liveStatus, w as openStore } from "./src-BeR6f70A.mjs";
|
|
2
2
|
import { s as writeErr } from "./output-CnRzrbUM.mjs";
|
|
3
|
-
import { u as inheritedScrubber } from "./src-
|
|
3
|
+
import { u as inheritedScrubber } from "./src-D93tHZ5B.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
// ../core/src/remote/send.ts
|
|
6
6
|
/**
|