cc-claw 0.16.3 → 0.17.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/cli.js +887 -372
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ var VERSION;
33
33
  var init_version = __esm({
34
34
  "src/version.ts"() {
35
35
  "use strict";
36
- VERSION = true ? "0.16.3" : (() => {
36
+ VERSION = true ? "0.17.0" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -1729,6 +1729,12 @@ function initSchema(db3) {
1729
1729
  mode TEXT NOT NULL DEFAULT 'auto'
1730
1730
  );
1731
1731
  `);
1732
+ db3.exec(`
1733
+ CREATE TABLE IF NOT EXISTS chat_exec_mode (
1734
+ chat_id TEXT PRIMARY KEY,
1735
+ mode TEXT NOT NULL DEFAULT 'approved'
1736
+ );
1737
+ `);
1732
1738
  db3.exec(`
1733
1739
  CREATE TABLE IF NOT EXISTS backend_credentials (
1734
1740
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -2643,6 +2649,22 @@ function setAgentMode(chatId, mode) {
2643
2649
  function clearAgentMode(chatId) {
2644
2650
  getDb().prepare("DELETE FROM chat_agent_mode WHERE chat_id = ?").run(chatId);
2645
2651
  }
2652
+ function getExecMode(chatId) {
2653
+ const row = getDb().prepare(
2654
+ "SELECT mode FROM chat_exec_mode WHERE chat_id = ?"
2655
+ ).get(chatId);
2656
+ return row?.mode ?? "approved";
2657
+ }
2658
+ function setExecMode(chatId, mode) {
2659
+ getDb().prepare(`
2660
+ INSERT INTO chat_exec_mode (chat_id, mode)
2661
+ VALUES (?, ?)
2662
+ ON CONFLICT(chat_id) DO UPDATE SET mode = excluded.mode
2663
+ `).run(chatId, mode);
2664
+ }
2665
+ function clearExecMode(chatId) {
2666
+ getDb().prepare("DELETE FROM chat_exec_mode WHERE chat_id = ?").run(chatId);
2667
+ }
2646
2668
  var pendingEscalations, ESCALATION_TTL_MS, ALL_TOOLS;
2647
2669
  var init_chat_settings = __esm({
2648
2670
  "src/memory/chat-settings.ts"() {
@@ -3450,6 +3472,7 @@ __export(store_exports5, {
3450
3472
  clearChatBackendSlot: () => clearChatBackendSlot,
3451
3473
  clearChatGeminiSlot: () => clearChatGeminiSlot,
3452
3474
  clearCwd: () => clearCwd,
3475
+ clearExecMode: () => clearExecMode,
3453
3476
  clearMessageLog: () => clearMessageLog,
3454
3477
  clearModel: () => clearModel,
3455
3478
  clearSession: () => clearSession,
@@ -3487,6 +3510,7 @@ __export(store_exports5, {
3487
3510
  getEligibleBackendSlots: () => getEligibleBackendSlots,
3488
3511
  getEligibleGeminiSlots: () => getEligibleGeminiSlots,
3489
3512
  getEnabledTools: () => getEnabledTools,
3513
+ getExecMode: () => getExecMode,
3490
3514
  getGeminiRotationMode: () => getGeminiRotationMode,
3491
3515
  getGeminiSlots: () => getGeminiSlots,
3492
3516
  getHeartbeatConfig: () => getHeartbeatConfig,
@@ -3557,6 +3581,7 @@ __export(store_exports5, {
3557
3581
  setBootTime: () => setBootTime,
3558
3582
  setChatAlias: () => setChatAlias,
3559
3583
  setCwd: () => setCwd,
3584
+ setExecMode: () => setExecMode,
3560
3585
  setGeminiRotationMode: () => setGeminiRotationMode,
3561
3586
  setGeminiSlotEnabled: () => setGeminiSlotEnabled,
3562
3587
  setHeartbeatConfig: () => setHeartbeatConfig,
@@ -3944,10 +3969,199 @@ var init_claude = __esm({
3944
3969
  }
3945
3970
  });
3946
3971
 
3972
+ // src/slots/symlink-manager.ts
3973
+ var symlink_manager_exports = {};
3974
+ __export(symlink_manager_exports, {
3975
+ SYMLINK_LAYOUTS: () => SYMLINK_LAYOUTS,
3976
+ getPrimaryDir: () => getPrimaryDir,
3977
+ migrateAllSlots: () => migrateAllSlots,
3978
+ migrateExistingSlots: () => migrateExistingSlots,
3979
+ setupSlotSymlinks: () => setupSlotSymlinks,
3980
+ validateSlotSymlinks: () => validateSlotSymlinks
3981
+ });
3982
+ import { existsSync as existsSync3, lstatSync, mkdirSync, readlinkSync, readdirSync as readdirSync2, symlinkSync, rmSync, copyFileSync, statSync as statSync2 } from "fs";
3983
+ import { join as join5, dirname } from "path";
3984
+ function setupSlotSymlinks(backend2, slotDir, primaryDir) {
3985
+ const layout = SYMLINK_LAYOUTS[backend2];
3986
+ if (!layout) {
3987
+ log(`[symlink] No layout defined for backend "${backend2}", skipping`);
3988
+ return;
3989
+ }
3990
+ for (const entry of layout.symlinks) {
3991
+ const slotPath = join5(slotDir, entry.slotSubpath);
3992
+ const primaryTarget = join5(primaryDir, entry.primarySubpath);
3993
+ if (!existsSync3(primaryTarget)) {
3994
+ mkdirSync(primaryTarget, { recursive: true });
3995
+ }
3996
+ if (existsSync3(slotPath) || isSymlink(slotPath)) {
3997
+ if (isSymlink(slotPath)) {
3998
+ const currentTarget = readlinkSync(slotPath);
3999
+ if (currentTarget === primaryTarget) {
4000
+ continue;
4001
+ }
4002
+ rmSync(slotPath);
4003
+ } else {
4004
+ migrateDirectoryContents(slotPath, primaryTarget);
4005
+ rmSync(slotPath, { recursive: true });
4006
+ }
4007
+ }
4008
+ const parentDir = dirname(slotPath);
4009
+ if (!existsSync3(parentDir)) {
4010
+ mkdirSync(parentDir, { recursive: true });
4011
+ }
4012
+ symlinkSync(primaryTarget, slotPath);
4013
+ log(`[symlink] ${backend2}: ${slotPath} \u2192 ${primaryTarget}`);
4014
+ }
4015
+ }
4016
+ function validateSlotSymlinks(backend2, slotDir, primaryDir) {
4017
+ const layout = SYMLINK_LAYOUTS[backend2];
4018
+ if (!layout) return { valid: true, broken: [] };
4019
+ const broken = [];
4020
+ for (const entry of layout.symlinks) {
4021
+ const slotPath = join5(slotDir, entry.slotSubpath);
4022
+ const primaryTarget = join5(primaryDir, entry.primarySubpath);
4023
+ if (!isSymlink(slotPath)) {
4024
+ if (existsSync3(slotPath)) {
4025
+ broken.push({ path: slotPath, issue: "real directory instead of symlink" });
4026
+ } else {
4027
+ broken.push({ path: slotPath, issue: "symlink missing" });
4028
+ }
4029
+ continue;
4030
+ }
4031
+ const currentTarget = readlinkSync(slotPath);
4032
+ if (currentTarget !== primaryTarget) {
4033
+ broken.push({ path: slotPath, issue: `symlink points to ${currentTarget}, expected ${primaryTarget}` });
4034
+ continue;
4035
+ }
4036
+ if (!existsSync3(primaryTarget)) {
4037
+ broken.push({ path: slotPath, issue: `symlink target ${primaryTarget} does not exist` });
4038
+ }
4039
+ }
4040
+ return { valid: broken.length === 0, broken };
4041
+ }
4042
+ function migrateExistingSlots(backend2, slotsDir, primaryDir) {
4043
+ if (!existsSync3(slotsDir)) {
4044
+ return { migrated: 0, skipped: 0, errors: [] };
4045
+ }
4046
+ const layout = SYMLINK_LAYOUTS[backend2];
4047
+ if (!layout) return { migrated: 0, skipped: 0, errors: [] };
4048
+ const entries = readdirSync2(slotsDir, { withFileTypes: true });
4049
+ let migrated = 0;
4050
+ let skipped = 0;
4051
+ const errors = [];
4052
+ for (const entry of entries) {
4053
+ if (!entry.isDirectory()) continue;
4054
+ const slotDir = join5(slotsDir, entry.name);
4055
+ const validation = validateSlotSymlinks(backend2, slotDir, primaryDir);
4056
+ if (validation.valid) {
4057
+ skipped++;
4058
+ continue;
4059
+ }
4060
+ try {
4061
+ setupSlotSymlinks(backend2, slotDir, primaryDir);
4062
+ migrated++;
4063
+ log(`[symlink] Migrated slot: ${entry.name}`);
4064
+ } catch (err) {
4065
+ const msg = `Failed to migrate ${entry.name}: ${err instanceof Error ? err.message : String(err)}`;
4066
+ errors.push(msg);
4067
+ log(`[symlink] ERROR: ${msg}`);
4068
+ }
4069
+ }
4070
+ return { migrated, skipped, errors };
4071
+ }
4072
+ function getPrimaryDir(backend2) {
4073
+ const resolver = PRIMARY_DIR_MAP[backend2];
4074
+ return resolver ? resolver() : null;
4075
+ }
4076
+ function migrateAllSlots(ccClawHome) {
4077
+ const backends = [
4078
+ { id: "claude", slotsSubdir: "claude-slots" },
4079
+ { id: "codex", slotsSubdir: "codex-slots" },
4080
+ { id: "gemini", slotsSubdir: "gemini-slots" }
4081
+ ];
4082
+ for (const { id, slotsSubdir } of backends) {
4083
+ const slotsDir = join5(ccClawHome, slotsSubdir);
4084
+ const primaryDir = getPrimaryDir(id);
4085
+ if (!primaryDir || !existsSync3(slotsDir)) continue;
4086
+ const result = migrateExistingSlots(id, slotsDir, primaryDir);
4087
+ if (result.migrated > 0) {
4088
+ log(`[symlink] ${id}: migrated ${result.migrated} slot(s), skipped ${result.skipped}`);
4089
+ }
4090
+ if (result.errors.length > 0) {
4091
+ for (const err of result.errors) log(`[symlink] ${id}: ${err}`);
4092
+ }
4093
+ }
4094
+ }
4095
+ function isSymlink(path) {
4096
+ try {
4097
+ return lstatSync(path).isSymbolicLink();
4098
+ } catch {
4099
+ return false;
4100
+ }
4101
+ }
4102
+ function migrateDirectoryContents(src, dest) {
4103
+ if (!existsSync3(src) || !statSync2(src).isDirectory()) return;
4104
+ const entries = readdirSync2(src, { withFileTypes: true });
4105
+ for (const entry of entries) {
4106
+ const srcPath = join5(src, entry.name);
4107
+ const destPath = join5(dest, entry.name);
4108
+ if (entry.isDirectory()) {
4109
+ if (!existsSync3(destPath)) {
4110
+ mkdirSync(destPath, { recursive: true });
4111
+ }
4112
+ migrateDirectoryContents(srcPath, destPath);
4113
+ } else if (entry.isFile()) {
4114
+ if (!existsSync3(destPath)) {
4115
+ copyFileSync(srcPath, destPath);
4116
+ }
4117
+ }
4118
+ }
4119
+ }
4120
+ var SYMLINK_LAYOUTS, PRIMARY_DIR_MAP;
4121
+ var init_symlink_manager = __esm({
4122
+ "src/slots/symlink-manager.ts"() {
4123
+ "use strict";
4124
+ init_log();
4125
+ SYMLINK_LAYOUTS = {
4126
+ claude: {
4127
+ symlinks: [
4128
+ { slotSubpath: ".claude/projects", primarySubpath: "projects" },
4129
+ { slotSubpath: ".claude/plans", primarySubpath: "plans" }
4130
+ ]
4131
+ },
4132
+ codex: {
4133
+ symlinks: [
4134
+ { slotSubpath: "memories", primarySubpath: "memories" }
4135
+ ]
4136
+ },
4137
+ gemini: {
4138
+ symlinks: [
4139
+ { slotSubpath: ".gemini/history", primarySubpath: "history" },
4140
+ { slotSubpath: ".gemini/tmp", primarySubpath: "tmp" }
4141
+ ]
4142
+ }
4143
+ };
4144
+ PRIMARY_DIR_MAP = {
4145
+ claude: () => {
4146
+ const home = process.env.HOME ?? `/Users/${process.env.USER ?? "unknown"}`;
4147
+ return join5(home, ".claude");
4148
+ },
4149
+ codex: () => {
4150
+ const home = process.env.HOME ?? `/Users/${process.env.USER ?? "unknown"}`;
4151
+ return process.env.CODEX_HOME ?? join5(home, ".codex");
4152
+ },
4153
+ gemini: () => {
4154
+ const home = process.env.HOME ?? `/Users/${process.env.USER ?? "unknown"}`;
4155
+ return process.env.GEMINI_CLI_HOME ?? join5(home, ".gemini");
4156
+ }
4157
+ };
4158
+ }
4159
+ });
4160
+
3947
4161
  // src/backends/gemini.ts
3948
- import { existsSync as existsSync3, mkdirSync } from "fs";
4162
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
3949
4163
  import { spawnSync as spawnSync2 } from "child_process";
3950
- import { join as join5 } from "path";
4164
+ import { join as join6 } from "path";
3951
4165
  var GeminiAdapter;
3952
4166
  var init_gemini = __esm({
3953
4167
  "src/backends/gemini.ts"() {
@@ -4015,14 +4229,14 @@ var init_gemini = __esm({
4015
4229
  `${home}/.local/bin/gemini`,
4016
4230
  `${home}/.npm-global/bin/gemini`
4017
4231
  ];
4018
- this._resolvedPath = candidates.find((p) => existsSync3(p)) ?? "gemini";
4232
+ this._resolvedPath = candidates.find((p) => existsSync4(p)) ?? "gemini";
4019
4233
  }
4020
4234
  return this._resolvedPath;
4021
4235
  }
4022
4236
  getEnv(thinkingOverrides) {
4023
4237
  const env = buildBaseEnv(thinkingOverrides);
4024
- const identityFile = join5(IDENTITY_PATH, "CC-CLAW.md");
4025
- if (existsSync3(identityFile)) {
4238
+ const identityFile = join6(IDENTITY_PATH, "CC-CLAW.md");
4239
+ if (existsSync4(identityFile)) {
4026
4240
  env.GEMINI_SYSTEM_MD = identityFile;
4027
4241
  }
4028
4242
  return env;
@@ -4112,11 +4326,17 @@ var init_gemini = __esm({
4112
4326
  if (!slot) return { env, slot: null };
4113
4327
  if (slot.slotType === "api_key" && slot.apiKey) {
4114
4328
  env.GEMINI_API_KEY = slot.apiKey;
4115
- const isolatedHome = join5(CC_CLAW_HOME, "gemini-slots", `apikey-${slot.id}`);
4116
- if (!existsSync3(isolatedHome)) mkdirSync(isolatedHome, { recursive: true });
4329
+ const isolatedHome = join6(CC_CLAW_HOME, "gemini-slots", `apikey-${slot.id}`);
4330
+ if (!existsSync4(isolatedHome)) mkdirSync2(isolatedHome, { recursive: true });
4117
4331
  log(`[gemini] api_key slot ${slot.id}: isolated home \u2192 ${isolatedHome}`);
4118
4332
  env.GEMINI_CLI_HOME = isolatedHome;
4119
4333
  delete env.GOOGLE_API_KEY;
4334
+ try {
4335
+ const { setupSlotSymlinks: setupSlotSymlinks2, getPrimaryDir: getPrimaryDir2 } = (init_symlink_manager(), __toCommonJS(symlink_manager_exports));
4336
+ const primaryDir = getPrimaryDir2("gemini");
4337
+ if (primaryDir) setupSlotSymlinks2("gemini", isolatedHome, primaryDir);
4338
+ } catch {
4339
+ }
4120
4340
  } else if (slot.slotType === "oauth" && slot.configHome) {
4121
4341
  env.GEMINI_CLI_HOME = slot.configHome;
4122
4342
  delete env.GEMINI_API_KEY;
@@ -4135,7 +4355,7 @@ var init_gemini = __esm({
4135
4355
  });
4136
4356
 
4137
4357
  // src/backends/codex.ts
4138
- import { existsSync as existsSync4 } from "fs";
4358
+ import { existsSync as existsSync5 } from "fs";
4139
4359
  import { execSync as execSync2 } from "child_process";
4140
4360
  var CodexAdapter;
4141
4361
  var init_codex = __esm({
@@ -4210,7 +4430,7 @@ var init_codex = __esm({
4210
4430
  `${home}/.local/bin/codex`,
4211
4431
  `${home}/.npm-global/bin/codex`
4212
4432
  ];
4213
- this._resolvedPath = candidates.find((p) => existsSync4(p)) ?? "codex";
4433
+ this._resolvedPath = candidates.find((p) => existsSync5(p)) ?? "codex";
4214
4434
  }
4215
4435
  return this._resolvedPath;
4216
4436
  }
@@ -4321,7 +4541,7 @@ var init_codex = __esm({
4321
4541
  });
4322
4542
 
4323
4543
  // src/backends/cursor.ts
4324
- import { existsSync as existsSync5 } from "fs";
4544
+ import { existsSync as existsSync6 } from "fs";
4325
4545
  import { execSync as execSync3 } from "child_process";
4326
4546
  function extractToolInfo(tc) {
4327
4547
  if (tc.readToolCall) {
@@ -4470,7 +4690,7 @@ var init_cursor = __esm({
4470
4690
  `${home}/.local/bin/agent`,
4471
4691
  "/usr/local/bin/agent"
4472
4692
  ];
4473
- this._resolvedPath = candidates.find((p) => existsSync5(p)) ?? "agent";
4693
+ this._resolvedPath = candidates.find((p) => existsSync6(p)) ?? "agent";
4474
4694
  }
4475
4695
  return this._resolvedPath;
4476
4696
  }
@@ -4634,14 +4854,14 @@ __export(backends_exports, {
4634
4854
  isBackendAvailable: () => isBackendAvailable,
4635
4855
  probeBackendAvailability: () => probeBackendAvailability
4636
4856
  });
4637
- import { existsSync as existsSync6 } from "fs";
4857
+ import { existsSync as existsSync7 } from "fs";
4638
4858
  import { execSync as execSync4 } from "child_process";
4639
4859
  function probeBackendAvailability() {
4640
4860
  availableSet.clear();
4641
4861
  for (const [id, adapter] of Object.entries(adapters)) {
4642
4862
  try {
4643
4863
  const exe = adapter.getExecutablePath();
4644
- if (existsSync6(exe) || resolveOnPath(exe)) {
4864
+ if (existsSync7(exe) || resolveOnPath(exe)) {
4645
4865
  availableSet.add(id);
4646
4866
  }
4647
4867
  } catch {
@@ -4650,7 +4870,7 @@ function probeBackendAvailability() {
4650
4870
  log(`[backends] Available: ${[...availableSet].join(", ") || "none"}`);
4651
4871
  }
4652
4872
  function resolveOnPath(name) {
4653
- if (name.includes("/")) return existsSync6(name);
4873
+ if (name.includes("/")) return existsSync7(name);
4654
4874
  try {
4655
4875
  execSync4(`which ${name}`, { encoding: "utf-8", timeout: 3e3 });
4656
4876
  return true;
@@ -5073,19 +5293,19 @@ If the user asks *how* to do something with CC-Claw, use this expertise to sugge
5073
5293
 
5074
5294
  // src/bootstrap/init.ts
5075
5295
  import {
5076
- existsSync as existsSync7,
5296
+ existsSync as existsSync8,
5077
5297
  writeFileSync,
5078
- mkdirSync as mkdirSync2,
5298
+ mkdirSync as mkdirSync3,
5079
5299
  readFileSync as readFileSync2,
5080
- statSync as statSync2,
5081
- copyFileSync,
5300
+ statSync as statSync3,
5301
+ copyFileSync as copyFileSync2,
5082
5302
  unlinkSync as unlinkSync2
5083
5303
  } from "fs";
5084
- import { join as join6 } from "path";
5304
+ import { join as join7 } from "path";
5085
5305
  function migrateFile(legacyPath, newPath, label2) {
5086
- if (existsSync7(newPath)) return false;
5087
- if (existsSync7(legacyPath)) {
5088
- copyFileSync(legacyPath, newPath);
5306
+ if (existsSync8(newPath)) return false;
5307
+ if (existsSync8(legacyPath)) {
5308
+ copyFileSync2(legacyPath, newPath);
5089
5309
  const copied = readFileSync2(newPath, "utf-8");
5090
5310
  if (copied.length > 0) {
5091
5311
  unlinkSync2(legacyPath);
@@ -5098,28 +5318,28 @@ function migrateFile(legacyPath, newPath, label2) {
5098
5318
  return false;
5099
5319
  }
5100
5320
  function bootstrapWorkspaceFiles() {
5101
- if (!existsSync7(IDENTITY_PATH)) {
5102
- mkdirSync2(IDENTITY_PATH, { recursive: true });
5321
+ if (!existsSync8(IDENTITY_PATH)) {
5322
+ mkdirSync3(IDENTITY_PATH, { recursive: true });
5103
5323
  log("[bootstrap] Created identity/ directory");
5104
5324
  }
5105
- if (!existsSync7(WORKSPACE_PATH)) {
5106
- mkdirSync2(WORKSPACE_PATH, { recursive: true });
5325
+ if (!existsSync8(WORKSPACE_PATH)) {
5326
+ mkdirSync3(WORKSPACE_PATH, { recursive: true });
5107
5327
  }
5108
5328
  migrateFile(LEGACY_SOUL_PATH, SOUL_PATH, "SOUL.md");
5109
5329
  migrateFile(LEGACY_USER_PATH, USER_PATH, "USER.md");
5110
- if (existsSync7(LEGACY_CLAUDE_MD)) {
5330
+ if (existsSync8(LEGACY_CLAUDE_MD)) {
5111
5331
  unlinkSync2(LEGACY_CLAUDE_MD);
5112
5332
  log("[bootstrap] Removed legacy workspace/CLAUDE.md (replaced by identity/CC-CLAW.md)");
5113
5333
  }
5114
- if (existsSync7(LEGACY_GEMINI_MD)) {
5334
+ if (existsSync8(LEGACY_GEMINI_MD)) {
5115
5335
  unlinkSync2(LEGACY_GEMINI_MD);
5116
5336
  log("[bootstrap] Removed legacy workspace/GEMINI.md (replaced by identity/CC-CLAW.md)");
5117
5337
  }
5118
- if (!existsSync7(SOUL_PATH)) {
5338
+ if (!existsSync8(SOUL_PATH)) {
5119
5339
  writeFileSync(SOUL_PATH, DEFAULT_SOUL, "utf-8");
5120
5340
  log("[bootstrap] Created default SOUL.md");
5121
5341
  }
5122
- if (!existsSync7(USER_PATH)) {
5342
+ if (!existsSync8(USER_PATH)) {
5123
5343
  let tz = "UTC";
5124
5344
  try {
5125
5345
  tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
@@ -5129,16 +5349,16 @@ function bootstrapWorkspaceFiles() {
5129
5349
  writeFileSync(USER_PATH, userContent, "utf-8");
5130
5350
  log(`[bootstrap] Created default USER.md (timezone: ${tz})`);
5131
5351
  }
5132
- if (!existsSync7(CONTEXT_DIR)) {
5133
- mkdirSync2(CONTEXT_DIR, { recursive: true });
5352
+ if (!existsSync8(CONTEXT_DIR)) {
5353
+ mkdirSync3(CONTEXT_DIR, { recursive: true });
5134
5354
  log("[bootstrap] Created context/ directory");
5135
5355
  }
5136
- if (!existsSync7(MEDIA_PATH)) {
5137
- mkdirSync2(MEDIA_PATH, { recursive: true });
5356
+ if (!existsSync8(MEDIA_PATH)) {
5357
+ mkdirSync3(MEDIA_PATH, { recursive: true });
5138
5358
  log("[bootstrap] Created media/ directory");
5139
5359
  }
5140
- const expertisePath = join6(CONTEXT_DIR, "cc-claw-expertise.md");
5141
- if (!existsSync7(expertisePath)) {
5360
+ const expertisePath = join7(CONTEXT_DIR, "cc-claw-expertise.md");
5361
+ if (!existsSync8(expertisePath)) {
5142
5362
  writeFileSync(expertisePath, DEFAULT_EXPERTISE, "utf-8");
5143
5363
  log("[bootstrap] Created default context/cc-claw-expertise.md");
5144
5364
  }
@@ -5153,13 +5373,13 @@ function bootstrapWorkspaceFiles() {
5153
5373
  "!context/**",
5154
5374
  ""
5155
5375
  ].join("\n");
5156
- const gitignorePath = join6(WORKSPACE_PATH, ".gitignore");
5157
- if (!existsSync7(gitignorePath)) {
5376
+ const gitignorePath = join7(WORKSPACE_PATH, ".gitignore");
5377
+ if (!existsSync8(gitignorePath)) {
5158
5378
  writeFileSync(gitignorePath, IGNORE_CONTENT, "utf-8");
5159
5379
  log("[bootstrap] Created .gitignore (workspace allowlist)");
5160
5380
  }
5161
- const geminiignorePath = join6(WORKSPACE_PATH, ".geminiignore");
5162
- if (!existsSync7(geminiignorePath)) {
5381
+ const geminiignorePath = join7(WORKSPACE_PATH, ".geminiignore");
5382
+ if (!existsSync8(geminiignorePath)) {
5163
5383
  writeFileSync(geminiignorePath, IGNORE_CONTENT, "utf-8");
5164
5384
  log("[bootstrap] Created .geminiignore (workspace allowlist)");
5165
5385
  }
@@ -5185,8 +5405,8 @@ function syncNativeCliFiles() {
5185
5405
  }
5186
5406
  }
5187
5407
  try {
5188
- const soulMtime = existsSync7(SOUL_PATH) ? statSync2(SOUL_PATH).mtimeMs : 0;
5189
- const userMtime = existsSync7(USER_PATH) ? statSync2(USER_PATH).mtimeMs : 0;
5408
+ const soulMtime = existsSync8(SOUL_PATH) ? statSync3(SOUL_PATH).mtimeMs : 0;
5409
+ const userMtime = existsSync8(USER_PATH) ? statSync3(USER_PATH).mtimeMs : 0;
5190
5410
  if (soulMtime > 0 && soulMtime === lastSoulMtime && userMtime === lastUserMtime) {
5191
5411
  return;
5192
5412
  }
@@ -5223,15 +5443,38 @@ function syncNativeCliFiles() {
5223
5443
  "## CRITICAL: Tool Usage Rules",
5224
5444
  "",
5225
5445
  "- Do NOT use native CLI memory/storage tools (save_memory, etc.) \u2014 they are backend-local and invisible to other backends",
5226
- "- Do NOT modify the database directly with SQL (no INSERT/UPDATE/DELETE) \u2014 use CC-Claw commands only",
5227
5446
  "- To save a memory: use /remember in Telegram, or tell the user to use it",
5228
5447
  "- To learn your full CLI: run `cc-claw --ai`",
5229
5448
  "- All state changes must go through the CC-Claw API layer for cross-backend persistence",
5449
+ "",
5450
+ "## \u26D4 DATABASE SAFETY BOUNDARY \u2014 ABSOLUTE PROHIBITION",
5451
+ "",
5452
+ "**NEVER access ~/.cc-claw/data/cc-claw.db directly. No exceptions. No excuses.**",
5453
+ "",
5454
+ "This means ALL of the following are FORBIDDEN:",
5455
+ "- `sqlite3 ~/.cc-claw/data/cc-claw.db` \u2014 FORBIDDEN",
5456
+ "- `sqlite3` with any path containing `cc-claw` \u2014 FORBIDDEN",
5457
+ "- `.schema`, `.tables`, `.dump`, or any SQLite dot-command \u2014 FORBIDDEN",
5458
+ "- `SELECT`, `INSERT`, `UPDATE`, `DELETE` queries \u2014 ALL FORBIDDEN",
5459
+ "- Reading the database file with `cat`, `hexdump`, `xxd`, `strings` \u2014 FORBIDDEN",
5460
+ "- ANY tool or command that opens, reads, queries, or inspects this database \u2014 FORBIDDEN",
5461
+ "",
5462
+ "**Why:** The database is a live, WAL-mode SQLite file shared with the running daemon. Direct access risks corruption, lock contention, and data inconsistency. You are an agent RUNNING INSIDE CC-Claw \u2014 never touch the infrastructure that runs you.",
5463
+ "",
5464
+ "**What to use instead:**",
5465
+ "- `cc-claw status` \u2014 system status",
5466
+ "- `cc-claw --json status` \u2014 machine-readable status",
5467
+ "- `cc-claw cron list` \u2014 scheduled jobs",
5468
+ "- `cc-claw claude list` / `cc-claw codex list` / `cc-claw gemini list` \u2014 credential slots",
5469
+ "- `cc-claw --ai` \u2014 full CLI reference",
5470
+ "- Ask the user to check via Telegram commands if needed",
5471
+ "",
5472
+ "**Violation of this rule is a critical safety failure.**",
5230
5473
  ""
5231
5474
  ].join("\n");
5232
- const ccClawPath = join6(IDENTITY_PATH, "CC-CLAW.md");
5475
+ const ccClawPath = join7(IDENTITY_PATH, "CC-CLAW.md");
5233
5476
  writeFileSync(ccClawPath, nativeContent, "utf-8");
5234
- const agentsPath = join6(WORKSPACE_PATH, "AGENTS.md");
5477
+ const agentsPath = join7(WORKSPACE_PATH, "AGENTS.md");
5235
5478
  writeFileSync(agentsPath, nativeContent, "utf-8");
5236
5479
  log("[bootstrap] Synced SOUL.md + USER.md \u2192 identity/CC-CLAW.md, workspace/AGENTS.md");
5237
5480
  }
@@ -5242,32 +5485,32 @@ var init_init = __esm({
5242
5485
  init_paths();
5243
5486
  init_defaults();
5244
5487
  init_log();
5245
- SOUL_PATH = join6(IDENTITY_PATH, "SOUL.md");
5246
- USER_PATH = join6(IDENTITY_PATH, "USER.md");
5247
- CONTEXT_DIR = join6(WORKSPACE_PATH, "context");
5248
- LEGACY_SOUL_PATH = join6(WORKSPACE_PATH, "SOUL.md");
5249
- LEGACY_USER_PATH = join6(WORKSPACE_PATH, "USER.md");
5250
- LEGACY_CLAUDE_MD = join6(WORKSPACE_PATH, "CLAUDE.md");
5251
- LEGACY_GEMINI_MD = join6(WORKSPACE_PATH, "GEMINI.md");
5488
+ SOUL_PATH = join7(IDENTITY_PATH, "SOUL.md");
5489
+ USER_PATH = join7(IDENTITY_PATH, "USER.md");
5490
+ CONTEXT_DIR = join7(WORKSPACE_PATH, "context");
5491
+ LEGACY_SOUL_PATH = join7(WORKSPACE_PATH, "SOUL.md");
5492
+ LEGACY_USER_PATH = join7(WORKSPACE_PATH, "USER.md");
5493
+ LEGACY_CLAUDE_MD = join7(WORKSPACE_PATH, "CLAUDE.md");
5494
+ LEGACY_GEMINI_MD = join7(WORKSPACE_PATH, "GEMINI.md");
5252
5495
  lastSoulMtime = 0;
5253
5496
  lastUserMtime = 0;
5254
5497
  }
5255
5498
  });
5256
5499
 
5257
5500
  // src/bootstrap/loader.ts
5258
- import { readFileSync as readFileSync3, existsSync as existsSync8, readdirSync as readdirSync2 } from "fs";
5259
- import { join as join7 } from "path";
5501
+ import { readFileSync as readFileSync3, existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
5502
+ import { join as join8 } from "path";
5260
5503
  function searchContext(userMessage) {
5261
- if (!existsSync8(CONTEXT_DIR2)) return null;
5504
+ if (!existsSync9(CONTEXT_DIR2)) return null;
5262
5505
  const msgWords = new Set(
5263
5506
  userMessage.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 3)
5264
5507
  );
5265
5508
  if (msgWords.size === 0) return null;
5266
5509
  let bestMatch = null;
5267
5510
  try {
5268
- const files = readdirSync2(CONTEXT_DIR2).filter((f) => f.endsWith(".md"));
5511
+ const files = readdirSync3(CONTEXT_DIR2).filter((f) => f.endsWith(".md"));
5269
5512
  for (const file of files) {
5270
- const filePath = join7(CONTEXT_DIR2, file);
5513
+ const filePath = join8(CONTEXT_DIR2, file);
5271
5514
  try {
5272
5515
  const content = readFileSync3(filePath, "utf-8").trim();
5273
5516
  if (!content) continue;
@@ -5295,8 +5538,11 @@ function searchContext(userMessage) {
5295
5538
  }
5296
5539
  return null;
5297
5540
  }
5298
- async function assembleBootstrapPrompt(userMessage, tier = "full", chatId, permMode, responseStyle, agentMode, sideQuestContext) {
5541
+ async function assembleBootstrapPrompt(userMessage, tier = "full", chatId, permMode, responseStyle, agentMode, sideQuestContext, planningDirective) {
5299
5542
  const sections = [];
5543
+ if (planningDirective) {
5544
+ sections.push(planningDirective);
5545
+ }
5300
5546
  if (Date.now() - lastSyncMs >= 5e3) {
5301
5547
  syncNativeCliFiles();
5302
5548
  lastSyncMs = Date.now();
@@ -5492,7 +5738,7 @@ var init_loader = __esm({
5492
5738
  init_store();
5493
5739
  init_backends();
5494
5740
  lastSyncMs = 0;
5495
- CONTEXT_DIR2 = join7(WORKSPACE_PATH, "context");
5741
+ CONTEXT_DIR2 = join8(WORKSPACE_PATH, "context");
5496
5742
  MAX_CONTEXT_CHARS = 4e3;
5497
5743
  ACTIVITY_TOKEN_BUDGET = 1500;
5498
5744
  INBOX_TOKEN_BUDGET = 2e3;
@@ -5984,13 +6230,13 @@ var init_quota = __esm({
5984
6230
 
5985
6231
  // src/dashboard/middleware.ts
5986
6232
  import { randomBytes } from "crypto";
5987
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
6233
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync4 } from "fs";
5988
6234
  function getDashboardToken() {
5989
6235
  return DASHBOARD_TOKEN;
5990
6236
  }
5991
6237
  function persistToken() {
5992
6238
  try {
5993
- mkdirSync3(DATA_PATH, { recursive: true });
6239
+ mkdirSync4(DATA_PATH, { recursive: true });
5994
6240
  const tokenPath = `${DATA_PATH}/api-token`;
5995
6241
  writeFileSync2(tokenPath, DASHBOARD_TOKEN, { mode: 384 });
5996
6242
  } catch (err) {
@@ -6677,14 +6923,14 @@ var init_propagate = __esm({
6677
6923
  });
6678
6924
 
6679
6925
  // src/agents/mcp-config.ts
6680
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, existsSync as existsSync9, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
6681
- import { join as join8, dirname } from "path";
6926
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3, existsSync as existsSync10, readdirSync as readdirSync4, unlinkSync as unlinkSync3 } from "fs";
6927
+ import { join as join9, dirname as dirname2 } from "path";
6682
6928
  import { fileURLToPath } from "url";
6683
6929
  function generateOrchestratorMcpConfig(opts) {
6684
6930
  const port = opts.port ?? process.env.DASHBOARD_PORT ?? "3141";
6685
- const distPath = join8(__dirname, "agents", "mcp-server.js");
6686
- const tsxPath = join8(__dirname, "..", "src", "agents", "mcp-server.ts");
6687
- const useTs = !existsSync9(distPath);
6931
+ const distPath = join9(__dirname, "agents", "mcp-server.js");
6932
+ const tsxPath = join9(__dirname, "..", "src", "agents", "mcp-server.ts");
6933
+ const useTs = !existsSync10(distPath);
6688
6934
  return {
6689
6935
  name: opts.agentId === "main" ? "cc-claw" : `cc-claw-${opts.agentId.slice(0, 8)}`,
6690
6936
  transport: "stdio",
@@ -6699,7 +6945,7 @@ function generateOrchestratorMcpConfig(opts) {
6699
6945
  };
6700
6946
  }
6701
6947
  function writeMcpConfigFile(config2) {
6702
- mkdirSync4(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
6948
+ mkdirSync5(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
6703
6949
  const jsonConfig = {
6704
6950
  mcpServers: {
6705
6951
  [config2.name]: {
@@ -6710,13 +6956,13 @@ function writeMcpConfigFile(config2) {
6710
6956
  }
6711
6957
  };
6712
6958
  const safeName = config2.name.replace(/[^a-zA-Z0-9-]/g, "_");
6713
- const configPath = join8(MCP_CONFIG_DIR, `mcp-${safeName}.json`);
6959
+ const configPath = join9(MCP_CONFIG_DIR, `mcp-${safeName}.json`);
6714
6960
  writeFileSync3(configPath, JSON.stringify(jsonConfig, null, 2), { mode: 384 });
6715
6961
  return configPath;
6716
6962
  }
6717
6963
  function deleteMcpConfigFile(mcpName) {
6718
6964
  const safeName = mcpName.replace(/[^a-zA-Z0-9-]/g, "_");
6719
- const configPath = join8(MCP_CONFIG_DIR, `mcp-${safeName}.json`);
6965
+ const configPath = join9(MCP_CONFIG_DIR, `mcp-${safeName}.json`);
6720
6966
  try {
6721
6967
  unlinkSync3(configPath);
6722
6968
  } catch {
@@ -6724,12 +6970,12 @@ function deleteMcpConfigFile(mcpName) {
6724
6970
  }
6725
6971
  function cleanupOrphanedMcpConfigs() {
6726
6972
  try {
6727
- if (!existsSync9(MCP_CONFIG_DIR)) return;
6728
- const files = readdirSync3(MCP_CONFIG_DIR);
6973
+ if (!existsSync10(MCP_CONFIG_DIR)) return;
6974
+ const files = readdirSync4(MCP_CONFIG_DIR);
6729
6975
  for (const file of files) {
6730
6976
  if (file.startsWith("mcp-cc-claw-") && file.endsWith(".json")) {
6731
6977
  try {
6732
- unlinkSync3(join8(MCP_CONFIG_DIR, file));
6978
+ unlinkSync3(join9(MCP_CONFIG_DIR, file));
6733
6979
  } catch {
6734
6980
  }
6735
6981
  }
@@ -6743,8 +6989,8 @@ var init_mcp_config = __esm({
6743
6989
  "use strict";
6744
6990
  init_paths();
6745
6991
  __filename = fileURLToPath(import.meta.url);
6746
- __dirname = dirname(__filename);
6747
- MCP_CONFIG_DIR = join8(CC_CLAW_HOME, "mcp-configs");
6992
+ __dirname = dirname2(__filename);
6993
+ MCP_CONFIG_DIR = join9(CC_CLAW_HOME, "mcp-configs");
6748
6994
  }
6749
6995
  });
6750
6996
 
@@ -6754,8 +7000,8 @@ __export(loader_exports, {
6754
7000
  getTemplate: () => getTemplate,
6755
7001
  listTemplates: () => listTemplates
6756
7002
  });
6757
- import { readdirSync as readdirSync4, readFileSync as readFileSync5 } from "fs";
6758
- import { join as join9 } from "path";
7003
+ import { readdirSync as readdirSync5, readFileSync as readFileSync5 } from "fs";
7004
+ import { join as join10 } from "path";
6759
7005
  function parseFrontmatter(content) {
6760
7006
  const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/m);
6761
7007
  if (!match || match.index !== 0) return { meta: {}, body: content.trim() };
@@ -6788,12 +7034,12 @@ function scanTemplates() {
6788
7034
  templateCache.clear();
6789
7035
  let files;
6790
7036
  try {
6791
- files = readdirSync4(AGENTS_PATH).filter((f) => f.endsWith(".md"));
7037
+ files = readdirSync5(AGENTS_PATH).filter((f) => f.endsWith(".md"));
6792
7038
  } catch {
6793
7039
  return;
6794
7040
  }
6795
7041
  for (const file of files) {
6796
- const filePath = join9(AGENTS_PATH, file);
7042
+ const filePath = join10(AGENTS_PATH, file);
6797
7043
  try {
6798
7044
  const raw = readFileSync5(filePath, "utf-8");
6799
7045
  const { meta, body } = parseFrontmatter(raw);
@@ -6842,8 +7088,8 @@ var init_loader2 = __esm({
6842
7088
  });
6843
7089
 
6844
7090
  // src/agents/agent-log.ts
6845
- import { writeFileSync as writeFileSync4, readdirSync as readdirSync5, statSync as statSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync5 } from "fs";
6846
- import { join as join10 } from "path";
7091
+ import { writeFileSync as writeFileSync4, readdirSync as readdirSync6, statSync as statSync4, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
7092
+ import { join as join11 } from "path";
6847
7093
  function truncate(text, maxBytes) {
6848
7094
  if (Buffer.byteLength(text, "utf-8") <= maxBytes) return text;
6849
7095
  let lo = 0, hi = text.length;
@@ -6858,7 +7104,7 @@ function truncate(text, maxBytes) {
6858
7104
  [...truncated ${droppedBytes} bytes...]`;
6859
7105
  }
6860
7106
  function writeAgentLog(data) {
6861
- const logPath = join10(AGENTS_PATH, `${data.agentId}.log`);
7107
+ const logPath = join11(AGENTS_PATH, `${data.agentId}.log`);
6862
7108
  const exitDisplay = data.exitCodeForced ? `${data.exitCode} (forced \u2014 no output from original exit code 0)` : String(data.exitCode ?? "null");
6863
7109
  const stderrContent = truncate(data.stderr || "(empty)", MAX_STDERR_BYTES);
6864
7110
  const stdoutContent = truncate(data.rawStdoutLines.join("\n") || "(empty)", MAX_STDOUT_BYTES);
@@ -6882,7 +7128,7 @@ function writeAgentLog(data) {
6882
7128
  ""
6883
7129
  ];
6884
7130
  try {
6885
- mkdirSync5(AGENTS_PATH, { recursive: true });
7131
+ mkdirSync6(AGENTS_PATH, { recursive: true });
6886
7132
  writeFileSync4(logPath, lines.join("\n"), "utf-8");
6887
7133
  } catch (err) {
6888
7134
  log(`[agent-log] Failed to write log for ${data.agentId}: ${err}`);
@@ -6891,10 +7137,10 @@ function writeAgentLog(data) {
6891
7137
  }
6892
7138
  function pruneAgentLogs() {
6893
7139
  try {
6894
- mkdirSync5(AGENTS_PATH, { recursive: true });
6895
- const files = readdirSync5(AGENTS_PATH).filter((f) => f.endsWith(".log")).map((f) => {
6896
- const fullPath = join10(AGENTS_PATH, f);
6897
- const stat4 = statSync3(fullPath);
7140
+ mkdirSync6(AGENTS_PATH, { recursive: true });
7141
+ const files = readdirSync6(AGENTS_PATH).filter((f) => f.endsWith(".log")).map((f) => {
7142
+ const fullPath = join11(AGENTS_PATH, f);
7143
+ const stat4 = statSync4(fullPath);
6898
7144
  return { path: fullPath, mtime: stat4.mtimeMs, size: stat4.size };
6899
7145
  });
6900
7146
  const now = Date.now();
@@ -6939,7 +7185,7 @@ var init_agent_log = __esm({
6939
7185
  });
6940
7186
 
6941
7187
  // src/agents/orchestrator.ts
6942
- import { existsSync as existsSync10 } from "fs";
7188
+ import { existsSync as existsSync11 } from "fs";
6943
7189
  async function withRunnerLock(runnerId, fn) {
6944
7190
  const prev = runnerLocks.get(runnerId) ?? Promise.resolve();
6945
7191
  const next = prev.then(fn, () => fn());
@@ -7057,7 +7303,7 @@ async function spawnSubAgent(chatId, opts) {
7057
7303
  async function startAgent(agentId, chatId, opts) {
7058
7304
  const db3 = getDb();
7059
7305
  const runner = getRunner(opts.runner);
7060
- if (opts.cwd && !existsSync10(opts.cwd)) {
7306
+ if (opts.cwd && !existsSync11(opts.cwd)) {
7061
7307
  const msg = `Directory not found: ${opts.cwd}`;
7062
7308
  error(`[orchestrator] Agent ${agentId}: ${msg}`);
7063
7309
  updateAgentStatus(db3, agentId, "failed");
@@ -7079,7 +7325,7 @@ async function startAgent(agentId, chatId, opts) {
7079
7325
  return;
7080
7326
  }
7081
7327
  const exePath = runner.getExecutablePath();
7082
- if (exePath.startsWith("/") && !existsSync10(exePath)) {
7328
+ if (exePath.startsWith("/") && !existsSync11(exePath)) {
7083
7329
  const msg = `Executable not found: ${exePath}`;
7084
7330
  error(`[orchestrator] Agent ${agentId}: ${msg}`);
7085
7331
  updateAgentStatus(db3, agentId, "failed");
@@ -7349,10 +7595,10 @@ async function startAgent(agentId, chatId, opts) {
7349
7595
  function diagnoseSpawnError(err, exePath, cwd) {
7350
7596
  const nodeErr = err;
7351
7597
  if (nodeErr.code === "ENOENT") {
7352
- if (cwd && !existsSync10(cwd)) {
7598
+ if (cwd && !existsSync11(cwd)) {
7353
7599
  return `Directory not found: ${cwd}`;
7354
7600
  }
7355
- if (exePath.startsWith("/") && !existsSync10(exePath)) {
7601
+ if (exePath.startsWith("/") && !existsSync11(exePath)) {
7356
7602
  return `Executable not found: ${exePath}`;
7357
7603
  }
7358
7604
  return `ENOENT spawning ${exePath} (cwd: ${cwd ?? "inherited"}) \u2014 check that both the binary and directory exist`;
@@ -7741,7 +7987,7 @@ var init_registry2 = __esm({
7741
7987
  });
7742
7988
 
7743
7989
  // src/dashboard/routes/orchestrator.ts
7744
- import { existsSync as existsSync11 } from "fs";
7990
+ import { existsSync as existsSync12 } from "fs";
7745
7991
  var handleSpawn, handleCancel, handleCancelAll, handleCreateTask, handleUpdateTask, handleSendMessage, handleReadInbox, handleSetState, handleGetState, handleListState, handleBroadcast, handleListRunners, handleListMcps, handleListTemplates, handleCheckAgent;
7746
7992
  var init_orchestrator2 = __esm({
7747
7993
  "src/dashboard/routes/orchestrator.ts"() {
@@ -7757,7 +8003,7 @@ var init_orchestrator2 = __esm({
7757
8003
  handleSpawn = async (req, res) => {
7758
8004
  try {
7759
8005
  const body = JSON.parse(await readBody(req));
7760
- if (body.cwd && !existsSync11(body.cwd)) {
8006
+ if (body.cwd && !existsSync12(body.cwd)) {
7761
8007
  return jsonResponse(res, { error: `Directory not found: ${body.cwd}` }, 400);
7762
8008
  }
7763
8009
  if (!body.permMode || body.permMode === "inherit") {
@@ -9024,8 +9270,8 @@ __export(analyze_exports, {
9024
9270
  });
9025
9271
  import { spawn as spawn4 } from "child_process";
9026
9272
  import { createInterface as createInterface3 } from "readline";
9027
- import { readFileSync as readFileSync6, existsSync as existsSync12, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
9028
- import { join as join11 } from "path";
9273
+ import { readFileSync as readFileSync6, existsSync as existsSync13, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
9274
+ import { join as join12 } from "path";
9029
9275
  import { homedir as homedir4 } from "os";
9030
9276
  function applySignalDecay(confidence, createdAt) {
9031
9277
  const ageMs = Date.now() - (/* @__PURE__ */ new Date(createdAt + (createdAt.endsWith("Z") ? "" : "Z"))).getTime();
@@ -9034,16 +9280,16 @@ function applySignalDecay(confidence, createdAt) {
9034
9280
  return decayed >= SIGNAL_DECAY_MIN_CONFIDENCE ? Math.round(decayed * 100) / 100 : 0;
9035
9281
  }
9036
9282
  function discoverReflectionTargets() {
9037
- const ccClawHome = join11(homedir4(), ".cc-claw");
9283
+ const ccClawHome = join12(homedir4(), ".cc-claw");
9038
9284
  const targets = [];
9039
9285
  try {
9040
- const skillsDir = join11(ccClawHome, "workspace", "skills");
9041
- if (existsSync12(skillsDir)) {
9042
- for (const entry of readdirSync6(skillsDir)) {
9043
- const entryPath = join11(skillsDir, entry);
9044
- if (!statSync4(entryPath).isDirectory()) continue;
9045
- const skillFile = join11(entryPath, "SKILL.md");
9046
- if (!existsSync12(skillFile)) continue;
9286
+ const skillsDir = join12(ccClawHome, "workspace", "skills");
9287
+ if (existsSync13(skillsDir)) {
9288
+ for (const entry of readdirSync7(skillsDir)) {
9289
+ const entryPath = join12(skillsDir, entry);
9290
+ if (!statSync5(entryPath).isDirectory()) continue;
9291
+ const skillFile = join12(entryPath, "SKILL.md");
9292
+ if (!existsSync13(skillFile)) continue;
9047
9293
  let desc = "skill";
9048
9294
  try {
9049
9295
  const content = readFileSync6(skillFile, "utf-8");
@@ -9057,9 +9303,9 @@ function discoverReflectionTargets() {
9057
9303
  } catch {
9058
9304
  }
9059
9305
  try {
9060
- const contextDir = join11(ccClawHome, "workspace", "context");
9061
- if (existsSync12(contextDir)) {
9062
- for (const entry of readdirSync6(contextDir)) {
9306
+ const contextDir = join12(ccClawHome, "workspace", "context");
9307
+ if (existsSync13(contextDir)) {
9308
+ for (const entry of readdirSync7(contextDir)) {
9063
9309
  if (!entry.endsWith(".md")) continue;
9064
9310
  const name = entry.replace(/\.md$/, "");
9065
9311
  targets.push({ path: `workspace/context/${entry}`, description: `context file: ${name}` });
@@ -9247,7 +9493,7 @@ function resolveReflectionAdapter(chatId) {
9247
9493
  }
9248
9494
  function readIdentityFile(filename) {
9249
9495
  try {
9250
- return readFileSync6(join11(IDENTITY_PATH, filename), "utf-8");
9496
+ return readFileSync6(join12(IDENTITY_PATH, filename), "utf-8");
9251
9497
  } catch {
9252
9498
  return "";
9253
9499
  }
@@ -9395,7 +9641,7 @@ async function runAnalysisImpl(chatId, opts) {
9395
9641
  const availableTargets = discoverReflectionTargets();
9396
9642
  const SKILL_CONTENT_CAP = 15e3;
9397
9643
  const skillContents = [];
9398
- const ccClawHome = join11(homedir4(), ".cc-claw");
9644
+ const ccClawHome = join12(homedir4(), ".cc-claw");
9399
9645
  const signalCorpus = signals.map((s) => s.trigger).join(" ").toLowerCase();
9400
9646
  const convCorpus = (conversations ?? "").toLowerCase();
9401
9647
  const searchCorpus = signalCorpus + " " + convCorpus;
@@ -9408,8 +9654,8 @@ async function runAnalysisImpl(chatId, opts) {
9408
9654
  const isRelevant = searchCorpus.includes(skillNameNorm) || searchCorpus.includes(skillName.toLowerCase()) || descNorm.split(/\s+/).some((word) => word.length > 4 && searchCorpus.includes(word));
9409
9655
  if (!isRelevant) continue;
9410
9656
  try {
9411
- const fullPath = join11(ccClawHome, target.path);
9412
- if (existsSync12(fullPath)) {
9657
+ const fullPath = join12(ccClawHome, target.path);
9658
+ if (existsSync13(fullPath)) {
9413
9659
  const content = readFileSync6(fullPath, "utf-8");
9414
9660
  if (totalSkillChars + content.length > SKILL_CONTENT_CAP) break;
9415
9661
  skillContents.push({ path: target.path, content });
@@ -9615,8 +9861,8 @@ __export(apply_exports, {
9615
9861
  isTargetAllowed: () => isTargetAllowed,
9616
9862
  rollbackInsight: () => rollbackInsight
9617
9863
  });
9618
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync13, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync5 } from "fs";
9619
- import { join as join12, dirname as dirname2 } from "path";
9864
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync8, unlinkSync as unlinkSync5 } from "fs";
9865
+ import { join as join13, dirname as dirname3 } from "path";
9620
9866
  function isTargetAllowed(relativePath) {
9621
9867
  if (relativePath.includes("..")) return false;
9622
9868
  if (!relativePath.endsWith(".md")) return false;
@@ -9667,10 +9913,10 @@ function applyDiff(original, diff, action) {
9667
9913
  return original;
9668
9914
  }
9669
9915
  function pruneBackups(absolutePath) {
9670
- const dir = dirname2(absolutePath);
9916
+ const dir = dirname3(absolutePath);
9671
9917
  const baseName = absolutePath.split("/").pop() ?? "";
9672
9918
  try {
9673
- const backups = readdirSync7(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join12(dir, f));
9919
+ const backups = readdirSync8(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join13(dir, f));
9674
9920
  while (backups.length > MAX_BACKUPS_PER_FILE) {
9675
9921
  const oldest = backups.shift();
9676
9922
  try {
@@ -9696,9 +9942,9 @@ async function applyInsight(insightId) {
9696
9942
  if (!isTargetAllowed(insight.targetFile)) {
9697
9943
  return { success: false, message: `Target file "${insight.targetFile}" is not in the allowed list` };
9698
9944
  }
9699
- const absolutePath = join12(CC_CLAW_HOME, insight.targetFile);
9945
+ const absolutePath = join13(CC_CLAW_HOME, insight.targetFile);
9700
9946
  if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
9701
- if (existsSync13(absolutePath)) {
9947
+ if (existsSync14(absolutePath)) {
9702
9948
  const currentContent = readFileSync7(absolutePath, "utf-8");
9703
9949
  const lineCount = currentContent.split("\n").length;
9704
9950
  if (lineCount >= SOUL_LINE_CAP) {
@@ -9720,7 +9966,7 @@ async function applyInsight(insightId) {
9720
9966
  };
9721
9967
  }
9722
9968
  let original = "";
9723
- if (existsSync13(absolutePath)) {
9969
+ if (existsSync14(absolutePath)) {
9724
9970
  original = readFileSync7(absolutePath, "utf-8");
9725
9971
  } else if (insight.proposedAction !== "create") {
9726
9972
  return { success: false, message: `Target file "${insight.targetFile}" does not exist` };
@@ -9728,9 +9974,9 @@ async function applyInsight(insightId) {
9728
9974
  const timestamp = Date.now();
9729
9975
  const backupPath = absolutePath + `.bak.${timestamp}`;
9730
9976
  try {
9731
- const parentDir = dirname2(absolutePath);
9732
- if (!existsSync13(parentDir)) {
9733
- mkdirSync6(parentDir, { recursive: true });
9977
+ const parentDir = dirname3(absolutePath);
9978
+ if (!existsSync14(parentDir)) {
9979
+ mkdirSync7(parentDir, { recursive: true });
9734
9980
  }
9735
9981
  if (original) {
9736
9982
  writeFileSync5(backupPath, original, "utf-8");
@@ -9793,7 +10039,7 @@ async function rollbackInsight(insightId) {
9793
10039
  } catch {
9794
10040
  return { success: false, message: `Insight #${insightId} has malformed rollback data` };
9795
10041
  }
9796
- const absolutePath = join12(CC_CLAW_HOME, insight.targetFile);
10042
+ const absolutePath = join13(CC_CLAW_HOME, insight.targetFile);
9797
10043
  try {
9798
10044
  writeFileSync5(absolutePath, rollback.original, "utf-8");
9799
10045
  updateInsightStatus(db3, insightId, "rolled_back");
@@ -9826,8 +10072,8 @@ function calculateDrift(chatId) {
9826
10072
  if (!row || !row.baselineSoulMd && !row.baselineUserMd) {
9827
10073
  return null;
9828
10074
  }
9829
- const soulPath = join12(CC_CLAW_HOME, "identity/SOUL.md");
9830
- const userPath = join12(CC_CLAW_HOME, "identity/USER.md");
10075
+ const soulPath = join13(CC_CLAW_HOME, "identity/SOUL.md");
10076
+ const userPath = join13(CC_CLAW_HOME, "identity/USER.md");
9831
10077
  const soulDrift = computeLineDrift(row.baselineSoulMd, soulPath);
9832
10078
  const userDrift = computeLineDrift(row.baselineUserMd, userPath);
9833
10079
  return { soulDrift, userDrift };
@@ -9836,7 +10082,7 @@ function computeLineDrift(baseline, absolutePath) {
9836
10082
  if (!baseline) return 0;
9837
10083
  let current = "";
9838
10084
  try {
9839
- if (existsSync13(absolutePath)) {
10085
+ if (existsSync14(absolutePath)) {
9840
10086
  current = readFileSync7(absolutePath, "utf-8");
9841
10087
  }
9842
10088
  } catch {
@@ -9932,11 +10178,11 @@ var init_evolve = __esm({
9932
10178
  const body = JSON.parse(await readBody(req));
9933
10179
  const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
9934
10180
  const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
9935
- const { join: join29 } = await import("path");
10181
+ const { join: join30 } = await import("path");
9936
10182
  const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
9937
10183
  const chatId = body.chatId || (process.env.ALLOWED_CHAT_ID ?? "").split(",")[0]?.trim() || "default";
9938
- const soulPath = join29(home, "identity/SOUL.md");
9939
- const userPath = join29(home, "identity/USER.md");
10184
+ const soulPath = join30(home, "identity/SOUL.md");
10185
+ const userPath = join30(home, "identity/USER.md");
9940
10186
  const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
9941
10187
  const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
9942
10188
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -10882,7 +11128,7 @@ function askAgent(chatId, userMessage, opts) {
10882
11128
  return withChatLock(chatId, () => askAgentImpl(chatId, userMessage, opts));
10883
11129
  }
10884
11130
  async function askAgentImpl(chatId, userMessage, opts) {
10885
- const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, onModelDowngrade, agentMode: optsAgentMode, onSubagentActivity, settingsSourceChatId } = opts ?? {};
11131
+ const { cwd, onStream, model: model2, backend: backend2, permMode, onToolAction, bootstrapTier, timeoutMs, maxTurns, onSlotRotation, onModelDowngrade, agentMode: optsAgentMode, onSubagentActivity, settingsSourceChatId, planningDirective } = opts ?? {};
10886
11132
  const settingsChat = settingsSourceChatId ?? chatId;
10887
11133
  const adapter = backend2 ? getAdapter(backend2) : getAdapterForChat(settingsChat);
10888
11134
  const mode = permMode ?? getMode(settingsChat);
@@ -10892,7 +11138,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
10892
11138
  const tier = bootstrapTier ?? "full";
10893
11139
  const effectiveAgentMode = optsAgentMode ?? getAgentMode(settingsChat);
10894
11140
  const sideQuestCtx = settingsSourceChatId ? { parentChatId: settingsSourceChatId, actualChatId: chatId } : void 0;
10895
- const fullPrompt = await assembleBootstrapPrompt(userMessage, tier, settingsChat, mode, responseStyle, effectiveAgentMode, sideQuestCtx);
11141
+ const fullPrompt = await assembleBootstrapPrompt(userMessage, tier, settingsChat, mode, responseStyle, effectiveAgentMode, sideQuestCtx, planningDirective);
10896
11142
  const existingSessionId = settingsSourceChatId ? null : getSessionId(settingsChat);
10897
11143
  const allowedTools = getEnabledTools(settingsChat);
10898
11144
  const mcpConfigPath = tier !== "slim" && effectiveAgentMode !== "native" && MCP_CONFIG_FLAG[adapter.id] ? getMcpConfigPath(chatId) : null;
@@ -11494,9 +11740,9 @@ function buildReviewCompleteMessage(results) {
11494
11740
 
11495
11741
  Skipped proposals will appear in your next review.`;
11496
11742
  }
11497
- function formatNightlySummary(insights) {
11498
- const count = insights.length;
11499
- const header2 = `Nightly Reflection \u2014 ${count} proposal${count === 1 ? "" : "s"} ready`;
11743
+ function formatNightlySummary(insights, totalPending) {
11744
+ const displayCount = totalPending ?? insights.length;
11745
+ const header2 = `Nightly Reflection \u2014 ${displayCount} proposal${displayCount === 1 ? "" : "s"} ready`;
11500
11746
  const list = insights.map((ins, i) => `${i + 1}. [${ins.category}] ${ins.insight}`).join("\n");
11501
11747
  return `${header2}
11502
11748
 
@@ -11607,8 +11853,8 @@ var init_propose = __esm({
11607
11853
  });
11608
11854
 
11609
11855
  // src/bootstrap/profile.ts
11610
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync14 } from "fs";
11611
- import { join as join13 } from "path";
11856
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync15 } from "fs";
11857
+ import { join as join14 } from "path";
11612
11858
  function hasActiveProfile(chatId) {
11613
11859
  return activeProfiles.has(chatId);
11614
11860
  }
@@ -11737,7 +11983,7 @@ function extractUserUpdates(text) {
11737
11983
  return { cleanText, updates };
11738
11984
  }
11739
11985
  function appendToUserProfile(key, value) {
11740
- if (!existsSync14(USER_PATH2)) return;
11986
+ if (!existsSync15(USER_PATH2)) return;
11741
11987
  const content = readFileSync8(USER_PATH2, "utf-8");
11742
11988
  const line = `- **${key}**: ${value}`;
11743
11989
  if (content.includes(line)) return;
@@ -11753,7 +11999,7 @@ var init_profile = __esm({
11753
11999
  "use strict";
11754
12000
  init_paths();
11755
12001
  init_log();
11756
- USER_PATH2 = join13(IDENTITY_PATH, "USER.md");
12002
+ USER_PATH2 = join14(IDENTITY_PATH, "USER.md");
11757
12003
  activeProfiles = /* @__PURE__ */ new Map();
11758
12004
  }
11759
12005
  });
@@ -12584,6 +12830,88 @@ var init_classify2 = __esm({
12584
12830
  }
12585
12831
  });
12586
12832
 
12833
+ // src/execution/gate.ts
12834
+ function shouldRequireApproval(input) {
12835
+ if (input.execMode !== "approved") return false;
12836
+ if (input.intent !== "agentic") return false;
12837
+ if (input.isResuming) return false;
12838
+ if (input.messageText.startsWith(">>")) return false;
12839
+ if (EXEMPT_TIERS.has(input.bootstrapTier)) return false;
12840
+ if (input.isSideQuest) return false;
12841
+ return true;
12842
+ }
12843
+ function buildPlanningDirective() {
12844
+ return [
12845
+ "## PLANNING MODE \u2014 Read-Only",
12846
+ "",
12847
+ "You are in PLANNING mode. Your goal is to research and present a plan.",
12848
+ "",
12849
+ "**ALLOWED:**",
12850
+ "- Read files, directories, and code",
12851
+ "- Load and read skills",
12852
+ "- Search the codebase (grep, glob, find)",
12853
+ "- Search the web for documentation or solutions",
12854
+ "- Analyze and reason about architecture",
12855
+ "",
12856
+ "**NOT ALLOWED:**",
12857
+ "- Do NOT create, modify, or delete any files",
12858
+ "- Do NOT run shell commands that mutate state",
12859
+ "- Do NOT write code or make edits",
12860
+ "- Do NOT install packages or dependencies",
12861
+ "",
12862
+ "**YOUR TASK:**",
12863
+ "Research the request thoroughly, then present a clear, concise plan",
12864
+ "of what you will do. The user will review and approve before you execute.",
12865
+ "Structure your plan with numbered steps and be specific about which",
12866
+ "files you will modify and what changes you will make."
12867
+ ].join("\n");
12868
+ }
12869
+ function storePendingPlan(chatId, plan, originalMessage) {
12870
+ pendingPlans.set(chatId, {
12871
+ plan,
12872
+ originalMessage,
12873
+ createdAt: Date.now()
12874
+ });
12875
+ }
12876
+ function getPendingPlan(chatId) {
12877
+ const entry = pendingPlans.get(chatId);
12878
+ if (!entry) return void 0;
12879
+ if (Date.now() - entry.createdAt > PLAN_TTL_MS) {
12880
+ pendingPlans.delete(chatId);
12881
+ return void 0;
12882
+ }
12883
+ return entry;
12884
+ }
12885
+ function removePendingPlan(chatId) {
12886
+ pendingPlans.delete(chatId);
12887
+ }
12888
+ function setRejectionMode(chatId) {
12889
+ rejectionModes.set(chatId, Date.now());
12890
+ }
12891
+ function getRejectionMode(chatId) {
12892
+ const createdAt = rejectionModes.get(chatId);
12893
+ if (createdAt === void 0) return false;
12894
+ if (Date.now() - createdAt > REJECTION_TTL_MS) {
12895
+ rejectionModes.delete(chatId);
12896
+ return false;
12897
+ }
12898
+ return true;
12899
+ }
12900
+ function clearRejectionMode(chatId) {
12901
+ rejectionModes.delete(chatId);
12902
+ }
12903
+ var EXEMPT_TIERS, PLAN_TTL_MS, pendingPlans, REJECTION_TTL_MS, rejectionModes;
12904
+ var init_gate = __esm({
12905
+ "src/execution/gate.ts"() {
12906
+ "use strict";
12907
+ EXEMPT_TIERS = /* @__PURE__ */ new Set(["slim", "heartbeat", "chat"]);
12908
+ PLAN_TTL_MS = 5 * 60 * 1e3;
12909
+ pendingPlans = /* @__PURE__ */ new Map();
12910
+ REJECTION_TTL_MS = 5 * 60 * 1e3;
12911
+ rejectionModes = /* @__PURE__ */ new Map();
12912
+ }
12913
+ });
12914
+
12587
12915
  // src/router/helpers.ts
12588
12916
  import { resolve as resolvePath } from "path";
12589
12917
  function parseMcpListOutput(output2) {
@@ -13284,9 +13612,9 @@ var init_stt = __esm({
13284
13612
  });
13285
13613
 
13286
13614
  // src/media/image-gen.ts
13287
- import { mkdirSync as mkdirSync7, existsSync as existsSync15, unlink as unlink2, readdir, stat } from "fs";
13615
+ import { mkdirSync as mkdirSync8, existsSync as existsSync16, unlink as unlink2, readdir, stat } from "fs";
13288
13616
  import { writeFile } from "fs/promises";
13289
- import { join as join14 } from "path";
13617
+ import { join as join15 } from "path";
13290
13618
  async function generateImage(prompt) {
13291
13619
  const apiKey = process.env.GEMINI_API_KEY;
13292
13620
  if (!apiKey) {
@@ -13333,12 +13661,12 @@ async function generateImage(prompt) {
13333
13661
  if (!imageData) {
13334
13662
  throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
13335
13663
  }
13336
- if (!existsSync15(IMAGE_OUTPUT_DIR)) {
13337
- mkdirSync7(IMAGE_OUTPUT_DIR, { recursive: true });
13664
+ if (!existsSync16(IMAGE_OUTPUT_DIR)) {
13665
+ mkdirSync8(IMAGE_OUTPUT_DIR, { recursive: true });
13338
13666
  }
13339
13667
  const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
13340
13668
  const filename = `img_${Date.now()}.${ext}`;
13341
- const filePath = join14(IMAGE_OUTPUT_DIR, filename);
13669
+ const filePath = join15(IMAGE_OUTPUT_DIR, filename);
13342
13670
  const buffer = Buffer.from(imageData, "base64");
13343
13671
  await writeFile(filePath, buffer);
13344
13672
  log(`[image-gen] Saved ${buffer.length} bytes to ${filePath}`);
@@ -13356,7 +13684,7 @@ function cleanupGeneratedImage(filePath) {
13356
13684
  function pruneImageCache() {
13357
13685
  readdir(IMAGE_OUTPUT_DIR, (err, files) => {
13358
13686
  if (err || !files) return;
13359
- const imageFiles = files.filter((f) => /\.(png|jpg)$/.test(f)).map((f) => join14(IMAGE_OUTPUT_DIR, f));
13687
+ const imageFiles = files.filter((f) => /\.(png|jpg)$/.test(f)).map((f) => join15(IMAGE_OUTPUT_DIR, f));
13360
13688
  if (imageFiles.length === 0) return;
13361
13689
  const now = Date.now();
13362
13690
  let statsPending = imageFiles.length;
@@ -13388,8 +13716,8 @@ var init_image_gen = __esm({
13388
13716
  MAX_GENERATED_IMAGES = 20;
13389
13717
  IMAGE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
13390
13718
  IMAGE_MODEL = "gemini-3.1-flash-image-preview";
13391
- IMAGE_OUTPUT_DIR = join14(
13392
- process.env.CC_CLAW_HOME ?? join14(process.env.HOME ?? "/tmp", ".cc-claw"),
13719
+ IMAGE_OUTPUT_DIR = join15(
13720
+ process.env.CC_CLAW_HOME ?? join15(process.env.HOME ?? "/tmp", ".cc-claw"),
13393
13721
  "data",
13394
13722
  "images"
13395
13723
  );
@@ -13862,7 +14190,7 @@ var init_video = __esm({
13862
14190
  });
13863
14191
 
13864
14192
  // src/router/media.ts
13865
- import { join as join15 } from "path";
14193
+ import { join as join16 } from "path";
13866
14194
  import { mkdir, writeFile as writeFile2, readdir as readdir2, stat as stat2, unlink as unlink3 } from "fs/promises";
13867
14195
  function getMediaRetentionMs() {
13868
14196
  const hours = parseInt(process.env.MEDIA_RETENTION_HOURS ?? "24", 10);
@@ -13871,7 +14199,7 @@ function getMediaRetentionMs() {
13871
14199
  async function saveMedia(buffer, prefix, ext) {
13872
14200
  await mkdir(MEDIA_INCOMING_PATH, { recursive: true });
13873
14201
  const filename = `${prefix}-${Date.now()}.${ext}`;
13874
- const fullPath = join15(MEDIA_INCOMING_PATH, filename);
14202
+ const fullPath = join16(MEDIA_INCOMING_PATH, filename);
13875
14203
  await writeFile2(fullPath, buffer);
13876
14204
  return fullPath;
13877
14205
  }
@@ -13885,7 +14213,7 @@ async function cleanupOldMedia() {
13885
14213
  let removed = 0;
13886
14214
  for (const file of files) {
13887
14215
  try {
13888
- const filePath = join15(MEDIA_INCOMING_PATH, file);
14216
+ const filePath = join16(MEDIA_INCOMING_PATH, file);
13889
14217
  const s = await stat2(filePath);
13890
14218
  if (now - s.mtimeMs > retentionMs) {
13891
14219
  await unlink3(filePath);
@@ -14068,7 +14396,7 @@ var init_media = __esm({
14068
14396
  init_store5();
14069
14397
  init_helpers();
14070
14398
  init_response();
14071
- MEDIA_INCOMING_PATH = join15(MEDIA_PATH, "incoming");
14399
+ MEDIA_INCOMING_PATH = join16(MEDIA_PATH, "incoming");
14072
14400
  }
14073
14401
  });
14074
14402
 
@@ -14204,7 +14532,7 @@ __export(discover_exports, {
14204
14532
  import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
14205
14533
  import { createHash } from "crypto";
14206
14534
  import { homedir as homedir5 } from "os";
14207
- import { join as join16 } from "path";
14535
+ import { join as join17 } from "path";
14208
14536
  function invalidateSkillCache() {
14209
14537
  cachedSkills = null;
14210
14538
  cacheTimestamp = 0;
@@ -14222,7 +14550,7 @@ async function discoverAllSkills() {
14222
14550
  const rawSkills = [];
14223
14551
  rawSkills.push(...await scanSkillDir(SKILLS_PATH, "cc-claw"));
14224
14552
  for (const backendId of getAllBackendIds()) {
14225
- const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join16(homedir5(), `.${backendId}`, "skills")];
14553
+ const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join17(homedir5(), `.${backendId}`, "skills")];
14226
14554
  for (const dir of dirs) {
14227
14555
  rawSkills.push(...await scanSkillDir(dir, backendId));
14228
14556
  }
@@ -14250,7 +14578,7 @@ async function scanSkillDir(skillsDir, source) {
14250
14578
  let content;
14251
14579
  let resolvedPath;
14252
14580
  for (const candidate of SKILL_FILE_CANDIDATES) {
14253
- const p = join16(skillsDir, entry.name, candidate);
14581
+ const p = join17(skillsDir, entry.name, candidate);
14254
14582
  try {
14255
14583
  content = await readFile4(p, "utf-8");
14256
14584
  resolvedPath = p;
@@ -14354,15 +14682,15 @@ var init_discover = __esm({
14354
14682
  init_backends();
14355
14683
  SKILL_FILE_CANDIDATES = ["SKILL.md", "skill.md"];
14356
14684
  BACKEND_SKILL_DIRS = {
14357
- claude: [join16(homedir5(), ".claude", "skills")],
14358
- gemini: [join16(homedir5(), ".gemini", "skills")],
14685
+ claude: [join17(homedir5(), ".claude", "skills")],
14686
+ gemini: [join17(homedir5(), ".gemini", "skills")],
14359
14687
  codex: [
14360
- join16(homedir5(), ".agents", "skills"),
14361
- join16(homedir5(), ".codex", "skills")
14688
+ join17(homedir5(), ".agents", "skills"),
14689
+ join17(homedir5(), ".codex", "skills")
14362
14690
  ],
14363
14691
  cursor: [
14364
- join16(homedir5(), ".cursor", "skills"),
14365
- join16(homedir5(), ".cursor", "skills-cursor")
14692
+ join17(homedir5(), ".cursor", "skills"),
14693
+ join17(homedir5(), ".cursor", "skills-cursor")
14366
14694
  ]
14367
14695
  };
14368
14696
  CACHE_TTL_MS2 = 3e5;
@@ -14378,8 +14706,8 @@ __export(install_exports, {
14378
14706
  installSkillFromGitHub: () => installSkillFromGitHub
14379
14707
  });
14380
14708
  import { mkdir as mkdir2, readdir as readdir4, readFile as readFile5, cp } from "fs/promises";
14381
- import { existsSync as existsSync16 } from "fs";
14382
- import { join as join17, basename } from "path";
14709
+ import { existsSync as existsSync17 } from "fs";
14710
+ import { join as join18, basename } from "path";
14383
14711
  import { execSync as execSync5 } from "child_process";
14384
14712
  async function installSkillFromGitHub(urlOrShorthand) {
14385
14713
  let repoUrl;
@@ -14390,36 +14718,36 @@ async function installSkillFromGitHub(urlOrShorthand) {
14390
14718
  }
14391
14719
  repoUrl = parsed.cloneUrl;
14392
14720
  subPath = parsed.subPath;
14393
- const tmpDir = join17("/tmp", `cc-claw-skill-${Date.now()}`);
14721
+ const tmpDir = join18("/tmp", `cc-claw-skill-${Date.now()}`);
14394
14722
  try {
14395
14723
  log(`[skill-install] Cloning ${repoUrl} to ${tmpDir}`);
14396
14724
  execSync5(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
14397
14725
  stdio: "pipe",
14398
14726
  timeout: 3e4
14399
14727
  });
14400
- if (!existsSync16(join17(tmpDir, ".git"))) {
14728
+ if (!existsSync17(join18(tmpDir, ".git"))) {
14401
14729
  return { success: false, error: "Git clone failed: no .git directory produced" };
14402
14730
  }
14403
- const searchRoot = subPath ? join17(tmpDir, subPath) : tmpDir;
14731
+ const searchRoot = subPath ? join18(tmpDir, subPath) : tmpDir;
14404
14732
  const skillDir = await findSkillDir(searchRoot);
14405
14733
  if (!skillDir) {
14406
14734
  return { success: false, error: "No SKILL.md found in the repository." };
14407
14735
  }
14408
14736
  const skillFolderName = basename(skillDir);
14409
- const destDir = join17(SKILLS_PATH, skillFolderName);
14410
- if (existsSync16(destDir)) {
14737
+ const destDir = join18(SKILLS_PATH, skillFolderName);
14738
+ if (existsSync17(destDir)) {
14411
14739
  log(`[skill-install] Overwriting existing skill at ${destDir}`);
14412
14740
  }
14413
14741
  await mkdir2(destDir, { recursive: true });
14414
14742
  await cp(skillDir, destDir, { recursive: true });
14415
14743
  let skillName = skillFolderName;
14416
14744
  try {
14417
- const content = await readFile5(join17(destDir, "SKILL.md"), "utf-8");
14745
+ const content = await readFile5(join18(destDir, "SKILL.md"), "utf-8");
14418
14746
  const nameMatch = content.match(/^name:\s*(.+)$/m);
14419
14747
  if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
14420
14748
  } catch {
14421
14749
  try {
14422
- const content = await readFile5(join17(destDir, "skill.md"), "utf-8");
14750
+ const content = await readFile5(join18(destDir, "skill.md"), "utf-8");
14423
14751
  const nameMatch = content.match(/^name:\s*(.+)$/m);
14424
14752
  if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
14425
14753
  } catch {
@@ -14454,15 +14782,15 @@ function parseGitHubUrl(input) {
14454
14782
  async function findSkillDir(root) {
14455
14783
  const candidates = ["SKILL.md", "skill.md"];
14456
14784
  for (const c of candidates) {
14457
- if (existsSync16(join17(root, c))) return root;
14785
+ if (existsSync17(join18(root, c))) return root;
14458
14786
  }
14459
14787
  try {
14460
14788
  const entries = await readdir4(root, { withFileTypes: true });
14461
14789
  for (const entry of entries) {
14462
14790
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
14463
14791
  for (const c of candidates) {
14464
- if (existsSync16(join17(root, entry.name, c))) {
14465
- return join17(root, entry.name);
14792
+ if (existsSync17(join18(root, entry.name, c))) {
14793
+ return join18(root, entry.name);
14466
14794
  }
14467
14795
  }
14468
14796
  }
@@ -14474,15 +14802,15 @@ async function findSkillDir(root) {
14474
14802
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
14475
14803
  let subEntries;
14476
14804
  try {
14477
- subEntries = await readdir4(join17(root, entry.name), { withFileTypes: true });
14805
+ subEntries = await readdir4(join18(root, entry.name), { withFileTypes: true });
14478
14806
  } catch {
14479
14807
  continue;
14480
14808
  }
14481
14809
  for (const sub of subEntries) {
14482
14810
  if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
14483
14811
  for (const c of candidates) {
14484
- if (existsSync16(join17(root, entry.name, sub.name, c))) {
14485
- return join17(root, entry.name, sub.name);
14812
+ if (existsSync17(join18(root, entry.name, sub.name, c))) {
14813
+ return join18(root, entry.name, sub.name);
14486
14814
  }
14487
14815
  }
14488
14816
  }
@@ -14500,8 +14828,8 @@ var init_install = __esm({
14500
14828
  });
14501
14829
 
14502
14830
  // src/bootstrap/heartbeat.ts
14503
- import { readFileSync as readFileSync9, existsSync as existsSync17 } from "fs";
14504
- import { join as join18 } from "path";
14831
+ import { readFileSync as readFileSync9, existsSync as existsSync18 } from "fs";
14832
+ import { join as join19 } from "path";
14505
14833
  function initHeartbeat(channelReg) {
14506
14834
  registry2 = channelReg;
14507
14835
  }
@@ -14639,7 +14967,7 @@ ${healthLines.join("\n")}`);
14639
14967
  sections.push(`[Active watches]
14640
14968
  ${watchLines.join("\n")}`);
14641
14969
  }
14642
- if (existsSync17(HEARTBEAT_MD_PATH)) {
14970
+ if (existsSync18(HEARTBEAT_MD_PATH)) {
14643
14971
  try {
14644
14972
  const custom = readFileSync9(HEARTBEAT_MD_PATH, "utf-8").trim();
14645
14973
  if (custom) {
@@ -14687,7 +15015,7 @@ var init_heartbeat2 = __esm({
14687
15015
  init_backends();
14688
15016
  init_health2();
14689
15017
  init_log();
14690
- HEARTBEAT_MD_PATH = join18(WORKSPACE_PATH, "HEARTBEAT.md");
15018
+ HEARTBEAT_MD_PATH = join19(WORKSPACE_PATH, "HEARTBEAT.md");
14691
15019
  HEARTBEAT_OK = "HEARTBEAT_OK";
14692
15020
  registry2 = null;
14693
15021
  activeTimers = /* @__PURE__ */ new Map();
@@ -15744,9 +16072,9 @@ async function handleEvolveCallback(chatId, data, channel) {
15744
16072
  await channel.sendText(chatId, "No pending proposals.", { parseMode: "plain" });
15745
16073
  } else {
15746
16074
  const insightIds = pending.slice(0, 5).map((p) => p.id);
15747
- createReviewSession2(getDb(), reflChatId, insightIds);
16075
+ createReviewSession2(getDb(), chatId, insightIds);
15748
16076
  await channel.sendText(chatId, `${pending.length} proposal(s) ready. Let's review them one by one.`, { parseMode: "plain" });
15749
- await sendCurrentProposal(reflChatId, channel);
16077
+ await sendCurrentProposal(chatId, channel);
15750
16078
  }
15751
16079
  break;
15752
16080
  }
@@ -15904,13 +16232,13 @@ async function handleEvolveCallback(chatId, data, channel) {
15904
16232
  const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
15905
16233
  const current = getReflectionStatus2(getDb(), chatId);
15906
16234
  if (current === "frozen") {
15907
- const { readFileSync: readFileSync22, existsSync: existsSync49 } = await import("fs");
15908
- const { join: join29 } = await import("path");
16235
+ const { readFileSync: readFileSync22, existsSync: existsSync50 } = await import("fs");
16236
+ const { join: join30 } = await import("path");
15909
16237
  const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
15910
- const soulPath = join29(CC_CLAW_HOME3, "identity/SOUL.md");
15911
- const userPath = join29(CC_CLAW_HOME3, "identity/USER.md");
15912
- const soul = existsSync49(soulPath) ? readFileSync22(soulPath, "utf-8") : "";
15913
- const user = existsSync49(userPath) ? readFileSync22(userPath, "utf-8") : "";
16238
+ const soulPath = join30(CC_CLAW_HOME3, "identity/SOUL.md");
16239
+ const userPath = join30(CC_CLAW_HOME3, "identity/USER.md");
16240
+ const soul = existsSync50(soulPath) ? readFileSync22(soulPath, "utf-8") : "";
16241
+ const user = existsSync50(userPath) ? readFileSync22(userPath, "utf-8") : "";
15914
16242
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
15915
16243
  const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
15916
16244
  logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
@@ -16063,6 +16391,29 @@ ${cmds.map((c) => ` ${c.cmd} \u2014 ${c.desc}`).join("\n")}`
16063
16391
  }
16064
16392
  break;
16065
16393
  }
16394
+ case "mode":
16395
+ case "execmode": {
16396
+ const currentExecMode = getExecMode(chatId);
16397
+ const EXEC_MODES = {
16398
+ approved: "\u2705 Approved \u2014 AI shows a plan before acting",
16399
+ yolo: "\u26A1 YOLO \u2014 AI executes immediately"
16400
+ };
16401
+ if (typeof channel.sendKeyboard === "function") {
16402
+ const buttons = Object.entries(EXEC_MODES).map(([id, label2]) => [{
16403
+ label: `${id === currentExecMode ? "\u2713 " : ""}${label2}`,
16404
+ data: `execmode:${id}`,
16405
+ ...id === currentExecMode ? { style: "primary" } : {}
16406
+ }]);
16407
+ await channel.sendKeyboard(chatId, `Execution mode (current: <b>${currentExecMode}</b>):`, buttons);
16408
+ } else {
16409
+ const lines = ["Execution modes:", ""];
16410
+ for (const [id, label2] of Object.entries(EXEC_MODES)) {
16411
+ lines.push(`${id === currentExecMode ? "\u2713 " : " "}/mode ${id} \u2014 ${label2}`);
16412
+ }
16413
+ await channel.sendText(chatId, lines.join("\n"), { parseMode: "plain" });
16414
+ }
16415
+ break;
16416
+ }
16066
16417
  case "verbose": {
16067
16418
  const currentVerbose = getVerboseLevel(chatId);
16068
16419
  const buttons = Object.entries(VERBOSE_LEVELS).map(([id, label2]) => [{
@@ -17771,6 +18122,54 @@ ${PERM_MODES[chosen]}`,
17771
18122
  await channel.sendText(chatId, `Agent mode set to <b>${mode}</b>. Session cleared.`, { parseMode: "html" });
17772
18123
  }
17773
18124
  return;
18125
+ } else if (data === "exec:approve") {
18126
+ const plan = getPendingPlan(chatId);
18127
+ if (!plan) {
18128
+ await channel.sendText(chatId, "\u26A0\uFE0F Plan expired or already processed.", { parseMode: "plain" });
18129
+ return;
18130
+ }
18131
+ removePendingPlan(chatId);
18132
+ await channel.sendText(chatId, "\u2705 Approved. Executing...", { parseMode: "plain" });
18133
+ const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
18134
+ await handleMessage2(
18135
+ { text: `>>${plan.originalMessage}`, chatId, source: "telegram", type: "text", senderName: "", messageId: "" },
18136
+ channel
18137
+ );
18138
+ return;
18139
+ } else if (data === "exec:reject") {
18140
+ const plan = getPendingPlan(chatId);
18141
+ if (!plan) {
18142
+ await channel.sendText(chatId, "\u26A0\uFE0F Plan expired or already processed.", { parseMode: "plain" });
18143
+ return;
18144
+ }
18145
+ removePendingPlan(chatId);
18146
+ setRejectionMode(chatId);
18147
+ await channel.sendText(chatId, "\u270F\uFE0F Plan rejected. Send your feedback and I'll revise the plan.", { parseMode: "plain" });
18148
+ return;
18149
+ } else if (data === "exec:yolo") {
18150
+ const plan = getPendingPlan(chatId);
18151
+ if (!plan) {
18152
+ await channel.sendText(chatId, "\u26A0\uFE0F Plan expired or already processed.", { parseMode: "plain" });
18153
+ return;
18154
+ }
18155
+ removePendingPlan(chatId);
18156
+ setExecMode(chatId, "yolo");
18157
+ await channel.sendText(chatId, "\u26A1 Switched to YOLO mode. Executing without approval gate...", { parseMode: "plain" });
18158
+ const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router(), router_exports));
18159
+ await handleMessage2(
18160
+ { text: `>>${plan.originalMessage}`, chatId, source: "telegram", type: "text", senderName: "", messageId: "" },
18161
+ channel
18162
+ );
18163
+ return;
18164
+ } else if (data.startsWith("execmode:")) {
18165
+ const mode = data.split(":")[1];
18166
+ if (mode === "approved" || mode === "yolo") {
18167
+ setExecMode(chatId, mode);
18168
+ const desc = mode === "approved" ? "AI will show a plan for approval before acting." : "AI will execute immediately without showing a plan.";
18169
+ await channel.sendText(chatId, `Execution mode set to <b>${mode}</b>.
18170
+ ${desc}`, { parseMode: "html" });
18171
+ }
18172
+ return;
17774
18173
  } else if (data.startsWith("model_sig:")) {
17775
18174
  const value = data.slice(10);
17776
18175
  setModelSignature(chatId, value);
@@ -18530,6 +18929,7 @@ var init_callbacks = __esm({
18530
18929
  init_guard();
18531
18930
  init_pagination();
18532
18931
  init_stt();
18932
+ init_gate();
18533
18933
  init_helpers();
18534
18934
  init_response();
18535
18935
  init_shell();
@@ -18689,6 +19089,33 @@ async function handleText(msg, channel) {
18689
19089
  if (hasSqPrefix) {
18690
19090
  text = sqCleanText;
18691
19091
  }
19092
+ if (getRejectionMode(chatId)) {
19093
+ clearRejectionMode(chatId);
19094
+ await channel.sendTyping?.(chatId);
19095
+ const response = await askAgent(chatId, `Plan rejected. Feedback: "${text}". Revise your plan.`, {
19096
+ cwd: getCwd(chatId),
19097
+ model: model2,
19098
+ permMode: "yolo",
19099
+ agentMode: effectiveAgentMode
19100
+ });
19101
+ if (response.text) {
19102
+ storePendingPlan(chatId, response.text, text);
19103
+ if (typeof channel.sendKeyboard === "function") {
19104
+ await channel.sendKeyboard(chatId, `\u{1F50D} ${response.text}`, [
19105
+ [
19106
+ { label: "\u2705 Approve", data: "exec:approve", style: "success" },
19107
+ { label: "\u274C Reject", data: "exec:reject", style: "danger" }
19108
+ ],
19109
+ [
19110
+ { label: "\u26A1 Skip & YOLO", data: "exec:yolo" }
19111
+ ]
19112
+ ]);
19113
+ } else {
19114
+ await sendResponse(chatId, channel, response.text, void 0);
19115
+ }
19116
+ }
19117
+ return;
19118
+ }
18692
19119
  {
18693
19120
  const { getDiscussionMode: getDiscussionMode2, clearDiscussionMode: clearDiscussionMode2, setDiscussionMode: reenterDiscussion, getInsightById: getInsightById2, updateInsightProposal: updateInsightProposal2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
18694
19121
  const discussInsightId = getDiscussionMode2(chatId);
@@ -18765,6 +19192,64 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
18765
19192
  return;
18766
19193
  }
18767
19194
  }
19195
+ const execMode = getExecMode(chatId);
19196
+ const sessionId = getSessionId(chatId);
19197
+ const isResuming = !!sessionId;
19198
+ if (shouldRequireApproval({
19199
+ execMode,
19200
+ intent,
19201
+ bootstrapTier: bootstrapTier ?? "full",
19202
+ messageText: text,
19203
+ isResuming,
19204
+ isSideQuest: hasSqPrefix
19205
+ })) {
19206
+ const planDirective = buildPlanningDirective();
19207
+ let typingActive2 = true;
19208
+ const typingLoop2 = async () => {
19209
+ while (typingActive2) {
19210
+ try {
19211
+ await channel.sendTyping?.(chatId);
19212
+ } catch {
19213
+ }
19214
+ await new Promise((r) => setTimeout(r, 4e3));
19215
+ }
19216
+ };
19217
+ typingLoop2().catch(() => {
19218
+ });
19219
+ try {
19220
+ const planResponse = await askAgent(chatId, cleanText || text, {
19221
+ cwd: getCwd(chatId),
19222
+ model: model2,
19223
+ permMode: "yolo",
19224
+ bootstrapTier: bootstrapTier ?? "full",
19225
+ agentMode: effectiveAgentMode,
19226
+ planningDirective: planDirective
19227
+ });
19228
+ typingActive2 = false;
19229
+ if (planResponse.text) {
19230
+ storePendingPlan(chatId, planResponse.text, cleanText || text);
19231
+ if (typeof channel.sendKeyboard === "function") {
19232
+ await channel.sendKeyboard(chatId, `\u{1F50D} ${planResponse.text}`, [
19233
+ [
19234
+ { label: "\u2705 Approve", data: "exec:approve", style: "success" },
19235
+ { label: "\u274C Reject", data: "exec:reject", style: "danger" }
19236
+ ],
19237
+ [
19238
+ { label: "\u26A1 Skip & YOLO", data: "exec:yolo" }
19239
+ ]
19240
+ ]);
19241
+ } else {
19242
+ await sendResponse(chatId, channel, planResponse.text, void 0);
19243
+ }
19244
+ } else {
19245
+ await channel.sendText(chatId, "(No plan generated \u2014 proceeding normally)", { parseMode: "plain" });
19246
+ }
19247
+ } catch (err) {
19248
+ typingActive2 = false;
19249
+ await channel.sendText(chatId, `\u26A0\uFE0F Planning error: ${err.message}`, { parseMode: "plain" });
19250
+ }
19251
+ return;
19252
+ }
18768
19253
  let typingActive = true;
18769
19254
  const typingLoop = async () => {
18770
19255
  while (typingActive) {
@@ -18945,6 +19430,7 @@ var init_router = __esm({
18945
19430
  init_wizard();
18946
19431
  init_classify2();
18947
19432
  init_store3();
19433
+ init_gate();
18948
19434
  init_helpers();
18949
19435
  init_response();
18950
19436
  init_shell();
@@ -19205,6 +19691,8 @@ async function runWithRetry(job, model2, runId, t0) {
19205
19691
  if (job.jobType === "reflection") {
19206
19692
  const { runNightlyReflection: runNightlyReflection2 } = await Promise.resolve().then(() => (init_analyze(), analyze_exports));
19207
19693
  const { formatNightlySummary: formatNightlySummary2 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
19694
+ const { getPendingInsightCount: getPendingInsightCount2, getActiveReflectionChatIds: getActiveReflectionChatIds2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
19695
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
19208
19696
  const timeoutMs2 = job.timeout ? job.timeout * 1e3 : void 0;
19209
19697
  const { results } = await runNightlyReflection2({
19210
19698
  timeoutMs: timeoutMs2,
@@ -19217,7 +19705,13 @@ async function runWithRetry(job, model2, runId, t0) {
19217
19705
  const allInsights = results.flatMap(
19218
19706
  (r) => r.insights.map((ins) => ({ id: ++seq, ...ins }))
19219
19707
  );
19220
- return { text: formatNightlySummary2(allInsights) };
19708
+ const db3 = getDb2();
19709
+ const activeChats2 = getActiveReflectionChatIds2(db3);
19710
+ let totalPending = 0;
19711
+ for (const cid of activeChats2) {
19712
+ totalPending += getPendingInsightCount2(db3, cid);
19713
+ }
19714
+ return { text: formatNightlySummary2(allInsights, totalPending) };
19221
19715
  }
19222
19716
  if (job.thinking && job.thinking !== "auto") {
19223
19717
  setThinkingLevel(chatId, job.thinking);
@@ -19323,7 +19817,7 @@ var init_cron = __esm({
19323
19817
  });
19324
19818
 
19325
19819
  // src/agents/runners/wrap-backend.ts
19326
- import { join as join19 } from "path";
19820
+ import { join as join20 } from "path";
19327
19821
  function buildMcpCommands(backendId) {
19328
19822
  const exe = backendId === "cursor" ? "agent" : backendId;
19329
19823
  return {
@@ -19417,7 +19911,7 @@ function wrapBackendAdapter(adapter) {
19417
19911
  const configPath = writeMcpConfigFile(server);
19418
19912
  return ["--mcp-config", configPath];
19419
19913
  },
19420
- getSkillPath: () => join19(SKILLS_PATH, `agent-${adapter.id}.md`)
19914
+ getSkillPath: () => join20(SKILLS_PATH, `agent-${adapter.id}.md`)
19421
19915
  };
19422
19916
  }
19423
19917
  var BACKEND_CAPABILITIES;
@@ -19468,18 +19962,18 @@ var init_wrap_backend = __esm({
19468
19962
  });
19469
19963
 
19470
19964
  // src/agents/runners/config-loader.ts
19471
- import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync18, mkdirSync as mkdirSync8, watchFile, unwatchFile } from "fs";
19472
- import { join as join20 } from "path";
19965
+ import { readFileSync as readFileSync10, readdirSync as readdirSync9, existsSync as existsSync19, mkdirSync as mkdirSync9, watchFile, unwatchFile } from "fs";
19966
+ import { join as join21 } from "path";
19473
19967
  import { execFileSync as execFileSync2 } from "child_process";
19474
19968
  function resolveExecutable(config2) {
19475
- if (existsSync18(config2.executable)) return config2.executable;
19969
+ if (existsSync19(config2.executable)) return config2.executable;
19476
19970
  try {
19477
19971
  return execFileSync2("which", [config2.executable], { encoding: "utf-8" }).trim();
19478
19972
  } catch {
19479
19973
  }
19480
19974
  for (const fallback of config2.executableFallbacks ?? []) {
19481
19975
  const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
19482
- if (existsSync18(resolved)) return resolved;
19976
+ if (existsSync19(resolved)) return resolved;
19483
19977
  }
19484
19978
  return config2.executable;
19485
19979
  }
@@ -19605,7 +20099,7 @@ function configToRunner(config2) {
19605
20099
  prepareMcpInjection() {
19606
20100
  return [];
19607
20101
  },
19608
- getSkillPath: () => join20(SKILLS_PATH, `agent-${config2.id}.md`)
20102
+ getSkillPath: () => join21(SKILLS_PATH, `agent-${config2.id}.md`)
19609
20103
  };
19610
20104
  }
19611
20105
  function loadRunnerConfig(filePath) {
@@ -19618,14 +20112,14 @@ function loadRunnerConfig(filePath) {
19618
20112
  }
19619
20113
  }
19620
20114
  function loadAllRunnerConfigs() {
19621
- if (!existsSync18(RUNNERS_PATH)) {
19622
- mkdirSync8(RUNNERS_PATH, { recursive: true });
20115
+ if (!existsSync19(RUNNERS_PATH)) {
20116
+ mkdirSync9(RUNNERS_PATH, { recursive: true });
19623
20117
  return [];
19624
20118
  }
19625
- const files = readdirSync8(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
20119
+ const files = readdirSync9(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
19626
20120
  const configs = [];
19627
20121
  for (const file of files) {
19628
- const config2 = loadRunnerConfig(join20(RUNNERS_PATH, file));
20122
+ const config2 = loadRunnerConfig(join21(RUNNERS_PATH, file));
19629
20123
  if (config2) configs.push(config2);
19630
20124
  }
19631
20125
  return configs;
@@ -19646,16 +20140,16 @@ function registerConfigRunners() {
19646
20140
  return count;
19647
20141
  }
19648
20142
  function watchRunnerConfigs(onChange) {
19649
- if (!existsSync18(RUNNERS_PATH)) return;
20143
+ if (!existsSync19(RUNNERS_PATH)) return;
19650
20144
  for (const prev of watchedFiles) {
19651
- if (!existsSync18(prev)) {
20145
+ if (!existsSync19(prev)) {
19652
20146
  unwatchFile(prev);
19653
20147
  watchedFiles.delete(prev);
19654
20148
  }
19655
20149
  }
19656
- const files = readdirSync8(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
20150
+ const files = readdirSync9(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
19657
20151
  for (const file of files) {
19658
- const fullPath = join20(RUNNERS_PATH, file);
20152
+ const fullPath = join21(RUNNERS_PATH, file);
19659
20153
  if (watchedFiles.has(fullPath)) continue;
19660
20154
  watchedFiles.add(fullPath);
19661
20155
  watchFile(fullPath, { interval: 5e3 }, () => {
@@ -20053,6 +20547,7 @@ var init_telegram2 = __esm({
20053
20547
  { command: "summarizer", description: "Configure session summarization model" },
20054
20548
  // Permissions & tools
20055
20549
  { command: "permissions", description: "Permission mode (yolo/safe/readonly/plan)" },
20550
+ { command: "mode", description: "Execution gate (approved/yolo)" },
20056
20551
  { command: "tools", description: "Configure which tools the agent can use" },
20057
20552
  { command: "verbose", description: "Tool visibility (off/normal/verbose)" },
20058
20553
  { command: "cwd", description: "Set or show working directory" },
@@ -20489,19 +20984,19 @@ var init_telegram2 = __esm({
20489
20984
  });
20490
20985
 
20491
20986
  // src/skills/bootstrap.ts
20492
- import { existsSync as existsSync19 } from "fs";
20987
+ import { existsSync as existsSync20 } from "fs";
20493
20988
  import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
20494
- import { join as join21, dirname as dirname3 } from "path";
20989
+ import { join as join22, dirname as dirname4 } from "path";
20495
20990
  import { fileURLToPath as fileURLToPath2 } from "url";
20496
20991
  async function copyAgentManifestSkills() {
20497
- if (!existsSync19(PKG_SKILLS)) return;
20992
+ if (!existsSync20(PKG_SKILLS)) return;
20498
20993
  try {
20499
20994
  const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
20500
20995
  for (const entry of entries) {
20501
20996
  if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
20502
- const src = join21(PKG_SKILLS, entry.name);
20503
- const dest = join21(SKILLS_PATH, entry.name);
20504
- if (existsSync19(dest)) continue;
20997
+ const src = join22(PKG_SKILLS, entry.name);
20998
+ const dest = join22(SKILLS_PATH, entry.name);
20999
+ if (existsSync20(dest)) continue;
20505
21000
  await copyFile(src, dest);
20506
21001
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
20507
21002
  }
@@ -20511,8 +21006,8 @@ async function copyAgentManifestSkills() {
20511
21006
  }
20512
21007
  async function bootstrapSkills() {
20513
21008
  await copyAgentManifestSkills();
20514
- const usmDir = join21(SKILLS_PATH, USM_DIR_NAME);
20515
- if (existsSync19(usmDir)) return;
21009
+ const usmDir = join22(SKILLS_PATH, USM_DIR_NAME);
21010
+ if (existsSync20(usmDir)) return;
20516
21011
  try {
20517
21012
  const entries = await readdir6(SKILLS_PATH);
20518
21013
  const dirs = entries.filter((e) => !e.startsWith("."));
@@ -20534,8 +21029,8 @@ async function bootstrapSkills() {
20534
21029
  }
20535
21030
  }
20536
21031
  async function patchUsmForCcClaw(usmDir) {
20537
- const skillPath = join21(usmDir, "SKILL.md");
20538
- if (!existsSync19(skillPath)) return;
21032
+ const skillPath = join22(usmDir, "SKILL.md");
21033
+ if (!existsSync20(skillPath)) return;
20539
21034
  try {
20540
21035
  let content = await readFile8(skillPath, "utf-8");
20541
21036
  let patched = false;
@@ -20580,8 +21075,8 @@ var init_bootstrap = __esm({
20580
21075
  USM_REPO = "jacob-bd/universal-skills-manager";
20581
21076
  USM_DIR_NAME = "universal-skills-manager";
20582
21077
  CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
20583
- PKG_ROOT = join21(dirname3(fileURLToPath2(import.meta.url)), "..", "..");
20584
- PKG_SKILLS = join21(PKG_ROOT, "skills");
21078
+ PKG_ROOT = join22(dirname4(fileURLToPath2(import.meta.url)), "..", "..");
21079
+ PKG_SKILLS = join22(PKG_ROOT, "skills");
20585
21080
  }
20586
21081
  });
20587
21082
 
@@ -20803,13 +21298,13 @@ __export(ai_skill_exports, {
20803
21298
  generateAiSkill: () => generateAiSkill,
20804
21299
  installAiSkill: () => installAiSkill
20805
21300
  });
20806
- import { existsSync as existsSync20, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
20807
- import { join as join22 } from "path";
21301
+ import { existsSync as existsSync21, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10 } from "fs";
21302
+ import { join as join23 } from "path";
20808
21303
  import { homedir as homedir7 } from "os";
20809
21304
  function generateAiSkill() {
20810
21305
  const version = VERSION;
20811
21306
  let systemState = "";
20812
- if (existsSync20(DB_PATH)) {
21307
+ if (existsSync21(DB_PATH)) {
20813
21308
  try {
20814
21309
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
20815
21310
  const readDb = openDatabaseReadOnly2();
@@ -21213,10 +21708,10 @@ function installAiSkill() {
21213
21708
  const failed = [];
21214
21709
  for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
21215
21710
  for (const dir of dirs) {
21216
- const skillDir = join22(dir, "cc-claw-cli");
21217
- const skillPath = join22(skillDir, "SKILL.md");
21711
+ const skillDir = join23(dir, "cc-claw-cli");
21712
+ const skillPath = join23(skillDir, "SKILL.md");
21218
21713
  try {
21219
- mkdirSync9(skillDir, { recursive: true });
21714
+ mkdirSync10(skillDir, { recursive: true });
21220
21715
  writeFileSync7(skillPath, skill, "utf-8");
21221
21716
  installed.push(skillPath);
21222
21717
  } catch {
@@ -21233,11 +21728,11 @@ var init_ai_skill = __esm({
21233
21728
  init_paths();
21234
21729
  init_version();
21235
21730
  BACKEND_SKILL_DIRS2 = {
21236
- "cc-claw": [join22(homedir7(), ".cc-claw", "workspace", "skills")],
21237
- claude: [join22(homedir7(), ".claude", "skills")],
21238
- gemini: [join22(homedir7(), ".gemini", "skills")],
21239
- codex: [join22(homedir7(), ".agents", "skills")],
21240
- cursor: [join22(homedir7(), ".cursor", "skills"), join22(homedir7(), ".cursor", "skills-cursor")]
21731
+ "cc-claw": [join23(homedir7(), ".cc-claw", "workspace", "skills")],
21732
+ claude: [join23(homedir7(), ".claude", "skills")],
21733
+ gemini: [join23(homedir7(), ".gemini", "skills")],
21734
+ codex: [join23(homedir7(), ".agents", "skills")],
21735
+ cursor: [join23(homedir7(), ".cursor", "skills"), join23(homedir7(), ".cursor", "skills-cursor")]
21241
21736
  };
21242
21737
  }
21243
21738
  });
@@ -21247,23 +21742,23 @@ var index_exports = {};
21247
21742
  __export(index_exports, {
21248
21743
  main: () => main
21249
21744
  });
21250
- import { mkdirSync as mkdirSync10, existsSync as existsSync21, renameSync, statSync as statSync5, readFileSync as readFileSync12 } from "fs";
21251
- import { join as join23 } from "path";
21745
+ import { mkdirSync as mkdirSync11, existsSync as existsSync22, renameSync as renameSync2, statSync as statSync6, readFileSync as readFileSync12 } from "fs";
21746
+ import { join as join24 } from "path";
21252
21747
  import dotenv from "dotenv";
21253
21748
  function migrateLayout() {
21254
21749
  const moves = [
21255
- [join23(CC_CLAW_HOME, "cc-claw.db"), join23(DATA_PATH, "cc-claw.db")],
21256
- [join23(CC_CLAW_HOME, "cc-claw.db-shm"), join23(DATA_PATH, "cc-claw.db-shm")],
21257
- [join23(CC_CLAW_HOME, "cc-claw.db-wal"), join23(DATA_PATH, "cc-claw.db-wal")],
21258
- [join23(CC_CLAW_HOME, "cc-claw.log"), join23(LOGS_PATH, "cc-claw.log")],
21259
- [join23(CC_CLAW_HOME, "cc-claw.log.1"), join23(LOGS_PATH, "cc-claw.log.1")],
21260
- [join23(CC_CLAW_HOME, "cc-claw.error.log"), join23(LOGS_PATH, "cc-claw.error.log")],
21261
- [join23(CC_CLAW_HOME, "cc-claw.error.log.1"), join23(LOGS_PATH, "cc-claw.error.log.1")]
21750
+ [join24(CC_CLAW_HOME, "cc-claw.db"), join24(DATA_PATH, "cc-claw.db")],
21751
+ [join24(CC_CLAW_HOME, "cc-claw.db-shm"), join24(DATA_PATH, "cc-claw.db-shm")],
21752
+ [join24(CC_CLAW_HOME, "cc-claw.db-wal"), join24(DATA_PATH, "cc-claw.db-wal")],
21753
+ [join24(CC_CLAW_HOME, "cc-claw.log"), join24(LOGS_PATH, "cc-claw.log")],
21754
+ [join24(CC_CLAW_HOME, "cc-claw.log.1"), join24(LOGS_PATH, "cc-claw.log.1")],
21755
+ [join24(CC_CLAW_HOME, "cc-claw.error.log"), join24(LOGS_PATH, "cc-claw.error.log")],
21756
+ [join24(CC_CLAW_HOME, "cc-claw.error.log.1"), join24(LOGS_PATH, "cc-claw.error.log.1")]
21262
21757
  ];
21263
21758
  for (const [from, to] of moves) {
21264
- if (existsSync21(from) && !existsSync21(to)) {
21759
+ if (existsSync22(from) && !existsSync22(to)) {
21265
21760
  try {
21266
- renameSync(from, to);
21761
+ renameSync2(from, to);
21267
21762
  } catch {
21268
21763
  }
21269
21764
  }
@@ -21272,11 +21767,11 @@ function migrateLayout() {
21272
21767
  function rotateLogs() {
21273
21768
  for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
21274
21769
  try {
21275
- const { size } = statSync5(file);
21770
+ const { size } = statSync6(file);
21276
21771
  if (size > LOG_MAX_BYTES) {
21277
21772
  const archivePath = `${file}.1`;
21278
21773
  try {
21279
- renameSync(file, archivePath);
21774
+ renameSync2(file, archivePath);
21280
21775
  } catch {
21281
21776
  }
21282
21777
  log(`[cc-claw] Rotated ${file} (was ${(size / 1024 / 1024).toFixed(1)}MB)`);
@@ -21324,6 +21819,12 @@ async function main() {
21324
21819
  }
21325
21820
  setBootTime();
21326
21821
  log("[cc-claw] Database initialized (sessions preserved for resume)");
21822
+ try {
21823
+ const { migrateAllSlots: migrateAllSlots2 } = await Promise.resolve().then(() => (init_symlink_manager(), symlink_manager_exports));
21824
+ migrateAllSlots2(CC_CLAW_HOME);
21825
+ } catch (err) {
21826
+ warn(`[cc-claw] Slot symlink migration failed: ${err instanceof Error ? err.message : String(err)}`);
21827
+ }
21327
21828
  if (process.env.TELEGRAM_BOT_TOKEN) {
21328
21829
  channelRegistry.register(new TelegramChannel());
21329
21830
  }
@@ -21400,11 +21901,11 @@ async function main() {
21400
21901
  bootstrapSkills().catch((err) => error("[cc-claw] Skill bootstrap failed:", err));
21401
21902
  try {
21402
21903
  const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
21403
- const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync17 } = await import("fs");
21404
- const { join: join29 } = await import("path");
21405
- const skillDir = join29(SKILLS_PATH, "cc-claw-cli");
21406
- mkdirSync17(skillDir, { recursive: true });
21407
- writeFileSync12(join29(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
21904
+ const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync18 } = await import("fs");
21905
+ const { join: join30 } = await import("path");
21906
+ const skillDir = join30(SKILLS_PATH, "cc-claw-cli");
21907
+ mkdirSync18(skillDir, { recursive: true });
21908
+ writeFileSync12(join30(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
21408
21909
  log("[cc-claw] AI skill updated");
21409
21910
  } catch {
21410
21911
  }
@@ -21477,10 +21978,10 @@ var init_index = __esm({
21477
21978
  init_health3();
21478
21979
  init_image_gen();
21479
21980
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
21480
- if (!existsSync21(dir)) mkdirSync10(dir, { recursive: true });
21981
+ if (!existsSync22(dir)) mkdirSync11(dir, { recursive: true });
21481
21982
  }
21482
21983
  migrateLayout();
21483
- if (existsSync21(ENV_PATH)) {
21984
+ if (existsSync22(ENV_PATH)) {
21484
21985
  dotenv.config({ path: ENV_PATH });
21485
21986
  } else {
21486
21987
  console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
@@ -21501,12 +22002,12 @@ __export(api_client_exports, {
21501
22002
  apiPost: () => apiPost,
21502
22003
  isDaemonRunning: () => isDaemonRunning
21503
22004
  });
21504
- import { readFileSync as readFileSync13, existsSync as existsSync22 } from "fs";
22005
+ import { readFileSync as readFileSync13, existsSync as existsSync23 } from "fs";
21505
22006
  import { request as httpRequest, Agent } from "http";
21506
22007
  function getToken() {
21507
22008
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
21508
22009
  try {
21509
- if (existsSync22(TOKEN_PATH)) return readFileSync13(TOKEN_PATH, "utf-8").trim();
22010
+ if (existsSync23(TOKEN_PATH)) return readFileSync13(TOKEN_PATH, "utf-8").trim();
21510
22011
  } catch {
21511
22012
  }
21512
22013
  return null;
@@ -21605,10 +22106,10 @@ __export(service_exports, {
21605
22106
  serviceStatus: () => serviceStatus,
21606
22107
  uninstallService: () => uninstallService
21607
22108
  });
21608
- import { existsSync as existsSync23, mkdirSync as mkdirSync11, writeFileSync as writeFileSync8, unlinkSync as unlinkSync6 } from "fs";
22109
+ import { existsSync as existsSync24, mkdirSync as mkdirSync12, writeFileSync as writeFileSync8, unlinkSync as unlinkSync6 } from "fs";
21609
22110
  import { execFileSync as execFileSync3, execSync as execSync6 } from "child_process";
21610
22111
  import { homedir as homedir8, platform } from "os";
21611
- import { join as join24, dirname as dirname4 } from "path";
22112
+ import { join as join25, dirname as dirname5 } from "path";
21612
22113
  function xmlEscape(s) {
21613
22114
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
21614
22115
  }
@@ -21617,23 +22118,23 @@ function resolveExecutable2(name) {
21617
22118
  return execFileSync3("which", [name], { encoding: "utf-8" }).trim();
21618
22119
  } catch {
21619
22120
  const fallback = process.argv[1];
21620
- if (fallback && existsSync23(fallback)) return fallback;
22121
+ if (fallback && existsSync24(fallback)) return fallback;
21621
22122
  throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
21622
22123
  }
21623
22124
  }
21624
22125
  function getPathDirs() {
21625
- const nodeBin = dirname4(process.execPath);
22126
+ const nodeBin = dirname5(process.execPath);
21626
22127
  const home = homedir8();
21627
22128
  const dirs = /* @__PURE__ */ new Set([
21628
22129
  nodeBin,
21629
- join24(home, ".local", "bin"),
22130
+ join25(home, ".local", "bin"),
21630
22131
  "/usr/local/bin",
21631
22132
  "/usr/bin",
21632
22133
  "/bin"
21633
22134
  ]);
21634
22135
  try {
21635
22136
  const prefix = execSync6("npm config get prefix", { encoding: "utf-8" }).trim();
21636
- if (prefix) dirs.add(join24(prefix, "bin"));
22137
+ if (prefix) dirs.add(join25(prefix, "bin"));
21637
22138
  } catch {
21638
22139
  }
21639
22140
  return [...dirs].join(":");
@@ -21691,10 +22192,10 @@ function generatePlist() {
21691
22192
  </plist>`;
21692
22193
  }
21693
22194
  function installMacOS() {
21694
- const agentsDir = dirname4(PLIST_PATH);
21695
- if (!existsSync23(agentsDir)) mkdirSync11(agentsDir, { recursive: true });
21696
- if (!existsSync23(LOGS_PATH)) mkdirSync11(LOGS_PATH, { recursive: true });
21697
- if (existsSync23(PLIST_PATH)) {
22195
+ const agentsDir = dirname5(PLIST_PATH);
22196
+ if (!existsSync24(agentsDir)) mkdirSync12(agentsDir, { recursive: true });
22197
+ if (!existsSync24(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
22198
+ if (existsSync24(PLIST_PATH)) {
21698
22199
  try {
21699
22200
  execFileSync3("launchctl", ["unload", PLIST_PATH]);
21700
22201
  } catch {
@@ -21706,7 +22207,7 @@ function installMacOS() {
21706
22207
  console.log(" Service loaded and starting.");
21707
22208
  }
21708
22209
  function uninstallMacOS() {
21709
- if (!existsSync23(PLIST_PATH)) {
22210
+ if (!existsSync24(PLIST_PATH)) {
21710
22211
  console.log(" No service found to uninstall.");
21711
22212
  return;
21712
22213
  }
@@ -21781,8 +22282,8 @@ WantedBy=default.target
21781
22282
  `;
21782
22283
  }
21783
22284
  function installLinux() {
21784
- if (!existsSync23(SYSTEMD_DIR)) mkdirSync11(SYSTEMD_DIR, { recursive: true });
21785
- if (!existsSync23(LOGS_PATH)) mkdirSync11(LOGS_PATH, { recursive: true });
22285
+ if (!existsSync24(SYSTEMD_DIR)) mkdirSync12(SYSTEMD_DIR, { recursive: true });
22286
+ if (!existsSync24(LOGS_PATH)) mkdirSync12(LOGS_PATH, { recursive: true });
21786
22287
  writeFileSync8(UNIT_PATH, generateUnit());
21787
22288
  console.log(` Installed: ${UNIT_PATH}`);
21788
22289
  execFileSync3("systemctl", ["--user", "daemon-reload"]);
@@ -21791,7 +22292,7 @@ function installLinux() {
21791
22292
  console.log(" Service enabled and started.");
21792
22293
  }
21793
22294
  function uninstallLinux() {
21794
- if (!existsSync23(UNIT_PATH)) {
22295
+ if (!existsSync24(UNIT_PATH)) {
21795
22296
  console.log(" No service found to uninstall.");
21796
22297
  return;
21797
22298
  }
@@ -21816,7 +22317,7 @@ function statusLinux() {
21816
22317
  }
21817
22318
  }
21818
22319
  function installService() {
21819
- if (!existsSync23(join24(CC_CLAW_HOME, ".env"))) {
22320
+ if (!existsSync24(join25(CC_CLAW_HOME, ".env"))) {
21820
22321
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
21821
22322
  console.error(" Run 'cc-claw setup' before installing the service.");
21822
22323
  process.exitCode = 1;
@@ -21845,9 +22346,9 @@ var init_service = __esm({
21845
22346
  "use strict";
21846
22347
  init_paths();
21847
22348
  PLIST_LABEL = "com.cc-claw";
21848
- PLIST_PATH = join24(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
21849
- SYSTEMD_DIR = join24(homedir8(), ".config", "systemd", "user");
21850
- UNIT_PATH = join24(SYSTEMD_DIR, "cc-claw.service");
22349
+ PLIST_PATH = join25(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
22350
+ SYSTEMD_DIR = join25(homedir8(), ".config", "systemd", "user");
22351
+ UNIT_PATH = join25(SYSTEMD_DIR, "cc-claw.service");
21851
22352
  }
21852
22353
  });
21853
22354
 
@@ -22044,7 +22545,7 @@ var status_exports = {};
22044
22545
  __export(status_exports, {
22045
22546
  statusCommand: () => statusCommand
22046
22547
  });
22047
- import { existsSync as existsSync24, statSync as statSync6 } from "fs";
22548
+ import { existsSync as existsSync25, statSync as statSync7 } from "fs";
22048
22549
  async function statusCommand(globalOpts, localOpts) {
22049
22550
  try {
22050
22551
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -22084,7 +22585,7 @@ async function statusCommand(globalOpts, localOpts) {
22084
22585
  const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
22085
22586
  const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
22086
22587
  const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
22087
- const dbStat = existsSync24(DB_PATH) ? statSync6(DB_PATH) : null;
22588
+ const dbStat = existsSync25(DB_PATH) ? statSync7(DB_PATH) : null;
22088
22589
  let daemonRunning = false;
22089
22590
  let daemonInfo = {};
22090
22591
  try {
@@ -22173,12 +22674,12 @@ var doctor_exports = {};
22173
22674
  __export(doctor_exports, {
22174
22675
  doctorCommand: () => doctorCommand
22175
22676
  });
22176
- import { existsSync as existsSync25, statSync as statSync7, accessSync, constants } from "fs";
22677
+ import { existsSync as existsSync26, statSync as statSync8, accessSync, constants } from "fs";
22177
22678
  import { execFileSync as execFileSync4 } from "child_process";
22178
22679
  async function doctorCommand(globalOpts, localOpts) {
22179
22680
  const checks = [];
22180
- if (existsSync25(DB_PATH)) {
22181
- const size = statSync7(DB_PATH).size;
22681
+ if (existsSync26(DB_PATH)) {
22682
+ const size = statSync8(DB_PATH).size;
22182
22683
  checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
22183
22684
  try {
22184
22685
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -22207,7 +22708,7 @@ async function doctorCommand(globalOpts, localOpts) {
22207
22708
  } else {
22208
22709
  checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
22209
22710
  }
22210
- if (existsSync25(ENV_PATH)) {
22711
+ if (existsSync26(ENV_PATH)) {
22211
22712
  checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
22212
22713
  } else {
22213
22714
  checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
@@ -22262,7 +22763,7 @@ async function doctorCommand(globalOpts, localOpts) {
22262
22763
  } catch {
22263
22764
  }
22264
22765
  const tokenPath = `${DATA_PATH}/api-token`;
22265
- if (existsSync25(tokenPath)) {
22766
+ if (existsSync26(tokenPath)) {
22266
22767
  try {
22267
22768
  accessSync(tokenPath, constants.R_OK);
22268
22769
  checks.push({ name: "API token", status: "ok", message: "token file readable" });
@@ -22287,7 +22788,7 @@ async function doctorCommand(globalOpts, localOpts) {
22287
22788
  }
22288
22789
  } catch {
22289
22790
  }
22290
- if (existsSync25(ERROR_LOG_PATH)) {
22791
+ if (existsSync26(ERROR_LOG_PATH)) {
22291
22792
  try {
22292
22793
  const { readFileSync: readFileSync22 } = await import("fs");
22293
22794
  const logContent = readFileSync22(ERROR_LOG_PATH, "utf-8");
@@ -22413,10 +22914,10 @@ var logs_exports = {};
22413
22914
  __export(logs_exports, {
22414
22915
  logsCommand: () => logsCommand
22415
22916
  });
22416
- import { existsSync as existsSync26, readFileSync as readFileSync16, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
22917
+ import { existsSync as existsSync27, readFileSync as readFileSync16, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
22417
22918
  async function logsCommand(opts) {
22418
22919
  const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
22419
- if (!existsSync26(logFile)) {
22920
+ if (!existsSync27(logFile)) {
22420
22921
  outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
22421
22922
  process.exit(1);
22422
22923
  }
@@ -22468,11 +22969,11 @@ __export(gemini_exports, {
22468
22969
  geminiReorder: () => geminiReorder,
22469
22970
  geminiRotation: () => geminiRotation
22470
22971
  });
22471
- import { existsSync as existsSync27, mkdirSync as mkdirSync12, writeFileSync as writeFileSync9, readFileSync as readFileSync17, chmodSync } from "fs";
22472
- import { join as join25 } from "path";
22972
+ import { existsSync as existsSync28, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, readFileSync as readFileSync17, chmodSync } from "fs";
22973
+ import { join as join26 } from "path";
22473
22974
  import { createInterface as createInterface5 } from "readline";
22474
22975
  function requireDb() {
22475
- if (!existsSync27(DB_PATH)) {
22976
+ if (!existsSync28(DB_PATH)) {
22476
22977
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
22477
22978
  process.exit(1);
22478
22979
  }
@@ -22497,8 +22998,8 @@ async function resolveSlotId(idOrLabel) {
22497
22998
  function resolveOAuthEmail(configHome) {
22498
22999
  if (!configHome) return null;
22499
23000
  try {
22500
- const accountsPath = join25(configHome, ".gemini", "google_accounts.json");
22501
- if (!existsSync27(accountsPath)) return null;
23001
+ const accountsPath = join26(configHome, ".gemini", "google_accounts.json");
23002
+ if (!existsSync28(accountsPath)) return null;
22502
23003
  const accounts = JSON.parse(readFileSync17(accountsPath, "utf-8"));
22503
23004
  return accounts.active || null;
22504
23005
  } catch {
@@ -22581,14 +23082,14 @@ async function geminiAddKey(globalOpts, opts) {
22581
23082
  }
22582
23083
  async function geminiAddAccount(globalOpts, opts) {
22583
23084
  await requireWriteDb();
22584
- const slotsDir = join25(CC_CLAW_HOME, "gemini-slots");
22585
- if (!existsSync27(slotsDir)) mkdirSync12(slotsDir, { recursive: true });
23085
+ const slotsDir = join26(CC_CLAW_HOME, "gemini-slots");
23086
+ if (!existsSync28(slotsDir)) mkdirSync13(slotsDir, { recursive: true });
22586
23087
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
22587
23088
  const tempId = Date.now();
22588
- const slotDir = join25(slotsDir, `slot-${tempId}`);
22589
- mkdirSync12(slotDir, { recursive: true, mode: 448 });
22590
- mkdirSync12(join25(slotDir, ".gemini"), { recursive: true });
22591
- writeFileSync9(join25(slotDir, ".gemini", "settings.json"), JSON.stringify({
23089
+ const slotDir = join26(slotsDir, `slot-${tempId}`);
23090
+ mkdirSync13(slotDir, { recursive: true, mode: 448 });
23091
+ mkdirSync13(join26(slotDir, ".gemini"), { recursive: true });
23092
+ writeFileSync9(join26(slotDir, ".gemini", "settings.json"), JSON.stringify({
22592
23093
  security: { auth: { selectedType: "oauth-personal" } }
22593
23094
  }, null, 2));
22594
23095
  console.log("");
@@ -22605,8 +23106,8 @@ async function geminiAddAccount(globalOpts, opts) {
22605
23106
  });
22606
23107
  } catch {
22607
23108
  }
22608
- const oauthPath = join25(slotDir, ".gemini", "oauth_creds.json");
22609
- if (!existsSync27(oauthPath)) {
23109
+ const oauthPath = join26(slotDir, ".gemini", "oauth_creds.json");
23110
+ if (!existsSync28(oauthPath)) {
22610
23111
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
22611
23112
  console.log(" The slot directory is preserved at: " + slotDir);
22612
23113
  console.log(" Re-run: cc-claw gemini add-account\n");
@@ -22614,7 +23115,7 @@ async function geminiAddAccount(globalOpts, opts) {
22614
23115
  }
22615
23116
  let accountEmail = "unknown";
22616
23117
  try {
22617
- const accounts = JSON.parse(__require("fs").readFileSync(join25(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
23118
+ const accounts = JSON.parse(__require("fs").readFileSync(join26(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
22618
23119
  accountEmail = accounts.active || accountEmail;
22619
23120
  } catch {
22620
23121
  }
@@ -22625,6 +23126,13 @@ async function geminiAddAccount(globalOpts, opts) {
22625
23126
  configHome: slotDir,
22626
23127
  priority: opts.priority ? parseInt(opts.priority, 10) : 0
22627
23128
  });
23129
+ try {
23130
+ const { setupSlotSymlinks: setupSlotSymlinks2, getPrimaryDir: getPrimaryDir2 } = await Promise.resolve().then(() => (init_symlink_manager(), symlink_manager_exports));
23131
+ const primaryDir = getPrimaryDir2("gemini");
23132
+ if (primaryDir) setupSlotSymlinks2("gemini", slotDir, primaryDir);
23133
+ } catch (err) {
23134
+ console.log(warning(` Warning: could not set up state symlinks \u2014 ${err instanceof Error ? err.message : String(err)}`));
23135
+ }
22628
23136
  output(
22629
23137
  { id, type: "oauth", label: opts.label || accountEmail, configHome: slotDir },
22630
23138
  () => success(`
@@ -22726,11 +23234,11 @@ __export(backend_cmd_factory_exports, {
22726
23234
  makeReorder: () => makeReorder,
22727
23235
  registerBackendSlotCommands: () => registerBackendSlotCommands
22728
23236
  });
22729
- import { existsSync as existsSync28, mkdirSync as mkdirSync13, readFileSync as readFileSync18 } from "fs";
22730
- import { join as join26 } from "path";
23237
+ import { existsSync as existsSync29, mkdirSync as mkdirSync14, readFileSync as readFileSync18 } from "fs";
23238
+ import { join as join27 } from "path";
22731
23239
  import { createInterface as createInterface6 } from "readline";
22732
23240
  function requireDb2() {
22733
- if (!existsSync28(DB_PATH)) {
23241
+ if (!existsSync29(DB_PATH)) {
22734
23242
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
22735
23243
  process.exit(1);
22736
23244
  }
@@ -22819,11 +23327,11 @@ function makeAddAccount(backend2, displayName) {
22819
23327
  process.exit(1);
22820
23328
  }
22821
23329
  await requireWriteDb2();
22822
- const slotsDir = join26(CC_CLAW_HOME, config2.slotsSubdir);
22823
- if (!existsSync28(slotsDir)) mkdirSync13(slotsDir, { recursive: true });
23330
+ const slotsDir = join27(CC_CLAW_HOME, config2.slotsSubdir);
23331
+ if (!existsSync29(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
22824
23332
  const tempId = Date.now();
22825
- const slotDir = join26(slotsDir, `slot-${tempId}`);
22826
- mkdirSync13(slotDir, { recursive: true, mode: 448 });
23333
+ const slotDir = join27(slotsDir, `slot-${tempId}`);
23334
+ mkdirSync14(slotDir, { recursive: true, mode: 448 });
22827
23335
  if (config2.preSetup) config2.preSetup(slotDir);
22828
23336
  console.log("");
22829
23337
  console.log(` Opening ${displayName} CLI for sign-in...`);
@@ -22861,6 +23369,13 @@ function makeAddAccount(backend2, displayName) {
22861
23369
  configHome: slotDir,
22862
23370
  priority: opts.priority ? parseInt(opts.priority, 10) : 0
22863
23371
  });
23372
+ try {
23373
+ const { setupSlotSymlinks: setupSlotSymlinks2, getPrimaryDir: getPrimaryDir2 } = await Promise.resolve().then(() => (init_symlink_manager(), symlink_manager_exports));
23374
+ const primaryDir = getPrimaryDir2(backend2);
23375
+ if (primaryDir) setupSlotSymlinks2(backend2, slotDir, primaryDir);
23376
+ } catch (err) {
23377
+ console.log(warning(` Warning: could not set up state symlinks \u2014 ${err instanceof Error ? err.message : String(err)}`));
23378
+ }
22864
23379
  output(
22865
23380
  { id, type: "oauth", backend: backend2, label: accountLabel, configHome: slotDir },
22866
23381
  () => success(`Added ${displayName} subscription slot #${id} (${accountLabel})`)
@@ -22984,12 +23499,12 @@ var init_backend_cmd_factory = __esm({
22984
23499
  envValue: (slotDir) => slotDir,
22985
23500
  envOverrides: { ANTHROPIC_API_KEY: void 0 },
22986
23501
  preSetup: (slotDir) => {
22987
- mkdirSync13(join26(slotDir, ".claude"), { recursive: true });
23502
+ mkdirSync14(join27(slotDir, ".claude"), { recursive: true });
22988
23503
  },
22989
23504
  verifyCredentials: (slotDir) => {
22990
- const claudeJson = join26(slotDir, ".claude.json");
22991
- const claudeJsonNested = join26(slotDir, ".claude", ".claude.json");
22992
- if (existsSync28(claudeJson)) {
23505
+ const claudeJson = join27(slotDir, ".claude.json");
23506
+ const claudeJsonNested = join27(slotDir, ".claude", ".claude.json");
23507
+ if (existsSync29(claudeJson)) {
22993
23508
  try {
22994
23509
  const data = JSON.parse(readFileSync18(claudeJson, "utf-8"));
22995
23510
  return Boolean(data.oauthAccount);
@@ -22997,7 +23512,7 @@ var init_backend_cmd_factory = __esm({
22997
23512
  return false;
22998
23513
  }
22999
23514
  }
23000
- if (existsSync28(claudeJsonNested)) {
23515
+ if (existsSync29(claudeJsonNested)) {
23001
23516
  try {
23002
23517
  const data = JSON.parse(readFileSync18(claudeJsonNested, "utf-8"));
23003
23518
  return Boolean(data.oauthAccount);
@@ -23020,8 +23535,8 @@ var init_backend_cmd_factory = __esm({
23020
23535
  } catch {
23021
23536
  }
23022
23537
  try {
23023
- const claudeJson = join26(slotDir, ".claude.json");
23024
- if (existsSync28(claudeJson)) {
23538
+ const claudeJson = join27(slotDir, ".claude.json");
23539
+ if (existsSync29(claudeJson)) {
23025
23540
  const data = JSON.parse(readFileSync18(claudeJson, "utf-8"));
23026
23541
  if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
23027
23542
  }
@@ -23037,11 +23552,11 @@ var init_backend_cmd_factory = __esm({
23037
23552
  envValue: (slotDir) => slotDir,
23038
23553
  envOverrides: { OPENAI_API_KEY: void 0 },
23039
23554
  verifyCredentials: (slotDir) => {
23040
- return existsSync28(join26(slotDir, "auth.json"));
23555
+ return existsSync29(join27(slotDir, "auth.json"));
23041
23556
  },
23042
23557
  extractLabel: (slotDir) => {
23043
23558
  try {
23044
- const authData = JSON.parse(readFileSync18(join26(slotDir, "auth.json"), "utf-8"));
23559
+ const authData = JSON.parse(readFileSync18(join27(slotDir, "auth.json"), "utf-8"));
23045
23560
  if (authData.email) return authData.email;
23046
23561
  if (authData.account_name) return authData.account_name;
23047
23562
  if (authData.user?.email) return authData.user.email;
@@ -23061,12 +23576,12 @@ __export(backend_exports, {
23061
23576
  backendList: () => backendList,
23062
23577
  backendSet: () => backendSet
23063
23578
  });
23064
- import { existsSync as existsSync29 } from "fs";
23579
+ import { existsSync as existsSync30 } from "fs";
23065
23580
  async function backendList(globalOpts) {
23066
23581
  const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
23067
23582
  const chatId = resolveChatId(globalOpts);
23068
23583
  let activeBackend = null;
23069
- if (existsSync29(DB_PATH)) {
23584
+ if (existsSync30(DB_PATH)) {
23070
23585
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
23071
23586
  const readDb = openDatabaseReadOnly2();
23072
23587
  try {
@@ -23097,7 +23612,7 @@ async function backendList(globalOpts) {
23097
23612
  }
23098
23613
  async function backendGet(globalOpts) {
23099
23614
  const chatId = resolveChatId(globalOpts);
23100
- if (!existsSync29(DB_PATH)) {
23615
+ if (!existsSync30(DB_PATH)) {
23101
23616
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
23102
23617
  process.exit(1);
23103
23618
  }
@@ -23141,13 +23656,13 @@ __export(model_exports, {
23141
23656
  modelList: () => modelList,
23142
23657
  modelSet: () => modelSet
23143
23658
  });
23144
- import { existsSync as existsSync30 } from "fs";
23659
+ import { existsSync as existsSync31 } from "fs";
23145
23660
  async function modelList(globalOpts) {
23146
23661
  const chatId = resolveChatId(globalOpts);
23147
23662
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
23148
23663
  const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
23149
23664
  let backendId = "claude";
23150
- if (existsSync30(DB_PATH)) {
23665
+ if (existsSync31(DB_PATH)) {
23151
23666
  const readDb = openDatabaseReadOnly2();
23152
23667
  try {
23153
23668
  const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
@@ -23180,7 +23695,7 @@ async function modelList(globalOpts) {
23180
23695
  }
23181
23696
  async function modelGet(globalOpts) {
23182
23697
  const chatId = resolveChatId(globalOpts);
23183
- if (!existsSync30(DB_PATH)) {
23698
+ if (!existsSync31(DB_PATH)) {
23184
23699
  outputError("DB_NOT_FOUND", "Database not found.");
23185
23700
  process.exit(1);
23186
23701
  }
@@ -23224,9 +23739,9 @@ __export(memory_exports2, {
23224
23739
  memoryList: () => memoryList,
23225
23740
  memorySearch: () => memorySearch
23226
23741
  });
23227
- import { existsSync as existsSync31 } from "fs";
23742
+ import { existsSync as existsSync32 } from "fs";
23228
23743
  async function memoryList(globalOpts) {
23229
- if (!existsSync31(DB_PATH)) {
23744
+ if (!existsSync32(DB_PATH)) {
23230
23745
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
23231
23746
  process.exit(1);
23232
23747
  }
@@ -23250,7 +23765,7 @@ async function memoryList(globalOpts) {
23250
23765
  });
23251
23766
  }
23252
23767
  async function memorySearch(globalOpts, query) {
23253
- if (!existsSync31(DB_PATH)) {
23768
+ if (!existsSync32(DB_PATH)) {
23254
23769
  outputError("DB_NOT_FOUND", "Database not found.");
23255
23770
  process.exit(1);
23256
23771
  }
@@ -23272,7 +23787,7 @@ async function memorySearch(globalOpts, query) {
23272
23787
  });
23273
23788
  }
23274
23789
  async function memoryHistory(globalOpts, opts) {
23275
- if (!existsSync31(DB_PATH)) {
23790
+ if (!existsSync32(DB_PATH)) {
23276
23791
  outputError("DB_NOT_FOUND", "Database not found.");
23277
23792
  process.exit(1);
23278
23793
  }
@@ -23320,7 +23835,7 @@ __export(cron_exports2, {
23320
23835
  cronList: () => cronList,
23321
23836
  cronRuns: () => cronRuns
23322
23837
  });
23323
- import { existsSync as existsSync32 } from "fs";
23838
+ import { existsSync as existsSync33 } from "fs";
23324
23839
  function parseFallbacks(raw) {
23325
23840
  return raw.slice(0, 3).map((f) => {
23326
23841
  const [backend2, ...rest] = f.split(":");
@@ -23341,7 +23856,7 @@ function parseAndValidateTimeout(raw) {
23341
23856
  return val;
23342
23857
  }
23343
23858
  async function cronList(globalOpts) {
23344
- if (!existsSync32(DB_PATH)) {
23859
+ if (!existsSync33(DB_PATH)) {
23345
23860
  outputError("DB_NOT_FOUND", "Database not found.");
23346
23861
  process.exit(1);
23347
23862
  }
@@ -23379,7 +23894,7 @@ async function cronList(globalOpts) {
23379
23894
  });
23380
23895
  }
23381
23896
  async function cronHealth(globalOpts) {
23382
- if (!existsSync32(DB_PATH)) {
23897
+ if (!existsSync33(DB_PATH)) {
23383
23898
  outputError("DB_NOT_FOUND", "Database not found.");
23384
23899
  process.exit(1);
23385
23900
  }
@@ -23538,7 +24053,7 @@ async function cronEdit(globalOpts, id, opts) {
23538
24053
  }
23539
24054
  }
23540
24055
  async function cronRuns(globalOpts, jobId, opts) {
23541
- if (!existsSync32(DB_PATH)) {
24056
+ if (!existsSync33(DB_PATH)) {
23542
24057
  outputError("DB_NOT_FOUND", "Database not found.");
23543
24058
  process.exit(1);
23544
24059
  }
@@ -23585,9 +24100,9 @@ __export(agents_exports, {
23585
24100
  runnersList: () => runnersList,
23586
24101
  tasksList: () => tasksList
23587
24102
  });
23588
- import { existsSync as existsSync33 } from "fs";
24103
+ import { existsSync as existsSync34 } from "fs";
23589
24104
  async function agentsList(globalOpts) {
23590
- if (!existsSync33(DB_PATH)) {
24105
+ if (!existsSync34(DB_PATH)) {
23591
24106
  outputError("DB_NOT_FOUND", "Database not found.");
23592
24107
  process.exit(1);
23593
24108
  }
@@ -23618,7 +24133,7 @@ async function agentsList(globalOpts) {
23618
24133
  });
23619
24134
  }
23620
24135
  async function tasksList(globalOpts) {
23621
- if (!existsSync33(DB_PATH)) {
24136
+ if (!existsSync34(DB_PATH)) {
23622
24137
  outputError("DB_NOT_FOUND", "Database not found.");
23623
24138
  process.exit(1);
23624
24139
  }
@@ -23746,18 +24261,18 @@ __export(db_exports, {
23746
24261
  dbPath: () => dbPath,
23747
24262
  dbStats: () => dbStats
23748
24263
  });
23749
- import { existsSync as existsSync34, statSync as statSync8, copyFileSync as copyFileSync2, mkdirSync as mkdirSync14 } from "fs";
23750
- import { dirname as dirname5 } from "path";
24264
+ import { existsSync as existsSync35, statSync as statSync9, copyFileSync as copyFileSync3, mkdirSync as mkdirSync15 } from "fs";
24265
+ import { dirname as dirname6 } from "path";
23751
24266
  async function dbStats(globalOpts) {
23752
- if (!existsSync34(DB_PATH)) {
24267
+ if (!existsSync35(DB_PATH)) {
23753
24268
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
23754
24269
  process.exit(1);
23755
24270
  }
23756
24271
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
23757
24272
  const readDb = openDatabaseReadOnly2();
23758
- const mainSize = statSync8(DB_PATH).size;
24273
+ const mainSize = statSync9(DB_PATH).size;
23759
24274
  const walPath = DB_PATH + "-wal";
23760
- const walSize = existsSync34(walPath) ? statSync8(walPath).size : 0;
24275
+ const walSize = existsSync35(walPath) ? statSync9(walPath).size : 0;
23761
24276
  const tableNames = readDb.prepare(
23762
24277
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
23763
24278
  ).all();
@@ -23791,17 +24306,17 @@ async function dbPath(globalOpts) {
23791
24306
  output({ path: DB_PATH }, (d) => d.path);
23792
24307
  }
23793
24308
  async function dbBackup(globalOpts, destPath) {
23794
- if (!existsSync34(DB_PATH)) {
24309
+ if (!existsSync35(DB_PATH)) {
23795
24310
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
23796
24311
  process.exit(1);
23797
24312
  }
23798
24313
  const dest = destPath ?? `${DB_PATH}.backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
23799
24314
  try {
23800
- mkdirSync14(dirname5(dest), { recursive: true });
23801
- copyFileSync2(DB_PATH, dest);
24315
+ mkdirSync15(dirname6(dest), { recursive: true });
24316
+ copyFileSync3(DB_PATH, dest);
23802
24317
  const walPath = DB_PATH + "-wal";
23803
- if (existsSync34(walPath)) copyFileSync2(walPath, dest + "-wal");
23804
- output({ path: dest, sizeBytes: statSync8(dest).size }, (d) => {
24318
+ if (existsSync35(walPath)) copyFileSync3(walPath, dest + "-wal");
24319
+ output({ path: dest, sizeBytes: statSync9(dest).size }, (d) => {
23805
24320
  const b = d;
23806
24321
  return `
23807
24322
  ${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
@@ -23829,9 +24344,9 @@ __export(usage_exports, {
23829
24344
  usageCost: () => usageCost,
23830
24345
  usageTokens: () => usageTokens
23831
24346
  });
23832
- import { existsSync as existsSync35 } from "fs";
24347
+ import { existsSync as existsSync36 } from "fs";
23833
24348
  function ensureDb() {
23834
- if (!existsSync35(DB_PATH)) {
24349
+ if (!existsSync36(DB_PATH)) {
23835
24350
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
23836
24351
  process.exit(1);
23837
24352
  }
@@ -24021,9 +24536,9 @@ __export(config_exports2, {
24021
24536
  configList: () => configList,
24022
24537
  configSet: () => configSet
24023
24538
  });
24024
- import { existsSync as existsSync36, readFileSync as readFileSync19 } from "fs";
24539
+ import { existsSync as existsSync37, readFileSync as readFileSync19 } from "fs";
24025
24540
  async function configList(globalOpts) {
24026
- if (!existsSync36(DB_PATH)) {
24541
+ if (!existsSync37(DB_PATH)) {
24027
24542
  outputError("DB_NOT_FOUND", "Database not found.");
24028
24543
  process.exit(1);
24029
24544
  }
@@ -24057,7 +24572,7 @@ async function configGet(globalOpts, key) {
24057
24572
  outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
24058
24573
  process.exit(1);
24059
24574
  }
24060
- if (!existsSync36(DB_PATH)) {
24575
+ if (!existsSync37(DB_PATH)) {
24061
24576
  outputError("DB_NOT_FOUND", "Database not found.");
24062
24577
  process.exit(1);
24063
24578
  }
@@ -24103,7 +24618,7 @@ async function configSet(globalOpts, key, value) {
24103
24618
  }
24104
24619
  }
24105
24620
  async function configEnv(_globalOpts) {
24106
- if (!existsSync36(ENV_PATH)) {
24621
+ if (!existsSync37(ENV_PATH)) {
24107
24622
  outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
24108
24623
  process.exit(1);
24109
24624
  }
@@ -24157,9 +24672,9 @@ __export(session_exports, {
24157
24672
  sessionGet: () => sessionGet,
24158
24673
  sessionNew: () => sessionNew
24159
24674
  });
24160
- import { existsSync as existsSync37 } from "fs";
24675
+ import { existsSync as existsSync38 } from "fs";
24161
24676
  async function sessionGet(globalOpts) {
24162
- if (!existsSync37(DB_PATH)) {
24677
+ if (!existsSync38(DB_PATH)) {
24163
24678
  outputError("DB_NOT_FOUND", "Database not found.");
24164
24679
  process.exit(1);
24165
24680
  }
@@ -24220,9 +24735,9 @@ __export(permissions_exports, {
24220
24735
  verboseGet: () => verboseGet,
24221
24736
  verboseSet: () => verboseSet
24222
24737
  });
24223
- import { existsSync as existsSync38 } from "fs";
24738
+ import { existsSync as existsSync39 } from "fs";
24224
24739
  function ensureDb2() {
24225
- if (!existsSync38(DB_PATH)) {
24740
+ if (!existsSync39(DB_PATH)) {
24226
24741
  outputError("DB_NOT_FOUND", "Database not found.");
24227
24742
  process.exit(1);
24228
24743
  }
@@ -24369,9 +24884,9 @@ __export(cwd_exports, {
24369
24884
  cwdGet: () => cwdGet,
24370
24885
  cwdSet: () => cwdSet
24371
24886
  });
24372
- import { existsSync as existsSync39 } from "fs";
24887
+ import { existsSync as existsSync40 } from "fs";
24373
24888
  async function cwdGet(globalOpts) {
24374
- if (!existsSync39(DB_PATH)) {
24889
+ if (!existsSync40(DB_PATH)) {
24375
24890
  outputError("DB_NOT_FOUND", "Database not found.");
24376
24891
  process.exit(1);
24377
24892
  }
@@ -24433,9 +24948,9 @@ __export(voice_exports, {
24433
24948
  voiceGet: () => voiceGet,
24434
24949
  voiceSet: () => voiceSet
24435
24950
  });
24436
- import { existsSync as existsSync40 } from "fs";
24951
+ import { existsSync as existsSync41 } from "fs";
24437
24952
  async function voiceGet(globalOpts) {
24438
- if (!existsSync40(DB_PATH)) {
24953
+ if (!existsSync41(DB_PATH)) {
24439
24954
  outputError("DB_NOT_FOUND", "Database not found.");
24440
24955
  process.exit(1);
24441
24956
  }
@@ -24484,9 +24999,9 @@ __export(heartbeat_exports, {
24484
24999
  heartbeatGet: () => heartbeatGet,
24485
25000
  heartbeatSet: () => heartbeatSet
24486
25001
  });
24487
- import { existsSync as existsSync41 } from "fs";
25002
+ import { existsSync as existsSync42 } from "fs";
24488
25003
  async function heartbeatGet(globalOpts) {
24489
- if (!existsSync41(DB_PATH)) {
25004
+ if (!existsSync42(DB_PATH)) {
24490
25005
  outputError("DB_NOT_FOUND", "Database not found.");
24491
25006
  process.exit(1);
24492
25007
  }
@@ -24595,9 +25110,9 @@ __export(summarizer_exports, {
24595
25110
  summarizerGet: () => summarizerGet,
24596
25111
  summarizerSet: () => summarizerSet
24597
25112
  });
24598
- import { existsSync as existsSync42 } from "fs";
25113
+ import { existsSync as existsSync43 } from "fs";
24599
25114
  async function summarizerGet(globalOpts) {
24600
- if (!existsSync42(DB_PATH)) {
25115
+ if (!existsSync43(DB_PATH)) {
24601
25116
  outputError("DB_NOT_FOUND", "Database not found.");
24602
25117
  process.exit(1);
24603
25118
  }
@@ -24641,9 +25156,9 @@ __export(thinking_exports, {
24641
25156
  thinkingGet: () => thinkingGet,
24642
25157
  thinkingSet: () => thinkingSet
24643
25158
  });
24644
- import { existsSync as existsSync43 } from "fs";
25159
+ import { existsSync as existsSync44 } from "fs";
24645
25160
  async function thinkingGet(globalOpts) {
24646
- if (!existsSync43(DB_PATH)) {
25161
+ if (!existsSync44(DB_PATH)) {
24647
25162
  outputError("DB_NOT_FOUND", "Database not found.");
24648
25163
  process.exit(1);
24649
25164
  }
@@ -24687,9 +25202,9 @@ __export(chats_exports, {
24687
25202
  chatsList: () => chatsList,
24688
25203
  chatsRemoveAlias: () => chatsRemoveAlias
24689
25204
  });
24690
- import { existsSync as existsSync44 } from "fs";
25205
+ import { existsSync as existsSync45 } from "fs";
24691
25206
  async function chatsList(_globalOpts) {
24692
- if (!existsSync44(DB_PATH)) {
25207
+ if (!existsSync45(DB_PATH)) {
24693
25208
  outputError("DB_NOT_FOUND", "Database not found.");
24694
25209
  process.exit(1);
24695
25210
  }
@@ -24817,9 +25332,9 @@ var mcps_exports2 = {};
24817
25332
  __export(mcps_exports2, {
24818
25333
  mcpsList: () => mcpsList
24819
25334
  });
24820
- import { existsSync as existsSync45 } from "fs";
25335
+ import { existsSync as existsSync46 } from "fs";
24821
25336
  async function mcpsList(_globalOpts) {
24822
- if (!existsSync45(DB_PATH)) {
25337
+ if (!existsSync46(DB_PATH)) {
24823
25338
  outputError("DB_NOT_FOUND", "Database not found.");
24824
25339
  process.exit(1);
24825
25340
  }
@@ -24856,11 +25371,11 @@ __export(chat_exports2, {
24856
25371
  chatSend: () => chatSend
24857
25372
  });
24858
25373
  import { request as httpRequest2 } from "http";
24859
- import { readFileSync as readFileSync20, existsSync as existsSync46 } from "fs";
25374
+ import { readFileSync as readFileSync20, existsSync as existsSync47 } from "fs";
24860
25375
  function getToken2() {
24861
25376
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
24862
25377
  try {
24863
- if (existsSync46(TOKEN_PATH2)) return readFileSync20(TOKEN_PATH2, "utf-8").trim();
25378
+ if (existsSync47(TOKEN_PATH2)) return readFileSync20(TOKEN_PATH2, "utf-8").trim();
24864
25379
  } catch {
24865
25380
  }
24866
25381
  return null;
@@ -25139,8 +25654,8 @@ var completion_exports = {};
25139
25654
  __export(completion_exports, {
25140
25655
  completionCommand: () => completionCommand
25141
25656
  });
25142
- import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync15 } from "fs";
25143
- import { join as join27 } from "path";
25657
+ import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync16 } from "fs";
25658
+ import { join as join28 } from "path";
25144
25659
  import { homedir as homedir9 } from "os";
25145
25660
  async function completionCommand(opts) {
25146
25661
  const shell = opts.shell ?? detectShell();
@@ -25156,10 +25671,10 @@ async function completionCommand(opts) {
25156
25671
  process.exit(1);
25157
25672
  }
25158
25673
  if (opts.install) {
25159
- const dir = join27(homedir9(), ".config", "cc-claw", "completions");
25160
- mkdirSync15(dir, { recursive: true });
25674
+ const dir = join28(homedir9(), ".config", "cc-claw", "completions");
25675
+ mkdirSync16(dir, { recursive: true });
25161
25676
  const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
25162
- const filepath = join27(dir, filename);
25677
+ const filepath = join28(dir, filename);
25163
25678
  writeFileSync10(filepath, script, "utf-8");
25164
25679
  console.log(`\u2713 Completion script written to ${filepath}
25165
25680
  `);
@@ -25330,9 +25845,9 @@ __export(evolve_exports2, {
25330
25845
  evolveStatus: () => evolveStatus,
25331
25846
  evolveUndo: () => evolveUndo
25332
25847
  });
25333
- import { existsSync as existsSync47 } from "fs";
25848
+ import { existsSync as existsSync48 } from "fs";
25334
25849
  function ensureDb3() {
25335
- if (!existsSync47(DB_PATH)) {
25850
+ if (!existsSync48(DB_PATH)) {
25336
25851
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
25337
25852
  process.exit(1);
25338
25853
  }
@@ -25748,10 +26263,10 @@ var init_evolve3 = __esm({
25748
26263
 
25749
26264
  // src/setup.ts
25750
26265
  var setup_exports = {};
25751
- import { existsSync as existsSync48, writeFileSync as writeFileSync11, readFileSync as readFileSync21, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16, statSync as statSync9 } from "fs";
26266
+ import { existsSync as existsSync49, writeFileSync as writeFileSync11, readFileSync as readFileSync21, copyFileSync as copyFileSync4, mkdirSync as mkdirSync17, statSync as statSync10 } from "fs";
25752
26267
  import { execFileSync as execFileSync5 } from "child_process";
25753
26268
  import { createInterface as createInterface8 } from "readline";
25754
- import { join as join28 } from "path";
26269
+ import { join as join29 } from "path";
25755
26270
  function divider2() {
25756
26271
  console.log(dim("\u2500".repeat(55)));
25757
26272
  }
@@ -25826,10 +26341,10 @@ async function setup() {
25826
26341
  }
25827
26342
  console.log("");
25828
26343
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
25829
- if (!existsSync48(dir)) mkdirSync16(dir, { recursive: true });
26344
+ if (!existsSync49(dir)) mkdirSync17(dir, { recursive: true });
25830
26345
  }
25831
26346
  const env = {};
25832
- const envSource = existsSync48(ENV_PATH) ? ENV_PATH : existsSync48(".env") ? ".env" : null;
26347
+ const envSource = existsSync49(ENV_PATH) ? ENV_PATH : existsSync49(".env") ? ".env" : null;
25833
26348
  if (envSource) {
25834
26349
  console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
25835
26350
  console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
@@ -25839,13 +26354,13 @@ async function setup() {
25839
26354
  if (match) env[match[1].trim()] = match[2].trim();
25840
26355
  }
25841
26356
  }
25842
- const cwdDb = join28(process.cwd(), "cc-claw.db");
25843
- if (existsSync48(cwdDb) && !existsSync48(DB_PATH)) {
25844
- const { size } = statSync9(cwdDb);
26357
+ const cwdDb = join29(process.cwd(), "cc-claw.db");
26358
+ if (existsSync49(cwdDb) && !existsSync49(DB_PATH)) {
26359
+ const { size } = statSync10(cwdDb);
25845
26360
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
25846
26361
  const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
25847
26362
  if (migrate) {
25848
- copyFileSync3(cwdDb, DB_PATH);
26363
+ copyFileSync4(cwdDb, DB_PATH);
25849
26364
  console.log(green(` Database copied to ${DB_PATH}`));
25850
26365
  }
25851
26366
  console.log("");