claude-task-worker 0.142.2 → 0.142.4
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/{chunk-EYML7T7A.js → chunk-WTY7GTRT.js} +56 -25
- package/dist/index.js +1 -1
- package/dist/lib.js +1 -1
- package/dist/slack.d.ts +2 -0
- package/package.json +1 -1
|
@@ -2140,9 +2140,9 @@ function generateWorktreeName() {
|
|
|
2140
2140
|
}
|
|
2141
2141
|
|
|
2142
2142
|
// src/slack.ts
|
|
2143
|
-
import { exec } from "node:child_process";
|
|
2143
|
+
import { exec, execFile as execFile2 } from "node:child_process";
|
|
2144
2144
|
import { readFileSync as readFileSync2, renameSync as renameSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2145
|
-
import { homedir as homedir3 } from "node:os";
|
|
2145
|
+
import { homedir as homedir3, tmpdir } from "node:os";
|
|
2146
2146
|
import { join as join3 } from "node:path";
|
|
2147
2147
|
import { promisify as promisify2 } from "node:util";
|
|
2148
2148
|
|
|
@@ -2233,10 +2233,13 @@ function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
|
|
|
2233
2233
|
|
|
2234
2234
|
// src/slack.ts
|
|
2235
2235
|
var execAsync = promisify2(exec);
|
|
2236
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
2236
2237
|
var WEBHOOK_URL = process.env.CLAUDE_TASK_WORKER_SLACK_WEBHOOK_URL;
|
|
2237
2238
|
var USAGE_POLL_INTERVAL_SECONDS = 600;
|
|
2238
2239
|
var USAGE_BACKOFF_PATH = "/tmp/claude-usage-backoff.json";
|
|
2239
2240
|
var USAGE_RATE_LIMIT_DEFAULT_BACKOFF_SECONDS = 600;
|
|
2241
|
+
var USAGE_CACHE_PATH = "/tmp/claude-usage-cache.json";
|
|
2242
|
+
var USAGE_CACHE_TTL_SECONDS = 600;
|
|
2240
2243
|
async function send(payload) {
|
|
2241
2244
|
if (!WEBHOOK_URL) return;
|
|
2242
2245
|
try {
|
|
@@ -2297,38 +2300,66 @@ function writeBackoffUntil(until) {
|
|
|
2297
2300
|
} catch {
|
|
2298
2301
|
}
|
|
2299
2302
|
}
|
|
2303
|
+
function readUsageCache(now = Date.now()) {
|
|
2304
|
+
try {
|
|
2305
|
+
const { fetchedAt, usage } = JSON.parse(readFileSync2(USAGE_CACHE_PATH, "utf-8"));
|
|
2306
|
+
return now - Number(fetchedAt) < USAGE_CACHE_TTL_SECONDS * 1e3 ? usage : null;
|
|
2307
|
+
} catch {
|
|
2308
|
+
return null;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
function writeUsageCache(usage) {
|
|
2312
|
+
try {
|
|
2313
|
+
const tmp = `${USAGE_CACHE_PATH}.${process.pid}.tmp`;
|
|
2314
|
+
writeFileSync4(tmp, JSON.stringify({ fetchedAt: Date.now(), usage }));
|
|
2315
|
+
renameSync3(tmp, USAGE_CACHE_PATH);
|
|
2316
|
+
} catch {
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2300
2319
|
async function fetchUsageInfo() {
|
|
2301
2320
|
const backoffUntil = readBackoffUntil();
|
|
2302
2321
|
if (Date.now() < backoffUntil) {
|
|
2303
2322
|
console.error(`[slack] Usage API rate limited; skipping until ${new Date(backoffUntil).toISOString()}`);
|
|
2304
2323
|
return null;
|
|
2305
2324
|
}
|
|
2325
|
+
const cached = readUsageCache();
|
|
2326
|
+
if (cached) return cached;
|
|
2306
2327
|
try {
|
|
2307
|
-
|
|
2308
|
-
if (envToken) {
|
|
2309
|
-
const res = await requestUsage(envToken);
|
|
2310
|
-
if (res.status !== 401 && res.status !== 403) return await handleUsageResponse(res);
|
|
2311
|
-
console.error(
|
|
2312
|
-
`[slack] Usage API rejected CLAUDE_CODE_OAUTH_TOKEN (${res.status}); falling back to stored credentials`
|
|
2313
|
-
);
|
|
2314
|
-
}
|
|
2315
|
-
const { token, expiresAt } = await getStoredCredential();
|
|
2328
|
+
let { token, expiresAt } = await getStoredCredential();
|
|
2316
2329
|
if (!token) {
|
|
2317
|
-
console.error("[slack] No OAuth token found (
|
|
2330
|
+
console.error("[slack] No OAuth token found (sign in to Claude Code)");
|
|
2318
2331
|
return null;
|
|
2319
2332
|
}
|
|
2320
|
-
if (expiresAt
|
|
2333
|
+
if (isExpired(expiresAt)) {
|
|
2321
2334
|
console.error(
|
|
2322
|
-
`[slack] OAuth token expired at ${new Date(expiresAt).toISOString()}
|
|
2335
|
+
`[slack] OAuth token expired at ${new Date(expiresAt).toISOString()}; running claude to refresh it`
|
|
2323
2336
|
);
|
|
2324
|
-
|
|
2337
|
+
await refreshTokenByRunningClaude();
|
|
2338
|
+
({ token, expiresAt } = await getStoredCredential());
|
|
2339
|
+
if (!token || isExpired(expiresAt)) {
|
|
2340
|
+
console.error("[slack] OAuth token is still expired after running claude");
|
|
2341
|
+
return null;
|
|
2342
|
+
}
|
|
2325
2343
|
}
|
|
2326
|
-
|
|
2344
|
+
const usage = await handleUsageResponse(await requestUsage(token));
|
|
2345
|
+
if (usage) writeUsageCache(usage);
|
|
2346
|
+
return usage;
|
|
2327
2347
|
} catch (err) {
|
|
2328
2348
|
console.error(`[slack] Failed to fetch usage info: ${err}`);
|
|
2329
2349
|
return null;
|
|
2330
2350
|
}
|
|
2331
2351
|
}
|
|
2352
|
+
function isExpired(expiresAt) {
|
|
2353
|
+
return expiresAt !== void 0 && expiresAt <= Date.now();
|
|
2354
|
+
}
|
|
2355
|
+
async function refreshTokenByRunningClaude() {
|
|
2356
|
+
const { CLAUDE_CODE_OAUTH_TOKEN: _ignored, ...env } = process.env;
|
|
2357
|
+
try {
|
|
2358
|
+
await execFileAsync2("claude", ["-p", "/exit"], { cwd: tmpdir(), env, timeout: 12e4 });
|
|
2359
|
+
} catch (err) {
|
|
2360
|
+
console.error(`[slack] Failed to run claude for token refresh: ${err}`);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2332
2363
|
function requestUsage(token) {
|
|
2333
2364
|
return fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
2334
2365
|
headers: {
|
|
@@ -2450,7 +2481,7 @@ import { promisify as promisify3 } from "node:util";
|
|
|
2450
2481
|
import { rm, stat } from "node:fs/promises";
|
|
2451
2482
|
import { basename as basename2, resolve as resolve2, sep } from "node:path";
|
|
2452
2483
|
var childProcess2 = createRequire2(import.meta.url)("node:child_process");
|
|
2453
|
-
var
|
|
2484
|
+
var execFileAsync3 = (command, args) => promisify3(childProcess2.execFile)(command, args);
|
|
2454
2485
|
var WORKTREES_DIR = ".claude/worktrees";
|
|
2455
2486
|
function isManagedWorktreePath(path2) {
|
|
2456
2487
|
return resolve2(path2).startsWith(resolve2(WORKTREES_DIR) + sep);
|
|
@@ -2477,7 +2508,7 @@ async function forceRemoveIfExists(path2) {
|
|
|
2477
2508
|
}
|
|
2478
2509
|
}
|
|
2479
2510
|
async function listWorktreeEntries() {
|
|
2480
|
-
const { stdout } = await
|
|
2511
|
+
const { stdout } = await execFileAsync3("git", ["worktree", "list", "--porcelain"]);
|
|
2481
2512
|
return stdout.replace(/\r\n/g, "\n").trim().split("\n\n").filter(Boolean).map((entry) => {
|
|
2482
2513
|
const lines = entry.split("\n");
|
|
2483
2514
|
const worktreeLine = lines.find((l) => l.startsWith("worktree "));
|
|
@@ -2491,7 +2522,7 @@ async function listWorktreeEntries() {
|
|
|
2491
2522
|
}
|
|
2492
2523
|
async function removeRegisteredWorktree(worktreePath) {
|
|
2493
2524
|
try {
|
|
2494
|
-
await
|
|
2525
|
+
await execFileAsync3("git", ["worktree", "remove", "--force", "--force", worktreePath]);
|
|
2495
2526
|
} catch (error) {
|
|
2496
2527
|
console.error(`[worktree] Failed to remove worktree ${worktreePath}:`, error);
|
|
2497
2528
|
}
|
|
@@ -2500,7 +2531,7 @@ async function removeRegisteredWorktree(worktreePath) {
|
|
|
2500
2531
|
var PROTECTED_BRANCHES = /* @__PURE__ */ new Set(["main", "master", "develop"]);
|
|
2501
2532
|
async function getDefaultBranchName() {
|
|
2502
2533
|
try {
|
|
2503
|
-
const { stdout } = await
|
|
2534
|
+
const { stdout } = await execFileAsync3("git", ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
2504
2535
|
return stdout.trim().replace(/^origin\//, "");
|
|
2505
2536
|
} catch {
|
|
2506
2537
|
return void 0;
|
|
@@ -2513,7 +2544,7 @@ async function deleteLocalBranch(branchName) {
|
|
|
2513
2544
|
return;
|
|
2514
2545
|
}
|
|
2515
2546
|
try {
|
|
2516
|
-
await
|
|
2547
|
+
await execFileAsync3("git", ["branch", "-D", branchName]);
|
|
2517
2548
|
console.log(`[worktree] Deleted local branch: ${branchName}`);
|
|
2518
2549
|
} catch (error) {
|
|
2519
2550
|
const stderr = String(error?.stderr ?? "");
|
|
@@ -2523,7 +2554,7 @@ async function deleteLocalBranch(branchName) {
|
|
|
2523
2554
|
}
|
|
2524
2555
|
async function localBranchExists(branchName) {
|
|
2525
2556
|
try {
|
|
2526
|
-
await
|
|
2557
|
+
await execFileAsync3("git", ["rev-parse", "--verify", "--quiet", `refs/heads/${branchName}`]);
|
|
2527
2558
|
return true;
|
|
2528
2559
|
} catch {
|
|
2529
2560
|
return false;
|
|
@@ -2541,7 +2572,7 @@ function createWorktreeFromBranch(worktreeId, baseBranch) {
|
|
|
2541
2572
|
}
|
|
2542
2573
|
async function addWorktree(worktreeId, baseBranch) {
|
|
2543
2574
|
const worktreePath = getWorktreePath(worktreeId);
|
|
2544
|
-
await
|
|
2575
|
+
await execFileAsync3("git", ["worktree", "add", "--track", "-B", worktreeId, worktreePath, `origin/${baseBranch}`]);
|
|
2545
2576
|
}
|
|
2546
2577
|
async function removeWorktree(worktreeId) {
|
|
2547
2578
|
const worktreePath = getWorktreePath(worktreeId);
|
|
@@ -2987,7 +3018,7 @@ function createPrPollingWorker(config) {
|
|
|
2987
3018
|
import { createRequire as createRequire3 } from "node:module";
|
|
2988
3019
|
import { promisify as promisify4 } from "node:util";
|
|
2989
3020
|
var childProcess3 = createRequire3(import.meta.url)("node:child_process");
|
|
2990
|
-
var
|
|
3021
|
+
var execFileAsync4 = (command, args) => promisify4(childProcess3.execFile)(command, args);
|
|
2991
3022
|
var CONFIG_FILE = "claude-task-worker.json";
|
|
2992
3023
|
var LABEL_TRIAGE_SCOPE2 = "cc-triage-scope";
|
|
2993
3024
|
function lastRunBranchName(workerName) {
|
|
@@ -3010,7 +3041,7 @@ function lastRunPrBody(workerName, at) {
|
|
|
3010
3041
|
].join("\n");
|
|
3011
3042
|
}
|
|
3012
3043
|
async function git(cwd, args) {
|
|
3013
|
-
const { stdout } = await
|
|
3044
|
+
const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args]);
|
|
3014
3045
|
return stdout;
|
|
3015
3046
|
}
|
|
3016
3047
|
async function publishLastRunPr(workerName, defaultBranch, at) {
|
package/dist/index.js
CHANGED
package/dist/lib.js
CHANGED
package/dist/slack.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** `usage` コマンドが利用状況をポーリングする間隔 */
|
|
2
2
|
export declare const USAGE_POLL_INTERVAL_SECONDS = 600;
|
|
3
|
+
/** 取得結果を使い回す期間。この間は usage API を叩かない */
|
|
4
|
+
export declare const USAGE_CACHE_TTL_SECONDS = 600;
|
|
3
5
|
export declare function send(payload: Record<string, unknown>): Promise<void>;
|
|
4
6
|
export interface UsageInfo {
|
|
5
7
|
fiveHourUtilization: number | null;
|