claude-task-worker 0.68.0 → 0.70.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.
- package/README.md +17 -0
- package/dist/index.js +342 -252
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,6 +185,7 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
185
185
|
{
|
|
186
186
|
"mode": "default",
|
|
187
187
|
"advisor": false,
|
|
188
|
+
"permission": "bypassPermissions",
|
|
188
189
|
"projects": {
|
|
189
190
|
"app-a": "/Users/me/repos/app-a",
|
|
190
191
|
"app-b": "/Users/me/repos/app-b"
|
|
@@ -215,6 +216,7 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
215
216
|
| `projectGroups` | `{}` | グループ名 → プロジェクト名配列 |
|
|
216
217
|
| `mode` | `"default"` | タスクの実行形態(下記) |
|
|
217
218
|
| `advisor` | `false` | `--advisor` を渡すか(下記) |
|
|
219
|
+
| `permission` | `"bypassPermissions"` | Claude CLI の権限モード(下記) |
|
|
218
220
|
|
|
219
221
|
#### `mode`(タスクの実行形態)
|
|
220
222
|
|
|
@@ -235,6 +237,21 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
235
237
|
|
|
236
238
|
advisor は main モデル以上の能力が必要(Claude CLI の制約)。全ワーカーの既定 `model` が `opus` なので、`advisorModel` の既定値はすべて空文字(advisor なし)。`model` を `sonnet` 等へ下げたワーカーには `advisorModel: "opus"` を指定できる。
|
|
237
239
|
|
|
240
|
+
#### `permission`(権限モード)
|
|
241
|
+
|
|
242
|
+
タスク起動時に Claude CLI へ渡す[権限モード](https://code.claude.com/docs/ja/permission-modes)。`mode` / `advisor` と同じくトップレベル一括で、プロジェクト単位・ワーカー単位の指定はできない。
|
|
243
|
+
|
|
244
|
+
| `permission` | 挙動 |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `"bypassPermissions"`(既定) | 全許可。承認するユーザーが常駐しない自律実行のため既定 |
|
|
247
|
+
| `"dontAsk"` | 許可されていない操作は確認せずスキップする |
|
|
248
|
+
| `"auto"` | 安全な操作は自動承認、危険な操作のみ確認 |
|
|
249
|
+
| `"acceptEdits"` | ファイル編集は自動承認、それ以外は都度確認 |
|
|
250
|
+
| `"manual"` | 標準の権限確認 |
|
|
251
|
+
| `"plan"` | 読み取りのみ。変更は行わない |
|
|
252
|
+
|
|
253
|
+
値は Claude CLI の `--permission-mode` にそのまま渡される(choices と同じ綴り)。ワーカーには承認するユーザーがいないため、`bypassPermissions` / `dontAsk` 以外ではタスクが承認待ちで止まりうる(`mode: "herdr"` なら herdr のタブを開いて手動で承認できる)。
|
|
254
|
+
|
|
238
255
|
### `claude-task-worker.json`(リポジトリ)
|
|
239
256
|
|
|
240
257
|
| キー | 型 | 既定 | 説明 |
|
package/dist/index.js
CHANGED
|
@@ -16,11 +16,16 @@ __export(table_exports, {
|
|
|
16
16
|
TASK_DISPLAY_LIMIT: () => TASK_DISPLAY_LIMIT,
|
|
17
17
|
buildLogTableLines: () => buildLogTableLines,
|
|
18
18
|
buildTaskTableLines: () => buildTaskTableLines,
|
|
19
|
+
captureConsole: () => captureConsole,
|
|
19
20
|
getDisplayWidth: () => getDisplayWidth,
|
|
21
|
+
logLines: () => logLines,
|
|
20
22
|
padToWidth: () => padToWidth,
|
|
23
|
+
pushLogLine: () => pushLogLine,
|
|
21
24
|
selectRecentTasks: () => selectRecentTasks,
|
|
22
|
-
truncateToWidth: () => truncateToWidth
|
|
25
|
+
truncateToWidth: () => truncateToWidth,
|
|
26
|
+
writeScreen: () => writeScreen
|
|
23
27
|
});
|
|
28
|
+
import { format } from "node:util";
|
|
24
29
|
function getDisplayWidth(str) {
|
|
25
30
|
let width = 0;
|
|
26
31
|
for (const char of str) {
|
|
@@ -132,6 +137,32 @@ function buildTaskTableLines(entries, now = /* @__PURE__ */ new Date()) {
|
|
|
132
137
|
function taskRow(t, title, path2, hasPath, status, time, duration) {
|
|
133
138
|
return hasPath ? [`#${t.id}`, title, t.workerName, path2, status, time, duration] : [`#${t.id}`, title, t.workerName, status, time, duration];
|
|
134
139
|
}
|
|
140
|
+
function pushLogLine(entry) {
|
|
141
|
+
if (entry.text.trim().length === 0) return;
|
|
142
|
+
logLines.push(entry);
|
|
143
|
+
if (logLines.length > LOG_DISPLAY_LIMIT) {
|
|
144
|
+
logLines.splice(0, logLines.length - LOG_DISPLAY_LIMIT);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function writeScreen(lines) {
|
|
148
|
+
rawClear();
|
|
149
|
+
rawLog(lines.join("\n"));
|
|
150
|
+
}
|
|
151
|
+
function captureConsole() {
|
|
152
|
+
if (consoleCaptured) return;
|
|
153
|
+
consoleCaptured = true;
|
|
154
|
+
process.on("exit", () => {
|
|
155
|
+
if (logLines.length > 0) rawLog(buildLogTableLines(logLines).join("\n"));
|
|
156
|
+
});
|
|
157
|
+
const streams = { log: "stdout", info: "stdout", warn: "stderr", error: "stderr" };
|
|
158
|
+
for (const [method, stream] of Object.entries(streams)) {
|
|
159
|
+
console[method] = (...args) => {
|
|
160
|
+
for (const line of format(...args).split("\n")) {
|
|
161
|
+
pushLogLine({ stream, text: line, time: /* @__PURE__ */ new Date() });
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
135
166
|
function sanitizeLogText(text) {
|
|
136
167
|
return text.replace(CONTROL_CHARS, " ").replace(/\t/g, " ");
|
|
137
168
|
}
|
|
@@ -142,19 +173,23 @@ function buildLogTableLines(entries) {
|
|
|
142
173
|
const text = sanitizeLogText(e.text);
|
|
143
174
|
return [
|
|
144
175
|
formatTime(e.time),
|
|
145
|
-
`#${e.id}`,
|
|
176
|
+
e.id === void 0 ? "-" : `#${e.id}`,
|
|
146
177
|
e.stream,
|
|
147
178
|
getDisplayWidth(text) > maxTextWidth ? truncateToWidth(text, maxTextWidth) : text
|
|
148
179
|
];
|
|
149
180
|
});
|
|
150
181
|
return renderBoxTable(["Time", "#", "Stream", "Log"], [rows]);
|
|
151
182
|
}
|
|
152
|
-
var TASK_DISPLAY_LIMIT, LOG_DISPLAY_LIMIT, CONTROL_CHARS;
|
|
183
|
+
var TASK_DISPLAY_LIMIT, LOG_DISPLAY_LIMIT, logLines, rawLog, rawClear, consoleCaptured, CONTROL_CHARS;
|
|
153
184
|
var init_table = __esm({
|
|
154
185
|
"src/table.ts"() {
|
|
155
186
|
"use strict";
|
|
156
187
|
TASK_DISPLAY_LIMIT = 20;
|
|
157
188
|
LOG_DISPLAY_LIMIT = 20;
|
|
189
|
+
logLines = [];
|
|
190
|
+
rawLog = console.log.bind(console);
|
|
191
|
+
rawClear = console.clear.bind(console);
|
|
192
|
+
consoleCaptured = false;
|
|
158
193
|
CONTROL_CHARS = /\x1b\[[0-9;?]*[ -/]*[@-~]|[\x00-\x08\x0b-\x1f\x7f]/g;
|
|
159
194
|
}
|
|
160
195
|
});
|
|
@@ -1001,7 +1036,11 @@ function formatUptime(start, now) {
|
|
|
1001
1036
|
}
|
|
1002
1037
|
function renderSessionTable(sessions) {
|
|
1003
1038
|
const entries = [...sessions.values()];
|
|
1004
|
-
|
|
1039
|
+
const logTableLines = buildLogTableLines2(logLines2);
|
|
1040
|
+
if (entries.length === 0) {
|
|
1041
|
+
if (logTableLines.length > 0) writeScreen2(["Logs", ...logTableLines]);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1005
1044
|
const maxProjectWidth = 20;
|
|
1006
1045
|
const rows = entries.map((session) => ({
|
|
1007
1046
|
project: getDisplayWidth2(session.name) > maxProjectWidth ? truncateToWidth2(session.name, maxProjectWidth) : session.name,
|
|
@@ -1028,8 +1067,8 @@ function renderSessionTable(sessions) {
|
|
|
1028
1067
|
lines.push(row(r.project, r.workspace, r.pane, r.status, r.uptime));
|
|
1029
1068
|
}
|
|
1030
1069
|
lines.push(line("\u2514", "\u2534", "\u2518", "\u2500"));
|
|
1031
|
-
|
|
1032
|
-
|
|
1070
|
+
if (logTableLines.length > 0) lines.push("", "Logs", ...logTableLines);
|
|
1071
|
+
writeScreen2(lines);
|
|
1033
1072
|
}
|
|
1034
1073
|
function monitorSessions(sessions, herdr, options) {
|
|
1035
1074
|
const pollIntervalMs = options?.pollIntervalMs ?? POLL_INTERVAL_MS;
|
|
@@ -1179,11 +1218,11 @@ function createDispatcherShutdownHandler(shutdown2) {
|
|
|
1179
1218
|
};
|
|
1180
1219
|
return { handle, isShuttingDown: () => shuttingDown2 };
|
|
1181
1220
|
}
|
|
1182
|
-
var getDisplayWidth2, truncateToWidth2, padToWidth2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS, PANE_READY_TIMEOUT_MS2, PANE_READY_POLL_INTERVAL_MS2, WORKER_STARTUP_TIMEOUT_MS, WORKER_STARTUP_POLL_INTERVAL_MS, SEND_MAX_ATTEMPTS, LABEL_PREFIX, SHELL_NAME_PATTERN, SHUTDOWN_RETRY_TIMEOUT_MS, CTRL_C_KEY, shutdownPromise;
|
|
1221
|
+
var getDisplayWidth2, truncateToWidth2, padToWidth2, buildLogTableLines2, logLines2, writeScreen2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS, PANE_READY_TIMEOUT_MS2, PANE_READY_POLL_INTERVAL_MS2, WORKER_STARTUP_TIMEOUT_MS, WORKER_STARTUP_POLL_INTERVAL_MS, SEND_MAX_ATTEMPTS, LABEL_PREFIX, SHELL_NAME_PATTERN, SHUTDOWN_RETRY_TIMEOUT_MS, CTRL_C_KEY, shutdownPromise;
|
|
1183
1222
|
var init_dispatcher = __esm({
|
|
1184
1223
|
async "src/dispatcher.ts"() {
|
|
1185
1224
|
"use strict";
|
|
1186
|
-
({ getDisplayWidth: getDisplayWidth2, truncateToWidth: truncateToWidth2, padToWidth: padToWidth2 } = await loadTable());
|
|
1225
|
+
({ getDisplayWidth: getDisplayWidth2, truncateToWidth: truncateToWidth2, padToWidth: padToWidth2, buildLogTableLines: buildLogTableLines2, logLines: logLines2, writeScreen: writeScreen2 } = await loadTable());
|
|
1187
1226
|
POLL_INTERVAL_MS = 7 * 1e3;
|
|
1188
1227
|
SHUTDOWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1189
1228
|
PANE_READY_TIMEOUT_MS2 = 30 * 1e3;
|
|
@@ -1325,6 +1364,11 @@ async function findPrStateByHeadRef(headRefName) {
|
|
|
1325
1364
|
if (prs.length === 0) return null;
|
|
1326
1365
|
return { number: prs[0].number, state: prs[0].state, mergedAt: prs[0].mergedAt ?? null };
|
|
1327
1366
|
}
|
|
1367
|
+
async function getPrMergeable(prNumber) {
|
|
1368
|
+
const output = await execGh(["pr", "view", String(prNumber), "--json", "mergeable"]);
|
|
1369
|
+
const parsed = JSON.parse(output);
|
|
1370
|
+
return typeof parsed?.mergeable === "string" ? parsed.mergeable : "UNKNOWN";
|
|
1371
|
+
}
|
|
1328
1372
|
async function getIssueBody(issueNumber) {
|
|
1329
1373
|
const output = await execGh(["issue", "view", String(issueNumber), "--json", "body"]);
|
|
1330
1374
|
const parsed = JSON.parse(output);
|
|
@@ -1489,6 +1533,244 @@ async function createLabel(name, color, force) {
|
|
|
1489
1533
|
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
1490
1534
|
import os from "node:os";
|
|
1491
1535
|
import path from "node:path";
|
|
1536
|
+
|
|
1537
|
+
// src/user-config.ts
|
|
1538
|
+
import { readFileSync, statSync } from "node:fs";
|
|
1539
|
+
import { homedir } from "node:os";
|
|
1540
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
1541
|
+
var RESERVED_ALL = "all";
|
|
1542
|
+
var DEFAULT_RUN_MODE = "default";
|
|
1543
|
+
var DEFAULT_ADVISOR_ENABLED = false;
|
|
1544
|
+
var PERMISSION_MODES = [
|
|
1545
|
+
"manual",
|
|
1546
|
+
"auto",
|
|
1547
|
+
"acceptEdits",
|
|
1548
|
+
"dontAsk",
|
|
1549
|
+
"plan",
|
|
1550
|
+
"bypassPermissions"
|
|
1551
|
+
];
|
|
1552
|
+
var DEFAULT_PERMISSION_MODE = "bypassPermissions";
|
|
1553
|
+
var UserConfigError = class extends Error {
|
|
1554
|
+
constructor(message) {
|
|
1555
|
+
super(message);
|
|
1556
|
+
this.name = "UserConfigError";
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
function getConfigDir() {
|
|
1560
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
1561
|
+
const configHome = xdg && xdg.length > 0 ? xdg : join(homedir(), ".config");
|
|
1562
|
+
return join(configHome, "claude-task-worker");
|
|
1563
|
+
}
|
|
1564
|
+
function getUserConfigPath() {
|
|
1565
|
+
return join(getConfigDir(), "config.json");
|
|
1566
|
+
}
|
|
1567
|
+
function isDirectory(path2) {
|
|
1568
|
+
try {
|
|
1569
|
+
return statSync(path2).isDirectory();
|
|
1570
|
+
} catch {
|
|
1571
|
+
return false;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function parseConfigFile(path2) {
|
|
1575
|
+
let content;
|
|
1576
|
+
try {
|
|
1577
|
+
content = readFileSync(path2, "utf-8");
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
if (err.code === "ENOENT") return void 0;
|
|
1580
|
+
throw err;
|
|
1581
|
+
}
|
|
1582
|
+
try {
|
|
1583
|
+
return JSON.parse(content);
|
|
1584
|
+
} catch (err) {
|
|
1585
|
+
if (err instanceof SyntaxError) {
|
|
1586
|
+
throw new UserConfigError(`config file contains invalid JSON: ${path2}: ${err.message}`);
|
|
1587
|
+
}
|
|
1588
|
+
throw err;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
function readRawConfig() {
|
|
1592
|
+
return parseConfigFile(getUserConfigPath());
|
|
1593
|
+
}
|
|
1594
|
+
function parseMode(raw, path2) {
|
|
1595
|
+
if (!("mode" in raw)) return DEFAULT_RUN_MODE;
|
|
1596
|
+
const value = raw["mode"];
|
|
1597
|
+
if (value === "default" || value === "herdr") return value;
|
|
1598
|
+
console.warn(`[config] invalid mode: ${JSON.stringify(value)} in ${path2}, using "${DEFAULT_RUN_MODE}"`);
|
|
1599
|
+
return DEFAULT_RUN_MODE;
|
|
1600
|
+
}
|
|
1601
|
+
function parseAdvisor(raw, path2) {
|
|
1602
|
+
if (!("advisor" in raw)) return DEFAULT_ADVISOR_ENABLED;
|
|
1603
|
+
const value = raw["advisor"];
|
|
1604
|
+
if (typeof value === "boolean") return value;
|
|
1605
|
+
console.warn(`[config] invalid advisor: ${JSON.stringify(value)} in ${path2}, using ${DEFAULT_ADVISOR_ENABLED}`);
|
|
1606
|
+
return DEFAULT_ADVISOR_ENABLED;
|
|
1607
|
+
}
|
|
1608
|
+
function parsePermission(raw, path2) {
|
|
1609
|
+
if (!("permission" in raw)) return DEFAULT_PERMISSION_MODE;
|
|
1610
|
+
const value = raw["permission"];
|
|
1611
|
+
if (typeof value === "string" && PERMISSION_MODES.includes(value)) return value;
|
|
1612
|
+
console.warn(`[config] invalid permission: ${JSON.stringify(value)} in ${path2}, using "${DEFAULT_PERMISSION_MODE}"`);
|
|
1613
|
+
return DEFAULT_PERMISSION_MODE;
|
|
1614
|
+
}
|
|
1615
|
+
function loadUserConfig() {
|
|
1616
|
+
const path2 = getUserConfigPath();
|
|
1617
|
+
const raw = readRawConfig();
|
|
1618
|
+
if (raw === void 0) {
|
|
1619
|
+
throw new UserConfigError(`config.json not found: ${path2}`);
|
|
1620
|
+
}
|
|
1621
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1622
|
+
throw new UserConfigError(`config.json must contain a JSON object: ${path2}`);
|
|
1623
|
+
}
|
|
1624
|
+
if (!("projects" in raw) || typeof raw["projects"] !== "object" || raw["projects"] === null || Array.isArray(raw["projects"])) {
|
|
1625
|
+
throw new UserConfigError(`config.json must contain a "projects" section as an object: ${path2}`);
|
|
1626
|
+
}
|
|
1627
|
+
if ("projectGroups" in raw && (typeof raw["projectGroups"] !== "object" || raw["projectGroups"] === null || Array.isArray(raw["projectGroups"]))) {
|
|
1628
|
+
throw new UserConfigError(`config.json "projectGroups" must be an object: ${path2}`);
|
|
1629
|
+
}
|
|
1630
|
+
const mode = parseMode(raw, path2);
|
|
1631
|
+
const advisor = parseAdvisor(raw, path2);
|
|
1632
|
+
const permission = parsePermission(raw, path2);
|
|
1633
|
+
const rawProjects = raw["projects"];
|
|
1634
|
+
const rawProjectGroups = "projectGroups" in raw ? raw["projectGroups"] : {};
|
|
1635
|
+
const projectKeys = Object.keys(rawProjects);
|
|
1636
|
+
const groupKeys = Object.keys(rawProjectGroups);
|
|
1637
|
+
if (projectKeys.includes(RESERVED_ALL) || groupKeys.includes(RESERVED_ALL)) {
|
|
1638
|
+
throw new UserConfigError(
|
|
1639
|
+
`"${RESERVED_ALL}" is a reserved word and cannot be used as a key in "projects" or "projectGroups"`
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
const groupKeySet = new Set(groupKeys);
|
|
1643
|
+
const duplicateKeys = projectKeys.filter((key) => groupKeySet.has(key));
|
|
1644
|
+
if (duplicateKeys.length > 0) {
|
|
1645
|
+
throw new UserConfigError(
|
|
1646
|
+
`"projects" and "projectGroups" share the same key namespace; duplicate keys are not allowed: ${duplicateKeys.join(", ")}`
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
const projects = {};
|
|
1650
|
+
for (const [name, value] of Object.entries(rawProjects)) {
|
|
1651
|
+
if (name === "__proto__") {
|
|
1652
|
+
throw new UserConfigError(`"__proto__" cannot be used as a key in "projects": ${path2}`);
|
|
1653
|
+
}
|
|
1654
|
+
if (typeof value !== "string" || !isAbsolute(value)) {
|
|
1655
|
+
console.warn(`[config] invalid projects.${name}: expected an absolute path, skipping`);
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
if (!isDirectory(value)) {
|
|
1659
|
+
console.warn(`[config] projects.${name} does not exist as a directory: ${value}, skipping`);
|
|
1660
|
+
continue;
|
|
1661
|
+
}
|
|
1662
|
+
projects[name] = value;
|
|
1663
|
+
}
|
|
1664
|
+
const projectGroups = {};
|
|
1665
|
+
for (const [groupName, value] of Object.entries(rawProjectGroups)) {
|
|
1666
|
+
if (groupName === "__proto__") {
|
|
1667
|
+
throw new UserConfigError(`"__proto__" cannot be used as a key in "projectGroups": ${path2}`);
|
|
1668
|
+
}
|
|
1669
|
+
if (!Array.isArray(value)) {
|
|
1670
|
+
console.warn(`[config] invalid projectGroups.${groupName}: expected an array, skipping`);
|
|
1671
|
+
continue;
|
|
1672
|
+
}
|
|
1673
|
+
const members = [];
|
|
1674
|
+
for (const member of value) {
|
|
1675
|
+
if (typeof member !== "string" || !Object.prototype.hasOwnProperty.call(projects, member)) {
|
|
1676
|
+
console.warn(`[config] projectGroups.${groupName} references unknown project "${String(member)}", skipping`);
|
|
1677
|
+
continue;
|
|
1678
|
+
}
|
|
1679
|
+
members.push(member);
|
|
1680
|
+
}
|
|
1681
|
+
projectGroups[groupName] = members;
|
|
1682
|
+
}
|
|
1683
|
+
return { mode, advisor, permission, projects, projectGroups };
|
|
1684
|
+
}
|
|
1685
|
+
var cachedRunMode;
|
|
1686
|
+
function getRunMode() {
|
|
1687
|
+
if (cachedRunMode === void 0) {
|
|
1688
|
+
cachedRunMode = readRunMode();
|
|
1689
|
+
}
|
|
1690
|
+
return cachedRunMode;
|
|
1691
|
+
}
|
|
1692
|
+
var cachedAdvisorEnabled;
|
|
1693
|
+
function isAdvisorEnabled() {
|
|
1694
|
+
if (cachedAdvisorEnabled === void 0) {
|
|
1695
|
+
cachedAdvisorEnabled = readAdvisorEnabled();
|
|
1696
|
+
}
|
|
1697
|
+
return cachedAdvisorEnabled;
|
|
1698
|
+
}
|
|
1699
|
+
var cachedPermissionMode;
|
|
1700
|
+
function getPermissionMode() {
|
|
1701
|
+
if (cachedPermissionMode === void 0) {
|
|
1702
|
+
cachedPermissionMode = readTopLevel(parsePermission, DEFAULT_PERMISSION_MODE, "permission");
|
|
1703
|
+
}
|
|
1704
|
+
return cachedPermissionMode;
|
|
1705
|
+
}
|
|
1706
|
+
function readTopLevel(parse, fallback, label) {
|
|
1707
|
+
let raw;
|
|
1708
|
+
try {
|
|
1709
|
+
raw = readRawConfig();
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
console.warn(`[config] failed to read config file, using default ${label}: ${err}`);
|
|
1712
|
+
return fallback;
|
|
1713
|
+
}
|
|
1714
|
+
if (raw === void 0) return fallback;
|
|
1715
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1716
|
+
return fallback;
|
|
1717
|
+
}
|
|
1718
|
+
return parse(raw, getUserConfigPath());
|
|
1719
|
+
}
|
|
1720
|
+
function readAdvisorEnabled() {
|
|
1721
|
+
return readTopLevel(parseAdvisor, DEFAULT_ADVISOR_ENABLED, "advisor");
|
|
1722
|
+
}
|
|
1723
|
+
function readRunMode() {
|
|
1724
|
+
return readTopLevel(parseMode, DEFAULT_RUN_MODE, "mode");
|
|
1725
|
+
}
|
|
1726
|
+
function findProjectNameByPath(path2) {
|
|
1727
|
+
let config;
|
|
1728
|
+
try {
|
|
1729
|
+
config = loadUserConfig();
|
|
1730
|
+
} catch {
|
|
1731
|
+
return void 0;
|
|
1732
|
+
}
|
|
1733
|
+
const target = resolve(path2);
|
|
1734
|
+
for (const [name, projectPath] of Object.entries(config.projects)) {
|
|
1735
|
+
if (resolve(projectPath) === target) return name;
|
|
1736
|
+
}
|
|
1737
|
+
return void 0;
|
|
1738
|
+
}
|
|
1739
|
+
function resolveTargetProjects(requested, config) {
|
|
1740
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1741
|
+
for (const name of requested) {
|
|
1742
|
+
if (name === RESERVED_ALL) {
|
|
1743
|
+
for (const [projectName, projectPath] of Object.entries(config.projects)) {
|
|
1744
|
+
resolved.set(projectName, { name: projectName, path: projectPath });
|
|
1745
|
+
}
|
|
1746
|
+
continue;
|
|
1747
|
+
}
|
|
1748
|
+
if (Object.prototype.hasOwnProperty.call(config.projects, name)) {
|
|
1749
|
+
resolved.set(name, { name, path: config.projects[name] });
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
if (Object.prototype.hasOwnProperty.call(config.projectGroups, name)) {
|
|
1753
|
+
for (const projectName of config.projectGroups[name]) {
|
|
1754
|
+
const projectPath = config.projects[projectName];
|
|
1755
|
+
if (projectPath === void 0) continue;
|
|
1756
|
+
resolved.set(projectName, { name: projectName, path: projectPath });
|
|
1757
|
+
}
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1760
|
+
const availableProjects = Object.keys(config.projects).join(", ") || "(none)";
|
|
1761
|
+
const availableGroups = Object.keys(config.projectGroups).join(", ") || "(none)";
|
|
1762
|
+
throw new UserConfigError(
|
|
1763
|
+
`Unknown project or group: "${name}". Available projects: ${availableProjects}. Available groups: ${availableGroups}.`
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
const resolvedProjects = Array.from(resolved.values());
|
|
1767
|
+
if (resolvedProjects.length === 0) {
|
|
1768
|
+
throw new UserConfigError(`No projects resolved from requested targets: ${requested.join(", ")}`);
|
|
1769
|
+
}
|
|
1770
|
+
return resolvedProjects;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// src/claude-args.ts
|
|
1492
1774
|
var DISALLOWED_TOOLS = [
|
|
1493
1775
|
// 遅延 / yield: 後続ウェイクアップ前提。print モードではウェイクアップが発火せず、
|
|
1494
1776
|
// 呼ぶと処理未完のままプロセスが終了する。
|
|
@@ -1565,12 +1847,21 @@ function systemPromptFilePath(model) {
|
|
|
1565
1847
|
cachedSystemPromptFilePaths.set(variant, target);
|
|
1566
1848
|
return target;
|
|
1567
1849
|
}
|
|
1568
|
-
function buildClaudeArgs({
|
|
1850
|
+
function buildClaudeArgs({
|
|
1851
|
+
mode,
|
|
1852
|
+
prompt,
|
|
1853
|
+
model,
|
|
1854
|
+
effort,
|
|
1855
|
+
advisorModel,
|
|
1856
|
+
permissionMode
|
|
1857
|
+
}) {
|
|
1569
1858
|
const advisor = advisorModel?.trim() ?? "";
|
|
1859
|
+
const permission = permissionMode ?? DEFAULT_PERMISSION_MODE;
|
|
1570
1860
|
return [
|
|
1571
1861
|
...mode === "herdr" ? [] : ["-p"],
|
|
1572
1862
|
prompt,
|
|
1573
|
-
"--
|
|
1863
|
+
"--permission-mode",
|
|
1864
|
+
permission,
|
|
1574
1865
|
"--chrome",
|
|
1575
1866
|
"--disallowedTools",
|
|
1576
1867
|
DISALLOWED_TOOLS_ARG,
|
|
@@ -1593,8 +1884,8 @@ function buildClaudeEnv(mode) {
|
|
|
1593
1884
|
}
|
|
1594
1885
|
|
|
1595
1886
|
// src/config.ts
|
|
1596
|
-
import { readFileSync } from "node:fs";
|
|
1597
|
-
import { isAbsolute, join, normalize, sep as SEP } from "node:path";
|
|
1887
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1888
|
+
import { isAbsolute as isAbsolute2, join as join2, normalize, sep as SEP } from "node:path";
|
|
1598
1889
|
var DEFAULT_UI_DESIGN_CONFIG = {
|
|
1599
1890
|
enabled: false,
|
|
1600
1891
|
designDir: "designs",
|
|
@@ -1724,7 +2015,7 @@ var DEFAULT_CONFIG = {
|
|
|
1724
2015
|
uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG },
|
|
1725
2016
|
workers: {}
|
|
1726
2017
|
};
|
|
1727
|
-
var CONFIG_PATH =
|
|
2018
|
+
var CONFIG_PATH = join2(process.cwd(), "claude-task-worker.json");
|
|
1728
2019
|
function defaultsFor(name) {
|
|
1729
2020
|
return WORKER_DEFAULTS[name] ?? DEFAULT_WORKER_CONFIG;
|
|
1730
2021
|
}
|
|
@@ -1825,7 +2116,7 @@ function parseUiDesignEntry(val) {
|
|
|
1825
2116
|
}
|
|
1826
2117
|
if ("designDir" in entry) {
|
|
1827
2118
|
const normalized = typeof entry.designDir === "string" && entry.designDir.length > 0 ? normalize(entry.designDir) : null;
|
|
1828
|
-
const isContained = normalized !== null && !
|
|
2119
|
+
const isContained = normalized !== null && !isAbsolute2(normalized) && normalized !== ".." && !normalized.startsWith(`..${SEP}`);
|
|
1829
2120
|
if (isContained) {
|
|
1830
2121
|
result.designDir = normalized;
|
|
1831
2122
|
} else {
|
|
@@ -1840,7 +2131,7 @@ function loadConfig() {
|
|
|
1840
2131
|
const configPath = CONFIG_PATH;
|
|
1841
2132
|
let raw;
|
|
1842
2133
|
try {
|
|
1843
|
-
raw = JSON.parse(
|
|
2134
|
+
raw = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
1844
2135
|
} catch (err) {
|
|
1845
2136
|
if (err.code === "ENOENT") {
|
|
1846
2137
|
return { ...DEFAULT_CONFIG, uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG }, workers: {} };
|
|
@@ -1951,239 +2242,13 @@ function buildTaskResult(code, stdout, stderrTail) {
|
|
|
1951
2242
|
return { status: completed ? "completed" : "failed", output };
|
|
1952
2243
|
}
|
|
1953
2244
|
|
|
1954
|
-
// src/user-config.ts
|
|
1955
|
-
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1956
|
-
import { homedir } from "node:os";
|
|
1957
|
-
import { isAbsolute as isAbsolute2, join as join2, resolve } from "node:path";
|
|
1958
|
-
var RESERVED_ALL = "all";
|
|
1959
|
-
var DEFAULT_RUN_MODE = "default";
|
|
1960
|
-
var DEFAULT_ADVISOR_ENABLED = false;
|
|
1961
|
-
var UserConfigError = class extends Error {
|
|
1962
|
-
constructor(message) {
|
|
1963
|
-
super(message);
|
|
1964
|
-
this.name = "UserConfigError";
|
|
1965
|
-
}
|
|
1966
|
-
};
|
|
1967
|
-
function getConfigDir() {
|
|
1968
|
-
const xdg = process.env.XDG_CONFIG_HOME;
|
|
1969
|
-
const configHome = xdg && xdg.length > 0 ? xdg : join2(homedir(), ".config");
|
|
1970
|
-
return join2(configHome, "claude-task-worker");
|
|
1971
|
-
}
|
|
1972
|
-
function getUserConfigPath() {
|
|
1973
|
-
return join2(getConfigDir(), "config.json");
|
|
1974
|
-
}
|
|
1975
|
-
function isDirectory(path2) {
|
|
1976
|
-
try {
|
|
1977
|
-
return statSync(path2).isDirectory();
|
|
1978
|
-
} catch {
|
|
1979
|
-
return false;
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
function parseConfigFile(path2) {
|
|
1983
|
-
let content;
|
|
1984
|
-
try {
|
|
1985
|
-
content = readFileSync2(path2, "utf-8");
|
|
1986
|
-
} catch (err) {
|
|
1987
|
-
if (err.code === "ENOENT") return void 0;
|
|
1988
|
-
throw err;
|
|
1989
|
-
}
|
|
1990
|
-
try {
|
|
1991
|
-
return JSON.parse(content);
|
|
1992
|
-
} catch (err) {
|
|
1993
|
-
if (err instanceof SyntaxError) {
|
|
1994
|
-
throw new UserConfigError(`config file contains invalid JSON: ${path2}: ${err.message}`);
|
|
1995
|
-
}
|
|
1996
|
-
throw err;
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
function readRawConfig() {
|
|
2000
|
-
return parseConfigFile(getUserConfigPath());
|
|
2001
|
-
}
|
|
2002
|
-
function parseMode(raw, path2) {
|
|
2003
|
-
if (!("mode" in raw)) return DEFAULT_RUN_MODE;
|
|
2004
|
-
const value = raw["mode"];
|
|
2005
|
-
if (value === "default" || value === "herdr") return value;
|
|
2006
|
-
console.warn(`[config] invalid mode: ${JSON.stringify(value)} in ${path2}, using "${DEFAULT_RUN_MODE}"`);
|
|
2007
|
-
return DEFAULT_RUN_MODE;
|
|
2008
|
-
}
|
|
2009
|
-
function parseAdvisor(raw, path2) {
|
|
2010
|
-
if (!("advisor" in raw)) return DEFAULT_ADVISOR_ENABLED;
|
|
2011
|
-
const value = raw["advisor"];
|
|
2012
|
-
if (typeof value === "boolean") return value;
|
|
2013
|
-
console.warn(`[config] invalid advisor: ${JSON.stringify(value)} in ${path2}, using ${DEFAULT_ADVISOR_ENABLED}`);
|
|
2014
|
-
return DEFAULT_ADVISOR_ENABLED;
|
|
2015
|
-
}
|
|
2016
|
-
function loadUserConfig() {
|
|
2017
|
-
const path2 = getUserConfigPath();
|
|
2018
|
-
const raw = readRawConfig();
|
|
2019
|
-
if (raw === void 0) {
|
|
2020
|
-
throw new UserConfigError(`config.json not found: ${path2}`);
|
|
2021
|
-
}
|
|
2022
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2023
|
-
throw new UserConfigError(`config.json must contain a JSON object: ${path2}`);
|
|
2024
|
-
}
|
|
2025
|
-
if (!("projects" in raw) || typeof raw["projects"] !== "object" || raw["projects"] === null || Array.isArray(raw["projects"])) {
|
|
2026
|
-
throw new UserConfigError(`config.json must contain a "projects" section as an object: ${path2}`);
|
|
2027
|
-
}
|
|
2028
|
-
if ("projectGroups" in raw && (typeof raw["projectGroups"] !== "object" || raw["projectGroups"] === null || Array.isArray(raw["projectGroups"]))) {
|
|
2029
|
-
throw new UserConfigError(`config.json "projectGroups" must be an object: ${path2}`);
|
|
2030
|
-
}
|
|
2031
|
-
const mode = parseMode(raw, path2);
|
|
2032
|
-
const advisor = parseAdvisor(raw, path2);
|
|
2033
|
-
const rawProjects = raw["projects"];
|
|
2034
|
-
const rawProjectGroups = "projectGroups" in raw ? raw["projectGroups"] : {};
|
|
2035
|
-
const projectKeys = Object.keys(rawProjects);
|
|
2036
|
-
const groupKeys = Object.keys(rawProjectGroups);
|
|
2037
|
-
if (projectKeys.includes(RESERVED_ALL) || groupKeys.includes(RESERVED_ALL)) {
|
|
2038
|
-
throw new UserConfigError(
|
|
2039
|
-
`"${RESERVED_ALL}" is a reserved word and cannot be used as a key in "projects" or "projectGroups"`
|
|
2040
|
-
);
|
|
2041
|
-
}
|
|
2042
|
-
const groupKeySet = new Set(groupKeys);
|
|
2043
|
-
const duplicateKeys = projectKeys.filter((key) => groupKeySet.has(key));
|
|
2044
|
-
if (duplicateKeys.length > 0) {
|
|
2045
|
-
throw new UserConfigError(
|
|
2046
|
-
`"projects" and "projectGroups" share the same key namespace; duplicate keys are not allowed: ${duplicateKeys.join(", ")}`
|
|
2047
|
-
);
|
|
2048
|
-
}
|
|
2049
|
-
const projects = {};
|
|
2050
|
-
for (const [name, value] of Object.entries(rawProjects)) {
|
|
2051
|
-
if (name === "__proto__") {
|
|
2052
|
-
throw new UserConfigError(`"__proto__" cannot be used as a key in "projects": ${path2}`);
|
|
2053
|
-
}
|
|
2054
|
-
if (typeof value !== "string" || !isAbsolute2(value)) {
|
|
2055
|
-
console.warn(`[config] invalid projects.${name}: expected an absolute path, skipping`);
|
|
2056
|
-
continue;
|
|
2057
|
-
}
|
|
2058
|
-
if (!isDirectory(value)) {
|
|
2059
|
-
console.warn(`[config] projects.${name} does not exist as a directory: ${value}, skipping`);
|
|
2060
|
-
continue;
|
|
2061
|
-
}
|
|
2062
|
-
projects[name] = value;
|
|
2063
|
-
}
|
|
2064
|
-
const projectGroups = {};
|
|
2065
|
-
for (const [groupName, value] of Object.entries(rawProjectGroups)) {
|
|
2066
|
-
if (groupName === "__proto__") {
|
|
2067
|
-
throw new UserConfigError(`"__proto__" cannot be used as a key in "projectGroups": ${path2}`);
|
|
2068
|
-
}
|
|
2069
|
-
if (!Array.isArray(value)) {
|
|
2070
|
-
console.warn(`[config] invalid projectGroups.${groupName}: expected an array, skipping`);
|
|
2071
|
-
continue;
|
|
2072
|
-
}
|
|
2073
|
-
const members = [];
|
|
2074
|
-
for (const member of value) {
|
|
2075
|
-
if (typeof member !== "string" || !Object.prototype.hasOwnProperty.call(projects, member)) {
|
|
2076
|
-
console.warn(`[config] projectGroups.${groupName} references unknown project "${String(member)}", skipping`);
|
|
2077
|
-
continue;
|
|
2078
|
-
}
|
|
2079
|
-
members.push(member);
|
|
2080
|
-
}
|
|
2081
|
-
projectGroups[groupName] = members;
|
|
2082
|
-
}
|
|
2083
|
-
return { mode, advisor, projects, projectGroups };
|
|
2084
|
-
}
|
|
2085
|
-
var cachedRunMode;
|
|
2086
|
-
function getRunMode() {
|
|
2087
|
-
if (cachedRunMode === void 0) {
|
|
2088
|
-
cachedRunMode = readRunMode();
|
|
2089
|
-
}
|
|
2090
|
-
return cachedRunMode;
|
|
2091
|
-
}
|
|
2092
|
-
var cachedAdvisorEnabled;
|
|
2093
|
-
function isAdvisorEnabled() {
|
|
2094
|
-
if (cachedAdvisorEnabled === void 0) {
|
|
2095
|
-
cachedAdvisorEnabled = readAdvisorEnabled();
|
|
2096
|
-
}
|
|
2097
|
-
return cachedAdvisorEnabled;
|
|
2098
|
-
}
|
|
2099
|
-
function readAdvisorEnabled() {
|
|
2100
|
-
let raw;
|
|
2101
|
-
try {
|
|
2102
|
-
raw = readRawConfig();
|
|
2103
|
-
} catch (err) {
|
|
2104
|
-
console.warn(`[config] failed to read config file, advisor disabled: ${err}`);
|
|
2105
|
-
return DEFAULT_ADVISOR_ENABLED;
|
|
2106
|
-
}
|
|
2107
|
-
if (raw === void 0) return DEFAULT_ADVISOR_ENABLED;
|
|
2108
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2109
|
-
return DEFAULT_ADVISOR_ENABLED;
|
|
2110
|
-
}
|
|
2111
|
-
return parseAdvisor(raw, getUserConfigPath());
|
|
2112
|
-
}
|
|
2113
|
-
function readRunMode() {
|
|
2114
|
-
let raw;
|
|
2115
|
-
try {
|
|
2116
|
-
raw = readRawConfig();
|
|
2117
|
-
} catch (err) {
|
|
2118
|
-
console.warn(`[config] failed to read config file, using "${DEFAULT_RUN_MODE}" mode: ${err}`);
|
|
2119
|
-
return DEFAULT_RUN_MODE;
|
|
2120
|
-
}
|
|
2121
|
-
if (raw === void 0) return DEFAULT_RUN_MODE;
|
|
2122
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2123
|
-
return DEFAULT_RUN_MODE;
|
|
2124
|
-
}
|
|
2125
|
-
return parseMode(raw, getUserConfigPath());
|
|
2126
|
-
}
|
|
2127
|
-
function findProjectNameByPath(path2) {
|
|
2128
|
-
let config;
|
|
2129
|
-
try {
|
|
2130
|
-
config = loadUserConfig();
|
|
2131
|
-
} catch {
|
|
2132
|
-
return void 0;
|
|
2133
|
-
}
|
|
2134
|
-
const target = resolve(path2);
|
|
2135
|
-
for (const [name, projectPath] of Object.entries(config.projects)) {
|
|
2136
|
-
if (resolve(projectPath) === target) return name;
|
|
2137
|
-
}
|
|
2138
|
-
return void 0;
|
|
2139
|
-
}
|
|
2140
|
-
function resolveTargetProjects(requested, config) {
|
|
2141
|
-
const resolved = /* @__PURE__ */ new Map();
|
|
2142
|
-
for (const name of requested) {
|
|
2143
|
-
if (name === RESERVED_ALL) {
|
|
2144
|
-
for (const [projectName, projectPath] of Object.entries(config.projects)) {
|
|
2145
|
-
resolved.set(projectName, { name: projectName, path: projectPath });
|
|
2146
|
-
}
|
|
2147
|
-
continue;
|
|
2148
|
-
}
|
|
2149
|
-
if (Object.prototype.hasOwnProperty.call(config.projects, name)) {
|
|
2150
|
-
resolved.set(name, { name, path: config.projects[name] });
|
|
2151
|
-
continue;
|
|
2152
|
-
}
|
|
2153
|
-
if (Object.prototype.hasOwnProperty.call(config.projectGroups, name)) {
|
|
2154
|
-
for (const projectName of config.projectGroups[name]) {
|
|
2155
|
-
const projectPath = config.projects[projectName];
|
|
2156
|
-
if (projectPath === void 0) continue;
|
|
2157
|
-
resolved.set(projectName, { name: projectName, path: projectPath });
|
|
2158
|
-
}
|
|
2159
|
-
continue;
|
|
2160
|
-
}
|
|
2161
|
-
const availableProjects = Object.keys(config.projects).join(", ") || "(none)";
|
|
2162
|
-
const availableGroups = Object.keys(config.projectGroups).join(", ") || "(none)";
|
|
2163
|
-
throw new UserConfigError(
|
|
2164
|
-
`Unknown project or group: "${name}". Available projects: ${availableProjects}. Available groups: ${availableGroups}.`
|
|
2165
|
-
);
|
|
2166
|
-
}
|
|
2167
|
-
const resolvedProjects = Array.from(resolved.values());
|
|
2168
|
-
if (resolvedProjects.length === 0) {
|
|
2169
|
-
throw new UserConfigError(`No projects resolved from requested targets: ${requested.join(", ")}`);
|
|
2170
|
-
}
|
|
2171
|
-
return resolvedProjects;
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
2245
|
// src/process-manager.ts
|
|
2175
2246
|
var childProcesses = /* @__PURE__ */ new Map();
|
|
2176
2247
|
var herdrTasks = /* @__PURE__ */ new Map();
|
|
2177
2248
|
var herdrAbortSignal = { aborted: false };
|
|
2178
2249
|
var tasks = /* @__PURE__ */ new Map();
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
const trimmed = text.replace(/\r$/, "");
|
|
2182
|
-
if (trimmed.trim().length === 0) return;
|
|
2183
|
-
logLines.push({ id, stream, text: trimmed, time: /* @__PURE__ */ new Date() });
|
|
2184
|
-
if (logLines.length > LOG_DISPLAY_LIMIT) {
|
|
2185
|
-
logLines.splice(0, logLines.length - LOG_DISPLAY_LIMIT);
|
|
2186
|
-
}
|
|
2250
|
+
function pushTaskLogLine(id, stream, text) {
|
|
2251
|
+
pushLogLine({ id, stream, text: text.replace(/\r$/, ""), time: /* @__PURE__ */ new Date() });
|
|
2187
2252
|
}
|
|
2188
2253
|
function makeLogFeeder(id, stream) {
|
|
2189
2254
|
let partial = "";
|
|
@@ -2193,12 +2258,12 @@ function makeLogFeeder(id, stream) {
|
|
|
2193
2258
|
partial += decoder.write(chunk);
|
|
2194
2259
|
const parts = partial.split("\n");
|
|
2195
2260
|
partial = parts.pop() ?? "";
|
|
2196
|
-
for (const part of parts)
|
|
2261
|
+
for (const part of parts) pushTaskLogLine(id, stream, part);
|
|
2197
2262
|
},
|
|
2198
2263
|
flush() {
|
|
2199
2264
|
partial += decoder.end();
|
|
2200
2265
|
if (partial.length > 0) {
|
|
2201
|
-
|
|
2266
|
+
pushTaskLogLine(id, stream, partial);
|
|
2202
2267
|
partial = "";
|
|
2203
2268
|
}
|
|
2204
2269
|
}
|
|
@@ -2245,8 +2310,7 @@ function renderTable() {
|
|
|
2245
2310
|
if (lines.length > 0) lines.push("");
|
|
2246
2311
|
lines.push("Logs", ...logTableLines);
|
|
2247
2312
|
}
|
|
2248
|
-
|
|
2249
|
-
console.log(lines.join("\n"));
|
|
2313
|
+
writeScreen(lines);
|
|
2250
2314
|
}
|
|
2251
2315
|
var renderInterval;
|
|
2252
2316
|
function ensureRenderInterval() {
|
|
@@ -3076,7 +3140,8 @@ function createIssuePollingWorker(config) {
|
|
|
3076
3140
|
model,
|
|
3077
3141
|
effort,
|
|
3078
3142
|
// config.json の advisor が false なら advisorModel の指定に関わらず渡さない。
|
|
3079
|
-
advisorModel: isAdvisorEnabled() ? advisorModel : ""
|
|
3143
|
+
advisorModel: isAdvisorEnabled() ? advisorModel : "",
|
|
3144
|
+
permissionMode: getPermissionMode()
|
|
3080
3145
|
});
|
|
3081
3146
|
let baseBranch = defaultBranch;
|
|
3082
3147
|
if (parentNumber !== void 0) {
|
|
@@ -3249,7 +3314,8 @@ function createPrPollingWorker(config) {
|
|
|
3249
3314
|
model,
|
|
3250
3315
|
effort,
|
|
3251
3316
|
// config.json の advisor が false なら advisorModel の指定に関わらず渡さない。
|
|
3252
|
-
advisorModel: isAdvisorEnabled() ? advisorModel : ""
|
|
3317
|
+
advisorModel: isAdvisorEnabled() ? advisorModel : "",
|
|
3318
|
+
permissionMode: getPermissionMode()
|
|
3253
3319
|
});
|
|
3254
3320
|
run(
|
|
3255
3321
|
execution.command,
|
|
@@ -3262,7 +3328,7 @@ function createPrPollingWorker(config) {
|
|
|
3262
3328
|
lastCompletionAt = Date.now();
|
|
3263
3329
|
try {
|
|
3264
3330
|
if (status === "completed") {
|
|
3265
|
-
await config.onCompleted?.(pr);
|
|
3331
|
+
await config.onCompleted?.(pr, output);
|
|
3266
3332
|
await notifyTaskCompleted(config.name, name, pr.number, pr.title, prUrl, output);
|
|
3267
3333
|
} else {
|
|
3268
3334
|
await notifyTaskFailed(config.name, name, pr.number, pr.title, prUrl, output);
|
|
@@ -3407,14 +3473,32 @@ var triagePrWorker = createPrPollingWorker({
|
|
|
3407
3473
|
name: "triage-pr",
|
|
3408
3474
|
command: "/claude-task-worker:triage-pr",
|
|
3409
3475
|
triggerLabel: "cc-triage-scope",
|
|
3410
|
-
excludeLabels: ["cc-fix-onetime", "cc-resolve-conflict", "cc-release-ready"]
|
|
3476
|
+
excludeLabels: ["cc-fix-onetime", "cc-resolve-conflict", "cc-release-ready", "cc-need-human-check"]
|
|
3411
3477
|
});
|
|
3412
3478
|
|
|
3413
3479
|
// src/workers/resolve-conflict.ts
|
|
3480
|
+
var LABEL_NEED_HUMAN_CHECK = "cc-need-human-check";
|
|
3481
|
+
function shouldFlagUnresolvedConflict(output, mergeable) {
|
|
3482
|
+
return /aborted/i.test(output) && mergeable === "CONFLICTING";
|
|
3483
|
+
}
|
|
3414
3484
|
var resolveConflictWorker = createPrPollingWorker({
|
|
3415
3485
|
name: "resolve-conflict",
|
|
3416
3486
|
command: "/claude-task-worker:resolve-pr-conflict",
|
|
3417
|
-
triggerLabel: "cc-resolve-conflict"
|
|
3487
|
+
triggerLabel: "cc-resolve-conflict",
|
|
3488
|
+
onCompleted: async (pr, output) => {
|
|
3489
|
+
const mergeable = await getPrMergeable(pr.number);
|
|
3490
|
+
if (!shouldFlagUnresolvedConflict(output, mergeable)) return;
|
|
3491
|
+
await addLabel("pr", pr.number, LABEL_NEED_HUMAN_CHECK);
|
|
3492
|
+
await commentOnPR(
|
|
3493
|
+
pr.number,
|
|
3494
|
+
[
|
|
3495
|
+
"\u30B3\u30F3\u30D5\u30EA\u30AF\u30C8\u3092\u81EA\u52D5\u89E3\u6D88\u3067\u304D\u306A\u304B\u3063\u305F\u305F\u3081\u3001`cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u4ED8\u4E0E\u3057\u307E\u3057\u305F\u3002",
|
|
3496
|
+
"",
|
|
3497
|
+
"- \u624B\u52D5\u3067\u30B3\u30F3\u30D5\u30EA\u30AF\u30C8\u3092\u89E3\u6D88\u3057\u305F\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08`triage-pr` \u304C\u518D\u958B\u3057\u307E\u3059\uFF09",
|
|
3498
|
+
"- \u81EA\u52D5\u89E3\u6D88\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-resolve-conflict` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
3499
|
+
].join("\n")
|
|
3500
|
+
);
|
|
3501
|
+
}
|
|
3418
3502
|
});
|
|
3419
3503
|
|
|
3420
3504
|
// src/workers/check-dependabot.ts
|
|
@@ -3707,6 +3791,9 @@ var applyUiDesignWorker = async (opts = {}) => {
|
|
|
3707
3791
|
})();
|
|
3708
3792
|
};
|
|
3709
3793
|
|
|
3794
|
+
// src/index.ts
|
|
3795
|
+
init_table();
|
|
3796
|
+
|
|
3710
3797
|
// src/commands/init.ts
|
|
3711
3798
|
import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promises";
|
|
3712
3799
|
|
|
@@ -4217,6 +4304,8 @@ async function assertRunModeAvailable() {
|
|
|
4217
4304
|
console.log("[worker] run mode: herdr (each task runs as a TUI session in its own herdr tab)");
|
|
4218
4305
|
}
|
|
4219
4306
|
async function assertRunPrerequisites() {
|
|
4307
|
+
captureConsole();
|
|
4308
|
+
ensureRenderInterval();
|
|
4220
4309
|
await assertRunModeAvailable();
|
|
4221
4310
|
}
|
|
4222
4311
|
if (!hasProjectFilter()) {
|
|
@@ -4254,6 +4343,7 @@ if (hasProjectFilter()) {
|
|
|
4254
4343
|
let monitorHandle;
|
|
4255
4344
|
const herdr = await Promise.resolve().then(() => (init_herdr(), herdr_exports));
|
|
4256
4345
|
const dispatcher = await init_dispatcher().then(() => dispatcher_exports);
|
|
4346
|
+
captureConsole();
|
|
4257
4347
|
const shutdownController = dispatcher.createDispatcherShutdownHandler(
|
|
4258
4348
|
(options) => dispatcher.shutdownDispatcher(sessions, monitorHandle, options)
|
|
4259
4349
|
);
|