claude-task-worker 0.33.1 → 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 +96 -21
  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;
@@ -2352,16 +2427,16 @@ function isGeneratedWorktreeName(name) {
2352
2427
 
2353
2428
  // src/slack.ts
2354
2429
  import { exec } from "node:child_process";
2355
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
2356
- import { homedir as homedir3 } from "node:os";
2357
- 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";
2358
2433
  import { promisify as promisify2 } from "node:util";
2359
2434
 
2360
2435
  // src/runcat.ts
2361
2436
  import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
2362
- import { homedir as homedir2 } from "node:os";
2363
- import { dirname, join as join3 } from "node:path";
2364
- 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");
2365
2440
  var JST = "Asia/Tokyo";
2366
2441
  function formatG(value) {
2367
2442
  return String(Number(value.toPrecision(6)));
@@ -2425,7 +2500,7 @@ function buildRuncatSnapshot(usage, now = /* @__PURE__ */ new Date()) {
2425
2500
  function writeRuncatUsage(usage, outFile = RUNCAT_OUT_FILE) {
2426
2501
  const snapshot = buildRuncatSnapshot(usage);
2427
2502
  const dir = dirname(outFile);
2428
- const tmp = join3(dir, `.runcat-${process.pid}-${Date.now()}.json`);
2503
+ const tmp = join4(dir, `.runcat-${process.pid}-${Date.now()}.json`);
2429
2504
  try {
2430
2505
  mkdirSync(dir, { recursive: true });
2431
2506
  writeFileSync(tmp, JSON.stringify(snapshot), "utf-8");
@@ -2462,13 +2537,13 @@ async function getOAuthToken() {
2462
2537
  const { stdout } = await execAsync('security find-generic-password -s "Claude Code-credentials" -w');
2463
2538
  return extractToken(JSON.parse(stdout.trim()));
2464
2539
  } catch {
2465
- const raw = readFileSync3(join4(homedir3(), ".claude", ".credentials.json"), "utf-8");
2540
+ const raw = readFileSync4(join5(homedir4(), ".claude", ".credentials.json"), "utf-8");
2466
2541
  return extractToken(JSON.parse(raw));
2467
2542
  }
2468
2543
  }
2469
2544
  function readUsageCache() {
2470
2545
  try {
2471
- const raw = readFileSync3(USAGE_CACHE_PATH, "utf-8");
2546
+ const raw = readFileSync4(USAGE_CACHE_PATH, "utf-8");
2472
2547
  const cached = JSON.parse(raw);
2473
2548
  if (Date.now() - cached.timestamp < USAGE_CACHE_TTL_SECONDS * 1e3) {
2474
2549
  return cached.data;
@@ -3161,17 +3236,17 @@ import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promis
3161
3236
 
3162
3237
  // src/commands/codegraph.ts
3163
3238
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3164
- import { homedir as homedir4 } from "node:os";
3165
- 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";
3166
3241
  async function loadRunCommand() {
3167
3242
  return await Promise.resolve().then(() => (init_run_command(), run_command_exports));
3168
3243
  }
3169
3244
  var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
3170
3245
  var CODEGRAPH_IGNORE_ENTRY = ".codegraph/";
3171
- function globalGitIgnorePath(env = process.env, home = homedir4()) {
3246
+ function globalGitIgnorePath(env = process.env, home = homedir5()) {
3172
3247
  const xdg = env.XDG_CONFIG_HOME?.trim();
3173
- const base = xdg ? xdg : join5(home, ".config");
3174
- return join5(base, "git", "ignore");
3248
+ const base = xdg ? xdg : join6(home, ".config");
3249
+ return join6(base, "git", "ignore");
3175
3250
  }
3176
3251
  function appendIgnoreEntry(current, entry) {
3177
3252
  const bare = entry.replace(/\/$/, "");
@@ -3445,14 +3520,14 @@ async function update() {
3445
3520
  }
3446
3521
 
3447
3522
  // src/commands/version.ts
3448
- import { readFileSync as readFileSync4 } from "node:fs";
3449
- 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";
3450
3525
  import { fileURLToPath } from "node:url";
3451
3526
  function version() {
3452
3527
  const here = dirname3(fileURLToPath(import.meta.url));
3453
- const pkgPath = join6(here, "..", "package.json");
3528
+ const pkgPath = join7(here, "..", "package.json");
3454
3529
  try {
3455
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
3530
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
3456
3531
  console.log(pkg.version ?? "unknown");
3457
3532
  } catch (err) {
3458
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.1",
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",