claude-task-worker 0.33.0 → 0.34.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.
Files changed (2) hide show
  1. package/dist/index.js +103 -24
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -164,6 +164,69 @@ var init_task_result = __esm({
164
164
  }
165
165
  });
166
166
 
167
+ // src/transcript.ts
168
+ import { existsSync, readFileSync as readFileSync3, readdirSync } from "node:fs";
169
+ import { homedir as homedir2 } from "node:os";
170
+ import { join as join3 } from "node:path";
171
+ function transcriptRoot() {
172
+ return join3(homedir2(), ".claude", "projects");
173
+ }
174
+ function findTranscriptPath(sessionId, root = transcriptRoot()) {
175
+ if (sessionId === "") return null;
176
+ let entries;
177
+ try {
178
+ entries = readdirSync(root);
179
+ } catch {
180
+ return null;
181
+ }
182
+ for (const entry of entries) {
183
+ const candidate = join3(root, entry, `${sessionId}.jsonl`);
184
+ if (existsSync(candidate)) return candidate;
185
+ }
186
+ return null;
187
+ }
188
+ function textOf(entry) {
189
+ const content = entry.message?.content;
190
+ if (typeof content === "string") return content;
191
+ if (!Array.isArray(content)) return "";
192
+ return content.filter(
193
+ (block) => typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string"
194
+ ).map((block) => block.text).join("\n").trim();
195
+ }
196
+ function extractFinalAssistantText(jsonl) {
197
+ const lines = jsonl.split("\n");
198
+ for (let i = lines.length - 1; i >= 0; i--) {
199
+ const line = lines[i].trim();
200
+ if (line === "") continue;
201
+ let entry;
202
+ try {
203
+ entry = JSON.parse(line);
204
+ } catch {
205
+ continue;
206
+ }
207
+ if (entry.type !== "assistant" || entry.isSidechain === true) continue;
208
+ const text = textOf(entry);
209
+ if (text !== "") return text;
210
+ }
211
+ return "";
212
+ }
213
+ function readFinalReport(sessionId, root = transcriptRoot()) {
214
+ if (!sessionId) return "";
215
+ const path = findTranscriptPath(sessionId, root);
216
+ if (!path) return "";
217
+ try {
218
+ return extractFinalAssistantText(readFileSync3(path, "utf-8"));
219
+ } catch (err) {
220
+ console.error(`[transcript] failed to read ${path}: ${err}`);
221
+ return "";
222
+ }
223
+ }
224
+ var init_transcript = __esm({
225
+ "src/transcript.ts"() {
226
+ "use strict";
227
+ }
228
+ });
229
+
167
230
  // src/herdr.ts
168
231
  var herdr_exports = {};
169
232
  __export(herdr_exports, {
@@ -368,11 +431,14 @@ async function agentGet(target) {
368
431
  if (!agent?.pane_id) {
369
432
  throw new Error(`Failed to get agent info for ${target}: invalid response structure from herdr`);
370
433
  }
434
+ const session = agent.agent_session;
435
+ const sessionId = session?.kind === "id" && typeof session.value === "string" ? session.value : void 0;
371
436
  return {
372
437
  paneId: agent.pane_id,
373
438
  tabId: agent.tab_id ?? "",
374
439
  workspaceId: agent.workspace_id ?? "",
375
- agentStatus: toAgentStatus(agent.agent_status)
440
+ agentStatus: toAgentStatus(agent.agent_status),
441
+ sessionId
376
442
  };
377
443
  }
378
444
  function getCurrentWorkspaceId() {
@@ -523,6 +589,10 @@ function observeAgentStatus(tracker, status) {
523
589
  return { tracker, decision: "running" };
524
590
  }
525
591
  function buildHerdrTaskResult(paneOutput, options) {
592
+ const report = options?.report?.trim() ?? "";
593
+ if (report !== "") {
594
+ return { status: "completed", output: report };
595
+ }
526
596
  const meaningful = options?.headroom ? stripHeadroomBanner(paneOutput) : paneOutput;
527
597
  if (meaningful.trim() === "") {
528
598
  return {
@@ -559,13 +629,16 @@ async function waitForHerdrTask(paneId, options) {
559
629
  const mod = options?.herdr ?? await loadHerdr();
560
630
  const pollIntervalMs = options?.pollIntervalMs ?? AGENT_POLL_INTERVAL_MS;
561
631
  let tracker = createCompletionTracker();
632
+ let sessionId;
562
633
  for (; ; ) {
563
634
  if (options?.signal?.aborted) {
564
635
  return { status: "failed", output: "[worker] the worker is shutting down; the task was interrupted" };
565
636
  }
566
637
  let status;
567
638
  try {
568
- status = (await mod.agentGet(paneId)).agentStatus;
639
+ const agent = await mod.agentGet(paneId);
640
+ status = agent.agentStatus;
641
+ if (agent.sessionId) sessionId = agent.sessionId;
569
642
  } catch (err) {
570
643
  if (err instanceof mod.HerdrError && err.code === "pane_not_found") {
571
644
  return {
@@ -582,7 +655,8 @@ async function waitForHerdrTask(paneId, options) {
582
655
  tracker = observed.tracker;
583
656
  if (observed.decision === "completed") {
584
657
  const output = await readPaneOutput(paneId, mod);
585
- return buildHerdrTaskResult(output, { headroom: options?.headroom });
658
+ const report = (options?.readReport ?? readFinalReport)(sessionId);
659
+ return buildHerdrTaskResult(output, { headroom: options?.headroom, report });
586
660
  }
587
661
  if (observed.decision === "blocked-first-seen") {
588
662
  options?.onBlocked?.();
@@ -643,6 +717,7 @@ var init_herdr_runner = __esm({
643
717
  "src/herdr-runner.ts"() {
644
718
  "use strict";
645
719
  init_task_result();
720
+ init_transcript();
646
721
  AGENT_POLL_INTERVAL_MS = 3 * 1e3;
647
722
  PANE_OUTPUT_LINES = 300;
648
723
  CLAUDE_EXIT_TIMEOUT_MS = 15 * 1e3;
@@ -1414,8 +1489,12 @@ var SYSTEM_PROMPT = `\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F \`claude-t
1414
1489
  - \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`;
1415
1490
  var CLAUDE_COMMAND = "claude";
1416
1491
  var HEADROOM_COMMAND = "headroom";
1417
- var HEADROOM_WRAP_OPTIONS = ["--1m", "--memory", "--code-graph"];
1418
- function buildClaudeArgs({ mode, prompt, model, effort }) {
1492
+ var HEADROOM_WRAP_OPTIONS = ["--1m", "--memory", "--no-tokensave", "--no-serena"];
1493
+ var CONTEXT_1M_SUFFIX = "[1m]";
1494
+ function withContext1mSuffix(model) {
1495
+ return model.endsWith(CONTEXT_1M_SUFFIX) ? model : `${model}${CONTEXT_1M_SUFFIX}`;
1496
+ }
1497
+ function buildClaudeArgs({ mode, prompt, model, effort, headroom }) {
1419
1498
  return [
1420
1499
  ...mode === "herdr" ? [] : ["-p"],
1421
1500
  prompt,
@@ -1426,7 +1505,7 @@ function buildClaudeArgs({ mode, prompt, model, effort }) {
1426
1505
  "--append-system-prompt",
1427
1506
  SYSTEM_PROMPT,
1428
1507
  "--model",
1429
- model,
1508
+ headroom ? withContext1mSuffix(model) : model,
1430
1509
  "--effort",
1431
1510
  effort
1432
1511
  ];
@@ -2348,16 +2427,16 @@ function isGeneratedWorktreeName(name) {
2348
2427
 
2349
2428
  // src/slack.ts
2350
2429
  import { exec } from "node:child_process";
2351
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
2352
- import { homedir as homedir3 } from "node:os";
2353
- import { join as join4 } from "node:path";
2430
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
2431
+ import { homedir as homedir4 } from "node:os";
2432
+ import { join as join5 } from "node:path";
2354
2433
  import { promisify as promisify2 } from "node:util";
2355
2434
 
2356
2435
  // src/runcat.ts
2357
2436
  import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
2358
- import { homedir as homedir2 } from "node:os";
2359
- import { dirname, join as join3 } from "node:path";
2360
- var RUNCAT_OUT_FILE = process.env.RUNCAT_OUT_FILE ?? join3(process.env.HOME ?? homedir2(), ".claude", "runcat-usage.json");
2437
+ import { homedir as homedir3 } from "node:os";
2438
+ import { dirname, join as join4 } from "node:path";
2439
+ var RUNCAT_OUT_FILE = process.env.RUNCAT_OUT_FILE ?? join4(process.env.HOME ?? homedir3(), ".claude", "runcat-usage.json");
2361
2440
  var JST = "Asia/Tokyo";
2362
2441
  function formatG(value) {
2363
2442
  return String(Number(value.toPrecision(6)));
@@ -2421,7 +2500,7 @@ function buildRuncatSnapshot(usage, now = /* @__PURE__ */ new Date()) {
2421
2500
  function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
2422
2501
  const snapshot = buildRuncatSnapshot(usage);
2423
2502
  const dir = dirname(outFile);
2424
- const tmp = join3(dir, `.runcat-${process.pid}-${Date.now()}.json`);
2503
+ const tmp = join4(dir, `.runcat-${process.pid}-${Date.now()}.json`);
2425
2504
  try {
2426
2505
  mkdirSync(dir, { recursive: true });
2427
2506
  writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
@@ -2458,13 +2537,13 @@ async function getOAuthToken() {
2458
2537
  const { stdout } = await execAsync('security find-generic-password -s "Claude Code-credentials" -w');
2459
2538
  return extractToken(JSON.parse(stdout.trim()));
2460
2539
  } catch {
2461
- const raw = readFileSync3(join4(homedir3(), ".claude", ".credentials.json"), "utf-8");
2540
+ const raw = readFileSync4(join5(homedir4(), ".claude", ".credentials.json"), "utf-8");
2462
2541
  return extractToken(JSON.parse(raw));
2463
2542
  }
2464
2543
  }
2465
2544
  function readUsageCache() {
2466
2545
  try {
2467
- const raw = readFileSync3(USAGE_CACHE_PATH, "utf-8");
2546
+ const raw = readFileSync4(USAGE_CACHE_PATH, "utf-8");
2468
2547
  const cached = JSON.parse(raw);
2469
2548
  if (Date.now() - cached.timestamp < USAGE_CACHE_TTL_SECONDS * 1e3) {
2470
2549
  return cached.data;
@@ -3157,17 +3236,17 @@ import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promis
3157
3236
 
3158
3237
  // src/commands/codegraph.ts
3159
3238
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3160
- import { homedir as homedir4 } from "node:os";
3161
- import { dirname as dirname2, join as join5 } from "node:path";
3239
+ import { homedir as homedir5 } from "node:os";
3240
+ import { dirname as dirname2, join as join6 } from "node:path";
3162
3241
  async function loadRunCommand() {
3163
3242
  return await Promise.resolve().then(() => (init_run_command(), run_command_exports));
3164
3243
  }
3165
3244
  var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
3166
3245
  var CODEGRAPH_IGNORE_ENTRY = ".codegraph/";
3167
- function globalGitIgnorePath(env = process.env, home = homedir4()) {
3246
+ function globalGitIgnorePath(env = process.env, home = homedir5()) {
3168
3247
  const xdg = env.XDG_CONFIG_HOME?.trim();
3169
- const base = xdg ? xdg : join5(home, ".config");
3170
- return join5(base, "git", "ignore");
3248
+ const base = xdg ? xdg : join6(home, ".config");
3249
+ return join6(base, "git", "ignore");
3171
3250
  }
3172
3251
  function appendIgnoreEntry(current, entry) {
3173
3252
  const bare = entry.replace(/\/$/, "");
@@ -3441,14 +3520,14 @@ async function update() {
3441
3520
  }
3442
3521
 
3443
3522
  // src/commands/version.ts
3444
- import { readFileSync as readFileSync4 } from "node:fs";
3445
- import { dirname as dirname3, join as join6 } from "node:path";
3523
+ import { readFileSync as readFileSync5 } from "node:fs";
3524
+ import { dirname as dirname3, join as join7 } from "node:path";
3446
3525
  import { fileURLToPath } from "node:url";
3447
3526
  function version() {
3448
3527
  const here = dirname3(fileURLToPath(import.meta.url));
3449
- const pkgPath = join6(here, "..", "package.json");
3528
+ const pkgPath = join7(here, "..", "package.json");
3450
3529
  try {
3451
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
3530
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
3452
3531
  console.log(pkg.version ?? "unknown");
3453
3532
  } catch (err) {
3454
3533
  console.error(`[version] Failed to read version: ${err.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
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",