claude-task-worker 0.27.0 → 0.28.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 +172 -83
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -65,7 +65,6 @@ __export(herdr_exports, {
65
65
  getCurrentWorkspaceId: () => getCurrentWorkspaceId,
66
66
  paneClose: () => paneClose,
67
67
  paneGet: () => paneGet,
68
- paneMoveToNewTab: () => paneMoveToNewTab,
69
68
  paneProcessInfo: () => paneProcessInfo,
70
69
  paneRead: () => paneRead,
71
70
  paneSendKeys: () => paneSendKeys,
@@ -79,6 +78,7 @@ __export(herdr_exports, {
79
78
  workspaceList: () => workspaceList
80
79
  });
81
80
  import { createRequire as createRequire2 } from "node:module";
81
+ import { resolve as resolvePath } from "node:path";
82
82
  function runHerdr(args) {
83
83
  return new Promise((resolve3) => {
84
84
  childProcess2.execFile(
@@ -86,24 +86,30 @@ function runHerdr(args) {
86
86
  args,
87
87
  { timeout: HERDR_TIMEOUT_MS, killSignal: "SIGKILL" },
88
88
  (error, stdout, stderr) => {
89
- let parsed;
90
- try {
91
- parsed = JSON.parse(stdout);
92
- } catch {
93
- parsed = void 0;
94
- }
95
- resolve3({ execError: error, parsed, stdout, stderr });
89
+ const parsed = parseHerdrResponse(stdout);
90
+ const stderrError = parsed?.error ? void 0 : parseHerdrResponse(stderr)?.error;
91
+ resolve3({ execError: error, parsed, stderrError, stdout, stderr });
96
92
  }
97
93
  );
98
94
  });
99
95
  }
96
+ function parseHerdrResponse(output) {
97
+ try {
98
+ const parsed = JSON.parse(output);
99
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
100
+ return parsed;
101
+ } catch {
102
+ return void 0;
103
+ }
104
+ }
100
105
  async function execHerdr(args, options) {
101
- const { execError, parsed, stdout, stderr } = await runHerdr(args);
106
+ const { execError, parsed, stderrError, stdout, stderr } = await runHerdr(args);
102
107
  const stderrSuffix = stderr.trim() ? `: ${stderr.trim()}` : "";
103
- if (parsed?.error) {
108
+ const errorPayload = parsed?.error ?? stderrError;
109
+ if (errorPayload) {
104
110
  throw new HerdrError(
105
- `herdr ${args.join(" ")} failed: [${parsed.error.code}] ${parsed.error.message}`,
106
- parsed.error.code
111
+ `herdr ${args.join(" ")} failed: [${errorPayload.code}] ${errorPayload.message}`,
112
+ errorPayload.code
107
113
  );
108
114
  }
109
115
  if (execError) {
@@ -121,6 +127,9 @@ function envArgs(env) {
121
127
  if (!env) return [];
122
128
  return Object.entries(env).flatMap(([key, value]) => ["--env", `${key}=${value}`]);
123
129
  }
130
+ function cwdArgs(cwd) {
131
+ return ["--cwd", resolvePath(cwd)];
132
+ }
124
133
  async function tabCreate({
125
134
  label,
126
135
  cwd,
@@ -133,8 +142,7 @@ async function tabCreate({
133
142
  ...workspaceId ? ["--workspace", workspaceId] : [],
134
143
  "--label",
135
144
  label,
136
- "--cwd",
137
- cwd,
145
+ ...cwdArgs(cwd),
138
146
  ...envArgs(env),
139
147
  "--no-focus"
140
148
  ]);
@@ -183,8 +191,7 @@ async function workspaceCreate({
183
191
  "create",
184
192
  "--label",
185
193
  label,
186
- "--cwd",
187
- cwd,
194
+ ...cwdArgs(cwd),
188
195
  ...envArgs(env),
189
196
  "--no-focus"
190
197
  ]);
@@ -214,6 +221,7 @@ async function agentStart({
214
221
  cwd,
215
222
  argv,
216
223
  workspaceId,
224
+ tabId: targetTabId,
217
225
  env
218
226
  }) {
219
227
  const result = await execHerdr([
@@ -221,8 +229,8 @@ async function agentStart({
221
229
  "start",
222
230
  name,
223
231
  ...workspaceId ? ["--workspace", workspaceId] : [],
224
- "--cwd",
225
- cwd,
232
+ ...targetTabId ? ["--tab", targetTabId] : [],
233
+ ...cwdArgs(cwd),
226
234
  ...envArgs(env),
227
235
  "--no-focus",
228
236
  "--",
@@ -235,23 +243,6 @@ async function agentStart({
235
243
  }
236
244
  return { paneId, tabId };
237
245
  }
238
- async function paneMoveToNewTab(paneId, { label, workspaceId }) {
239
- const result = await execHerdr([
240
- "pane",
241
- "move",
242
- paneId,
243
- "--new-tab",
244
- ...workspaceId ? ["--workspace", workspaceId] : [],
245
- "--label",
246
- label,
247
- "--no-focus"
248
- ]);
249
- const tabId = result?.move_result?.created_tab?.tab_id;
250
- if (!tabId) {
251
- throw new Error("Failed to move pane to a new tab: invalid response structure from herdr");
252
- }
253
- return { tabId };
254
- }
255
246
  function toAgentStatus(value) {
256
247
  return value === "working" || value === "idle" || value === "blocked" ? value : "unknown";
257
248
  }
@@ -430,15 +421,19 @@ async function startHerdrTask({
430
421
  herdr
431
422
  }) {
432
423
  const mod = herdr ?? await loadHerdr();
433
- const { paneId } = await mod.agentStart({ name: label, cwd, argv, env, workspaceId });
424
+ const { tabId, paneId: shellPaneId } = await mod.tabCreate({ label, cwd, workspaceId, env });
425
+ let paneId;
434
426
  try {
435
- const { tabId } = await mod.paneMoveToNewTab(paneId, { label, workspaceId });
436
- return { paneId, tabId };
427
+ ({ paneId } = await mod.agentStart({ name: label, cwd, argv, env, workspaceId, tabId }));
437
428
  } catch (err) {
438
- await mod.paneClose(paneId).catch(() => {
429
+ await mod.tabClose(tabId).catch(() => {
439
430
  });
440
431
  throw err;
441
432
  }
433
+ await mod.paneClose(shellPaneId).catch((err) => {
434
+ console.error(`[herdr-runner] failed to close the placeholder shell pane ${shellPaneId}: ${err}`);
435
+ });
436
+ return { paneId, tabId };
442
437
  }
443
438
  async function waitForHerdrTask(paneId, options) {
444
439
  const mod = options?.herdr ?? await loadHerdr();
@@ -534,6 +529,49 @@ var init_herdr_runner = __esm({
534
529
  }
535
530
  });
536
531
 
532
+ // src/commands/run-command.ts
533
+ var run_command_exports = {};
534
+ __export(run_command_exports, {
535
+ runCommand: () => runCommand
536
+ });
537
+ import { spawn as spawn2 } from "node:child_process";
538
+ function runCommand(command, args) {
539
+ return new Promise((resolve3, reject) => {
540
+ const child = spawn2(command, args, {
541
+ stdio: "inherit",
542
+ shell: process.platform === "win32"
543
+ });
544
+ const forwardSignal = (signal) => {
545
+ child.kill(signal);
546
+ };
547
+ const onSigint = () => forwardSignal("SIGINT");
548
+ const onSigterm = () => forwardSignal("SIGTERM");
549
+ const cleanup = () => {
550
+ process.removeListener("SIGINT", onSigint);
551
+ process.removeListener("SIGTERM", onSigterm);
552
+ };
553
+ process.once("SIGINT", onSigint);
554
+ process.once("SIGTERM", onSigterm);
555
+ child.on("error", (err) => {
556
+ cleanup();
557
+ reject(err);
558
+ });
559
+ child.on("close", (code) => {
560
+ cleanup();
561
+ if (code === 0) {
562
+ resolve3();
563
+ } else {
564
+ reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
565
+ }
566
+ });
567
+ });
568
+ }
569
+ var init_run_command = __esm({
570
+ "src/commands/run-command.ts"() {
571
+ "use strict";
572
+ }
573
+ });
574
+
537
575
  // src/dispatcher.ts
538
576
  var dispatcher_exports = {};
539
577
  __export(dispatcher_exports, {
@@ -2997,7 +3035,85 @@ var epicIssueWorker = (opts = {}) => createIssuePollingWorker({
2997
3035
  })();
2998
3036
 
2999
3037
  // src/commands/init.ts
3000
- import { mkdir, writeFile, access } from "node:fs/promises";
3038
+ import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promises";
3039
+
3040
+ // src/commands/codegraph.ts
3041
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3042
+ import { homedir as homedir4 } from "node:os";
3043
+ import { dirname as dirname2, join as join5 } from "node:path";
3044
+ async function loadRunCommand() {
3045
+ return await Promise.resolve().then(() => (init_run_command(), run_command_exports));
3046
+ }
3047
+ var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
3048
+ var CODEGRAPH_IGNORE_ENTRY = ".codegraph/";
3049
+ function globalGitIgnorePath(env = process.env, home = homedir4()) {
3050
+ const xdg = env.XDG_CONFIG_HOME?.trim();
3051
+ const base = xdg ? xdg : join5(home, ".config");
3052
+ return join5(base, "git", "ignore");
3053
+ }
3054
+ function appendIgnoreEntry(current, entry) {
3055
+ const bare = entry.replace(/\/$/, "");
3056
+ const alreadyListed = current.split("\n").map((line) => line.trim()).some((line) => line === entry || line === bare);
3057
+ if (alreadyListed) return null;
3058
+ if (current === "") return `${entry}
3059
+ `;
3060
+ return current.endsWith("\n") ? `${current}${entry}
3061
+ ` : `${current}
3062
+ ${entry}
3063
+ `;
3064
+ }
3065
+ async function installCodegraphCli(logPrefix, mode) {
3066
+ const progressive = mode === "install" ? "Installing" : "Updating";
3067
+ const past = mode === "install" ? "installed" : "updated";
3068
+ console.log(`[${logPrefix}] ${progressive} CodeGraph CLI (npm install -g ${CODEGRAPH_PACKAGE}@latest)...`);
3069
+ try {
3070
+ const { runCommand: runCommand2 } = await loadRunCommand();
3071
+ await runCommand2("npm", ["install", "-g", `${CODEGRAPH_PACKAGE}@latest`]);
3072
+ console.log(`[${logPrefix}] CodeGraph CLI ${past}.`);
3073
+ return true;
3074
+ } catch (err) {
3075
+ console.error(`[${logPrefix}] Failed to ${mode} CodeGraph CLI: ${err.message}`);
3076
+ return false;
3077
+ }
3078
+ }
3079
+ async function runCodegraphInit(logPrefix) {
3080
+ console.log(`[${logPrefix}] Initializing CodeGraph index (codegraph init)...`);
3081
+ try {
3082
+ const { runCommand: runCommand2 } = await loadRunCommand();
3083
+ await runCommand2("codegraph", ["init"]);
3084
+ console.log(`[${logPrefix}] CodeGraph index initialized.`);
3085
+ return true;
3086
+ } catch (err) {
3087
+ console.error(
3088
+ `[${logPrefix}] Failed to run codegraph init (install it with \`claude-task-worker install\`): ${err.message}`
3089
+ );
3090
+ return false;
3091
+ }
3092
+ }
3093
+ async function ensureCodegraphGitIgnore(logPrefix) {
3094
+ const path = globalGitIgnorePath();
3095
+ try {
3096
+ let current = "";
3097
+ try {
3098
+ current = await readFile(path, "utf-8");
3099
+ } catch {
3100
+ }
3101
+ const next = appendIgnoreEntry(current, CODEGRAPH_IGNORE_ENTRY);
3102
+ if (next === null) {
3103
+ console.log(`[${logPrefix}] Already ignored: ${CODEGRAPH_IGNORE_ENTRY} (${path})`);
3104
+ return true;
3105
+ }
3106
+ await mkdir(dirname2(path), { recursive: true });
3107
+ await writeFile(path, next, "utf-8");
3108
+ console.log(`[${logPrefix}] Added ${CODEGRAPH_IGNORE_ENTRY} to ${path}`);
3109
+ return true;
3110
+ } catch (err) {
3111
+ console.error(`[${logPrefix}] Failed to update ${path}: ${err.message}`);
3112
+ return false;
3113
+ }
3114
+ }
3115
+
3116
+ // src/commands/init.ts
3001
3117
  var LABELS = [
3002
3118
  { name: "cc-update-issue", color: "e4e669" },
3003
3119
  { name: "cc-answer-issue-questions", color: "5319e7" },
@@ -3053,10 +3169,10 @@ async function writeFileWithMode(path, content, force) {
3053
3169
  try {
3054
3170
  await access(path);
3055
3171
  if (!force) return "skipped";
3056
- await writeFile(path, content, "utf-8");
3172
+ await writeFile2(path, content, "utf-8");
3057
3173
  return "overwritten";
3058
3174
  } catch {
3059
- await writeFile(path, content, "utf-8");
3175
+ await writeFile2(path, content, "utf-8");
3060
3176
  return "created";
3061
3177
  }
3062
3178
  }
@@ -3082,53 +3198,23 @@ async function init(options = {}) {
3082
3198
  }
3083
3199
  }
3084
3200
  console.log("[init] Creating issue template...");
3085
- await mkdir(".github/ISSUE_TEMPLATE", { recursive: true });
3201
+ await mkdir2(".github/ISSUE_TEMPLATE", { recursive: true });
3086
3202
  const templatePath = ".github/ISSUE_TEMPLATE/cc-triage-scope.yml";
3087
3203
  logWriteResult(await writeFileWithMode(templatePath, ISSUE_TEMPLATE, force), templatePath);
3088
3204
  console.log("[init] Creating GitHub Actions workflow...");
3089
- await mkdir(".github/workflows", { recursive: true });
3205
+ await mkdir2(".github/workflows", { recursive: true });
3090
3206
  const workflowPath = ".github/workflows/assign-creator-on-cc-triage-scope.yml";
3091
3207
  logWriteResult(await writeFileWithMode(workflowPath, ASSIGN_CREATOR_WORKFLOW, force), workflowPath);
3092
3208
  console.log("[init] Creating config file...");
3093
3209
  await createConfig(force);
3210
+ console.log("[init] Setting up CodeGraph...");
3211
+ await ensureCodegraphGitIgnore("init");
3212
+ await runCodegraphInit("init");
3094
3213
  console.log("[init] Done.");
3095
3214
  }
3096
3215
 
3097
- // src/commands/run-command.ts
3098
- import { spawn as spawn2 } from "node:child_process";
3099
- function runCommand(command, args) {
3100
- return new Promise((resolve3, reject) => {
3101
- const child = spawn2(command, args, {
3102
- stdio: "inherit",
3103
- shell: process.platform === "win32"
3104
- });
3105
- const forwardSignal = (signal) => {
3106
- child.kill(signal);
3107
- };
3108
- const onSigint = () => forwardSignal("SIGINT");
3109
- const onSigterm = () => forwardSignal("SIGTERM");
3110
- const cleanup = () => {
3111
- process.removeListener("SIGINT", onSigint);
3112
- process.removeListener("SIGTERM", onSigterm);
3113
- };
3114
- process.once("SIGINT", onSigint);
3115
- process.once("SIGTERM", onSigterm);
3116
- child.on("error", (err) => {
3117
- cleanup();
3118
- reject(err);
3119
- });
3120
- child.on("close", (code) => {
3121
- cleanup();
3122
- if (code === 0) {
3123
- resolve3();
3124
- } else {
3125
- reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
3126
- }
3127
- });
3128
- });
3129
- }
3130
-
3131
3216
  // src/commands/install.ts
3217
+ init_run_command();
3132
3218
  var PLUGIN_NAME = "claude-task-worker";
3133
3219
  var MARKETPLACE_NAME = "claude-task-worker";
3134
3220
  var MARKETPLACE_SOURCE = "getty104/claude-task-worker";
@@ -3170,13 +3256,15 @@ async function install() {
3170
3256
  await addMarketplace();
3171
3257
  const pluginOk = await installPlugin();
3172
3258
  const cliOk = await installCli();
3173
- if (!pluginOk || !cliOk) {
3259
+ const codegraphOk = await installCodegraphCli("install", "install");
3260
+ if (!pluginOk || !cliOk || !codegraphOk) {
3174
3261
  process.exitCode = 1;
3175
3262
  }
3176
3263
  console.log("[install] Done.");
3177
3264
  }
3178
3265
 
3179
3266
  // src/commands/update.ts
3267
+ init_run_command();
3180
3268
  var PLUGIN_NAME2 = "claude-task-worker";
3181
3269
  var MARKETPLACE_NAME2 = "claude-task-worker";
3182
3270
  async function updateMarketplace() {
@@ -3217,7 +3305,8 @@ async function update() {
3217
3305
  const marketplaceOk = await updateMarketplace();
3218
3306
  const pluginOk = await updatePlugin();
3219
3307
  const cliOk = await updateCli();
3220
- if (!marketplaceOk || !pluginOk || !cliOk) {
3308
+ const codegraphOk = await installCodegraphCli("update", "update");
3309
+ if (!marketplaceOk || !pluginOk || !cliOk || !codegraphOk) {
3221
3310
  process.exitCode = 1;
3222
3311
  }
3223
3312
  console.log("[update] Done.");
@@ -3225,11 +3314,11 @@ async function update() {
3225
3314
 
3226
3315
  // src/commands/version.ts
3227
3316
  import { readFileSync as readFileSync4 } from "node:fs";
3228
- import { dirname as dirname2, join as join5 } from "node:path";
3317
+ import { dirname as dirname3, join as join6 } from "node:path";
3229
3318
  import { fileURLToPath } from "node:url";
3230
3319
  function version() {
3231
- const here = dirname2(fileURLToPath(import.meta.url));
3232
- const pkgPath = join5(here, "..", "package.json");
3320
+ const here = dirname3(fileURLToPath(import.meta.url));
3321
+ const pkgPath = join6(here, "..", "package.json");
3233
3322
  try {
3234
3323
  const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
3235
3324
  console.log(pkg.version ?? "unknown");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.27.0",
3
+ "version": "0.28.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",