claude-task-worker 0.39.0 → 0.39.2

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.
Files changed (2) hide show
  1. package/dist/index.js +83 -62
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -109,7 +109,7 @@ function buildTaskTableLines(entries, now = /* @__PURE__ */ new Date()) {
109
109
  colWidths.duration
110
110
  ] : [colWidths.id, colWidths.title, colWidths.worker, colWidths.status, colWidths.time, colWidths.duration];
111
111
  const line = (l, m, r, f) => `${l}${cols.map((w) => f.repeat(w + 2)).join(m)}${r}`;
112
- const row = (id, title, worker, path, status, time, duration) => hasPath ? `\u2502 ${pad(id, colWidths.id)} \u2502 ${pad(title, colWidths.title, true)} \u2502 ${pad(worker, colWidths.worker)} \u2502 ${pad(path, colWidths.path)} \u2502 ${pad(status, colWidths.status)} \u2502 ${pad(time, colWidths.time)} \u2502 ${pad(duration, colWidths.duration)} \u2502` : `\u2502 ${pad(id, colWidths.id)} \u2502 ${pad(title, colWidths.title, true)} \u2502 ${pad(worker, colWidths.worker)} \u2502 ${pad(status, colWidths.status)} \u2502 ${pad(time, colWidths.time)} \u2502 ${pad(duration, colWidths.duration)} \u2502`;
112
+ const row = (id, title, worker, path2, status, time, duration) => hasPath ? `\u2502 ${pad(id, colWidths.id)} \u2502 ${pad(title, colWidths.title, true)} \u2502 ${pad(worker, colWidths.worker)} \u2502 ${pad(path2, colWidths.path)} \u2502 ${pad(status, colWidths.status)} \u2502 ${pad(time, colWidths.time)} \u2502 ${pad(duration, colWidths.duration)} \u2502` : `\u2502 ${pad(id, colWidths.id)} \u2502 ${pad(title, colWidths.title, true)} \u2502 ${pad(worker, colWidths.worker)} \u2502 ${pad(status, colWidths.status)} \u2502 ${pad(time, colWidths.time)} \u2502 ${pad(duration, colWidths.duration)} \u2502`;
113
113
  const lines = [];
114
114
  lines.push(line("\u250C", "\u252C", "\u2510", "\u2500"));
115
115
  lines.push(row("#", "Title", "Worker", "Worktree", "Status", "Time", "Duration"));
@@ -180,12 +180,12 @@ function extractFinalAssistantText(jsonl) {
180
180
  }
181
181
  function readFinalReport(sessionId, root = transcriptRoot()) {
182
182
  if (!sessionId) return "";
183
- const path = findTranscriptPath(sessionId, root);
184
- if (!path) return "";
183
+ const path2 = findTranscriptPath(sessionId, root);
184
+ if (!path2) return "";
185
185
  try {
186
- return extractFinalAssistantText(readFileSync3(path, "utf-8"));
186
+ return extractFinalAssistantText(readFileSync3(path2, "utf-8"));
187
187
  } catch (err) {
188
- console.error(`[transcript] failed to read ${path}: ${err}`);
188
+ console.error(`[transcript] failed to read ${path2}: ${err}`);
189
189
  return "";
190
190
  }
191
191
  }
@@ -523,6 +523,7 @@ __export(herdr_runner_exports, {
523
523
  startHerdrTask: () => startHerdrTask,
524
524
  stopHerdrTask: () => stopHerdrTask,
525
525
  taskTabLabel: () => taskTabLabel,
526
+ toAgentName: () => toAgentName,
526
527
  waitForHerdrTask: () => waitForHerdrTask
527
528
  });
528
529
  async function loadHerdr() {
@@ -531,6 +532,11 @@ async function loadHerdr() {
531
532
  function taskTabLabel(projectName, number) {
532
533
  return `ctw:${projectName}:#${number}`;
533
534
  }
535
+ function toAgentName(label) {
536
+ const sanitized = label.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^[-_]+/, "");
537
+ const withLeadingLetter = /^[a-z]/.test(sanitized) ? sanitized : `ctw-${sanitized}`;
538
+ return withLeadingLetter.slice(0, 32).replace(/[-_]+$/, "");
539
+ }
534
540
  function createCompletionTracker() {
535
541
  return { seenWorking: false, warnedBlocked: false };
536
542
  }
@@ -582,7 +588,7 @@ async function startHerdrTask({
582
588
  if (!ready) {
583
589
  console.warn(`[herdr-runner] pane ${paneId} produced no prompt before the timeout, launching anyway`);
584
590
  }
585
- await mod.agentStart(paneId, { name: label, args, readyTimeoutMs: timing?.agentStartReadyTimeoutMs });
591
+ await mod.agentStart(paneId, { name: toAgentName(label), args, readyTimeoutMs: timing?.agentStartReadyTimeoutMs });
586
592
  } catch (err) {
587
593
  await mod.tabClose(tabId).catch(() => {
588
594
  });
@@ -1453,6 +1459,9 @@ async function createLabel(name, color, force) {
1453
1459
  }
1454
1460
 
1455
1461
  // src/claude-args.ts
1462
+ import { mkdirSync, renameSync, writeFileSync } from "node:fs";
1463
+ import os from "node:os";
1464
+ import path from "node:path";
1456
1465
  var DISALLOWED_TOOLS = [
1457
1466
  // 遅延 / yield: 後続ウェイクアップ前提。print モードではウェイクアップが発火せず、
1458
1467
  // 呼ぶと処理未完のままプロセスが終了する。
@@ -1494,6 +1503,18 @@ var SYSTEM_PROMPT = `\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F \`claude-t
1494
1503
  - \u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u30FB\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u30FB\u30B3\u30E1\u30F3\u30C8/\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u30FB\u672A\u5BFE\u5FDC\u8A00\u8A9E\u306A\u3069 CodeGraph \u304C\u6271\u308F\u306A\u3044\u5BFE\u8C61\u306F\u3001\u5F93\u6765\u3069\u304A\u308A\u30C6\u30AD\u30B9\u30C8\u691C\u7D22\u3067\u88DC\u3046
1495
1504
  - \u63A2\u7D22\u3092\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u3078\u59D4\u8B72\u3059\u308B\u5834\u5408\u306F\u3001\u3053\u306E\u65B9\u91DD\u3082\u59D4\u8B72\u30D7\u30ED\u30F3\u30D7\u30C8\u306B\u660E\u8A18\u3057\u3066\u4F1D\u3048\u308B`;
1496
1505
  var CLAUDE_COMMAND = "claude";
1506
+ var cachedSystemPromptFilePath;
1507
+ function systemPromptFilePath() {
1508
+ if (cachedSystemPromptFilePath) return cachedSystemPromptFilePath;
1509
+ const dir = path.join(os.tmpdir(), "claude-task-worker");
1510
+ mkdirSync(dir, { recursive: true });
1511
+ const target = path.join(dir, `append-system-prompt-${process.pid}.txt`);
1512
+ const tmp = `${target}.tmp`;
1513
+ writeFileSync(tmp, SYSTEM_PROMPT, "utf8");
1514
+ renameSync(tmp, target);
1515
+ cachedSystemPromptFilePath = target;
1516
+ return target;
1517
+ }
1497
1518
  function buildClaudeArgs({ mode, prompt, model, effort }) {
1498
1519
  return [
1499
1520
  ...mode === "herdr" ? [] : ["-p"],
@@ -1502,8 +1523,8 @@ function buildClaudeArgs({ mode, prompt, model, effort }) {
1502
1523
  "--chrome",
1503
1524
  "--disallowedTools",
1504
1525
  DISALLOWED_TOOLS_ARG,
1505
- "--append-system-prompt",
1506
- SYSTEM_PROMPT,
1526
+ "--append-system-prompt-file",
1527
+ systemPromptFilePath(),
1507
1528
  "--model",
1508
1529
  model,
1509
1530
  "--effort",
@@ -1863,17 +1884,17 @@ function getConfigDir() {
1863
1884
  function getUserConfigPath() {
1864
1885
  return join2(getConfigDir(), "config.json");
1865
1886
  }
1866
- function isDirectory(path) {
1887
+ function isDirectory(path2) {
1867
1888
  try {
1868
- return statSync(path).isDirectory();
1889
+ return statSync(path2).isDirectory();
1869
1890
  } catch {
1870
1891
  return false;
1871
1892
  }
1872
1893
  }
1873
- function parseConfigFile(path) {
1894
+ function parseConfigFile(path2) {
1874
1895
  let content;
1875
1896
  try {
1876
- content = readFileSync2(path, "utf-8");
1897
+ content = readFileSync2(path2, "utf-8");
1877
1898
  } catch (err) {
1878
1899
  if (err.code === "ENOENT") return void 0;
1879
1900
  throw err;
@@ -1882,7 +1903,7 @@ function parseConfigFile(path) {
1882
1903
  return JSON.parse(content);
1883
1904
  } catch (err) {
1884
1905
  if (err instanceof SyntaxError) {
1885
- throw new UserConfigError(`config file contains invalid JSON: ${path}: ${err.message}`);
1906
+ throw new UserConfigError(`config file contains invalid JSON: ${path2}: ${err.message}`);
1886
1907
  }
1887
1908
  throw err;
1888
1909
  }
@@ -1890,29 +1911,29 @@ function parseConfigFile(path) {
1890
1911
  function readRawConfig() {
1891
1912
  return parseConfigFile(getUserConfigPath());
1892
1913
  }
1893
- function parseMode(raw, path) {
1914
+ function parseMode(raw, path2) {
1894
1915
  if (!("mode" in raw)) return DEFAULT_RUN_MODE;
1895
1916
  const value = raw["mode"];
1896
1917
  if (value === "default" || value === "herdr") return value;
1897
- console.warn(`[config] invalid mode: ${JSON.stringify(value)} in ${path}, using "${DEFAULT_RUN_MODE}"`);
1918
+ console.warn(`[config] invalid mode: ${JSON.stringify(value)} in ${path2}, using "${DEFAULT_RUN_MODE}"`);
1898
1919
  return DEFAULT_RUN_MODE;
1899
1920
  }
1900
1921
  function loadUserConfig() {
1901
- const path = getUserConfigPath();
1922
+ const path2 = getUserConfigPath();
1902
1923
  const raw = readRawConfig();
1903
1924
  if (raw === void 0) {
1904
- throw new UserConfigError(`config.json not found: ${path}`);
1925
+ throw new UserConfigError(`config.json not found: ${path2}`);
1905
1926
  }
1906
1927
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
1907
- throw new UserConfigError(`config.json must contain a JSON object: ${path}`);
1928
+ throw new UserConfigError(`config.json must contain a JSON object: ${path2}`);
1908
1929
  }
1909
1930
  if (!("projects" in raw) || typeof raw["projects"] !== "object" || raw["projects"] === null || Array.isArray(raw["projects"])) {
1910
- throw new UserConfigError(`config.json must contain a "projects" section as an object: ${path}`);
1931
+ throw new UserConfigError(`config.json must contain a "projects" section as an object: ${path2}`);
1911
1932
  }
1912
1933
  if ("projectGroups" in raw && (typeof raw["projectGroups"] !== "object" || raw["projectGroups"] === null || Array.isArray(raw["projectGroups"]))) {
1913
- throw new UserConfigError(`config.json "projectGroups" must be an object: ${path}`);
1934
+ throw new UserConfigError(`config.json "projectGroups" must be an object: ${path2}`);
1914
1935
  }
1915
- const mode = parseMode(raw, path);
1936
+ const mode = parseMode(raw, path2);
1916
1937
  const rawProjects = raw["projects"];
1917
1938
  const rawProjectGroups = "projectGroups" in raw ? raw["projectGroups"] : {};
1918
1939
  const projectKeys = Object.keys(rawProjects);
@@ -1932,7 +1953,7 @@ function loadUserConfig() {
1932
1953
  const projects = {};
1933
1954
  for (const [name, value] of Object.entries(rawProjects)) {
1934
1955
  if (name === "__proto__") {
1935
- throw new UserConfigError(`"__proto__" cannot be used as a key in "projects": ${path}`);
1956
+ throw new UserConfigError(`"__proto__" cannot be used as a key in "projects": ${path2}`);
1936
1957
  }
1937
1958
  if (typeof value !== "string" || !isAbsolute2(value)) {
1938
1959
  console.warn(`[config] invalid projects.${name}: expected an absolute path, skipping`);
@@ -1947,7 +1968,7 @@ function loadUserConfig() {
1947
1968
  const projectGroups = {};
1948
1969
  for (const [groupName, value] of Object.entries(rawProjectGroups)) {
1949
1970
  if (groupName === "__proto__") {
1950
- throw new UserConfigError(`"__proto__" cannot be used as a key in "projectGroups": ${path}`);
1971
+ throw new UserConfigError(`"__proto__" cannot be used as a key in "projectGroups": ${path2}`);
1951
1972
  }
1952
1973
  if (!Array.isArray(value)) {
1953
1974
  console.warn(`[config] invalid projectGroups.${groupName}: expected an array, skipping`);
@@ -1986,14 +2007,14 @@ function readRunMode() {
1986
2007
  }
1987
2008
  return parseMode(raw, getUserConfigPath());
1988
2009
  }
1989
- function findProjectNameByPath(path) {
2010
+ function findProjectNameByPath(path2) {
1990
2011
  let config;
1991
2012
  try {
1992
2013
  config = loadUserConfig();
1993
2014
  } catch {
1994
2015
  return void 0;
1995
2016
  }
1996
- const target = resolve(path);
2017
+ const target = resolve(path2);
1997
2018
  for (const [name, projectPath] of Object.entries(config.projects)) {
1998
2019
  if (resolve(projectPath) === target) return name;
1999
2020
  }
@@ -2137,13 +2158,13 @@ async function runViaHerdr(args, id, onComplete, cwd, env) {
2137
2158
  await finishTask(id, result, onComplete);
2138
2159
  herdrTasks.delete(id);
2139
2160
  }
2140
- function run(command, args, id, title, workerName, path, onComplete, cwd, env) {
2161
+ function run(command, args, id, title, workerName, path2, onComplete, cwd, env) {
2141
2162
  tasks.set(id, {
2142
2163
  id,
2143
2164
  title,
2144
2165
  status: "running",
2145
2166
  workerName,
2146
- path,
2167
+ path: path2,
2147
2168
  startedAt: /* @__PURE__ */ new Date()
2148
2169
  });
2149
2170
  ensureRenderInterval();
@@ -2466,13 +2487,13 @@ function isGeneratedWorktreeName(name) {
2466
2487
 
2467
2488
  // src/slack.ts
2468
2489
  import { exec } from "node:child_process";
2469
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
2490
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
2470
2491
  import { homedir as homedir4 } from "node:os";
2471
2492
  import { join as join5 } from "node:path";
2472
2493
  import { promisify as promisify2 } from "node:util";
2473
2494
 
2474
2495
  // src/runcat.ts
2475
- import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
2496
+ import { mkdirSync as mkdirSync2, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
2476
2497
  import { homedir as homedir3 } from "node:os";
2477
2498
  import { dirname, join as join4 } from "node:path";
2478
2499
  var RUNCAT_OUT_FILE = process.env.RUNCAT_OUT_FILE ?? join4(process.env.HOME ?? homedir3(), ".claude", "runcat-usage.json");
@@ -2541,9 +2562,9 @@ function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
2541
2562
  const dir = dirname(outFile);
2542
2563
  const tmp = join4(dir, `.runcat-${process.pid}-${Date.now()}.json`);
2543
2564
  try {
2544
- mkdirSync(dir, { recursive: true });
2545
- writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
2546
- renameSync(tmp, outFile);
2565
+ mkdirSync2(dir, { recursive: true });
2566
+ writeFileSync2(tmp, JSON.stringify(snapshot), "utf-8");
2567
+ renameSync2(tmp, outFile);
2547
2568
  } catch (err) {
2548
2569
  rmSync(tmp, { force: true });
2549
2570
  console.error(`[runcat] Failed to write ${outFile}: ${err}`);
@@ -2593,7 +2614,7 @@ function readUsageCache() {
2593
2614
  }
2594
2615
  function writeUsageCache(data) {
2595
2616
  try {
2596
- writeFileSync2(USAGE_CACHE_PATH, JSON.stringify({ timestamp: Date.now(), data }));
2617
+ writeFileSync3(USAGE_CACHE_PATH, JSON.stringify({ timestamp: Date.now(), data }));
2597
2618
  } catch {
2598
2619
  }
2599
2620
  }
@@ -2687,28 +2708,28 @@ import { readdir, rm, stat } from "node:fs/promises";
2687
2708
  import { basename as basename2, resolve as resolve2, sep } from "node:path";
2688
2709
  var execFileAsync2 = promisify3(execFile2);
2689
2710
  var WORKTREES_DIR = ".claude/worktrees";
2690
- function isManagedWorktreePath(path) {
2691
- return resolve2(path).startsWith(resolve2(WORKTREES_DIR) + sep);
2711
+ function isManagedWorktreePath(path2) {
2712
+ return resolve2(path2).startsWith(resolve2(WORKTREES_DIR) + sep);
2692
2713
  }
2693
- async function pathExists(path) {
2714
+ async function pathExists(path2) {
2694
2715
  try {
2695
- await stat(path);
2716
+ await stat(path2);
2696
2717
  return true;
2697
2718
  } catch {
2698
2719
  return false;
2699
2720
  }
2700
2721
  }
2701
- async function forceRemoveIfExists(path) {
2702
- if (!isManagedWorktreePath(path)) {
2703
- console.error(`[worktree] Refusing to remove path outside ${WORKTREES_DIR}: ${path}`);
2722
+ async function forceRemoveIfExists(path2) {
2723
+ if (!isManagedWorktreePath(path2)) {
2724
+ console.error(`[worktree] Refusing to remove path outside ${WORKTREES_DIR}: ${path2}`);
2704
2725
  return;
2705
2726
  }
2706
- if (!await pathExists(path)) return;
2727
+ if (!await pathExists(path2)) return;
2707
2728
  try {
2708
- await rm(path, { recursive: true, force: true });
2709
- console.log(`[worktree] Force removed remaining directory: ${path}`);
2729
+ await rm(path2, { recursive: true, force: true });
2730
+ console.log(`[worktree] Force removed remaining directory: ${path2}`);
2710
2731
  } catch (error) {
2711
- console.error(`[worktree] Failed to remove directory ${path}:`, error);
2732
+ console.error(`[worktree] Failed to remove directory ${path2}:`, error);
2712
2733
  }
2713
2734
  }
2714
2735
  async function listWorktreeEntries() {
@@ -3287,9 +3308,9 @@ function extractDesignFilePath(body) {
3287
3308
  if (section === null) return null;
3288
3309
  const match = DESIGN_FILE_LINE.exec(section);
3289
3310
  if (match === null) return null;
3290
- const path = match[1].trim();
3291
- if (path.length === 0 || path.includes("<") || path.includes(">") || !path.endsWith(".pen")) return null;
3292
- return path;
3311
+ const path2 = match[1].trim();
3312
+ if (path2.length === 0 || path2.includes("<") || path2.includes(">") || !path2.endsWith(".pen")) return null;
3313
+ return path2;
3293
3314
  }
3294
3315
  function classifyDesignPr(pr) {
3295
3316
  if (pr === null) return "needs-human";
@@ -3560,24 +3581,24 @@ async function runCodegraphInit(logPrefix) {
3560
3581
  }
3561
3582
  }
3562
3583
  async function ensureCodegraphGitIgnore(logPrefix) {
3563
- const path = globalGitIgnorePath();
3584
+ const path2 = globalGitIgnorePath();
3564
3585
  try {
3565
3586
  let current = "";
3566
3587
  try {
3567
- current = await readFile(path, "utf-8");
3588
+ current = await readFile(path2, "utf-8");
3568
3589
  } catch {
3569
3590
  }
3570
3591
  const next = appendIgnoreEntry(current, CODEGRAPH_IGNORE_ENTRY);
3571
3592
  if (next === null) {
3572
- console.log(`[${logPrefix}] Already ignored: ${CODEGRAPH_IGNORE_ENTRY} (${path})`);
3593
+ console.log(`[${logPrefix}] Already ignored: ${CODEGRAPH_IGNORE_ENTRY} (${path2})`);
3573
3594
  return true;
3574
3595
  }
3575
- await mkdir(dirname2(path), { recursive: true });
3576
- await writeFile(path, next, "utf-8");
3577
- console.log(`[${logPrefix}] Added ${CODEGRAPH_IGNORE_ENTRY} to ${path}`);
3596
+ await mkdir(dirname2(path2), { recursive: true });
3597
+ await writeFile(path2, next, "utf-8");
3598
+ console.log(`[${logPrefix}] Added ${CODEGRAPH_IGNORE_ENTRY} to ${path2}`);
3578
3599
  return true;
3579
3600
  } catch (err) {
3580
- console.error(`[${logPrefix}] Failed to update ${path}: ${err.message}`);
3601
+ console.error(`[${logPrefix}] Failed to update ${path2}: ${err.message}`);
3581
3602
  return false;
3582
3603
  }
3583
3604
  }
@@ -3638,21 +3659,21 @@ jobs:
3638
3659
  assignees: [context.payload.issue.user.login]
3639
3660
  });
3640
3661
  `;
3641
- async function writeFileWithMode(path, content, force) {
3662
+ async function writeFileWithMode(path2, content, force) {
3642
3663
  try {
3643
- await access(path);
3664
+ await access(path2);
3644
3665
  if (!force) return "skipped";
3645
- await writeFile2(path, content, "utf-8");
3666
+ await writeFile2(path2, content, "utf-8");
3646
3667
  return "overwritten";
3647
3668
  } catch {
3648
- await writeFile2(path, content, "utf-8");
3669
+ await writeFile2(path2, content, "utf-8");
3649
3670
  return "created";
3650
3671
  }
3651
3672
  }
3652
- function logWriteResult(result, path) {
3653
- if (result === "created") console.log(`[init] Created: ${path}`);
3654
- else if (result === "overwritten") console.log(`[init] Overwritten: ${path}`);
3655
- else console.log(`[init] Already exists: ${path}`);
3673
+ function logWriteResult(result, path2) {
3674
+ if (result === "created") console.log(`[init] Created: ${path2}`);
3675
+ else if (result === "overwritten") console.log(`[init] Overwritten: ${path2}`);
3676
+ else console.log(`[init] Already exists: ${path2}`);
3656
3677
  }
3657
3678
  async function createConfig(force) {
3658
3679
  const initialConfig = { ...DEFAULT_CONFIG, workers: { ...WORKER_DEFAULTS } };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.39.0",
3
+ "version": "0.39.2",
4
4
  "description": "CLI tool that polls GitHub Issues/PRs and delegates work to Claude CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",