claude-task-worker 0.24.0 → 0.26.0
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/index.js +233 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ __export(herdr_exports, {
|
|
|
61
61
|
HerdrUnavailableError: () => HerdrUnavailableError,
|
|
62
62
|
checkHerdrAvailable: () => checkHerdrAvailable,
|
|
63
63
|
paneProcessInfo: () => paneProcessInfo,
|
|
64
|
+
paneRead: () => paneRead,
|
|
64
65
|
paneSendKeys: () => paneSendKeys,
|
|
65
66
|
paneSendText: () => paneSendText,
|
|
66
67
|
tabClose: () => tabClose,
|
|
@@ -129,6 +130,50 @@ async function tabList() {
|
|
|
129
130
|
workspaceId: tab.workspace_id
|
|
130
131
|
}));
|
|
131
132
|
}
|
|
133
|
+
function isPaneReadErrorPayload(value) {
|
|
134
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
const keys = Object.keys(value);
|
|
138
|
+
if (keys.some((key) => !PANE_READ_ERROR_ALLOWED_KEYS.has(key))) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const payload = value;
|
|
142
|
+
if (typeof payload.code !== "string") {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if ("message" in payload && typeof payload.message !== "string") {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
async function paneRead(paneId, options) {
|
|
151
|
+
const args = ["pane", "read", paneId, "--source", options?.source ?? "visible"];
|
|
152
|
+
if (options?.lines !== void 0) {
|
|
153
|
+
args.push("--lines", String(options.lines));
|
|
154
|
+
}
|
|
155
|
+
const { execError, stdout, stderr } = await runHerdr(args);
|
|
156
|
+
const trimmed = stdout.trim();
|
|
157
|
+
if (trimmed.startsWith("{")) {
|
|
158
|
+
let parsed;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(trimmed);
|
|
161
|
+
} catch {
|
|
162
|
+
parsed = void 0;
|
|
163
|
+
}
|
|
164
|
+
if (isPaneReadErrorPayload(parsed)) {
|
|
165
|
+
throw new HerdrError(
|
|
166
|
+
`herdr ${args.join(" ")} failed: [${parsed.code}] ${parsed.message ?? ""}`.trim(),
|
|
167
|
+
parsed.code
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (execError) {
|
|
172
|
+
const stderrSuffix = stderr.trim() ? `: ${stderr.trim()}` : "";
|
|
173
|
+
throw new Error(`herdr ${args.join(" ")} failed: ${execError.message}${stderrSuffix}`);
|
|
174
|
+
}
|
|
175
|
+
return stdout;
|
|
176
|
+
}
|
|
132
177
|
async function paneSendText(paneId, text) {
|
|
133
178
|
await execHerdr(["pane", "send-text", paneId, text], { allowEmptyResult: true });
|
|
134
179
|
}
|
|
@@ -162,7 +207,7 @@ async function checkHerdrAvailable() {
|
|
|
162
207
|
);
|
|
163
208
|
}
|
|
164
209
|
}
|
|
165
|
-
var childProcess2, HerdrUnavailableError, HerdrError, HERDR_TIMEOUT_MS;
|
|
210
|
+
var childProcess2, HerdrUnavailableError, HerdrError, HERDR_TIMEOUT_MS, PANE_READ_ERROR_ALLOWED_KEYS;
|
|
166
211
|
var init_herdr = __esm({
|
|
167
212
|
"src/herdr.ts"() {
|
|
168
213
|
"use strict";
|
|
@@ -184,25 +229,36 @@ var init_herdr = __esm({
|
|
|
184
229
|
}
|
|
185
230
|
};
|
|
186
231
|
HERDR_TIMEOUT_MS = 15 * 1e3;
|
|
232
|
+
PANE_READ_ERROR_ALLOWED_KEYS = /* @__PURE__ */ new Set(["code", "message"]);
|
|
187
233
|
}
|
|
188
234
|
});
|
|
189
235
|
|
|
190
236
|
// src/dispatcher.ts
|
|
191
237
|
var dispatcher_exports = {};
|
|
192
238
|
__export(dispatcher_exports, {
|
|
239
|
+
PANE_READY_POLL_INTERVAL_MS: () => PANE_READY_POLL_INTERVAL_MS,
|
|
240
|
+
PANE_READY_TIMEOUT_MS: () => PANE_READY_TIMEOUT_MS,
|
|
193
241
|
POLL_INTERVAL_MS: () => POLL_INTERVAL_MS,
|
|
242
|
+
SEND_MAX_ATTEMPTS: () => SEND_MAX_ATTEMPTS,
|
|
194
243
|
SHUTDOWN_RETRY_TIMEOUT_MS: () => SHUTDOWN_RETRY_TIMEOUT_MS,
|
|
195
244
|
SHUTDOWN_TIMEOUT_MS: () => SHUTDOWN_TIMEOUT_MS,
|
|
196
245
|
TAB_LABEL_PREFIX: () => TAB_LABEL_PREFIX,
|
|
246
|
+
WORKER_STARTUP_POLL_INTERVAL_MS: () => WORKER_STARTUP_POLL_INTERVAL_MS,
|
|
247
|
+
WORKER_STARTUP_TIMEOUT_MS: () => WORKER_STARTUP_TIMEOUT_MS,
|
|
197
248
|
createDispatcherShutdownHandler: () => createDispatcherShutdownHandler,
|
|
198
249
|
formatUptime: () => formatUptime,
|
|
250
|
+
isShellProcess: () => isShellProcess,
|
|
251
|
+
isWorkerProcess: () => isWorkerProcess,
|
|
199
252
|
monitorSessions: () => monitorSessions,
|
|
200
253
|
pollOnce: () => pollOnce,
|
|
201
254
|
removeSession: () => removeSession,
|
|
202
255
|
renderSessionTable: () => renderSessionTable,
|
|
203
256
|
runDispatcher: () => runDispatcher,
|
|
204
257
|
shutdownDispatcher: () => shutdownDispatcher,
|
|
205
|
-
|
|
258
|
+
startWorkerInPane: () => startWorkerInPane,
|
|
259
|
+
tabLabelFor: () => tabLabelFor,
|
|
260
|
+
waitForPaneReady: () => waitForPaneReady,
|
|
261
|
+
waitForWorkerStartup: () => waitForWorkerStartup
|
|
206
262
|
});
|
|
207
263
|
async function loadHerdr() {
|
|
208
264
|
return await Promise.resolve().then(() => (init_herdr(), herdr_exports));
|
|
@@ -213,8 +269,72 @@ async function loadTable() {
|
|
|
213
269
|
function tabLabelFor(projectName) {
|
|
214
270
|
return `${TAB_LABEL_PREFIX}${projectName}`;
|
|
215
271
|
}
|
|
216
|
-
|
|
217
|
-
|
|
272
|
+
function sleep(ms) {
|
|
273
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
274
|
+
}
|
|
275
|
+
function isWorkerProcess(process2) {
|
|
276
|
+
return process2.cmdline?.includes("claude-task-worker") ?? false;
|
|
277
|
+
}
|
|
278
|
+
function isShellProcess(process2) {
|
|
279
|
+
return SHELL_NAME_PATTERN.test(process2.name ?? "") || SHELL_NAME_PATTERN.test(process2.cmdline ?? "");
|
|
280
|
+
}
|
|
281
|
+
async function waitForPaneReady(paneId, herdr, options) {
|
|
282
|
+
const timeoutMs = options?.timeoutMs ?? PANE_READY_TIMEOUT_MS;
|
|
283
|
+
const pollIntervalMs = options?.pollIntervalMs ?? PANE_READY_POLL_INTERVAL_MS;
|
|
284
|
+
const deadline = Date.now() + timeoutMs;
|
|
285
|
+
for (; ; ) {
|
|
286
|
+
const content = await herdr.paneRead(paneId, { source: "visible" });
|
|
287
|
+
if (content.trim() !== "") return true;
|
|
288
|
+
if (Date.now() >= deadline) return false;
|
|
289
|
+
await sleep(pollIntervalMs);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async function waitForWorkerStartup(paneId, herdr, options) {
|
|
293
|
+
const timeoutMs = options?.timeoutMs ?? WORKER_STARTUP_TIMEOUT_MS;
|
|
294
|
+
const pollIntervalMs = options?.pollIntervalMs ?? WORKER_STARTUP_POLL_INTERVAL_MS;
|
|
295
|
+
const deadline = Date.now() + timeoutMs;
|
|
296
|
+
for (; ; ) {
|
|
297
|
+
const { foregroundProcesses } = await herdr.paneProcessInfo(paneId);
|
|
298
|
+
if (foregroundProcesses.some(isWorkerProcess)) return "started";
|
|
299
|
+
if (foregroundProcesses.length > 0 && !foregroundProcesses.every(isShellProcess)) return "other";
|
|
300
|
+
if (Date.now() >= deadline) return "shell";
|
|
301
|
+
await sleep(pollIntervalMs);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async function startWorkerInPane(paneId, forwardedCommand, herdr, options) {
|
|
305
|
+
const maxAttempts = options?.sendMaxAttempts ?? SEND_MAX_ATTEMPTS;
|
|
306
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
307
|
+
const ready = await waitForPaneReady(paneId, herdr, {
|
|
308
|
+
timeoutMs: options?.paneReadyTimeoutMs,
|
|
309
|
+
pollIntervalMs: options?.paneReadyPollIntervalMs
|
|
310
|
+
});
|
|
311
|
+
if (!ready) {
|
|
312
|
+
console.warn(`[dispatcher] pane ${paneId} produced no prompt before the timeout, sending the command anyway`);
|
|
313
|
+
}
|
|
314
|
+
await herdr.paneSendText(paneId, forwardedCommand);
|
|
315
|
+
await herdr.paneSendKeys(paneId, "enter");
|
|
316
|
+
const result = await waitForWorkerStartup(paneId, herdr, {
|
|
317
|
+
timeoutMs: options?.workerStartupTimeoutMs,
|
|
318
|
+
pollIntervalMs: options?.workerStartupPollIntervalMs
|
|
319
|
+
});
|
|
320
|
+
if (result === "started") return true;
|
|
321
|
+
if (result === "other") {
|
|
322
|
+
console.warn(
|
|
323
|
+
`[dispatcher] pane ${paneId} foreground is neither the shell nor the worker, giving up without resending`
|
|
324
|
+
);
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (attempt < maxAttempts) {
|
|
328
|
+
console.warn(
|
|
329
|
+
`[dispatcher] worker did not start in pane ${paneId} (attempt ${attempt}/${maxAttempts}), resending the command`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
async function runDispatcher(projects, forwardedCommand, timing) {
|
|
336
|
+
const herdr = await loadHerdr();
|
|
337
|
+
const { checkHerdrAvailable: checkHerdrAvailable2, tabCreate: tabCreate2, tabClose: tabClose2, tabList: tabList2 } = herdr;
|
|
218
338
|
try {
|
|
219
339
|
await checkHerdrAvailable2();
|
|
220
340
|
} catch (error) {
|
|
@@ -241,8 +361,12 @@ async function runDispatcher(projects, forwardedCommand) {
|
|
|
241
361
|
startedAt: /* @__PURE__ */ new Date(),
|
|
242
362
|
status: "running"
|
|
243
363
|
});
|
|
244
|
-
await
|
|
245
|
-
|
|
364
|
+
const started = await startWorkerInPane(paneId, forwardedCommand, herdr, timing);
|
|
365
|
+
if (!started) {
|
|
366
|
+
throw new Error(
|
|
367
|
+
`worker did not start in pane ${paneId} after ${timing?.sendMaxAttempts ?? SEND_MAX_ATTEMPTS} attempt(s)`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
246
370
|
} catch (error) {
|
|
247
371
|
console.error(`[dispatcher] failed to dispatch project "${project.name}": ${error}`);
|
|
248
372
|
sessions.delete(project.name);
|
|
@@ -270,8 +394,7 @@ async function pollOnce(sessions, herdr) {
|
|
|
270
394
|
for (const [name, session] of [...sessions.entries()]) {
|
|
271
395
|
try {
|
|
272
396
|
const { foregroundProcesses } = await herdr.paneProcessInfo(session.paneId);
|
|
273
|
-
|
|
274
|
-
if (!isAlive) {
|
|
397
|
+
if (!foregroundProcesses.some(isWorkerProcess)) {
|
|
275
398
|
await removeSession(sessions, name, { closeTab: true });
|
|
276
399
|
}
|
|
277
400
|
} catch (error) {
|
|
@@ -467,14 +590,20 @@ function createDispatcherShutdownHandler(shutdown2) {
|
|
|
467
590
|
};
|
|
468
591
|
return { handle, isShuttingDown: () => shuttingDown2 };
|
|
469
592
|
}
|
|
470
|
-
var getDisplayWidth2, truncateToWidth2, padToWidth2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS, TAB_LABEL_PREFIX, SHUTDOWN_RETRY_TIMEOUT_MS, CTRL_C_KEY, shutdownPromise;
|
|
593
|
+
var getDisplayWidth2, truncateToWidth2, padToWidth2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS, PANE_READY_TIMEOUT_MS, PANE_READY_POLL_INTERVAL_MS, WORKER_STARTUP_TIMEOUT_MS, WORKER_STARTUP_POLL_INTERVAL_MS, SEND_MAX_ATTEMPTS, TAB_LABEL_PREFIX, SHELL_NAME_PATTERN, SHUTDOWN_RETRY_TIMEOUT_MS, CTRL_C_KEY, shutdownPromise;
|
|
471
594
|
var init_dispatcher = __esm({
|
|
472
595
|
async "src/dispatcher.ts"() {
|
|
473
596
|
"use strict";
|
|
474
597
|
({ getDisplayWidth: getDisplayWidth2, truncateToWidth: truncateToWidth2, padToWidth: padToWidth2 } = await loadTable());
|
|
475
598
|
POLL_INTERVAL_MS = 7 * 1e3;
|
|
476
599
|
SHUTDOWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
600
|
+
PANE_READY_TIMEOUT_MS = 30 * 1e3;
|
|
601
|
+
PANE_READY_POLL_INTERVAL_MS = 200;
|
|
602
|
+
WORKER_STARTUP_TIMEOUT_MS = 30 * 1e3;
|
|
603
|
+
WORKER_STARTUP_POLL_INTERVAL_MS = 500;
|
|
604
|
+
SEND_MAX_ATTEMPTS = 3;
|
|
477
605
|
TAB_LABEL_PREFIX = "ctw:";
|
|
606
|
+
SHELL_NAME_PATTERN = /^-?(zsh|bash|sh)$/;
|
|
478
607
|
SHUTDOWN_RETRY_TIMEOUT_MS = 90 * 1e3;
|
|
479
608
|
CTRL_C_KEY = "ctrl+c";
|
|
480
609
|
}
|
|
@@ -1510,10 +1639,86 @@ function isGeneratedWorktreeName(name) {
|
|
|
1510
1639
|
|
|
1511
1640
|
// src/slack.ts
|
|
1512
1641
|
import { exec } from "node:child_process";
|
|
1513
|
-
import { readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
1514
|
-
import { homedir } from "node:os";
|
|
1515
|
-
import { join as
|
|
1642
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1643
|
+
import { homedir as homedir2 } from "node:os";
|
|
1644
|
+
import { join as join3 } from "node:path";
|
|
1516
1645
|
import { promisify as promisify2 } from "node:util";
|
|
1646
|
+
|
|
1647
|
+
// src/runcat.ts
|
|
1648
|
+
import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
1649
|
+
import { homedir } from "node:os";
|
|
1650
|
+
import { dirname, join as join2 } from "node:path";
|
|
1651
|
+
var RUNCAT_OUT_FILE = process.env.RUNCAT_OUT_FILE ?? join2(process.env.HOME ?? homedir(), ".claude", "runcat-usage.json");
|
|
1652
|
+
var JST = "Asia/Tokyo";
|
|
1653
|
+
function formatG(value) {
|
|
1654
|
+
return String(Number(value.toPrecision(6)));
|
|
1655
|
+
}
|
|
1656
|
+
function jstFields(date) {
|
|
1657
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
1658
|
+
timeZone: JST,
|
|
1659
|
+
month: "2-digit",
|
|
1660
|
+
day: "2-digit",
|
|
1661
|
+
hour: "2-digit",
|
|
1662
|
+
minute: "2-digit",
|
|
1663
|
+
hourCycle: "h23"
|
|
1664
|
+
}).formatToParts(date);
|
|
1665
|
+
const pick2 = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
1666
|
+
return { month: pick2("month"), day: pick2("day"), hour: pick2("hour"), minute: pick2("minute") };
|
|
1667
|
+
}
|
|
1668
|
+
function parseResetsAt(isoString) {
|
|
1669
|
+
const date = new Date(isoString);
|
|
1670
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
1671
|
+
}
|
|
1672
|
+
function resetStamp(isoString, now = /* @__PURE__ */ new Date()) {
|
|
1673
|
+
const date = parseResetsAt(isoString);
|
|
1674
|
+
if (!date) return "";
|
|
1675
|
+
const reset = jstFields(date);
|
|
1676
|
+
const today = jstFields(now);
|
|
1677
|
+
const time = `${reset.hour}:${reset.minute}`;
|
|
1678
|
+
if (reset.month === today.month && reset.day === today.day) return time;
|
|
1679
|
+
return `${reset.month}/${reset.day} ${time}`;
|
|
1680
|
+
}
|
|
1681
|
+
function resetHour(isoString) {
|
|
1682
|
+
const date = parseResetsAt(isoString);
|
|
1683
|
+
return date ? jstFields(date).hour : "";
|
|
1684
|
+
}
|
|
1685
|
+
function metric(title, pct, resetsAt, now) {
|
|
1686
|
+
const stamp = resetStamp(resetsAt, now);
|
|
1687
|
+
return {
|
|
1688
|
+
title,
|
|
1689
|
+
formattedValue: `${formatG(pct)}%` + (stamp ? ` \u21BB${stamp}` : ""),
|
|
1690
|
+
normalizedValue: Math.round(pct / 100 * 1e4) / 1e4
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
function buildRuncatSnapshot(usage, now = /* @__PURE__ */ new Date()) {
|
|
1694
|
+
const bar = `${formatG(usage.fiveHourUtilization)}/${formatG(usage.sevenDayUtilization)}`;
|
|
1695
|
+
const stamp = resetHour(usage.fiveHourResetsAt);
|
|
1696
|
+
return {
|
|
1697
|
+
title: "Claude Code",
|
|
1698
|
+
symbol: "staroflife",
|
|
1699
|
+
metrics: [
|
|
1700
|
+
metric("5h", usage.fiveHourUtilization, usage.fiveHourResetsAt, now),
|
|
1701
|
+
metric("7d", usage.sevenDayUtilization, usage.sevenDayResetsAt, now)
|
|
1702
|
+
],
|
|
1703
|
+
metricsBarValue: stamp ? `${bar} \u21BB${stamp}` : bar,
|
|
1704
|
+
lastUpdatedDate: now.toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
|
|
1708
|
+
const snapshot = buildRuncatSnapshot(usage);
|
|
1709
|
+
const dir = dirname(outFile);
|
|
1710
|
+
const tmp = join2(dir, `.runcat-${process.pid}-${Date.now()}.json`);
|
|
1711
|
+
try {
|
|
1712
|
+
mkdirSync(dir, { recursive: true });
|
|
1713
|
+
writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
|
|
1714
|
+
renameSync(tmp, outFile);
|
|
1715
|
+
} catch (err) {
|
|
1716
|
+
rmSync(tmp, { force: true });
|
|
1717
|
+
console.error(`[runcat] Failed to write ${outFile}: ${err}`);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// src/slack.ts
|
|
1517
1722
|
var execAsync = promisify2(exec);
|
|
1518
1723
|
var WEBHOOK_URL = process.env.CLAUDE_TASK_WORKER_SLACK_WEBHOOK_URL;
|
|
1519
1724
|
var USAGE_CACHE_PATH = "/tmp/claude-usage-cache.json";
|
|
@@ -1539,7 +1744,7 @@ async function getOAuthToken() {
|
|
|
1539
1744
|
const { stdout } = await execAsync('security find-generic-password -s "Claude Code-credentials" -w');
|
|
1540
1745
|
return extractToken(JSON.parse(stdout.trim()));
|
|
1541
1746
|
} catch {
|
|
1542
|
-
const raw = readFileSync2(
|
|
1747
|
+
const raw = readFileSync2(join3(homedir2(), ".claude", ".credentials.json"), "utf-8");
|
|
1543
1748
|
return extractToken(JSON.parse(raw));
|
|
1544
1749
|
}
|
|
1545
1750
|
}
|
|
@@ -1556,7 +1761,7 @@ function readUsageCache() {
|
|
|
1556
1761
|
}
|
|
1557
1762
|
function writeUsageCache(data) {
|
|
1558
1763
|
try {
|
|
1559
|
-
|
|
1764
|
+
writeFileSync2(USAGE_CACHE_PATH, JSON.stringify({ timestamp: Date.now(), data }));
|
|
1560
1765
|
} catch {
|
|
1561
1766
|
}
|
|
1562
1767
|
}
|
|
@@ -1604,9 +1809,7 @@ function formatResetTimeJST(isoString) {
|
|
|
1604
1809
|
minute: "2-digit"
|
|
1605
1810
|
});
|
|
1606
1811
|
}
|
|
1607
|
-
|
|
1608
|
-
const usage = await fetchUsageInfo();
|
|
1609
|
-
if (!usage) return "";
|
|
1812
|
+
function formatTokenLimitText(usage) {
|
|
1610
1813
|
const fiveH = usage.fiveHourUtilization.toFixed(1);
|
|
1611
1814
|
const sevenD = usage.sevenDayUtilization.toFixed(1);
|
|
1612
1815
|
const emoji = utilizationEmoji(Math.max(usage.fiveHourUtilization, usage.sevenDayUtilization));
|
|
@@ -1614,6 +1817,12 @@ async function buildTokenLimitText() {
|
|
|
1614
1817
|
const sevenDReset = formatResetTimeJST(usage.sevenDayResetsAt);
|
|
1615
1818
|
return ` | ${emoji} 5h: ${fiveH}% (reset: ${fiveHReset}) / 7d: ${sevenD}% (reset: ${sevenDReset})`;
|
|
1616
1819
|
}
|
|
1820
|
+
async function buildTokenLimitText() {
|
|
1821
|
+
const usage = await fetchUsageInfo();
|
|
1822
|
+
if (!usage) return "";
|
|
1823
|
+
writeRuncatUsage(usage);
|
|
1824
|
+
return formatTokenLimitText(usage);
|
|
1825
|
+
}
|
|
1617
1826
|
async function notifyTaskCompleted(workerName, repoName, id, title, url, output) {
|
|
1618
1827
|
const tokenText = await buildTokenLimitText();
|
|
1619
1828
|
const truncatedOutput = output && output.length > 1e3 ? `\u2026${output.slice(-1e3)}` : output;
|
|
@@ -2473,11 +2682,11 @@ async function update() {
|
|
|
2473
2682
|
|
|
2474
2683
|
// src/commands/version.ts
|
|
2475
2684
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
2476
|
-
import { dirname, join as
|
|
2685
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
2477
2686
|
import { fileURLToPath } from "node:url";
|
|
2478
2687
|
function version() {
|
|
2479
|
-
const here =
|
|
2480
|
-
const pkgPath =
|
|
2688
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2689
|
+
const pkgPath = join4(here, "..", "package.json");
|
|
2481
2690
|
try {
|
|
2482
2691
|
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
2483
2692
|
console.log(pkg.version ?? "unknown");
|
|
@@ -2532,8 +2741,8 @@ function buildForwardedCommand(argv) {
|
|
|
2532
2741
|
|
|
2533
2742
|
// src/projects-config.ts
|
|
2534
2743
|
import { readFileSync as readFileSync4, statSync } from "node:fs";
|
|
2535
|
-
import { homedir as
|
|
2536
|
-
import { isAbsolute, join as
|
|
2744
|
+
import { homedir as homedir3 } from "node:os";
|
|
2745
|
+
import { isAbsolute, join as join5 } from "node:path";
|
|
2537
2746
|
var RESERVED_ALL = "all";
|
|
2538
2747
|
var ProjectsConfigError = class extends Error {
|
|
2539
2748
|
constructor(message) {
|
|
@@ -2543,8 +2752,8 @@ var ProjectsConfigError = class extends Error {
|
|
|
2543
2752
|
};
|
|
2544
2753
|
function getProjectsConfigPath() {
|
|
2545
2754
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
2546
|
-
const configHome = xdg && xdg.length > 0 ? xdg :
|
|
2547
|
-
return
|
|
2755
|
+
const configHome = xdg && xdg.length > 0 ? xdg : join5(homedir3(), ".config");
|
|
2756
|
+
return join5(configHome, "claude-task-worker", "projects.json");
|
|
2548
2757
|
}
|
|
2549
2758
|
var PROJECTS_CONFIG_PATH = getProjectsConfigPath();
|
|
2550
2759
|
function isDirectory(path) {
|