@krapht/ork 1.0.0-alpha.15 → 1.0.0-alpha.17
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/README.md +10 -4
- package/dist/{__build_info__-Bsb1kjgF.mjs → __build_info__-C1Nm0hlJ.mjs} +25 -6
- package/dist/apply-Mb0fNpCX.mjs +17 -0
- package/dist/{attach-CPespxlQ.mjs → attach-EP374oMP.mjs} +5 -5
- package/dist/{attach-BHO3X3cf.mjs → attach-RQx__RzH.mjs} +46 -8
- package/dist/bin.mjs +238 -369
- package/dist/brief-Bs3cMQU0.mjs +100 -0
- package/dist/{builtin-files-2bHf76x-.mjs → builtin-files-yYaNTQRU.mjs} +1 -1
- package/dist/command-tree-BkSYWmYJ.mjs +63 -0
- package/dist/{completion-CQ2UYKuJ.mjs → completion-DIXWlnAl.mjs} +87 -6
- package/dist/{context-BNqDw9z1.mjs → context-Dq-VM_sq.mjs} +3 -3
- package/dist/{find-BYLlszqj.mjs → find-k489laBa.mjs} +2 -2
- package/dist/flags-B4ZZWspN.mjs +125 -0
- package/dist/{follow-ups-B4GJ3Vzw.mjs → follow-ups-DD8NTPe6.mjs} +59 -24
- package/dist/{format-C8MsFj8_.mjs → format-DQc9A_ei.mjs} +17 -4
- package/dist/{help-groups-CQ98mLjF.mjs → help-groups-hB6kY34d.mjs} +1 -63
- package/dist/in-a-run-D_9GlAlS.mjs +27 -0
- package/dist/{install-DWtXTq4y.mjs → install-PVlV2QPq.mjs} +1 -1
- package/dist/{limits-B1qzS4cX.mjs → limits-CHqBO7wb.mjs} +1 -1
- package/dist/{mcp-BOrVkyhN.mjs → mcp-D38Ajb0b.mjs} +6 -6
- package/dist/{once-C1fL3GVo.mjs → once-DuUzpzL2.mjs} +3 -3
- package/dist/parse-BzWpMN-a.mjs +107 -0
- package/dist/{pause-DOMK-R8V.mjs → pause-Bx3ePGrn.mjs} +3 -3
- package/dist/{post-BzA6Qobq.mjs → post-2CaJz_mV.mjs} +5 -3
- package/dist/print-n2qetUHc.mjs +19 -0
- package/dist/project-records-Cune1l6I.mjs +230 -0
- package/dist/{relay-OWuu4fib.mjs → relay-D7RN4m68.mjs} +1 -1
- package/dist/{run-CiPsW9Kf.mjs → run-BfxdsQJk.mjs} +1 -1
- package/dist/{run--4-1xAF2.mjs → run-OOWQIKMJ.mjs} +33 -20
- package/dist/{send-CnNNW-ot.mjs → send-CKth_vgn.mjs} +2 -2
- package/dist/{src-B9zWIVqo.mjs → src-BHod38UQ.mjs} +104 -72
- package/dist/{src-Dr_fTSu-.mjs → src-DLsFsmOD.mjs} +790 -502
- package/dist/{src-DQKz2eOH.mjs → src-DOjTY2ET.mjs} +238 -79
- package/dist/{src-DcrhgipG.mjs → src-DmmrX2_C.mjs} +162 -58
- package/dist/{store-oKJ-cCf3.mjs → store-DACH768X.mjs} +1 -1
- package/dist/ui/assets/app-9Q-62Ywz.css +1 -0
- package/dist/ui/assets/app-CN3acQ-1.js +111 -0
- package/dist/ui/assets/{index-BtwkftKe.js → index-B2uGxA4W.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-CzKlsCnm.mjs → ui-CJ-BX12n.mjs} +3 -3
- package/dist/{usage-DHGNk2JL.mjs → usage-DxZ6JGd4.mjs} +62 -107
- package/dist/{validate-Bs_gg22g.mjs → validate-BS0nCccW.mjs} +35 -8
- package/dist/{watch-CCCfw3n7.mjs → watch-Dp7IB4FR.mjs} +5 -5
- package/dist/{workflows-CW28ZU-z.mjs → workflows-Djo1edlK.mjs} +2 -2
- package/dist/{worktrees-CyE8aF6j.mjs → worktrees-Drof_Nyx.mjs} +49 -20
- package/package.json +8 -4
- package/dist/brief-za0ozN_E.mjs +0 -58
- package/dist/in-a-run-Bp0k0J09.mjs +0 -24
- package/dist/ui/assets/app-Bdc6OBeZ.css +0 -1
- package/dist/ui/assets/app-Drp8Dm9y.js +0 -111
package/dist/ui/index.html
CHANGED
|
@@ -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-
|
|
22
|
+
<script type="module" crossorigin src="/assets/index-B2uGxA4W.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__-
|
|
1
|
+
import { n as ORK_VERSION, t as ORK_NAME } from "./__build_info__-C1Nm0hlJ.mjs";
|
|
2
2
|
import { c as write, l as writeErr, s as style } from "./output-B1kwo0YU.mjs";
|
|
3
|
-
import { o as mayShowSignIn } from "./in-a-run-
|
|
4
|
-
import { i as uiFilePath, l as newToken, n as startServer, r as runningServer, t as DEFAULT_PORT } from "./src-
|
|
3
|
+
import { o as mayShowSignIn } from "./in-a-run-D_9GlAlS.mjs";
|
|
4
|
+
import { i as uiFilePath, l as newToken, n as startServer, r as runningServer, t as DEFAULT_PORT } from "./src-DOjTY2ET.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { constants } from "node:os";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
@@ -1,57 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as planPrune, Fr as placeFor, L as openStore, Wt as usageListTable, g as usageReport, h as USAGE_DIMENSIONS, z as applyPrune } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { r as agoTime } from "./parse-BzWpMN-a.mjs";
|
|
2
3
|
import { C as termOf, c as write, l as writeErr, n as cost, o as shortCount, r as costOf, s as style, t as confirm } from "./output-B1kwo0YU.mjs";
|
|
3
4
|
import { n as chip, t as CHIP_LABELS } from "./chips-BqcT58qr.mjs";
|
|
4
|
-
import { n as limitsHere } from "./limits-
|
|
5
|
-
import {
|
|
5
|
+
import { n as limitsHere } from "./limits-CHqBO7wb.mjs";
|
|
6
|
+
import { i as readListArgs, n as filterArgs, o as allAlias, r as projectScope } from "./flags-B4ZZWspN.mjs";
|
|
7
|
+
import { a as header, o as table } from "./format-DQc9A_ei.mjs";
|
|
6
8
|
import { defineCommand } from "citty";
|
|
7
9
|
// src/runs/usage.ts
|
|
8
|
-
/**
|
|
9
|
-
* @file How usage reads on the terminal (`ork usage`, specs/usage.md), and the
|
|
10
|
-
* times its `--since`, `--until` and `ork prune --older-than` take.
|
|
11
|
-
*/
|
|
12
|
-
const UNITS = {
|
|
13
|
-
h: 36e5,
|
|
14
|
-
d: 864e5,
|
|
15
|
-
w: 6048e5
|
|
16
|
-
};
|
|
17
|
-
/** `30d`, `12w`, `24h` before `now`, as an ISO time; `null` when it is not one. */
|
|
18
|
-
const agoTime = (text, now) => {
|
|
19
|
-
const match = /^(\d+)([hdw])$/u.exec(text);
|
|
20
|
-
if (match === null) return null;
|
|
21
|
-
const [, amount = "0", unit = "d"] = match;
|
|
22
|
-
if (Number(amount) === 0) return null;
|
|
23
|
-
const date = new Date(now - Number(amount) * (UNITS[unit] ?? 0));
|
|
24
|
-
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
25
|
-
};
|
|
26
|
-
/** A `YYYY-MM-DD` day's start in the machine's time zone, `after` days on. */
|
|
27
|
-
const dayTime = (text, after) => {
|
|
28
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})$/u.exec(text);
|
|
29
|
-
if (match === null) return null;
|
|
30
|
-
const [, year = "", month = "", day = ""] = match;
|
|
31
|
-
const start = new Date(Number(year), Number(month) - 1, Number(day));
|
|
32
|
-
if (start.getMonth() !== Number(month) - 1) return null;
|
|
33
|
-
if (start.getDate() !== Number(day)) return null;
|
|
34
|
-
start.setDate(start.getDate() + after);
|
|
35
|
-
return start.toISOString();
|
|
36
|
-
};
|
|
37
|
-
/** The start of the day `days` whole days ago, counting today as one. */
|
|
38
|
-
const wholeDays = (days, now) => {
|
|
39
|
-
const today = new Date(now);
|
|
40
|
-
return new Date(today.getFullYear(), today.getMonth(), today.getDate() - (days - 1)).toISOString();
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* `--since`: an age or the day it starts from. Days and weeks are whole days,
|
|
44
|
-
* today among them, as the Usage panel counts them; hours are exact.
|
|
45
|
-
*/
|
|
46
|
-
const sinceTime = (text, now) => {
|
|
47
|
-
const ago = agoTime(text, now);
|
|
48
|
-
if (ago === null) return dayTime(text, 0);
|
|
49
|
-
if (text.endsWith("h")) return ago;
|
|
50
|
-
const amount = Number(text.slice(0, -1));
|
|
51
|
-
return wholeDays(text.endsWith("w") ? amount * 7 : amount, now);
|
|
52
|
-
};
|
|
53
|
-
/** `--until`: the last day it includes. */
|
|
54
|
-
const untilTime = (text) => dayTime(text, 1);
|
|
55
10
|
/** `950`, `12.3k`, `4.5M`. */
|
|
56
11
|
const tokens = shortCount;
|
|
57
12
|
const percent = (share) => `${String(Math.round(share * 100))}%`;
|
|
@@ -87,7 +42,7 @@ const usageTable = (term, groups, cpu = false) => table(term, [
|
|
|
87
42
|
{ text: group.key },
|
|
88
43
|
{ text: cost(group.costUsd) },
|
|
89
44
|
{ text: String(group.sessions) },
|
|
90
|
-
{ text: `${tokens(group.inputTokens + group.cacheReadTokens + group.cacheWriteTokens)}
|
|
45
|
+
{ text: `${tokens(group.inputTokens + group.cacheReadTokens + group.cacheWriteTokens)} prompt / ${tokens(group.outputTokens)} out` },
|
|
91
46
|
{ text: percent(group.cacheHitRate) },
|
|
92
47
|
...cpu ? [{ text: cpuText(group.cpuMs) }] : []
|
|
93
48
|
])], " ");
|
|
@@ -106,6 +61,15 @@ const shortTime = (iso) => new Date(iso).toLocaleString(void 0, {
|
|
|
106
61
|
});
|
|
107
62
|
/** A warning line: a `WARN` chip when rich, else the line in yellow. */
|
|
108
63
|
const warned = (term, text) => term.rich ? ` ${chip(term, CHIP_LABELS.warn, "warn")} ${text}` : style("yellow", ` ${text}`);
|
|
64
|
+
/**
|
|
65
|
+
* `$0.0000 of $0.0100`: both sides of a dollar cap with the same digits, four
|
|
66
|
+
* when either is under a dollar, else cents (`usd` alone gives `$0.00 of
|
|
67
|
+
* $0.0100`).
|
|
68
|
+
*/
|
|
69
|
+
const capAmounts = (spent, cap) => {
|
|
70
|
+
const places = cap < 1 || spent > 0 && spent < 1 ? 4 : 2;
|
|
71
|
+
return `$${spent.toFixed(places)} of $${cap.toFixed(places)}`;
|
|
72
|
+
};
|
|
109
73
|
/** The limits across runs, above a report; nothing with none set. */
|
|
110
74
|
const formatLimits = ({ problems, caps, tokenCaps = [], plan }, term = termOf(process.stdout)) => {
|
|
111
75
|
if (problems.length === 0 && caps.length === 0 && tokenCaps.length === 0 && plan.length === 0) return [];
|
|
@@ -113,7 +77,7 @@ const formatLimits = ({ problems, caps, tokenCaps = [], plan }, term = termOf(pr
|
|
|
113
77
|
style("bold", "Limits"),
|
|
114
78
|
...problems.map((problem) => warned(term, problem)),
|
|
115
79
|
...caps.map((cap) => {
|
|
116
|
-
const line = ` ${cap.project === void 0 ? "all projects" : "this project"}, this ${cap.window}: ${
|
|
80
|
+
const line = ` ${cap.project === void 0 ? "all projects" : "this project"}, this ${cap.window}: ${capAmounts(cap.spentUsd, cap.capUsd)}, resets ${shortTime(cap.resetsAt)}`;
|
|
117
81
|
return cap.leftUsd <= 0 ? warned(term, line.trimStart()) : line;
|
|
118
82
|
}),
|
|
119
83
|
...tokenCaps.map((cap) => {
|
|
@@ -128,7 +92,7 @@ const formatLimits = ({ problems, caps, tokenCaps = [], plan }, term = termOf(pr
|
|
|
128
92
|
const formatUsage = (report, scope, by, term = termOf(process.stdout)) => {
|
|
129
93
|
const { totals } = report;
|
|
130
94
|
if (totals.sessions === 0) return [`No Claude sessions in ${scope}.`];
|
|
131
|
-
const lines = [`${style("bold", costOf(totals.costUsd, totals.partial, totals.tokens))} in ${scope}`, `${counted(totals.runs, "run")} · ${counted(totals.sessions, "session")} · ${counted(totals.turns, "turn")} · ${tokens(totals.inputTokens + totals.cacheReadTokens + totals.cacheWriteTokens)}
|
|
95
|
+
const lines = [`${style("bold", costOf(totals.costUsd, totals.partial, totals.tokens))} in ${scope}`, `${counted(totals.runs, "run")} · ${counted(totals.sessions, "session")} · ${counted(totals.turns, "turn")} · ${tokens(totals.inputTokens + totals.cacheReadTokens + totals.cacheWriteTokens)} prompt / ${tokens(totals.outputTokens)} out${totals.tokens === void 0 ? "" : ` (${tokens(totals.tokens)} counted)`} · ${percent(totals.cacheHitRate)} from cache`];
|
|
132
96
|
for (const dimension of by === void 0 ? OVERVIEW : [by]) {
|
|
133
97
|
const groups = report.groups[dimension];
|
|
134
98
|
const shown = by === void 0 ? dimension === "day" ? groups.slice(-10) : groups.slice(0, OVERVIEW_ROWS) : groups;
|
|
@@ -163,67 +127,58 @@ const usage = defineCommand({
|
|
|
163
127
|
name: "usage",
|
|
164
128
|
description: "Show what this project's runs spent over time"
|
|
165
129
|
},
|
|
166
|
-
args: {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
default: "30d"
|
|
181
|
-
},
|
|
182
|
-
until: {
|
|
183
|
-
type: "string",
|
|
184
|
-
description: "The last day to include"
|
|
185
|
-
},
|
|
186
|
-
by: {
|
|
187
|
-
type: "string",
|
|
188
|
-
description: USAGE_DIMENSIONS.join(", ")
|
|
189
|
-
},
|
|
190
|
-
workflow: {
|
|
191
|
-
type: "string",
|
|
192
|
-
description: "Only this workflow"
|
|
193
|
-
},
|
|
194
|
-
json: {
|
|
195
|
-
type: "boolean",
|
|
196
|
-
description: "Print JSON",
|
|
197
|
-
default: false
|
|
130
|
+
args: filterArgs(usageListTable, {
|
|
131
|
+
ids: false,
|
|
132
|
+
limit: false,
|
|
133
|
+
extra: {
|
|
134
|
+
...allAlias,
|
|
135
|
+
"clear-plan-limits": {
|
|
136
|
+
type: "boolean",
|
|
137
|
+
description: "Forget what Claude Code last said of your plan's limits, for one that has lifted",
|
|
138
|
+
default: false
|
|
139
|
+
},
|
|
140
|
+
by: {
|
|
141
|
+
type: "string",
|
|
142
|
+
description: USAGE_DIMENSIONS.join(", ")
|
|
143
|
+
}
|
|
198
144
|
}
|
|
199
|
-
},
|
|
145
|
+
}),
|
|
200
146
|
run: ({ args }) => {
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
refuse(`--by takes one of ${USAGE_DIMENSIONS.join(", ")}, not \`${args.by}\`.`);
|
|
147
|
+
const asked = args["since"];
|
|
148
|
+
const since = typeof asked === "string" ? asked : "30d";
|
|
149
|
+
const request = readListArgs(usageListTable, {
|
|
150
|
+
...args,
|
|
151
|
+
since
|
|
152
|
+
}, { all: "project" });
|
|
153
|
+
if (request === void 0) return;
|
|
154
|
+
const rawBy = args["by"];
|
|
155
|
+
const given = typeof rawBy === "string" ? rawBy : void 0;
|
|
156
|
+
if (given !== void 0 && !isDimension(given)) {
|
|
157
|
+
refuse(`--by takes one of ${USAGE_DIMENSIONS.join(", ")}, not \`${given}\`.`);
|
|
213
158
|
return;
|
|
214
159
|
}
|
|
160
|
+
const by = given;
|
|
215
161
|
const store = openStore();
|
|
216
162
|
try {
|
|
217
|
-
|
|
163
|
+
const scope = projectScope(request.filter, store.projects());
|
|
164
|
+
if (scope === void 0) return;
|
|
165
|
+
const named = typeof scope === "object" ? scope.root : void 0;
|
|
166
|
+
const place = scope === "here" ? placeFor(process.cwd(), store.projects()) : store.projects().find((p) => p.root === named);
|
|
167
|
+
const { workflow, until, since: from } = request.filter;
|
|
168
|
+
if (args["clear-plan-limits"] === true) {
|
|
169
|
+
const cleared = store.clearPlanLimits();
|
|
170
|
+
const said = cleared === 0 ? "No plan limit was recorded." : `Cleared ${String(cleared)} plan limit(s).`;
|
|
171
|
+
(args["json"] === true ? writeErr : write)(said);
|
|
172
|
+
}
|
|
218
173
|
const filter = {
|
|
219
|
-
...
|
|
220
|
-
...
|
|
221
|
-
...
|
|
174
|
+
...place === void 0 ? {} : { project: place.root },
|
|
175
|
+
...workflow === void 0 ? {} : { workflow },
|
|
176
|
+
...from === void 0 || from === "all" ? {} : { since: from },
|
|
222
177
|
...until === void 0 ? {} : { until }
|
|
223
178
|
};
|
|
224
179
|
const report = usageReport(store.usage(filter), store.toolCpu(filter));
|
|
225
|
-
const limits = limitsHere(store,
|
|
226
|
-
if (args
|
|
180
|
+
const limits = limitsHere(store, place);
|
|
181
|
+
if (args["json"] === true) {
|
|
227
182
|
write(JSON.stringify({
|
|
228
183
|
...report,
|
|
229
184
|
limits
|
|
@@ -231,9 +186,9 @@ const usage = defineCommand({
|
|
|
231
186
|
return;
|
|
232
187
|
}
|
|
233
188
|
for (const line of formatLimits(limits)) write(line);
|
|
234
|
-
const
|
|
235
|
-
const period =
|
|
236
|
-
for (const line of formatUsage(report, `${
|
|
189
|
+
const where = scope === "here" ? "this project" : scope === "all" ? "every project" : `project ${String(request.filter["project"])}`;
|
|
190
|
+
const period = since === "all" ? "" : `, since ${since}`;
|
|
191
|
+
for (const line of formatUsage(report, `${where}${period}`, by)) write(line);
|
|
237
192
|
} finally {
|
|
238
193
|
store.close();
|
|
239
194
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as readUpdateCache, f as refreshUpdateCache, i as registryOf, l as newerVersion, m as writeUpdateCache, n as ORK_VERSION, o as updateSwitchOff, p as updateCachePath, r as isSwitchedOn, s as checkDue, t as ORK_NAME, u as pendingNotice } from "./__build_info__-
|
|
1
|
+
import { Ai as knownExperiments, D as triggersReport, Di as firstLine, E as lateTriggers, Ei as DRIVER_IDS, Fr as placeFor, J as driverRefusals, L as openStore, M as workflowTextHash, Oi as EXPERIMENTS, Pr as placeFiles, R as storePath, Si as readyDriver, St as walkSummary, Ti as AGENT_DRIVERS, Un as loadProject, X as driverQueues, _i as INTEGRATIONS, bt as checkWorkflowText, gr as socketRoom, hi as retiredDriverHint, in as namingNoDriver, j as readProjectTriggers, ki as experimentsOn, pi as DriverSchema, q as budgetWarnings, xi as driverChecks, xt as walkChecks, zr as workflowDirOf } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { d as readUpdateCache, f as refreshUpdateCache, i as registryOf, l as newerVersion, m as writeUpdateCache, n as ORK_VERSION, o as updateSwitchOff, p as updateCachePath, r as isSwitchedOn, s as checkDue, t as ORK_NAME, u as pendingNotice } from "./__build_info__-C1Nm0hlJ.mjs";
|
|
3
3
|
import { C as termOf, D as wrap, E as widthOf, a as plain, c as write, h as paint, l as writeErr, s as style, w as cut, x as plainEnv } from "./output-B1kwo0YU.mjs";
|
|
4
4
|
import { n as chip, t as CHIP_LABELS } from "./chips-BqcT58qr.mjs";
|
|
5
|
-
import { c as registeredProjects, i as refusedBuiltin, r as findWorkflowFiles, s as projectAt } from "./workflows-
|
|
5
|
+
import { c as registeredProjects, i as refusedBuiltin, r as findWorkflowFiles, s as projectAt } from "./workflows-Djo1edlK.mjs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { readFileSync } from "node:fs";
|
|
8
8
|
import { execFile, spawn } from "node:child_process";
|
|
@@ -304,10 +304,30 @@ const experimentsCheck = (place, env = process.env, registry = EXPERIMENTS) => {
|
|
|
304
304
|
* `driver.ts` has the whole rule): the one `ork doctor`'s own checks find
|
|
305
305
|
* ready on this machine, said in one line. With none ready, the run stops
|
|
306
306
|
* before any session starts, with the hints `ork doctor` gives. A resumed run
|
|
307
|
-
* keeps the driver it recorded.
|
|
307
|
+
* keeps the driver it recorded. `--driver <id>` skips that look but checks
|
|
308
|
+
* that one driver's tool, and stops the run the same way when it isn't
|
|
309
|
+
* ready.
|
|
308
310
|
*/
|
|
309
311
|
/** The real checks: the tools on this machine and its environment. */
|
|
310
|
-
const checksHere = () => driverChecks(exec, process.env)
|
|
312
|
+
const checksHere = (only) => only === void 0 ? driverChecks(exec, process.env) : Promise.all(AGENT_DRIVERS.filter(({ id }) => id === only).map(async (driver) => ({
|
|
313
|
+
id: driver.id,
|
|
314
|
+
result: await driver.doctor(exec, process.env)
|
|
315
|
+
})));
|
|
316
|
+
/**
|
|
317
|
+
* What stops a run on `--driver <id>`: its own doctor check isn't `ok`, so its
|
|
318
|
+
* tool isn't found or isn't signed in. Empty when it is ready. Drivers named on
|
|
319
|
+
* nodes aren't looked at here; they can sit on a branch that never runs.
|
|
320
|
+
*/
|
|
321
|
+
const overrideRefusal = async (id, checks) => {
|
|
322
|
+
const found = (await (checks ?? checksHere)(id)).find((c) => c.id === id);
|
|
323
|
+
if (found === void 0 || found.result.status === "ok") return [];
|
|
324
|
+
const { detail, hint } = found.result;
|
|
325
|
+
return [
|
|
326
|
+
`--driver ${id}: ${id} isn't ready here (${detail}).`,
|
|
327
|
+
...hint === void 0 ? [] : [hint],
|
|
328
|
+
"See `ork doctor`."
|
|
329
|
+
];
|
|
330
|
+
};
|
|
311
331
|
const subject = (names, all) => {
|
|
312
332
|
if (all) return "No driver is named, so the run uses";
|
|
313
333
|
const [only] = names;
|
|
@@ -340,7 +360,13 @@ const chooseReadyDriver = (names, all, checks) => {
|
|
|
340
360
|
* recorded; otherwise the one ready here.
|
|
341
361
|
*/
|
|
342
362
|
const runReadyDriver = async (workflow, options) => {
|
|
343
|
-
if (options.override !== void 0)
|
|
363
|
+
if (options.override !== void 0) {
|
|
364
|
+
const lines = await overrideRefusal(options.override, options.checks);
|
|
365
|
+
return lines.length === 0 ? { ok: true } : {
|
|
366
|
+
ok: false,
|
|
367
|
+
lines
|
|
368
|
+
};
|
|
369
|
+
}
|
|
344
370
|
const names = namingNoDriver(workflow);
|
|
345
371
|
if (names.length === 0) return { ok: true };
|
|
346
372
|
if (options.recorded !== void 0) return {
|
|
@@ -431,7 +457,8 @@ const pathLines = (walk) => {
|
|
|
431
457
|
// src/commands/validate-report.ts
|
|
432
458
|
const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
433
459
|
const diagnosticLine = (file, d, term) => {
|
|
434
|
-
const
|
|
460
|
+
const at = d.file ?? file;
|
|
461
|
+
const where = d.line === void 0 ? at : `${at}:${d.line}:${d.column ?? 1}`;
|
|
435
462
|
if (term.rich) return [
|
|
436
463
|
`${d.severity === "error" ? chip(term, CHIP_LABELS.error, "danger") : chip(term, CHIP_LABELS.warn, "warn")} ${paint(term, "muted", cut(where, term.width - 9))}`,
|
|
437
464
|
...wrap(d.message, term.width - 2).map((line) => ` ${line}`),
|
|
@@ -602,4 +629,4 @@ const validate = defineCommand({
|
|
|
602
629
|
if (reports.some((r) => hasErrors(r.diagnostics))) process.exitCode = 1;
|
|
603
630
|
}
|
|
604
631
|
});
|
|
605
|
-
export {
|
|
632
|
+
export { startUpdateCheck as C, showUpdateNotice as S, runChecks as _, formatReport as a, UPDATE_CHILD_ENV as b, checksHere as c, runReadyDriver as d, unfitLines as f, orkCheck as g, headWarning as h, walkLoaded as i, chooseReadyDriver as l, experimentsCheck as m, validate as n, warningLines as o, exec as p, validateFile as r, budgetWarningLines as s, loadWorkflow as t, overrideRefusal as u, socketCheck as v, updateCheckOff as w, runUpdateChild as x, triggerChecks as y };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as newRunId } from "./find-
|
|
1
|
+
import { A as declaredTriggers, An as liveStatus, D as triggersReport, L as openStore, Ln as stillTheSameProcess, N as takeWatchLock, O as createWatcher, P as watchingPid, Pr as placeFiles, fi as isToolNode, gi as timeoutMs, gn as startFollowUpChecks, j as readProjectTriggers, k as triggerStanding, lt as detachRun, nr as runGh, si as CheckReportSchema } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { n as newRunId } from "./find-k489laBa.mjs";
|
|
3
3
|
import { C as termOf, E as widthOf, a as plain, c as write, l as writeErr, s as style, t as confirm, w as cut } from "./output-B1kwo0YU.mjs";
|
|
4
4
|
import { n as chip, t as CHIP_LABELS } from "./chips-BqcT58qr.mjs";
|
|
5
|
-
import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-
|
|
6
|
-
import { i as runLimits, r as limitsRefusal } from "./limits-
|
|
7
|
-
import { t as acceptRefusal } from "./in-a-run-
|
|
5
|
+
import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-DmmrX2_C.mjs";
|
|
6
|
+
import { i as runLimits, r as limitsRefusal } from "./limits-CHqBO7wb.mjs";
|
|
7
|
+
import { t as acceptRefusal } from "./in-a-run-D_9GlAlS.mjs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { mkdirSync } from "node:fs";
|
|
10
10
|
import { homedir } from "node:os";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as isBuiltinArg, n as builtinWorkflowFile, t as builtinProblem } from "./builtin-files-
|
|
1
|
+
import { Br as inside, Fr as placeFor, L as openStore, Lr as runDirOf, Pr as placeFiles, R as storePath } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { a as isBuiltinArg, n as builtinWorkflowFile, t as builtinProblem } from "./builtin-files-yYaNTQRU.mjs";
|
|
3
3
|
import { l as writeErr } from "./output-B1kwo0YU.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Gt as worktreeListTable, Jt as keyOf, Kt as applyClean, L as openStore, Qt as inspectProject, Xt as stepActs, Yt as planClean, a as planRemove, c as repoRoot, d as planLine, i as lostWork, l as labelOf, p as stateParts, r as applyRemove, s as readWorktrees, u as mergeStateOf } from "./src-DLsFsmOD.mjs";
|
|
2
|
+
import { t as applyFilters } from "./apply-Mb0fNpCX.mjs";
|
|
2
3
|
import { C as termOf, c as write, h as paint, l as writeErr, s as style, t as confirm, w as cut } from "./output-B1kwo0YU.mjs";
|
|
3
4
|
import { n as chip } from "./chips-BqcT58qr.mjs";
|
|
5
|
+
import { i as readListArgs, n as filterArgs, r as projectScope } from "./flags-B4ZZWspN.mjs";
|
|
6
|
+
import { t as printList } from "./print-n2qetUHc.mjs";
|
|
7
|
+
import { r as withStore } from "./project-records-Cune1l6I.mjs";
|
|
4
8
|
import path from "node:path";
|
|
5
|
-
import { realpathSync } from "node:fs";
|
|
9
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
6
10
|
import { defineCommand } from "citty";
|
|
7
11
|
// src/project/go-ahead.ts
|
|
8
12
|
/**
|
|
@@ -24,11 +28,11 @@ const goAhead = async (yes, verb, terminal = process.stdin.isTTY, ask = confirm)
|
|
|
24
28
|
};
|
|
25
29
|
// src/project/worktrees.ts
|
|
26
30
|
/**
|
|
27
|
-
* @file What `ork worktrees` prints: each worktree
|
|
28
|
-
* its state read from git, the plan `ork worktrees
|
|
29
|
-
* carry out, and what a forced remove would lose.
|
|
30
|
-
* (worktree/words.ts), which the Worktrees panel says
|
|
31
|
-
* them.
|
|
31
|
+
* @file What `ork worktrees` reads across projects, and prints: each worktree
|
|
32
|
+
* or branch a run left, with its state read from git, the plan `ork worktrees
|
|
33
|
+
* clean` or `remove` would carry out, and what a forced remove would lose.
|
|
34
|
+
* The words are core's (worktree/words.ts), which the Worktrees panel says
|
|
35
|
+
* too; this only colors them.
|
|
32
36
|
*/
|
|
33
37
|
/** One line of state: its merge state, then what clean would care about. */
|
|
34
38
|
const worktreeState = (item, term = termOf(process.stdout)) => {
|
|
@@ -55,6 +59,22 @@ const formatLosses = (losses) => losses.flatMap(({ item, lost }) => {
|
|
|
55
59
|
const lines = formatLost(lost);
|
|
56
60
|
return lines.length === 0 ? [] : [`Loses in ${labelOf(item)}:`, ...lines];
|
|
57
61
|
});
|
|
62
|
+
/** What Ork created in each registered project's repository still on disk. */
|
|
63
|
+
const inProjects = async (roots) => {
|
|
64
|
+
const store = openStore();
|
|
65
|
+
try {
|
|
66
|
+
return (await Promise.all([...new Set(roots)].filter((root) => existsSync(root)).map(async (root) => {
|
|
67
|
+
try {
|
|
68
|
+
return (await readWorktrees(store, root)).items;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
writeErr(`Skipped ${root}: ${error instanceof Error ? error.message : String(error)}`);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}))).flat();
|
|
74
|
+
} finally {
|
|
75
|
+
store.close();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
58
78
|
// src/commands/worktrees.ts
|
|
59
79
|
/**
|
|
60
80
|
* @file `ork worktrees` (or `ork wt`): lists the worktrees and branches runs
|
|
@@ -105,23 +125,31 @@ const realOr = (target) => {
|
|
|
105
125
|
const done = (lines) => {
|
|
106
126
|
for (const line of lines) write(`${style("green", "✓")} ${line}`);
|
|
107
127
|
};
|
|
108
|
-
const show = async (
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
128
|
+
const show = async (args) => {
|
|
129
|
+
const request = readListArgs(worktreeListTable, args);
|
|
130
|
+
if (request === void 0) return;
|
|
131
|
+
const projects = withStore((store) => store.projects());
|
|
132
|
+
const scope = projectScope(request.filter, projects);
|
|
133
|
+
if (scope === void 0) return;
|
|
134
|
+
let items;
|
|
135
|
+
if (scope === "here") {
|
|
136
|
+
const found = await here(true);
|
|
137
|
+
if (found === null) return;
|
|
138
|
+
items = found.items;
|
|
139
|
+
} else items = await inProjects(scope === "all" ? projects.map((p) => p.root) : [scope.root]);
|
|
140
|
+
const shown = applyFilters(worktreeListTable, items, request.filter).slice(0, request.limit);
|
|
141
|
+
printList(shown, worktreeListTable, args, (rows) => {
|
|
142
|
+
for (const line of formatWorktrees(rows)) write(line);
|
|
143
|
+
});
|
|
113
144
|
};
|
|
145
|
+
const listArgs = filterArgs(worktreeListTable);
|
|
114
146
|
const list = defineCommand({
|
|
115
147
|
meta: {
|
|
116
148
|
name: "list",
|
|
117
149
|
description: "List Ork's worktrees and branches (the default)"
|
|
118
150
|
},
|
|
119
|
-
args:
|
|
120
|
-
|
|
121
|
-
description: "Print JSON",
|
|
122
|
-
default: false
|
|
123
|
-
} },
|
|
124
|
-
run: ({ args }) => show(args.json)
|
|
151
|
+
args: listArgs,
|
|
152
|
+
run: ({ args }) => show(args)
|
|
125
153
|
});
|
|
126
154
|
const yes = {
|
|
127
155
|
type: "boolean",
|
|
@@ -256,15 +284,16 @@ const worktrees = defineCommand({
|
|
|
256
284
|
name: "worktrees",
|
|
257
285
|
description: "Track and clean up the git worktrees Ork creates for runs"
|
|
258
286
|
},
|
|
287
|
+
args: listArgs,
|
|
259
288
|
subCommands: {
|
|
260
289
|
list,
|
|
261
290
|
clean,
|
|
262
291
|
remove
|
|
263
292
|
},
|
|
264
|
-
run: async ({ rawArgs }) => {
|
|
293
|
+
run: async ({ args, rawArgs }) => {
|
|
265
294
|
const [first] = rawArgs;
|
|
266
295
|
if (first === "list" || first === "clean" || first === "remove") return;
|
|
267
|
-
await show(
|
|
296
|
+
await show(args);
|
|
268
297
|
}
|
|
269
298
|
});
|
|
270
299
|
export { worktrees };
|
package/package.json
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krapht/ork",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
4
|
-
"description": "Orchestrate
|
|
3
|
+
"version": "1.0.0-alpha.17",
|
|
4
|
+
"description": "Orchestrate coding agents (Claude Code, OpenCode, Command Code) on your machine: hierarchical, serializable workflows with a CLI and a localhost UI.",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"claude",
|
|
7
6
|
"agents",
|
|
7
|
+
"coding-agents",
|
|
8
8
|
"orchestration",
|
|
9
9
|
"workflow",
|
|
10
10
|
"cli",
|
|
11
|
-
"ai-engineering"
|
|
11
|
+
"ai-engineering",
|
|
12
|
+
"claude",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"opencode",
|
|
15
|
+
"command-code"
|
|
12
16
|
],
|
|
13
17
|
"license": "MIT",
|
|
14
18
|
"repository": {
|
package/dist/brief-za0ozN_E.mjs
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { un as takeFollowUps } from "./src-Dr_fTSu-.mjs";
|
|
2
|
-
import { l as briefOf, n as flagValues, u as checkTakeable } from "./run--4-1xAF2.mjs";
|
|
3
|
-
import { n as newRunId } from "./find-BYLlszqj.mjs";
|
|
4
|
-
import { l as writeErr } from "./output-B1kwo0YU.mjs";
|
|
5
|
-
import { t as loadWorkflow } from "./validate-Bs_gg22g.mjs";
|
|
6
|
-
// src/follow-ups/brief.ts
|
|
7
|
-
/**
|
|
8
|
-
* @file `ork run --follow-ups <ids>`: the `agent` follow-ups become the run's
|
|
9
|
-
* `brief` input, and are marked taken by the run, which finishes them when it
|
|
10
|
-
* publishes (`ork follow-ups published`). Everything that could refuse them
|
|
11
|
-
* (an unknown id, one for someone else, a workflow with no `brief` input) is
|
|
12
|
-
* checked before any is marked, so a run that doesn't start leaves them be.
|
|
13
|
-
*/
|
|
14
|
-
/** The ids `--follow-ups` was given, one per comma or repeat. */
|
|
15
|
-
const idsOf = (rawArgs) => flagValues(rawArgs, "--follow-ups").flatMap((value) => value.split(",")).map((id) => id.trim()).filter((id) => id !== "");
|
|
16
|
-
/**
|
|
17
|
-
* What stops `--follow-ups` from starting a run, one line each; none when
|
|
18
|
-
* nothing does.
|
|
19
|
-
*/
|
|
20
|
-
const problemsOf = (loaded, inputs) => {
|
|
21
|
-
const name = loaded.workflow?.name ?? "";
|
|
22
|
-
if (loaded.workflow?.inputs?.["brief"] === void 0) return [`--follow-ups fills a workflow's \`brief\` input, and ${name} has none.`];
|
|
23
|
-
return inputs.some((input) => input.startsWith("brief=")) ? ["--follow-ups and --input brief=… both set the brief."] : [];
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* The inputs and run id `ork run` starts with: those it was given and, for
|
|
27
|
-
* `--follow-ups`, a `brief` made of the follow-ups with the id of the run that
|
|
28
|
-
* takes them. `undefined` after saying why it can't start.
|
|
29
|
-
*/
|
|
30
|
-
const prepareFollowUps = (store, rawArgs, runId, target) => {
|
|
31
|
-
const inputs = flagValues(rawArgs, "--input");
|
|
32
|
-
const ids = idsOf(rawArgs);
|
|
33
|
-
const plain = {
|
|
34
|
-
inputs,
|
|
35
|
-
...runId === void 0 ? {} : { runId }
|
|
36
|
-
};
|
|
37
|
-
if (ids.length === 0) return plain;
|
|
38
|
-
const loaded = loadWorkflow(target.file, process.cwd(), void 0, store.projects());
|
|
39
|
-
if (loaded.workflow === null) return plain;
|
|
40
|
-
const takeable = checkTakeable(store, loaded.place.root, ids);
|
|
41
|
-
const problems = [...problemsOf(loaded, inputs), ...takeable.ok ? [] : takeable.lines];
|
|
42
|
-
if (!takeable.ok || problems.length > 0) {
|
|
43
|
-
for (const line of problems) writeErr(line);
|
|
44
|
-
process.exitCode = 1;
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const taker = runId ?? newRunId(store);
|
|
48
|
-
takeFollowUps(store, {
|
|
49
|
-
project: loaded.place.root,
|
|
50
|
-
run: taker,
|
|
51
|
-
ids: takeable.followUps.map((f) => f.id)
|
|
52
|
-
});
|
|
53
|
-
return {
|
|
54
|
-
inputs: [...inputs, `brief=${briefOf(takeable.followUps)}`],
|
|
55
|
-
runId: taker
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
export { prepareFollowUps };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { p as runMarkerIn } from "./src-DcrhgipG.mjs";
|
|
2
|
-
// src/commands/in-a-run.ts
|
|
3
|
-
/**
|
|
4
|
-
* @file The commands that act as the user refuse a program or an agent in a run
|
|
5
|
-
* (ADR-047). The refusal names the variable it saw, for someone at their own
|
|
6
|
-
* terminal who inherited it. It stops accidents; it is not a boundary.
|
|
7
|
-
*/
|
|
8
|
-
const refusal = (why, env) => {
|
|
9
|
-
const marker = runMarkerIn(env);
|
|
10
|
-
return marker === null ? null : `${why} ${marker} is set here. If this is your own terminal, it inherited that from a program in a run (a tmux server started by one, say); open a shell without it.`;
|
|
11
|
-
};
|
|
12
|
-
/** Why `ork watch --accept` refuses here, or `null` when it may run. */
|
|
13
|
-
const acceptRefusal = (env = process.env) => refusal("`ork watch --accept` approves code to run with nobody there, so a program or an agent in a run cannot use it.", env);
|
|
14
|
-
/** Why `ork chat` refuses here, or `null` when it may run. */
|
|
15
|
-
const chatRefusal = (env = process.env) => refusal("`ork chat` speaks as you, so a program or an agent in a run cannot use it. A program writes to a session with `ork send`.", env);
|
|
16
|
-
/** Why `ork decide` will not answer here, or `null` when it may. */
|
|
17
|
-
const decideRefusal = (env = process.env) => refusal("`ork decide` answers as you, so a program or an agent in a run cannot answer with it; `ork decide --list` still shows what is open.", env);
|
|
18
|
-
/** Why `ork continue` refuses here, or `null` when it may run. */
|
|
19
|
-
const continueRefusal = (env = process.env) => refusal("`ork continue` undoes a pause you set, so a program or an agent in a run cannot use it.", env);
|
|
20
|
-
/** Whether `ork ui` may print its sign-in link, which acts as the user. */
|
|
21
|
-
const mayShowSignIn = (env = process.env) => runMarkerIn(env) === null;
|
|
22
|
-
/** Why `ork attach` will not answer here, or `null` when it may. */
|
|
23
|
-
const attachRefusal = (env = process.env) => refusal("`ork attach` answers as you, so a program or an agent in a run cannot use it; `ork logs` still shows the run.", env);
|
|
24
|
-
export { decideRefusal as a, continueRefusal as i, attachRefusal as n, mayShowSignIn as o, chatRefusal as r, acceptRefusal as t };
|