claude-task-worker 0.102.0 → 0.103.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 (3) hide show
  1. package/README.md +15 -0
  2. package/dist/index.js +75 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -258,10 +258,25 @@ CI やクラウド VM など対話ログインできない環境では、環境
258
258
  | キー | 型 | 既定 | 説明 |
259
259
  |---|---|---|---|
260
260
  | `fixReviewPointCallbackCommentMessage` | string | - | `fix-review-point` 完了時に PR へ投稿するコメント(未設定なら投稿しない) |
261
+ | `remoteEnvId` | string \| null | `null` | クラウド実行(`--cloud`)時に `--environment` へ渡すクラウド環境ID。`null` なら渡さず claude 側の既定解決に任せる(下記) |
261
262
  | `uiDesign` | object | `{ "enabled": false, "designDir": "designs", "yolo": false }` | UIデザイン先行ワークフロー(下記) |
262
263
  | `workers` | object | `{}` | ワーカーごとの上書き設定(下記) |
263
264
  | `lastRun` | object | `{}` | 定期ワーカーの最終実行時刻。ワーカーが自動更新するため手で編集しない |
264
265
 
266
+ #### `claude-task-worker.local.json`(ローカル上書き)
267
+
268
+ 同じディレクトリに `claude-task-worker.local.json` を置くと、`claude-task-worker.json` と同じキーを書けて**同じキーはローカル側が勝つ**。マージはネストしたオブジェクトのキー単位(`workers.<name>.model` だけを差し替えられる。配列・スカラーは丸ごと置き換え)。
269
+
270
+ コミットしない前提のファイルで、`claude-task-worker init` が `.gitignore` へ登録する。`remoteEnvId` のように各自の環境で値が違う設定を置く。
271
+
272
+ #### クラウド環境の指定(`remoteEnvId`)
273
+
274
+ `--cloud` 実行時に `claude --environment <id>` へ渡す環境ID。指定しない場合の選択は claude CLI に任せる(`~/.claude/settings.json` の `remote.defaultEnvironmentId` → アカウントの最初の `anthropic_cloud` 環境 → 無ければ自動作成)。ID は claude.ai の環境設定、または `/remote-env` で確認できる。自己ホスト環境(`ccpool_...`)も同じキーに書ける。
275
+
276
+ ```json
277
+ { "remoteEnvId": "env_xxxxxxxx" }
278
+ ```
279
+
265
280
  #### ワーカーごとの設定
266
281
 
267
282
  未指定のワーカー・フィールドは既定値にフォールバックする。
package/dist/index.js CHANGED
@@ -1907,11 +1907,13 @@ function checkCloudConfig(input) {
1907
1907
  }
1908
1908
  var DEFAULT_CONFIG = {
1909
1909
  fixReviewPointCallbackCommentMessage: "",
1910
+ remoteEnvId: null,
1910
1911
  uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG },
1911
1912
  lastRun: {},
1912
1913
  workers: {}
1913
1914
  };
1914
1915
  var CONFIG_PATH = join(process.cwd(), "claude-task-worker.json");
1916
+ var LOCAL_CONFIG_PATH = join(process.cwd(), "claude-task-worker.local.json");
1915
1917
  function defaultsFor(name) {
1916
1918
  return WORKER_DEFAULTS[name] ?? DEFAULT_WORKER_CONFIG;
1917
1919
  }
@@ -2043,18 +2045,44 @@ function parseLastRunEntry(val) {
2043
2045
  }
2044
2046
  return result;
2045
2047
  }
2046
- function loadConfig() {
2047
- const configPath = CONFIG_PATH;
2048
- let raw;
2048
+ function isPlainObject(val) {
2049
+ return typeof val === "object" && val !== null && !Array.isArray(val);
2050
+ }
2051
+ function mergeConfigRaw(base, local) {
2052
+ const result = { ...base };
2053
+ for (const [key, val] of Object.entries(local)) {
2054
+ const current = result[key];
2055
+ result[key] = isPlainObject(current) && isPlainObject(val) ? mergeConfigRaw(current, val) : val;
2056
+ }
2057
+ return result;
2058
+ }
2059
+ function readRawConfig(path2) {
2060
+ let parsed;
2049
2061
  try {
2050
- raw = JSON.parse(readFileSync(configPath, "utf-8"));
2062
+ parsed = JSON.parse(readFileSync(path2, "utf-8"));
2051
2063
  } catch (err) {
2052
- if (err.code === "ENOENT") {
2053
- return { ...DEFAULT_CONFIG, uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG }, lastRun: {}, workers: {} };
2054
- }
2064
+ if (err.code === "ENOENT") return {};
2055
2065
  throw err;
2056
2066
  }
2067
+ if (!isPlainObject(parsed)) {
2068
+ console.warn(`[config] invalid ${path2}: expected object, ignoring`);
2069
+ return {};
2070
+ }
2071
+ return parsed;
2072
+ }
2073
+ function loadConfig() {
2074
+ const raw = mergeConfigRaw(readRawConfig(CONFIG_PATH), readRawConfig(LOCAL_CONFIG_PATH));
2057
2075
  const result = { ...DEFAULT_CONFIG, uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG }, lastRun: {}, workers: {} };
2076
+ if ("remoteEnvId" in raw) {
2077
+ const val = raw["remoteEnvId"];
2078
+ if (val === null) {
2079
+ result.remoteEnvId = null;
2080
+ } else if (typeof val === "string" && val.trim().length > 0) {
2081
+ result.remoteEnvId = val.trim();
2082
+ } else {
2083
+ console.warn(`[config] invalid remoteEnvId: ${String(val)}, using default null`);
2084
+ }
2085
+ }
2058
2086
  if ("lastRun" in raw) {
2059
2087
  result.lastRun = parseLastRunEntry(raw["lastRun"]);
2060
2088
  }
@@ -2114,6 +2142,14 @@ function writeLastRun(repoRoot, workerName, at = /* @__PURE__ */ new Date()) {
2114
2142
  writeFileSync(path2, `${JSON.stringify(raw, null, 2)}
2115
2143
  `, "utf-8");
2116
2144
  }
2145
+ function getRemoteEnvId() {
2146
+ try {
2147
+ return loadConfig().remoteEnvId;
2148
+ } catch (err) {
2149
+ console.warn(`[config] failed to load remoteEnvId, not passing --environment: ${err}`);
2150
+ return null;
2151
+ }
2152
+ }
2117
2153
  function getUiDesignConfig() {
2118
2154
  try {
2119
2155
  return loadConfig().uiDesign;
@@ -2177,7 +2213,7 @@ function parseConfigFile(path2) {
2177
2213
  throw err;
2178
2214
  }
2179
2215
  }
2180
- function readRawConfig() {
2216
+ function readRawConfig2() {
2181
2217
  return parseConfigFile(getUserConfigPath());
2182
2218
  }
2183
2219
  function parseMode(raw, path2) {
@@ -2203,7 +2239,7 @@ function parsePermission(raw, path2) {
2203
2239
  }
2204
2240
  function loadUserConfig() {
2205
2241
  const path2 = getUserConfigPath();
2206
- const raw = readRawConfig();
2242
+ const raw = readRawConfig2();
2207
2243
  if (raw === void 0) {
2208
2244
  throw new UserConfigError(`config.json not found: ${path2}`);
2209
2245
  }
@@ -2295,7 +2331,7 @@ function getPermissionMode() {
2295
2331
  function readTopLevel(parse, fallback, label) {
2296
2332
  let raw;
2297
2333
  try {
2298
- raw = readRawConfig();
2334
+ raw = readRawConfig2();
2299
2335
  } catch (err) {
2300
2336
  console.warn(`[config] failed to read config file, using default ${label}: ${err}`);
2301
2337
  return fallback;
@@ -2445,6 +2481,7 @@ function buildClaudeArgs({
2445
2481
  advisorModel,
2446
2482
  permissionMode,
2447
2483
  cloud,
2484
+ remoteEnvId,
2448
2485
  baseRef,
2449
2486
  onBranch
2450
2487
  }) {
@@ -2454,6 +2491,7 @@ function buildClaudeArgs({
2454
2491
  throw new Error("--on-branch and --ref both set the cloud session's base branch; pass one or the other");
2455
2492
  }
2456
2493
  const advisor = advisorModel?.trim() ?? "";
2494
+ const remoteEnv = remoteEnvId?.trim() ?? "";
2457
2495
  const permission = permissionMode ?? DEFAULT_PERMISSION_MODE;
2458
2496
  return [
2459
2497
  // default モードはプロンプトを引数で渡す(print モード)。herdr モードでは渡さない:
@@ -2477,6 +2515,9 @@ function buildClaudeArgs({
2477
2515
  // advisor 未指定(空文字)ならフラグごと省く。値なしの `--advisor` を渡すと
2478
2516
  // 後続フラグを値として食われるため、必ずモデル名とセットでのみ付ける。
2479
2517
  ...advisor === "" ? [] : ["--advisor", advisor],
2518
+ // クラウド環境の指名。値なしの `--environment` は後続フラグを値として食うため、
2519
+ // `--advisor` と同じく ID とセットでのみ付ける。
2520
+ ...cloud === true && remoteEnv !== "" ? ["--environment", remoteEnv] : [],
2480
2521
  // クラウド実行時は「作成コマンドの共通フラグ」だけをここで返す。`--cloud` 自体は
2481
2522
  // 付けない(値として渡す description(=クラウドセッションの初期プロンプト。
2482
2523
  // appendCloudDoneInstruction() 適用後のタスクプロンプトそのもの)は
@@ -3790,7 +3831,7 @@ function createIssuePollingWorker(config) {
3790
3831
  // config.json の advisor が false なら advisorModel の指定に関わらず渡さない。
3791
3832
  advisorModel: isAdvisorEnabled() ? advisorModel : "",
3792
3833
  permissionMode: getPermissionMode(),
3793
- ...cloud ? { cloud: true, baseRef: baseBranch } : {}
3834
+ ...cloud ? { cloud: true, baseRef: baseBranch, remoteEnvId: getRemoteEnvId() ?? "" } : {}
3794
3835
  });
3795
3836
  let cwd;
3796
3837
  if (cloud) {
@@ -4058,6 +4099,7 @@ function createPrPollingWorker(config) {
4058
4099
  advisorModel: isAdvisorEnabled() ? advisorModel : "",
4059
4100
  permissionMode: getPermissionMode(),
4060
4101
  cloud: isCloud,
4102
+ remoteEnvId: isCloud ? getRemoteEnvId() ?? "" : void 0,
4061
4103
  onBranch: isCloud ? pr.headRefName : void 0
4062
4104
  });
4063
4105
  if (isCloud) {
@@ -4664,7 +4706,7 @@ function createScheduledWorker(config) {
4664
4706
  effort,
4665
4707
  advisorModel: isAdvisorEnabled() ? advisorModel : "",
4666
4708
  permissionMode: getPermissionMode(),
4667
- ...cloud ? { cloud: true, baseRef: defaultBranch } : {}
4709
+ ...cloud ? { cloud: true, baseRef: defaultBranch, remoteEnvId: getRemoteEnvId() ?? "" } : {}
4668
4710
  });
4669
4711
  await publishLastRunPr(config.name, defaultBranch, new Date(now)).catch(
4670
4712
  (err) => console.error(`[${config.name}] publishLastRunPr failed: ${err}`)
@@ -4752,7 +4794,8 @@ var updateDesignMdWorker = createScheduledWorker({
4752
4794
  init_table();
4753
4795
 
4754
4796
  // src/commands/init.ts
4755
- import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promises";
4797
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, access } from "node:fs/promises";
4798
+ import { basename as basename3 } from "node:path";
4756
4799
 
4757
4800
  // src/commands/codegraph.ts
4758
4801
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -4941,6 +4984,22 @@ async function createConfig(force) {
4941
4984
  const result = await writeFileWithMode(CONFIG_PATH, JSON.stringify(initialConfig, null, 2), force);
4942
4985
  logWriteResult(result, CONFIG_PATH);
4943
4986
  }
4987
+ async function ensureLocalConfigGitIgnore() {
4988
+ const entry = basename3(LOCAL_CONFIG_PATH);
4989
+ const path2 = ".gitignore";
4990
+ let current = "";
4991
+ try {
4992
+ current = await readFile2(path2, "utf-8");
4993
+ } catch {
4994
+ }
4995
+ const next = appendIgnoreEntry(current, entry);
4996
+ if (next === null) {
4997
+ console.log(`[init] Already ignored: ${entry} (${path2})`);
4998
+ return;
4999
+ }
5000
+ await writeFile2(path2, next, "utf-8");
5001
+ console.log(`[init] Added ${entry} to ${path2}`);
5002
+ }
4944
5003
  async function init(options = {}) {
4945
5004
  const force = options.force ?? false;
4946
5005
  console.log(`[init] Creating labels...${force ? " (force mode)" : ""}`);
@@ -4962,6 +5021,7 @@ async function init(options = {}) {
4962
5021
  logWriteResult(await writeFileWithMode(workflowPath, ASSIGN_CREATOR_WORKFLOW, force), workflowPath);
4963
5022
  console.log("[init] Creating config file...");
4964
5023
  await createConfig(force);
5024
+ await ensureLocalConfigGitIgnore();
4965
5025
  console.log("[init] Setting up CodeGraph...");
4966
5026
  await ensureCodegraphGitIgnore("init");
4967
5027
  await runCodegraphInit("init");
@@ -5123,7 +5183,7 @@ async function install() {
5123
5183
  }
5124
5184
 
5125
5185
  // src/commands/cloud-setup.ts
5126
- import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile2 } from "node:fs/promises";
5186
+ import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile3 } from "node:fs/promises";
5127
5187
  import { homedir as homedir6 } from "node:os";
5128
5188
  import { join as join8 } from "node:path";
5129
5189
  var LOG_PREFIX = "cloud-setup";
@@ -5164,7 +5224,7 @@ async function writeClaudeSettings(force) {
5164
5224
  const path2 = claudeSettingsPath();
5165
5225
  let existing;
5166
5226
  try {
5167
- existing = await readFile2(path2, "utf-8");
5227
+ existing = await readFile3(path2, "utf-8");
5168
5228
  } catch {
5169
5229
  existing = null;
5170
5230
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.102.0",
3
+ "version": "0.103.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",