claude-task-worker 0.137.0 → 0.138.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/README.md +1 -1
- package/dist/{chunk-R4T3CDMO.js → chunk-3WIASXSK.js} +44 -28
- package/dist/index.js +13 -9
- package/dist/lib.js +1 -1
- package/dist/runcat.d.ts +2 -2
- package/dist/slack.d.ts +20 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ claude-task-worker <command> [--epic <issue-number>]... [--label <label>]... [--
|
|
|
139
139
|
| `install` / `update` | 上記「セットアップ」を参照 |
|
|
140
140
|
| `cloud-setup [--force]` | クラウド VM 側の準備(下記「`--cloud`」を参照) |
|
|
141
141
|
| `list-workers` | プリセットとカスタムの全ワーカーを名前・種別・有効/無効・ロード元で表示(`workerFiles` のロード失敗時は exit 1) |
|
|
142
|
-
| `usage` | Claude API 使用状況(5時間/7日間の利用率とリセット時刻)を表示し、Slack
|
|
142
|
+
| `usage` | Claude API 使用状況(5時間/7日間の利用率とリセット時刻)を表示し、Slack にも通知。以降は360秒(6分)ごとに取得し直して表示・RunCat 用スナップショットを更新し続ける(Ctrl-C で終了。Slack 通知は起動時のみ)。プランによって返らない窓(Ultra の5時間枠など)は省いて表示する |
|
|
143
143
|
| `version` | CLI のバージョンを表示(`--version` / `-v` も可) |
|
|
144
144
|
|
|
145
145
|
### `--epic <issue-number>`
|
|
@@ -2167,6 +2167,7 @@ function ceilToMinute(date) {
|
|
|
2167
2167
|
return remainder === 0 ? date : new Date(date.getTime() + (MINUTE_MS - remainder));
|
|
2168
2168
|
}
|
|
2169
2169
|
function parseResetsAt(isoString) {
|
|
2170
|
+
if (!isoString) return null;
|
|
2170
2171
|
const date = new Date(isoString);
|
|
2171
2172
|
return Number.isNaN(date.getTime()) ? null : ceilToMinute(date);
|
|
2172
2173
|
}
|
|
@@ -2192,15 +2193,17 @@ function metric(title, pct, resetsAt, now) {
|
|
|
2192
2193
|
};
|
|
2193
2194
|
}
|
|
2194
2195
|
function buildRuncatSnapshot(usage, now = /* @__PURE__ */ new Date()) {
|
|
2195
|
-
const
|
|
2196
|
-
|
|
2196
|
+
const windows = [
|
|
2197
|
+
["5h", usage.fiveHourUtilization, usage.fiveHourResetsAt],
|
|
2198
|
+
["7d", usage.sevenDayUtilization, usage.sevenDayResetsAt]
|
|
2199
|
+
];
|
|
2200
|
+
const present = windows.filter((w) => w[1] !== null);
|
|
2201
|
+
const bar = present.map(([, pct]) => formatG(pct)).join("/");
|
|
2202
|
+
const stamp = present.length > 0 ? resetHour(present[0][2]) : "";
|
|
2197
2203
|
return {
|
|
2198
2204
|
title: "Claude Code",
|
|
2199
2205
|
symbol: "staroflife",
|
|
2200
|
-
metrics: [
|
|
2201
|
-
metric("5h", usage.fiveHourUtilization, usage.fiveHourResetsAt, now),
|
|
2202
|
-
metric("7d", usage.sevenDayUtilization, usage.sevenDayResetsAt, now)
|
|
2203
|
-
],
|
|
2206
|
+
metrics: present.map(([title, pct, resetsAt]) => metric(title, pct, resetsAt, now)),
|
|
2204
2207
|
metricsBarValue: stamp ? `${bar} \u21BB${stamp}` : bar,
|
|
2205
2208
|
lastUpdatedDate: now.toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
2206
2209
|
};
|
|
@@ -2214,7 +2217,10 @@ function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
|
|
|
2214
2217
|
writeFileSync3(tmp, JSON.stringify(snapshot), "utf-8");
|
|
2215
2218
|
renameSync2(tmp, outFile);
|
|
2216
2219
|
} catch (err) {
|
|
2217
|
-
|
|
2220
|
+
try {
|
|
2221
|
+
rmSync(tmp, { force: true });
|
|
2222
|
+
} catch {
|
|
2223
|
+
}
|
|
2218
2224
|
console.error(`[runcat] Failed to write ${outFile}: ${err}`);
|
|
2219
2225
|
}
|
|
2220
2226
|
}
|
|
@@ -2223,6 +2229,7 @@ function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
|
|
|
2223
2229
|
var execAsync = promisify2(exec);
|
|
2224
2230
|
var WEBHOOK_URL = process.env.CLAUDE_TASK_WORKER_SLACK_WEBHOOK_URL;
|
|
2225
2231
|
var USAGE_CACHE_PATH = "/tmp/claude-usage-cache.json";
|
|
2232
|
+
var USAGE_POLL_INTERVAL_SECONDS = 360;
|
|
2226
2233
|
var USAGE_CACHE_TTL_SECONDS = 360;
|
|
2227
2234
|
async function send(payload) {
|
|
2228
2235
|
if (!WEBHOOK_URL) return;
|
|
@@ -2236,6 +2243,14 @@ async function send(payload) {
|
|
|
2236
2243
|
console.error(`[slack] Failed to send notification: ${err}`);
|
|
2237
2244
|
}
|
|
2238
2245
|
}
|
|
2246
|
+
function parseUsageResponse(body) {
|
|
2247
|
+
return {
|
|
2248
|
+
fiveHourUtilization: body.five_hour?.utilization ?? null,
|
|
2249
|
+
fiveHourResetsAt: body.five_hour?.resets_at ?? null,
|
|
2250
|
+
sevenDayUtilization: body.seven_day?.utilization ?? null,
|
|
2251
|
+
sevenDayResetsAt: body.seven_day?.resets_at ?? null
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2239
2254
|
function extractToken(credentials) {
|
|
2240
2255
|
if (typeof credentials === "string") return credentials;
|
|
2241
2256
|
return credentials.claudeAiOauth?.accessToken ?? credentials.oauth_token ?? credentials.access_token ?? "";
|
|
@@ -2266,8 +2281,8 @@ function writeUsageCache(data) {
|
|
|
2266
2281
|
} catch {
|
|
2267
2282
|
}
|
|
2268
2283
|
}
|
|
2269
|
-
async function fetchUsageInfo() {
|
|
2270
|
-
const cached = readUsageCache();
|
|
2284
|
+
async function fetchUsageInfo(fresh) {
|
|
2285
|
+
const cached = fresh ? null : readUsageCache();
|
|
2271
2286
|
if (cached) return cached;
|
|
2272
2287
|
try {
|
|
2273
2288
|
const token = await getOAuthToken();
|
|
@@ -2281,13 +2296,7 @@ async function fetchUsageInfo() {
|
|
|
2281
2296
|
console.error(`[slack] Usage API returned ${res.status}`);
|
|
2282
2297
|
return null;
|
|
2283
2298
|
}
|
|
2284
|
-
const
|
|
2285
|
-
const data = {
|
|
2286
|
-
fiveHourUtilization: body.five_hour.utilization,
|
|
2287
|
-
fiveHourResetsAt: body.five_hour.resets_at,
|
|
2288
|
-
sevenDayUtilization: body.seven_day.utilization,
|
|
2289
|
-
sevenDayResetsAt: body.seven_day.resets_at
|
|
2290
|
-
};
|
|
2299
|
+
const data = parseUsageResponse(await res.json());
|
|
2291
2300
|
writeUsageCache(data);
|
|
2292
2301
|
return data;
|
|
2293
2302
|
} catch (err) {
|
|
@@ -2310,17 +2319,23 @@ function formatResetTimeJST(isoString) {
|
|
|
2310
2319
|
minute: "2-digit"
|
|
2311
2320
|
});
|
|
2312
2321
|
}
|
|
2322
|
+
function formatWindow(label, utilization, resetsAt) {
|
|
2323
|
+
if (utilization === null) return null;
|
|
2324
|
+
const reset = resetsAt ? ` (reset: ${formatResetTimeJST(resetsAt)})` : "";
|
|
2325
|
+
return `${label}: ${utilization.toFixed(1)}%${reset}`;
|
|
2326
|
+
}
|
|
2313
2327
|
function formatTokenLimitText(usage) {
|
|
2314
|
-
const
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2328
|
+
const parts = [
|
|
2329
|
+
formatWindow("5h", usage.fiveHourUtilization, usage.fiveHourResetsAt),
|
|
2330
|
+
formatWindow("7d", usage.sevenDayUtilization, usage.sevenDayResetsAt)
|
|
2331
|
+
].filter((p) => p !== null);
|
|
2332
|
+
if (parts.length === 0) return "";
|
|
2333
|
+
const values = [usage.fiveHourUtilization, usage.sevenDayUtilization].filter((v) => v !== null);
|
|
2334
|
+
return ` | ${utilizationEmoji(Math.max(...values))} ${parts.join(" / ")}`;
|
|
2335
|
+
}
|
|
2336
|
+
async function buildTokenLimitText(fresh = false) {
|
|
2337
|
+
const usage = await fetchUsageInfo(fresh);
|
|
2338
|
+
if (!usage) return null;
|
|
2324
2339
|
writeRuncatUsage(usage);
|
|
2325
2340
|
return formatTokenLimitText(usage);
|
|
2326
2341
|
}
|
|
@@ -2348,7 +2363,7 @@ function buildTaskNotificationText(params) {
|
|
|
2348
2363
|
return `${sessionUrlPrefix}${body}`;
|
|
2349
2364
|
}
|
|
2350
2365
|
async function notifyTaskCompleted(workerName, repoName, id, title, url, output, cloud) {
|
|
2351
|
-
const tokenText = await buildTokenLimitText();
|
|
2366
|
+
const tokenText = await buildTokenLimitText() ?? "";
|
|
2352
2367
|
await send({
|
|
2353
2368
|
text: buildTaskNotificationText({
|
|
2354
2369
|
status: "completed",
|
|
@@ -2364,7 +2379,7 @@ async function notifyTaskCompleted(workerName, repoName, id, title, url, output,
|
|
|
2364
2379
|
});
|
|
2365
2380
|
}
|
|
2366
2381
|
async function notifyTaskFailed(workerName, repoName, id, title, url, output, cloud) {
|
|
2367
|
-
const tokenText = await buildTokenLimitText();
|
|
2382
|
+
const tokenText = await buildTokenLimitText() ?? "";
|
|
2368
2383
|
await send({
|
|
2369
2384
|
text: buildTaskNotificationText({
|
|
2370
2385
|
status: "failed",
|
|
@@ -3179,6 +3194,7 @@ export {
|
|
|
3179
3194
|
waitForAllProcesses,
|
|
3180
3195
|
shutdown,
|
|
3181
3196
|
generateWorktreeName,
|
|
3197
|
+
USAGE_POLL_INTERVAL_SECONDS,
|
|
3182
3198
|
send,
|
|
3183
3199
|
buildTokenLimitText,
|
|
3184
3200
|
notifyTaskCompleted,
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
INHERIT_CONFIG_KEY,
|
|
8
8
|
LOCAL_CONFIG_PATH,
|
|
9
9
|
SCHEDULED_WORKER_NAMES,
|
|
10
|
+
USAGE_POLL_INTERVAL_SECONDS,
|
|
10
11
|
addAssignee,
|
|
11
12
|
addLabel,
|
|
12
13
|
bodyMentionsIssue,
|
|
@@ -64,7 +65,7 @@ import {
|
|
|
64
65
|
shutdown,
|
|
65
66
|
waitForAllProcesses,
|
|
66
67
|
writeLastRun
|
|
67
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-3WIASXSK.js";
|
|
68
69
|
import {
|
|
69
70
|
UserConfigError,
|
|
70
71
|
assertCloudCompatibleCommand,
|
|
@@ -1822,15 +1823,18 @@ if (hasProjectFilter()) {
|
|
|
1822
1823
|
await cloudSetup({ force: process.argv.slice(3).includes("--force") });
|
|
1823
1824
|
})();
|
|
1824
1825
|
} else if (workerType === "usage") {
|
|
1825
|
-
|
|
1826
|
-
const text = await buildTokenLimitText();
|
|
1827
|
-
if (
|
|
1828
|
-
console.error(
|
|
1829
|
-
|
|
1826
|
+
const pollUsage = async (notify) => {
|
|
1827
|
+
const text = await buildTokenLimitText(true);
|
|
1828
|
+
if (text === null) {
|
|
1829
|
+
console.error(`[usage] ${(/* @__PURE__ */ new Date()).toISOString()} Failed to fetch usage info`);
|
|
1830
|
+
return;
|
|
1830
1831
|
}
|
|
1831
|
-
console.log(
|
|
1832
|
-
await send({ text: `\u{1F4CA} Usage${text}` });
|
|
1833
|
-
}
|
|
1832
|
+
console.log(`[usage] ${(/* @__PURE__ */ new Date()).toISOString()}${text}`);
|
|
1833
|
+
if (notify) await send({ text: `\u{1F4CA} Usage${text}` });
|
|
1834
|
+
};
|
|
1835
|
+
void pollUsage(true);
|
|
1836
|
+
setInterval(() => void pollUsage(false), USAGE_POLL_INTERVAL_SECONDS * 1e3);
|
|
1837
|
+
console.log(`[usage] polling every ${USAGE_POLL_INTERVAL_SECONDS}s (Ctrl-C to stop)`);
|
|
1834
1838
|
} else if (workerType === "list-workers") {
|
|
1835
1839
|
for (const e of PRESET_WORKERS) printWorkerRow(e.definition.name, "preset", "preset");
|
|
1836
1840
|
for (const c of customWorkers) printWorkerRow(c.definition.name, "custom", c.source);
|
package/dist/lib.js
CHANGED
package/dist/runcat.d.ts
CHANGED
|
@@ -12,9 +12,9 @@ export interface RuncatSnapshot {
|
|
|
12
12
|
lastUpdatedDate: string;
|
|
13
13
|
}
|
|
14
14
|
/** 'HH:MM' 形式。日を跨ぐ場合は 'MM/DD HH:MM' として日付も付ける。不正値は空文字。 */
|
|
15
|
-
export declare function resetStamp(isoString: string, now?: Date): string;
|
|
15
|
+
export declare function resetStamp(isoString: string | null, now?: Date): string;
|
|
16
16
|
/** 'HH' のみ。バーのように幅が限られる用途向け。不正値は空文字。 */
|
|
17
|
-
export declare function resetHour(isoString: string): string;
|
|
17
|
+
export declare function resetHour(isoString: string | null): string;
|
|
18
18
|
export declare function buildRuncatSnapshot(usage: UsageInfo, now?: Date): RuncatSnapshot;
|
|
19
19
|
/**
|
|
20
20
|
* RunCat Neo 用のスナップショットを書き出す。
|
package/dist/slack.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
/** `usage` コマンドが利用状況をポーリングする間隔 */
|
|
2
|
+
export declare const USAGE_POLL_INTERVAL_SECONDS = 360;
|
|
1
3
|
export declare function send(payload: Record<string, unknown>): Promise<void>;
|
|
2
4
|
export interface UsageInfo {
|
|
3
|
-
fiveHourUtilization: number;
|
|
4
|
-
fiveHourResetsAt: string;
|
|
5
|
-
sevenDayUtilization: number;
|
|
6
|
-
sevenDayResetsAt: string;
|
|
5
|
+
fiveHourUtilization: number | null;
|
|
6
|
+
fiveHourResetsAt: string | null;
|
|
7
|
+
sevenDayUtilization: number | null;
|
|
8
|
+
sevenDayResetsAt: string | null;
|
|
7
9
|
}
|
|
10
|
+
interface UsageWindow {
|
|
11
|
+
utilization?: number | null;
|
|
12
|
+
resets_at?: string | null;
|
|
13
|
+
}
|
|
14
|
+
/** usage API のレスポンスを UsageInfo へ。欠けている窓は null にする(throw しない) */
|
|
15
|
+
export declare function parseUsageResponse(body: {
|
|
16
|
+
five_hour?: UsageWindow | null;
|
|
17
|
+
seven_day?: UsageWindow | null;
|
|
18
|
+
}): UsageInfo;
|
|
19
|
+
/** 返ってきた窓だけを並べる。どちらも無ければ空文字 */
|
|
20
|
+
export declare function formatTokenLimitText(usage: UsageInfo): string;
|
|
8
21
|
/**
|
|
9
22
|
* 現在の利用状況を取得し、RunCat Neo 用スナップショットを更新したうえで通知に添えるテキストを返す。
|
|
10
23
|
* ワーカーの完了/失敗通知はすべてここを通るため、タスクが終わるたびに RunCat 側も最新化される
|
|
11
24
|
* (Slack webhook 未設定でも通知が no-op になるだけで、スナップショットの更新は行われる)。
|
|
25
|
+
* 取得に失敗したときだけ null を返す(どの枠も返らない正常応答は空文字)。
|
|
12
26
|
*/
|
|
13
|
-
export declare function buildTokenLimitText(): Promise<string>;
|
|
27
|
+
export declare function buildTokenLimitText(fresh?: boolean): Promise<string | null>;
|
|
14
28
|
/**
|
|
15
29
|
* 通知本文へ載せる output を末尾1000文字に切り詰める。
|
|
16
30
|
* 案内文(CLOUD_FAILURE_GUIDANCE)は appendCloudFailureGuidance が output の先頭に
|
|
@@ -44,3 +58,4 @@ export declare function notifyTaskFailed(workerName: string, repoName: string, i
|
|
|
44
58
|
sessionId?: string;
|
|
45
59
|
}): Promise<void>;
|
|
46
60
|
export declare function notifyError(workerName: string, repoName: string, error: unknown): Promise<void>;
|
|
61
|
+
export {};
|