open-walnut 0.4.2 → 0.4.3

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 (32) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +247 -245
  3. package/dist/integrations/calendar/index.js +42 -36
  4. package/dist/integrations/jira/index.js +100 -78
  5. package/dist/integrations/ms-todo/index.js +94 -72
  6. package/dist/web/server.js +295 -293
  7. package/dist/web/static/assets/{OfficePreview-CEHO0xkd.js → OfficePreview-DcPiG7nq.js} +2 -2
  8. package/dist/web/static/assets/{docx-preview-CuZwjAMS.js → docx-preview-BWSwr6o8.js} +1 -1
  9. package/dist/web/static/assets/index-1mQq6abn.css +32 -0
  10. package/dist/web/static/assets/{index-BRLxNhyy.js → index-A2G2h66W.js} +1 -1
  11. package/dist/web/static/assets/{index-DrWzb338.js → index-BWTJQD8q.js} +1 -1
  12. package/dist/web/static/assets/{index-DLjK8dGE.js → index-BcxyDA3F.js} +1 -1
  13. package/dist/web/static/assets/{index-DR-LSqAg.js → index-CEldo7Tq.js} +1 -1
  14. package/dist/web/static/assets/{index-DOXm2Aye.js → index-CYY_N36O.js} +1 -1
  15. package/dist/web/static/assets/{index-D1dpOEzW.js → index-CakB6vm_.js} +1 -1
  16. package/dist/web/static/assets/{index-DAOPV34I.js → index-Ch4LQw8-.js} +1 -1
  17. package/dist/web/static/assets/{index-BBjg7m-_.js → index-CnmikCRj.js} +1 -1
  18. package/dist/web/static/assets/{index-DtRwkh8J.js → index-CtytO7Ce.js} +1 -1
  19. package/dist/web/static/assets/{index-DXtp_ZWh.js → index-CvUyfkEn.js} +1 -1
  20. package/dist/web/static/assets/{index-BFF_G72i.js → index-Cw6d8sbx.js} +245 -245
  21. package/dist/web/static/assets/{index-0MyC-yGG.js → index-DK9AxMTA.js} +1 -1
  22. package/dist/web/static/assets/{index-mWEwJcqw.js → index-DPeOcZuH.js} +1 -1
  23. package/dist/web/static/assets/{index-D9qPPm7h.js → index-DUWox7Cm.js} +1 -1
  24. package/dist/web/static/assets/{index-C2YGUYGS.js → index-Zb9B6znf.js} +1 -1
  25. package/dist/web/static/assets/{index-ccs5s80D.js → index-a6-uB8ph.js} +1 -1
  26. package/dist/web/static/assets/{index-Bqg4_WEG.js → index-aAfs_cWd.js} +1 -1
  27. package/dist/web/static/assets/{index-unnPilnK.js → index-xpwLXfWl.js} +1 -1
  28. package/dist/web/static/assets/{jszip.min-DYFwy4PE.js → jszip.min-BXx8_j4Y.js} +1 -1
  29. package/dist/web/static/assets/{pptx-preview.es-eu2nX9JC.js → pptx-preview.es-ByVfeUXp.js} +1 -1
  30. package/dist/web/static/index.html +2 -2
  31. package/package.json +1 -1
  32. package/dist/web/static/assets/index-DeYCGmOR.css +0 -32
@@ -2018,10 +2018,155 @@ var init_model_catalog = __esm({
2018
2018
  }
2019
2019
  });
2020
2020
 
2021
- // src/core/ssh-config-scanner.ts
2022
- import fs3 from "fs/promises";
2023
- import path3 from "path";
2021
+ // src/core/claude-cli-detect.ts
2022
+ var claude_cli_detect_exports = {};
2023
+ __export(claude_cli_detect_exports, {
2024
+ _CLAUDE_CREDENTIALS_HOME: () => _CLAUDE_CREDENTIALS_HOME,
2025
+ describeClaudeCliAuth: () => describeClaudeCliAuth,
2026
+ detectClaudeCli: () => detectClaudeCli,
2027
+ hasClaudeSubscriptionAuth: () => hasClaudeSubscriptionAuth,
2028
+ isClaudeCliInstalled: () => isClaudeCliInstalled,
2029
+ resolveClaudeCliExecutable: () => resolveClaudeCliExecutable
2030
+ });
2031
+ import { execFileSync } from "child_process";
2032
+ import fs3 from "fs";
2024
2033
  import os2 from "os";
2034
+ import path3 from "path";
2035
+ function resolveClaudeCliExecutable(env3 = process.env) {
2036
+ const home = env3.HOME || os2.homedir();
2037
+ const pathDirs = (env3.PATH ?? "").split(path3.delimiter).filter(Boolean);
2038
+ const fallbackDirs = [
2039
+ path3.join(home, ".toolbox", "bin"),
2040
+ path3.join(home, ".local", "bin"),
2041
+ path3.join(home, ".npm-global", "bin"),
2042
+ path3.join(home, ".bun", "bin"),
2043
+ "/usr/local/bin",
2044
+ "/opt/homebrew/bin",
2045
+ "/usr/bin",
2046
+ "/bin"
2047
+ ];
2048
+ for (const dir2 of [.../* @__PURE__ */ new Set([...pathDirs, ...fallbackDirs])]) {
2049
+ const candidate = path3.join(dir2, "claude");
2050
+ try {
2051
+ fs3.accessSync(candidate, fs3.constants.X_OK);
2052
+ return candidate;
2053
+ } catch {
2054
+ }
2055
+ }
2056
+ return null;
2057
+ }
2058
+ function isClaudeCliInstalled() {
2059
+ return resolveClaudeCliExecutable() !== null;
2060
+ }
2061
+ function hasClaudeSubscriptionAuth() {
2062
+ if (process.platform === "darwin") {
2063
+ try {
2064
+ execFileSync("security", ["find-generic-password", "-s", KEYCHAIN_OAUTH_SERVICE], {
2065
+ stdio: "ignore"
2066
+ });
2067
+ return true;
2068
+ } catch {
2069
+ }
2070
+ }
2071
+ return fileCredentialExists();
2072
+ }
2073
+ function fileCredentialExists() {
2074
+ try {
2075
+ return fs3.existsSync(CLAUDE_CREDENTIALS_FILE);
2076
+ } catch {
2077
+ return false;
2078
+ }
2079
+ }
2080
+ function detectClaudeCli() {
2081
+ const installed2 = isClaudeCliInstalled();
2082
+ const subscriptionAuth = installed2 && hasClaudeSubscriptionAuth();
2083
+ return {
2084
+ installed: installed2,
2085
+ subscriptionAuth,
2086
+ subscriptionReady: installed2 && subscriptionAuth,
2087
+ ready: installed2,
2088
+ auth: installed2 ? describeClaudeCliAuth() : { mode: "unknown", label: "not installed" }
2089
+ };
2090
+ }
2091
+ function describeClaudeCliAuth(env3 = process.env, settingsEnv = readClaudeSettingsEnv()) {
2092
+ const merged = { ...env3, ...settingsEnv };
2093
+ const truthy = (v3) => !!v3 && v3 !== "0" && v3.toLowerCase() !== "false";
2094
+ if (truthy(merged.CLAUDE_CODE_USE_BEDROCK)) {
2095
+ const region = merged.AWS_REGION || merged.AWS_DEFAULT_REGION;
2096
+ return { mode: "bedrock", label: region ? `Bedrock (${region})` : "Bedrock" };
2097
+ }
2098
+ if (truthy(merged.CLAUDE_CODE_USE_VERTEX)) return { mode: "vertex", label: "Vertex AI" };
2099
+ if (merged.ANTHROPIC_API_KEY || merged.ANTHROPIC_AUTH_TOKEN) return { mode: "api-key", label: "an Anthropic API key" };
2100
+ if (hasClaudeSubscriptionAuth()) return { mode: "subscription", label: "your Claude subscription" };
2101
+ return { mode: "unknown", label: "its own login" };
2102
+ }
2103
+ function readClaudeSettingsEnv() {
2104
+ try {
2105
+ const raw = fs3.readFileSync(path3.join(os2.homedir(), ".claude", "settings.json"), "utf8");
2106
+ const env3 = JSON.parse(raw).env ?? {};
2107
+ return Object.fromEntries(Object.entries(env3).filter(([, v3]) => typeof v3 === "string"));
2108
+ } catch {
2109
+ return {};
2110
+ }
2111
+ }
2112
+ var KEYCHAIN_OAUTH_SERVICE, _CLAUDE_CREDENTIALS_HOME;
2113
+ var init_claude_cli_detect = __esm({
2114
+ "src/core/claude-cli-detect.ts"() {
2115
+ "use strict";
2116
+ init_constants();
2117
+ KEYCHAIN_OAUTH_SERVICE = "Claude Code-credentials";
2118
+ _CLAUDE_CREDENTIALS_HOME = os2.homedir();
2119
+ }
2120
+ });
2121
+
2122
+ // src/agent/providers/default-provider.ts
2123
+ var default_provider_exports = {};
2124
+ __export(default_provider_exports, {
2125
+ CLAUDE_CLI_PROVIDER: () => CLAUDE_CLI_PROVIDER,
2126
+ LEGACY_DEFAULT_PROVIDER: () => LEGACY_DEFAULT_PROVIDER,
2127
+ _resetDefaultProviderCacheForTesting: () => _resetDefaultProviderCacheForTesting,
2128
+ hasExplicitBedrockConfig: () => hasExplicitBedrockConfig,
2129
+ mainProviderIsImplicit: () => mainProviderIsImplicit,
2130
+ resolveMainProviderName: () => resolveMainProviderName
2131
+ });
2132
+ function claudeCliInstalledCached() {
2133
+ const now = Date.now();
2134
+ if (!cliProbe || now - cliProbe.at > CLI_PROBE_TTL_MS) {
2135
+ cliProbe = { at: now, installed: isClaudeCliInstalled() };
2136
+ }
2137
+ return cliProbe.installed;
2138
+ }
2139
+ function _resetDefaultProviderCacheForTesting() {
2140
+ cliProbe = void 0;
2141
+ }
2142
+ function hasExplicitBedrockConfig(config) {
2143
+ const b8 = config.providers?.bedrock;
2144
+ if (b8 && (b8.bearer_token || b8.aws_access_key_id || b8.aws_profile || b8.aws_credential_export)) return true;
2145
+ return !!config.provider?.bedrock_bearer_token;
2146
+ }
2147
+ function resolveMainProviderName(config, claudeInstalled = claudeCliInstalledCached()) {
2148
+ if (config.agent?.main_provider) return config.agent.main_provider;
2149
+ if (claudeInstalled) return CLAUDE_CLI_PROVIDER;
2150
+ return LEGACY_DEFAULT_PROVIDER;
2151
+ }
2152
+ function mainProviderIsImplicit(config) {
2153
+ return !config.agent?.main_provider;
2154
+ }
2155
+ var LEGACY_DEFAULT_PROVIDER, CLAUDE_CLI_PROVIDER, CLI_PROBE_TTL_MS, cliProbe;
2156
+ var init_default_provider = __esm({
2157
+ "src/agent/providers/default-provider.ts"() {
2158
+ "use strict";
2159
+ init_claude_cli_detect();
2160
+ LEGACY_DEFAULT_PROVIDER = "bedrock";
2161
+ CLAUDE_CLI_PROVIDER = "claude_cli";
2162
+ CLI_PROBE_TTL_MS = 6e4;
2163
+ }
2164
+ });
2165
+
2166
+ // src/core/ssh-config-scanner.ts
2167
+ import fs4 from "fs/promises";
2168
+ import path4 from "path";
2169
+ import os3 from "os";
2025
2170
  function isGitServerHost(h8) {
2026
2171
  if (h8.user === "git") return true;
2027
2172
  const gitPrefix = /^(git|github|gitlab|bitbucket|codecommit|ssh\.github)\./i;
@@ -2037,10 +2182,10 @@ function shortLabelForFqdn(hostname) {
2037
2182
  return `${first.slice(0, 12)}\u2026${first.slice(-8)}`;
2038
2183
  }
2039
2184
  async function scanSshConfig(configPath) {
2040
- const sshConfigPath = configPath ?? path3.join(os2.homedir(), ".ssh", "config");
2185
+ const sshConfigPath = configPath ?? path4.join(os3.homedir(), ".ssh", "config");
2041
2186
  let mtimeMs2;
2042
2187
  try {
2043
- mtimeMs2 = (await fs3.stat(sshConfigPath)).mtimeMs;
2188
+ mtimeMs2 = (await fs4.stat(sshConfigPath)).mtimeMs;
2044
2189
  } catch {
2045
2190
  return /* @__PURE__ */ new Map();
2046
2191
  }
@@ -2053,7 +2198,7 @@ async function scanSshConfig(configPath) {
2053
2198
  async function parseSshConfigFile(sshConfigPath) {
2054
2199
  const discovered = /* @__PURE__ */ new Map();
2055
2200
  try {
2056
- const content = await fs3.readFile(sshConfigPath, "utf-8");
2201
+ const content = await fs4.readFile(sshConfigPath, "utf-8");
2057
2202
  const lines = content.split("\n");
2058
2203
  let currentHost = null;
2059
2204
  for (const rawLine of lines) {
@@ -2154,23 +2299,24 @@ __export(config_manager_exports, {
2154
2299
  updatePushTokens: () => updatePushTokens,
2155
2300
  writeFileAtomic: () => writeFileAtomic
2156
2301
  });
2157
- import fs4 from "fs/promises";
2302
+ import fs5 from "fs/promises";
2158
2303
  import yaml from "js-yaml";
2159
- function resolveAgentEngineProvider(config) {
2304
+ function resolveAgentEngineProvider(config, claudeInstalled) {
2160
2305
  if (CLOUD_MODE) return "walnut-agent";
2161
2306
  const raw = config.agent?.provider;
2162
2307
  if (typeof raw === "string" && VALID_AGENT_ENGINE_PROVIDERS.has(raw)) {
2163
2308
  return raw;
2164
2309
  }
2165
- if (raw !== void 0) {
2166
- log.session.warn("config-manager: agent.provider is not a known engine \u2014 using the default", {
2167
- value: typeof raw === "string" ? raw : `<${typeof raw}>`,
2168
- using: FALLBACK_AGENT_ENGINE_PROVIDER,
2169
- valid: [...VALID_AGENT_ENGINE_PROVIDERS].join(", ")
2170
- });
2171
- return FALLBACK_AGENT_ENGINE_PROVIDER;
2310
+ if (raw === void 0) {
2311
+ const main = claudeInstalled === void 0 ? resolveMainProviderName(config) : resolveMainProviderName(config, claudeInstalled);
2312
+ return main === CLAUDE_CLI_PROVIDER ? "claude-code" : "walnut-agent";
2172
2313
  }
2173
- return DEFAULT_AGENT_ENGINE_PROVIDER;
2314
+ log.session.warn("config-manager: agent.provider is not a known engine \u2014 using the fallback", {
2315
+ value: typeof raw === "string" ? raw : `<${typeof raw}>`,
2316
+ using: FALLBACK_AGENT_ENGINE_PROVIDER,
2317
+ valid: [...VALID_AGENT_ENGINE_PROVIDERS].join(", ")
2318
+ });
2319
+ return FALLBACK_AGENT_ENGINE_PROVIDER;
2174
2320
  }
2175
2321
  function migrateConfigToProjectOnly(config) {
2176
2322
  let changed = false;
@@ -2243,13 +2389,13 @@ function migrateConfigToProjectOnly(config) {
2243
2389
  }
2244
2390
  async function readRawConfigContent() {
2245
2391
  try {
2246
- const primary = await fs4.readFile(CONFIG_FILE, "utf-8");
2392
+ const primary = await fs5.readFile(CONFIG_FILE, "utf-8");
2247
2393
  if (primary.trim()) return primary;
2248
2394
  throw new Error("config.yaml is empty");
2249
2395
  } catch (primaryErr) {
2250
2396
  let backup;
2251
2397
  try {
2252
- backup = await fs4.readFile(CONFIG_BACKUP_FILE, "utf-8");
2398
+ backup = await fs5.readFile(CONFIG_BACKUP_FILE, "utf-8");
2253
2399
  } catch {
2254
2400
  return null;
2255
2401
  }
@@ -2259,7 +2405,7 @@ async function readRawConfigContent() {
2259
2405
  backup: CONFIG_BACKUP_FILE
2260
2406
  });
2261
2407
  try {
2262
- await fs4.writeFile(CONFIG_FILE, backup, "utf-8");
2408
+ await fs5.writeFile(CONFIG_FILE, backup, "utf-8");
2263
2409
  } catch {
2264
2410
  }
2265
2411
  return backup;
@@ -2268,10 +2414,10 @@ async function readRawConfigContent() {
2268
2414
  async function writeFileAtomic(filePath, content) {
2269
2415
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now().toString(36)}`;
2270
2416
  try {
2271
- await fs4.writeFile(tmp, content, "utf-8");
2272
- await fs4.rename(tmp, filePath);
2417
+ await fs5.writeFile(tmp, content, "utf-8");
2418
+ await fs5.rename(tmp, filePath);
2273
2419
  } catch (err2) {
2274
- await fs4.rm(tmp, { force: true }).catch(() => {
2420
+ await fs5.rm(tmp, { force: true }).catch(() => {
2275
2421
  });
2276
2422
  throw err2;
2277
2423
  }
@@ -2469,7 +2615,7 @@ async function seedConfigDefaults() {
2469
2615
  const config = await getConfig();
2470
2616
  let needsWrite = false;
2471
2617
  try {
2472
- const raw = await fs4.readFile(CONFIG_FILE, "utf-8");
2618
+ const raw = await fs5.readFile(CONFIG_FILE, "utf-8");
2473
2619
  if (!raw.includes("available_models")) {
2474
2620
  needsWrite = true;
2475
2621
  }
@@ -2497,6 +2643,7 @@ var init_config_manager = __esm({
2497
2643
  init_constants();
2498
2644
  init_types();
2499
2645
  init_model_catalog();
2646
+ init_default_provider();
2500
2647
  init_ssh_config_scanner();
2501
2648
  DEFAULT_CONFIG = {
2502
2649
  version: 1,
@@ -2508,12 +2655,12 @@ var init_config_manager = __esm({
2508
2655
  // so this never re-routes an established setup.
2509
2656
  defaults: { priority: "none", platform: "local" },
2510
2657
  provider: { type: "claude-code" },
2511
- // Which ENGINE answers a Personal AI chat turn. 'walnut-agent' = today's in-process
2512
- // agent loop; 'claude-code' routes the turn into a lane-bound `claude` session.
2513
- // NOTE: getConfig() spreads the parsed file OVER these defaults at the TOP
2514
- // level, so a config.yaml with any `agent:` section replaces this whole object
2515
- // — resolveAgentEngineProvider() (below) is what actually applies the default.
2516
- agent: { provider: DEFAULT_AGENT_ENGINE_PROVIDER }
2658
+ // Which ENGINE answers a Personal AI chat turn is NOT defaulted here: it follows
2659
+ // the AI provider (Settings → AI Provider) — see resolveAgentEngineProvider().
2660
+ // getConfig() spreads the parsed file OVER these defaults at the TOP level, so
2661
+ // anything put in this object is dropped by any config.yaml with an `agent:`
2662
+ // section; the resolver is what actually applies the rule.
2663
+ agent: {}
2517
2664
  };
2518
2665
  CONFIG_BACKUP_FILE = `${CONFIG_FILE}.bak`;
2519
2666
  writeLock = Promise.resolve();
@@ -2521,14 +2668,14 @@ var init_config_manager = __esm({
2521
2668
  });
2522
2669
 
2523
2670
  // src/utils/file-lock.ts
2524
- import fs5 from "fs";
2671
+ import fs6 from "fs";
2525
2672
  import fsp2 from "fs/promises";
2526
- import path4 from "path";
2673
+ import path5 from "path";
2527
2674
  function lockDir(filePath) {
2528
2675
  return filePath + ".lock";
2529
2676
  }
2530
2677
  function pidFile(lock) {
2531
- return path4.join(lock, "pid");
2678
+ return path5.join(lock, "pid");
2532
2679
  }
2533
2680
  function isPidAlive(pid) {
2534
2681
  try {
@@ -2541,7 +2688,7 @@ function isPidAlive(pid) {
2541
2688
  async function withFileLock(filePath, fn) {
2542
2689
  const lock = lockDir(filePath);
2543
2690
  const deadline4 = Date.now() + TIMEOUT_MS;
2544
- await fsp2.mkdir(path4.dirname(lock), { recursive: true });
2691
+ await fsp2.mkdir(path5.dirname(lock), { recursive: true });
2545
2692
  while (true) {
2546
2693
  try {
2547
2694
  await fsp2.mkdir(lock);
@@ -2616,10 +2763,10 @@ __export(device_auth_exports, {
2616
2763
  verifyDeviceToken: () => verifyDeviceToken
2617
2764
  });
2618
2765
  import crypto2 from "crypto";
2619
- import fs6 from "fs/promises";
2620
- import path5 from "path";
2766
+ import fs7 from "fs/promises";
2767
+ import path6 from "path";
2621
2768
  function authFilePath() {
2622
- return path5.join(WALNUT_HOME, "auth.json");
2769
+ return path6.join(WALNUT_HOME, "auth.json");
2623
2770
  }
2624
2771
  function sha256Hex(input) {
2625
2772
  return crypto2.createHash("sha256").update(input, "utf-8").digest("hex");
@@ -2634,7 +2781,7 @@ async function loadAuth() {
2634
2781
  const file = authFilePath();
2635
2782
  let raw;
2636
2783
  try {
2637
- raw = await fs6.readFile(file, "utf-8");
2784
+ raw = await fs7.readFile(file, "utf-8");
2638
2785
  } catch {
2639
2786
  const recovered = await readAuthBackup();
2640
2787
  if (recovered) {
@@ -2667,7 +2814,7 @@ function authBackupPath() {
2667
2814
  }
2668
2815
  async function readAuthBackup() {
2669
2816
  try {
2670
- const raw = await fs6.readFile(authBackupPath(), "utf-8");
2817
+ const raw = await fs7.readFile(authBackupPath(), "utf-8");
2671
2818
  const parsed = JSON.parse(raw);
2672
2819
  if (!Array.isArray(parsed.devices)) return null;
2673
2820
  const devices = parsed.devices.filter((d8) => d8 && typeof d8.name === "string" && typeof d8.tokenHash === "string");
@@ -2678,14 +2825,14 @@ async function readAuthBackup() {
2678
2825
  }
2679
2826
  async function saveAuth(auth) {
2680
2827
  const file = authFilePath();
2681
- await fs6.mkdir(path5.dirname(file), { recursive: true });
2828
+ await fs7.mkdir(path6.dirname(file), { recursive: true });
2682
2829
  const tmp = `${file}.tmp-${process.pid}`;
2683
- await fs6.writeFile(tmp, JSON.stringify(auth, null, 2) + "\n", { mode: 384 });
2684
- await fs6.rename(tmp, file);
2830
+ await fs7.writeFile(tmp, JSON.stringify(auth, null, 2) + "\n", { mode: 384 });
2831
+ await fs7.rename(tmp, file);
2685
2832
  try {
2686
2833
  const btmp = `${authBackupPath()}.tmp-${process.pid}`;
2687
- await fs6.writeFile(btmp, JSON.stringify(auth, null, 2) + "\n", { mode: 384 });
2688
- await fs6.rename(btmp, authBackupPath());
2834
+ await fs7.writeFile(btmp, JSON.stringify(auth, null, 2) + "\n", { mode: 384 });
2835
+ await fs7.rename(btmp, authBackupPath());
2689
2836
  } catch (err2) {
2690
2837
  log.web.warn("failed to update auth.json.bak", { error: err2 instanceof Error ? err2.message : String(err2) });
2691
2838
  }
@@ -2813,7 +2960,7 @@ async function readProvisionedSetupToken() {
2813
2960
  if (file) {
2814
2961
  source = "file";
2815
2962
  try {
2816
- candidate = await fs6.readFile(file, "utf-8");
2963
+ candidate = await fs7.readFile(file, "utf-8");
2817
2964
  } catch (err2) {
2818
2965
  const code = err2.code;
2819
2966
  if (code !== "ENOENT") {
@@ -2904,7 +3051,7 @@ async function claimInstance(candidateToken, deviceName) {
2904
3051
  const tokenFile = process.env.WALNUT_SETUP_TOKEN_FILE;
2905
3052
  if (tokenFile) {
2906
3053
  try {
2907
- await fs6.unlink(tokenFile);
3054
+ await fs7.unlink(tokenFile);
2908
3055
  } catch {
2909
3056
  }
2910
3057
  }
@@ -4893,8 +5040,8 @@ var init_format = __esm({
4893
5040
 
4894
5041
  // src/utils/json-conflict-recovery.ts
4895
5042
  import fsp3 from "fs/promises";
4896
- import path6 from "path";
4897
- import os3 from "os";
5043
+ import path7 from "path";
5044
+ import os4 from "os";
4898
5045
  import crypto5 from "crypto";
4899
5046
  import { execFile } from "child_process";
4900
5047
  import { promisify } from "util";
@@ -4974,12 +5121,12 @@ function jsonCandidatesFromPorcelain(lines) {
4974
5121
  return [...out];
4975
5122
  }
4976
5123
  function resolveWalnutDataDir() {
4977
- return process.env.OPEN_WALNUT_HOME || path6.join(os3.homedir(), ".open-walnut");
5124
+ return process.env.OPEN_WALNUT_HOME || path7.join(os4.homedir(), ".open-walnut");
4978
5125
  }
4979
5126
  function isInsideWalnutDataDir(filePath) {
4980
- const dataDir2 = path6.resolve(resolveWalnutDataDir());
4981
- const abs = path6.resolve(filePath);
4982
- return abs === dataDir2 || abs.startsWith(dataDir2 + path6.sep);
5127
+ const dataDir2 = path7.resolve(resolveWalnutDataDir());
5128
+ const abs = path7.resolve(filePath);
5129
+ return abs === dataDir2 || abs.startsWith(dataDir2 + path7.sep);
4983
5130
  }
4984
5131
  async function gitRead(repoDir, args) {
4985
5132
  try {
@@ -5014,17 +5161,17 @@ async function findLastValidJsonVersion(repoDir, relPath, depth = HISTORY_DEPTH)
5014
5161
  return null;
5015
5162
  }
5016
5163
  async function findRepoRootUpward(startDir, boundaryDir) {
5017
- const boundary = path6.resolve(boundaryDir);
5018
- let dir2 = path6.resolve(startDir);
5019
- if (dir2 !== boundary && !dir2.startsWith(boundary + path6.sep)) return null;
5164
+ const boundary = path7.resolve(boundaryDir);
5165
+ let dir2 = path7.resolve(startDir);
5166
+ if (dir2 !== boundary && !dir2.startsWith(boundary + path7.sep)) return null;
5020
5167
  for (; ; ) {
5021
5168
  try {
5022
- await fsp3.stat(path6.join(dir2, ".git"));
5169
+ await fsp3.stat(path7.join(dir2, ".git"));
5023
5170
  return dir2;
5024
5171
  } catch {
5025
5172
  }
5026
5173
  if (dir2 === boundary) return null;
5027
- const parent = path6.dirname(dir2);
5174
+ const parent = path7.dirname(dir2);
5028
5175
  if (parent === dir2) return null;
5029
5176
  dir2 = parent;
5030
5177
  }
@@ -5055,8 +5202,8 @@ function sidecarPath(filePath, label) {
5055
5202
  return `${filePath}.${label}-${stamp}`;
5056
5203
  }
5057
5204
  async function writeFileAtomic2(filePath, content) {
5058
- const dir2 = path6.dirname(filePath);
5059
- const tmp = path6.join(dir2, `.open-walnut-${crypto5.randomBytes(8).toString("hex")}.tmp`);
5205
+ const dir2 = path7.dirname(filePath);
5206
+ const tmp = path7.join(dir2, `.open-walnut-${crypto5.randomBytes(8).toString("hex")}.tmp`);
5060
5207
  try {
5061
5208
  await fsp3.writeFile(tmp, content, "utf-8");
5062
5209
  await fsp3.rename(tmp, filePath);
@@ -5067,7 +5214,7 @@ async function writeFileAtomic2(filePath, content) {
5067
5214
  }
5068
5215
  }
5069
5216
  async function healJsonFileFromHistory(opts) {
5070
- const relPath = (opts.relPath ?? path6.relative(opts.repoDir, opts.filePath)).split(path6.sep).join("/");
5217
+ const relPath = (opts.relPath ?? path7.relative(opts.repoDir, opts.filePath)).split(path7.sep).join("/");
5071
5218
  if (relPath.startsWith("..")) return { action: "skipped", error: "file is outside repoDir" };
5072
5219
  const valid = await findLastValidJsonVersion(opts.repoDir, relPath, opts.depth);
5073
5220
  const parked = sidecarPath(opts.filePath, opts.label);
@@ -5094,7 +5241,7 @@ async function healJsonFileFromHistory(opts) {
5094
5241
  return { action: "restored", restoredFrom: valid.rev, movedTo, content: valid.content };
5095
5242
  }
5096
5243
  async function selfHealDataDirJson(filePath) {
5097
- const abs = path6.resolve(filePath);
5244
+ const abs = path7.resolve(filePath);
5098
5245
  if (!isInsideWalnutDataDir(abs)) return null;
5099
5246
  const failedAt = selfHealFailedAt.get(abs);
5100
5247
  if (failedAt !== void 0 && Date.now() - failedAt < SELF_HEAL_FAILURE_MEMO_MS) return null;
@@ -5102,7 +5249,7 @@ async function selfHealDataDirJson(filePath) {
5102
5249
  if (existing) return existing;
5103
5250
  const work = (async () => {
5104
5251
  const dataDir2 = resolveWalnutDataDir();
5105
- const repoRoot = await findRepoRootUpward(path6.dirname(abs), dataDir2);
5252
+ const repoRoot = await findRepoRootUpward(path7.dirname(abs), dataDir2);
5106
5253
  if (!repoRoot) return null;
5107
5254
  const result = await healJsonFileFromHistory({
5108
5255
  repoDir: repoRoot,
@@ -5145,25 +5292,25 @@ var init_json_conflict_recovery = __esm({
5145
5292
  });
5146
5293
 
5147
5294
  // src/utils/fs.ts
5148
- import fs7 from "fs/promises";
5149
- import path7 from "path";
5295
+ import fs8 from "fs/promises";
5296
+ import path8 from "path";
5150
5297
  import crypto6 from "crypto";
5151
5298
  async function writeJsonFile(filePath, data, options = {}) {
5152
- const dir2 = path7.dirname(filePath);
5153
- await fs7.mkdir(dir2, { recursive: true });
5154
- const tmpFile = path7.join(
5299
+ const dir2 = path8.dirname(filePath);
5300
+ await fs8.mkdir(dir2, { recursive: true });
5301
+ const tmpFile = path8.join(
5155
5302
  dir2,
5156
5303
  `.open-walnut-${crypto6.randomBytes(8).toString("hex")}.tmp`
5157
5304
  );
5158
5305
  try {
5159
- await fs7.writeFile(tmpFile, JSON.stringify(data, null, 2) + "\n", {
5306
+ await fs8.writeFile(tmpFile, JSON.stringify(data, null, 2) + "\n", {
5160
5307
  encoding: "utf-8",
5161
5308
  ...options.mode === void 0 ? {} : { mode: options.mode }
5162
5309
  });
5163
- await fs7.rename(tmpFile, filePath);
5164
- if (options.mode !== void 0) await fs7.chmod(filePath, options.mode);
5310
+ await fs8.rename(tmpFile, filePath);
5311
+ if (options.mode !== void 0) await fs8.chmod(filePath, options.mode);
5165
5312
  } catch (err2) {
5166
- await fs7.rm(tmpFile, { force: true }).catch(() => {
5313
+ await fs8.rm(tmpFile, { force: true }).catch(() => {
5167
5314
  });
5168
5315
  throw err2;
5169
5316
  }
@@ -5171,7 +5318,7 @@ async function writeJsonFile(filePath, data, options = {}) {
5171
5318
  async function readJsonFile(filePath, fallback) {
5172
5319
  let content;
5173
5320
  try {
5174
- content = await fs7.readFile(filePath, "utf-8");
5321
+ content = await fs8.readFile(filePath, "utf-8");
5175
5322
  } catch (err2) {
5176
5323
  if (err2 && typeof err2 === "object" && "code" in err2 && err2.code === "ENOENT") {
5177
5324
  return fallback;
@@ -5213,7 +5360,7 @@ async function updateJsonFile(filePath, fallback, mutate2, options = {}) {
5213
5360
  });
5214
5361
  }
5215
5362
  async function ensureDir(dirPath) {
5216
- await fs7.mkdir(dirPath, { recursive: true });
5363
+ await fs8.mkdir(dirPath, { recursive: true });
5217
5364
  }
5218
5365
  var init_fs = __esm({
5219
5366
  "src/utils/fs.ts"() {
@@ -5238,7 +5385,7 @@ __export(file_ops_exports, {
5238
5385
  });
5239
5386
  import crypto7 from "crypto";
5240
5387
  import fsp4 from "fs/promises";
5241
- import path8 from "path";
5388
+ import path9 from "path";
5242
5389
  function computeContentHash(content) {
5243
5390
  return crypto7.createHash("sha256").update(content).digest("hex").slice(0, 12);
5244
5391
  }
@@ -5314,7 +5461,7 @@ async function editFileContent(filePath, oldContent, newContent, opts) {
5314
5461
  });
5315
5462
  }
5316
5463
  async function writeFileChecked(filePath, content, opts) {
5317
- await fsp4.mkdir(path8.dirname(filePath), { recursive: true });
5464
+ await fsp4.mkdir(path9.dirname(filePath), { recursive: true });
5318
5465
  return withFileLock(filePath, async () => {
5319
5466
  if (opts?.expectedHash != null) {
5320
5467
  let raw;
@@ -5386,16 +5533,16 @@ __export(memory_file_exports, {
5386
5533
  getMemoryFile: () => getMemoryFile,
5387
5534
  updateMemoryFile: () => updateMemoryFile
5388
5535
  });
5389
- import fs8 from "fs";
5390
- import path9 from "path";
5536
+ import fs9 from "fs";
5537
+ import path10 from "path";
5391
5538
  function resolveMemoryPath(agentId) {
5392
5539
  if (!agentId || agentId === "general") return MEMORY_FILE;
5393
- return path9.join(agentMemoryDir(agentId), "MEMORY.md");
5540
+ return path10.join(agentMemoryDir(agentId), "MEMORY.md");
5394
5541
  }
5395
5542
  function getMemoryFile(agentId) {
5396
5543
  const filePath = resolveMemoryPath(agentId);
5397
5544
  try {
5398
- const content = fs8.readFileSync(filePath, "utf-8");
5545
+ const content = fs9.readFileSync(filePath, "utf-8");
5399
5546
  return { content, contentHash: computeContentHash(content) };
5400
5547
  } catch (err2) {
5401
5548
  log.memory.debug("memory-file: MEMORY.md not found or unreadable", {
@@ -5406,7 +5553,7 @@ function getMemoryFile(agentId) {
5406
5553
  }
5407
5554
  async function updateMemoryFile(content, expectedHash, agentId) {
5408
5555
  const filePath = resolveMemoryPath(agentId);
5409
- fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
5556
+ fs9.mkdirSync(path10.dirname(filePath), { recursive: true });
5410
5557
  const result = await writeFileChecked(filePath, content, {
5411
5558
  expectedHash
5412
5559
  });
@@ -5421,9 +5568,9 @@ async function editMemoryFile(oldContent, newContent, expectedHash, replaceAll,
5421
5568
  }
5422
5569
  function ensureMemoryFile(agentId) {
5423
5570
  const filePath = resolveMemoryPath(agentId);
5424
- if (fs8.existsSync(filePath)) return;
5425
- fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
5426
- fs8.writeFileSync(filePath, DEFAULT_TEMPLATE, "utf-8");
5571
+ if (fs9.existsSync(filePath)) return;
5572
+ fs9.mkdirSync(path10.dirname(filePath), { recursive: true });
5573
+ fs9.writeFileSync(filePath, DEFAULT_TEMPLATE, "utf-8");
5427
5574
  }
5428
5575
  var DEFAULT_TEMPLATE;
5429
5576
  var init_memory_file = __esm({
@@ -5443,15 +5590,15 @@ description: >
5443
5590
 
5444
5591
  // src/core/tmp-sweep.ts
5445
5592
  import fsp5 from "fs/promises";
5446
- import path10 from "path";
5593
+ import path11 from "path";
5447
5594
  function sweepDirs() {
5448
5595
  return [
5449
5596
  WALNUT_HOME,
5450
5597
  SYNC_DIR,
5451
- path10.join(WALNUT_HOME, "sessions"),
5452
- path10.join(WALNUT_HOME, "sessions", "transcripts"),
5598
+ path11.join(WALNUT_HOME, "sessions"),
5599
+ path11.join(WALNUT_HOME, "sessions", "transcripts"),
5453
5600
  TASKS_DIR,
5454
- path10.join(TASKS_DIR, "outbox"),
5601
+ path11.join(TASKS_DIR, "outbox"),
5455
5602
  CONVERSATIONS_DIR,
5456
5603
  MEMORY_DIR,
5457
5604
  DAILY_DIR,
@@ -5472,7 +5619,7 @@ async function sweepOrphanAtomicTmpFiles() {
5472
5619
  const entries = await fsp5.readdir(dir2, { withFileTypes: true });
5473
5620
  for (const entry of entries) {
5474
5621
  if (!entry.isFile() || !ORPHAN_RE.test(entry.name)) continue;
5475
- const full = path10.join(dir2, entry.name);
5622
+ const full = path11.join(dir2, entry.name);
5476
5623
  try {
5477
5624
  const st = await fsp5.stat(full);
5478
5625
  if (st.mtimeMs > cutoff) continue;
@@ -5509,10 +5656,10 @@ __export(init_exports, {
5509
5656
  initDirectories: () => initDirectories
5510
5657
  });
5511
5658
  import fsp6 from "fs/promises";
5512
- import fs9 from "fs";
5659
+ import fs10 from "fs";
5513
5660
  async function migrateLegacyMemoryFile() {
5514
5661
  try {
5515
- if (fs9.existsSync(LEGACY_MEMORY_FILE) && !fs9.existsSync(MEMORY_FILE)) {
5662
+ if (fs10.existsSync(LEGACY_MEMORY_FILE) && !fs10.existsSync(MEMORY_FILE)) {
5516
5663
  await fsp6.rename(LEGACY_MEMORY_FILE, MEMORY_FILE);
5517
5664
  log.memory.info("Migrated MEMORY.md into memory/ folder", { from: LEGACY_MEMORY_FILE, to: MEMORY_FILE });
5518
5665
  }
@@ -6057,15 +6204,15 @@ __export(task_db_exports, {
6057
6204
  transaction: () => transaction
6058
6205
  });
6059
6206
  import Database from "better-sqlite3";
6060
- import fs10 from "fs";
6061
- import path11 from "path";
6207
+ import fs11 from "fs";
6208
+ import path12 from "path";
6062
6209
  import yaml2 from "js-yaml";
6063
6210
  function getDb() {
6064
6211
  if (db) return db;
6065
6212
  if (initAttempted) throw initError;
6066
6213
  initAttempted = true;
6067
6214
  try {
6068
- fs10.mkdirSync(path11.dirname(TASK_DB_PATH), { recursive: true });
6215
+ fs11.mkdirSync(path12.dirname(TASK_DB_PATH), { recursive: true });
6069
6216
  const handle2 = new Database(TASK_DB_PATH);
6070
6217
  handle2.pragma("journal_mode = WAL");
6071
6218
  handle2.pragma("busy_timeout = 5000");
@@ -6295,8 +6442,8 @@ function migrateToProjectOnly(handle2) {
6295
6442
  }
6296
6443
  try {
6297
6444
  handle2.pragma("wal_checkpoint(TRUNCATE)");
6298
- if (!fs10.existsSync(TASK_DB_PRE_V5_BACKUP_PATH)) {
6299
- fs10.copyFileSync(TASK_DB_PATH, TASK_DB_PRE_V5_BACKUP_PATH);
6445
+ if (!fs11.existsSync(TASK_DB_PRE_V5_BACKUP_PATH)) {
6446
+ fs11.copyFileSync(TASK_DB_PATH, TASK_DB_PRE_V5_BACKUP_PATH);
6300
6447
  log.task.info("task-db v5: wrote pre-migration backup", { path: TASK_DB_PRE_V5_BACKUP_PATH });
6301
6448
  }
6302
6449
  } catch (err2) {
@@ -6806,7 +6953,7 @@ var init_task_db = __esm({
6806
6953
  init_constants();
6807
6954
  init_logging();
6808
6955
  init_phase2();
6809
- TASK_DB_PATH = path11.join(TASKS_DIR, "tasks.sqlite");
6956
+ TASK_DB_PATH = path12.join(TASKS_DIR, "tasks.sqlite");
6810
6957
  EXPLICIT_TASK_COLUMNS = [
6811
6958
  "id",
6812
6959
  "title",
@@ -6969,8 +7116,8 @@ var init_task_db = __esm({
6969
7116
  });
6970
7117
 
6971
7118
  // src/core/task-db-migration.ts
6972
- import fs11 from "fs";
6973
- import path12 from "path";
7119
+ import fs12 from "fs";
7120
+ import path13 from "path";
6974
7121
  import yaml3 from "js-yaml";
6975
7122
  async function runMigrationIfNeeded() {
6976
7123
  const db5 = getDb();
@@ -6981,7 +7128,7 @@ async function runMigrationIfNeeded() {
6981
7128
  if (existing.n > 0) {
6982
7129
  return { migrated: false, count: existing.n };
6983
7130
  }
6984
- if (!fs11.existsSync(TASKS_FILE)) {
7131
+ if (!fs12.existsSync(TASKS_FILE)) {
6985
7132
  return { migrated: false, count: 0 };
6986
7133
  }
6987
7134
  const store3 = await readJsonFile(TASKS_FILE, { version: 1, tasks: [] });
@@ -7138,9 +7285,9 @@ async function runMigrationIfNeeded() {
7138
7285
  }
7139
7286
  const after = db5.prepare("SELECT COUNT(*) AS n FROM tasks").get();
7140
7287
  const count2 = after.n;
7141
- const backupPath = path12.join(path12.dirname(TASKS_FILE), "tasks.json.migrated-from-json.backup");
7288
+ const backupPath = path13.join(path13.dirname(TASKS_FILE), "tasks.json.migrated-from-json.backup");
7142
7289
  try {
7143
- fs11.copyFileSync(TASKS_FILE, backupPath);
7290
+ fs12.copyFileSync(TASKS_FILE, backupPath);
7144
7291
  } catch (err2) {
7145
7292
  log.task.warn("task-db migration: backup copy failed (non-fatal)", {
7146
7293
  path: backupPath,
@@ -7164,9 +7311,9 @@ var init_task_db_migration = __esm({
7164
7311
  });
7165
7312
 
7166
7313
  // src/core/memory-dir-migration.ts
7167
- import fs12 from "fs";
7314
+ import fs13 from "fs";
7168
7315
  import fsp7 from "fs/promises";
7169
- import path13 from "path";
7316
+ import path14 from "path";
7170
7317
  function bodyOf(content) {
7171
7318
  const fm = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
7172
7319
  return fm ? content.slice(fm[0].length) : content;
@@ -7184,7 +7331,7 @@ ${legacyBody}
7184
7331
  }
7185
7332
  function mtimeMs(file) {
7186
7333
  try {
7187
- return fs12.statSync(file).mtimeMs;
7334
+ return fs13.statSync(file).mtimeMs;
7188
7335
  } catch {
7189
7336
  return 0;
7190
7337
  }
@@ -7193,24 +7340,24 @@ function findCandidates(root6) {
7193
7340
  const out = [];
7194
7341
  let level1;
7195
7342
  try {
7196
- level1 = fs12.readdirSync(root6, { withFileTypes: true });
7343
+ level1 = fs13.readdirSync(root6, { withFileTypes: true });
7197
7344
  } catch {
7198
7345
  return out;
7199
7346
  }
7200
7347
  for (const cat of level1) {
7201
7348
  if (!cat.isDirectory()) continue;
7202
- const catDir = path13.join(root6, cat.name);
7203
- if (fs12.existsSync(path13.join(catDir, MEMORY_FILE_NAME))) continue;
7349
+ const catDir = path14.join(root6, cat.name);
7350
+ if (fs13.existsSync(path14.join(catDir, MEMORY_FILE_NAME))) continue;
7204
7351
  let level2;
7205
7352
  try {
7206
- level2 = fs12.readdirSync(catDir, { withFileTypes: true });
7353
+ level2 = fs13.readdirSync(catDir, { withFileTypes: true });
7207
7354
  } catch {
7208
7355
  continue;
7209
7356
  }
7210
7357
  for (const proj of level2) {
7211
7358
  if (!proj.isDirectory()) continue;
7212
- const sourceDir = path13.join(catDir, proj.name);
7213
- if (!fs12.existsSync(path13.join(sourceDir, MEMORY_FILE_NAME))) continue;
7359
+ const sourceDir = path14.join(catDir, proj.name);
7360
+ if (!fs13.existsSync(path14.join(sourceDir, MEMORY_FILE_NAME))) continue;
7214
7361
  out.push({ category: cat.name, project: proj.name, sourceDir });
7215
7362
  }
7216
7363
  }
@@ -7224,11 +7371,11 @@ async function drainDir(from, to) {
7224
7371
  return;
7225
7372
  }
7226
7373
  for (const name of entries) {
7227
- const target = path13.join(to, name);
7228
- if (fs12.existsSync(target)) continue;
7229
- await fsp7.rename(path13.join(from, name), target).catch((err2) => {
7374
+ const target = path14.join(to, name);
7375
+ if (fs13.existsSync(target)) continue;
7376
+ await fsp7.rename(path14.join(from, name), target).catch((err2) => {
7230
7377
  log.memory.warn("memory-dir migration: entry move failed", {
7231
- from: path13.join(from, name),
7378
+ from: path14.join(from, name),
7232
7379
  to: target,
7233
7380
  error: String(err2)
7234
7381
  });
@@ -7240,23 +7387,23 @@ async function drainDir(from, to) {
7240
7387
  async function migrateProjectMemoryDirs() {
7241
7388
  const result = { ran: false, moved: 0, merged: 0 };
7242
7389
  try {
7243
- if (!fs12.existsSync(PROJECTS_MEMORY_DIR)) return result;
7244
- if (fs12.existsSync(MEMORY_DIR_MIGRATION_MARKER)) return result;
7390
+ if (!fs13.existsSync(PROJECTS_MEMORY_DIR)) return result;
7391
+ if (fs13.existsSync(MEMORY_DIR_MIGRATION_MARKER)) return result;
7245
7392
  result.ran = true;
7246
7393
  const candidates = findCandidates(PROJECTS_MEMORY_DIR);
7247
7394
  const touchedCategories = new Set(candidates.map((c8) => c8.category));
7248
7395
  for (const c8 of candidates) {
7249
- const targetDir = path13.join(PROJECTS_MEMORY_DIR, c8.project);
7396
+ const targetDir = path14.join(PROJECTS_MEMORY_DIR, c8.project);
7250
7397
  const label = `${c8.category}/${c8.project}`;
7251
7398
  try {
7252
- if (!fs12.existsSync(targetDir)) {
7399
+ if (!fs13.existsSync(targetDir)) {
7253
7400
  await fsp7.rename(c8.sourceDir, targetDir);
7254
7401
  result.moved += 1;
7255
7402
  continue;
7256
7403
  }
7257
- const sourceMem = path13.join(c8.sourceDir, MEMORY_FILE_NAME);
7258
- const targetMem = path13.join(targetDir, MEMORY_FILE_NAME);
7259
- if (!fs12.existsSync(targetMem)) {
7404
+ const sourceMem = path14.join(c8.sourceDir, MEMORY_FILE_NAME);
7405
+ const targetMem = path14.join(targetDir, MEMORY_FILE_NAME);
7406
+ if (!fs13.existsSync(targetMem)) {
7260
7407
  await fsp7.rename(sourceMem, targetMem);
7261
7408
  await drainDir(c8.sourceDir, targetDir);
7262
7409
  result.moved += 1;
@@ -7278,7 +7425,7 @@ async function migrateProjectMemoryDirs() {
7278
7425
  }
7279
7426
  }
7280
7427
  for (const cat of touchedCategories) {
7281
- await fsp7.rmdir(path13.join(PROJECTS_MEMORY_DIR, cat)).catch(() => {
7428
+ await fsp7.rmdir(path14.join(PROJECTS_MEMORY_DIR, cat)).catch(() => {
7282
7429
  });
7283
7430
  }
7284
7431
  await fsp7.writeFile(
@@ -7306,7 +7453,7 @@ var init_memory_dir_migration = __esm({
7306
7453
  "use strict";
7307
7454
  init_constants();
7308
7455
  init_logging();
7309
- MEMORY_DIR_MIGRATION_MARKER = path13.join(PROJECTS_MEMORY_DIR, ".migrated-project-only");
7456
+ MEMORY_DIR_MIGRATION_MARKER = path14.join(PROJECTS_MEMORY_DIR, ".migrated-project-only");
7310
7457
  MEMORY_FILE_NAME = "MEMORY.md";
7311
7458
  }
7312
7459
  });
@@ -7522,7 +7669,7 @@ __export(microsoft_todo_exports, {
7522
7669
  });
7523
7670
  import * as msal from "@azure/msal-node";
7524
7671
  import https from "https";
7525
- import path14 from "path";
7672
+ import path15 from "path";
7526
7673
  function getMsTodoConfig(config) {
7527
7674
  return config.plugins?.["ms-todo"];
7528
7675
  }
@@ -8741,8 +8888,8 @@ var init_microsoft_todo = __esm({
8741
8888
  init_format();
8742
8889
  init_task_manager();
8743
8890
  init_task_remote_links();
8744
- TOKENS_FILE = path14.join(SYNC_DIR, "ms-todo-tokens.json");
8745
- DELTA_FILE = path14.join(SYNC_DIR, "ms-todo-delta.json");
8891
+ TOKENS_FILE = path15.join(SYNC_DIR, "ms-todo-tokens.json");
8892
+ DELTA_FILE = path15.join(SYNC_DIR, "ms-todo-delta.json");
8746
8893
  GRAPH_BASE = "https://graph.microsoft.com/v1.0";
8747
8894
  SCOPES = ["Tasks.ReadWrite"];
8748
8895
  PRIORITY_TO_IMPORTANCE = {
@@ -8860,8 +9007,8 @@ var init_daemon_capabilities = __esm({
8860
9007
 
8861
9008
  // src/providers/daemon-version-check.ts
8862
9009
  import { createHash } from "crypto";
8863
- import fs13 from "fs";
8864
- import path15 from "path";
9010
+ import fs14 from "fs";
9011
+ import path16 from "path";
8865
9012
  import { spawnSync } from "child_process";
8866
9013
  import { fileURLToPath as fileURLToPath2 } from "url";
8867
9014
  function computeExpectedDaemonVersion() {
@@ -8870,11 +9017,11 @@ function computeExpectedDaemonVersion() {
8870
9017
  const hash = createHash("sha256");
8871
9018
  const NUL = Buffer.from([0]);
8872
9019
  for (const rel of DAEMON_SOURCE_FILES) {
8873
- const abs = path15.join(repoRoot, rel);
9020
+ const abs = path16.join(repoRoot, rel);
8874
9021
  try {
8875
9022
  hash.update(Buffer.from(rel));
8876
9023
  hash.update(NUL);
8877
- hash.update(fs13.readFileSync(abs));
9024
+ hash.update(fs14.readFileSync(abs));
8878
9025
  hash.update(NUL);
8879
9026
  } catch {
8880
9027
  return null;
@@ -8883,12 +9030,12 @@ function computeExpectedDaemonVersion() {
8883
9030
  return "walnut-daemon-" + hash.digest("hex").slice(0, 12);
8884
9031
  }
8885
9032
  function findRepoRoot() {
8886
- let dir2 = path15.dirname(fileURLToPath2(import.meta.url));
9033
+ let dir2 = path16.dirname(fileURLToPath2(import.meta.url));
8887
9034
  for (let i8 = 0; i8 < 10; i8++) {
8888
- if (fs13.existsSync(path15.join(dir2, "package.json")) && fs13.existsSync(path15.join(dir2, "src", "providers", "daemon-standalone.ts"))) {
9035
+ if (fs14.existsSync(path16.join(dir2, "package.json")) && fs14.existsSync(path16.join(dir2, "src", "providers", "daemon-standalone.ts"))) {
8889
9036
  return dir2;
8890
9037
  }
8891
- const parent = path15.dirname(dir2);
9038
+ const parent = path16.dirname(dir2);
8892
9039
  if (parent === dir2) break;
8893
9040
  dir2 = parent;
8894
9041
  }
@@ -9233,12 +9380,12 @@ var init_daemon_fold = __esm({
9233
9380
  });
9234
9381
 
9235
9382
  // src/providers/daemon-source.ts
9236
- import fs14 from "fs";
9237
- import path16 from "path";
9383
+ import fs15 from "fs";
9384
+ import path17 from "path";
9238
9385
  import { fileURLToPath as fileURLToPath3 } from "url";
9239
9386
  function resolveDaemonSourceVersion() {
9240
9387
  const here = fileURLToPath3(import.meta.url);
9241
- const bundled = here.split(path16.sep).includes("dist");
9388
+ const bundled = here.split(path17.sep).includes("dist");
9242
9389
  if (bundled) {
9243
9390
  const sidecar = readSidecarDaemonVersion(here);
9244
9391
  if (sidecar) return sidecar;
@@ -9246,32 +9393,32 @@ function resolveDaemonSourceVersion() {
9246
9393
  const computed = computeExpectedDaemonVersion();
9247
9394
  if (computed) return computed;
9248
9395
  if (process.env.DAEMON_VERSION) return process.env.DAEMON_VERSION;
9249
- let dir2 = path16.dirname(fileURLToPath3(import.meta.url));
9396
+ let dir2 = path17.dirname(fileURLToPath3(import.meta.url));
9250
9397
  for (let i8 = 0; i8 < 10; i8++) {
9251
9398
  try {
9252
- const pkg = JSON.parse(fs14.readFileSync(path16.join(dir2, "package.json"), "utf-8"));
9399
+ const pkg = JSON.parse(fs15.readFileSync(path17.join(dir2, "package.json"), "utf-8"));
9253
9400
  if (pkg.name === "open-walnut" && pkg.version) return `walnut-daemon-pkg-${pkg.version}`;
9254
9401
  } catch {
9255
9402
  }
9256
- const parent = path16.dirname(dir2);
9403
+ const parent = path17.dirname(dir2);
9257
9404
  if (parent === dir2) break;
9258
9405
  dir2 = parent;
9259
9406
  }
9260
9407
  return "dev-source";
9261
9408
  }
9262
9409
  function readSidecarDaemonVersion(fromPath) {
9263
- let dir2 = path16.dirname(fromPath);
9410
+ let dir2 = path17.dirname(fromPath);
9264
9411
  for (let i8 = 0; i8 < 5; i8++) {
9265
- const binDir = path16.join(dir2, "daemon-binaries");
9412
+ const binDir = path17.join(dir2, "daemon-binaries");
9266
9413
  try {
9267
- for (const name of fs14.readdirSync(binDir)) {
9414
+ for (const name of fs15.readdirSync(binDir)) {
9268
9415
  if (!name.endsWith(".version")) continue;
9269
- const v3 = fs14.readFileSync(path16.join(binDir, name), "utf-8").trim();
9416
+ const v3 = fs15.readFileSync(path17.join(binDir, name), "utf-8").trim();
9270
9417
  if (v3) return v3;
9271
9418
  }
9272
9419
  } catch {
9273
9420
  }
9274
- const parent = path16.dirname(dir2);
9421
+ const parent = path17.dirname(dir2);
9275
9422
  if (parent === dir2) break;
9276
9423
  dir2 = parent;
9277
9424
  }
@@ -16385,7 +16532,7 @@ if (action === '--start') {
16385
16532
  });
16386
16533
 
16387
16534
  // src/core/jsonl-tailer.ts
16388
- import fs15 from "fs";
16535
+ import fs16 from "fs";
16389
16536
  var init_jsonl_tailer = __esm({
16390
16537
  "src/core/jsonl-tailer.ts"() {
16391
16538
  "use strict";
@@ -16394,10 +16541,10 @@ var init_jsonl_tailer = __esm({
16394
16541
  });
16395
16542
 
16396
16543
  // src/providers/session-io.ts
16397
- import fs16 from "fs";
16544
+ import fs17 from "fs";
16398
16545
  import fsp8 from "fs/promises";
16399
- import path17 from "path";
16400
- import { execFileSync } from "child_process";
16546
+ import path18 from "path";
16547
+ import { execFileSync as execFileSync2 } from "child_process";
16401
16548
  function shellQuote(s4) {
16402
16549
  return "'" + s4.replace(/'/g, "'\\''") + "'";
16403
16550
  }
@@ -16442,7 +16589,7 @@ function findRelativeImageNames(text, opts) {
16442
16589
  function findLocalImagePaths(text) {
16443
16590
  return findImagePaths(text).filter((p6) => {
16444
16591
  try {
16445
- return fs16.statSync(p6).isFile();
16592
+ return fs17.statSync(p6).isFile();
16446
16593
  } catch {
16447
16594
  return false;
16448
16595
  }
@@ -17487,107 +17634,6 @@ var init_daemon_core = __esm({
17487
17634
  }
17488
17635
  });
17489
17636
 
17490
- // src/core/claude-cli-detect.ts
17491
- var claude_cli_detect_exports = {};
17492
- __export(claude_cli_detect_exports, {
17493
- _CLAUDE_CREDENTIALS_HOME: () => _CLAUDE_CREDENTIALS_HOME,
17494
- describeClaudeCliAuth: () => describeClaudeCliAuth,
17495
- detectClaudeCli: () => detectClaudeCli,
17496
- hasClaudeSubscriptionAuth: () => hasClaudeSubscriptionAuth,
17497
- isClaudeCliInstalled: () => isClaudeCliInstalled,
17498
- resolveClaudeCliExecutable: () => resolveClaudeCliExecutable
17499
- });
17500
- import { execFileSync as execFileSync2 } from "child_process";
17501
- import fs17 from "fs";
17502
- import os4 from "os";
17503
- import path18 from "path";
17504
- function resolveClaudeCliExecutable(env3 = process.env) {
17505
- const home = env3.HOME || os4.homedir();
17506
- const pathDirs = (env3.PATH ?? "").split(path18.delimiter).filter(Boolean);
17507
- const fallbackDirs = [
17508
- path18.join(home, ".toolbox", "bin"),
17509
- path18.join(home, ".local", "bin"),
17510
- path18.join(home, ".npm-global", "bin"),
17511
- path18.join(home, ".bun", "bin"),
17512
- "/usr/local/bin",
17513
- "/opt/homebrew/bin",
17514
- "/usr/bin",
17515
- "/bin"
17516
- ];
17517
- for (const dir2 of [.../* @__PURE__ */ new Set([...pathDirs, ...fallbackDirs])]) {
17518
- const candidate = path18.join(dir2, "claude");
17519
- try {
17520
- fs17.accessSync(candidate, fs17.constants.X_OK);
17521
- return candidate;
17522
- } catch {
17523
- }
17524
- }
17525
- return null;
17526
- }
17527
- function isClaudeCliInstalled() {
17528
- return resolveClaudeCliExecutable() !== null;
17529
- }
17530
- function hasClaudeSubscriptionAuth() {
17531
- if (process.platform === "darwin") {
17532
- try {
17533
- execFileSync2("security", ["find-generic-password", "-s", KEYCHAIN_OAUTH_SERVICE], {
17534
- stdio: "ignore"
17535
- });
17536
- return true;
17537
- } catch {
17538
- }
17539
- }
17540
- return fileCredentialExists();
17541
- }
17542
- function fileCredentialExists() {
17543
- try {
17544
- return fs17.existsSync(CLAUDE_CREDENTIALS_FILE);
17545
- } catch {
17546
- return false;
17547
- }
17548
- }
17549
- function detectClaudeCli() {
17550
- const installed2 = isClaudeCliInstalled();
17551
- const subscriptionAuth = installed2 && hasClaudeSubscriptionAuth();
17552
- return {
17553
- installed: installed2,
17554
- subscriptionAuth,
17555
- subscriptionReady: installed2 && subscriptionAuth,
17556
- ready: installed2,
17557
- auth: installed2 ? describeClaudeCliAuth() : { mode: "unknown", label: "not installed" }
17558
- };
17559
- }
17560
- function describeClaudeCliAuth(env3 = process.env, settingsEnv = readClaudeSettingsEnv()) {
17561
- const merged = { ...env3, ...settingsEnv };
17562
- const truthy = (v3) => !!v3 && v3 !== "0" && v3.toLowerCase() !== "false";
17563
- if (truthy(merged.CLAUDE_CODE_USE_BEDROCK)) {
17564
- const region = merged.AWS_REGION || merged.AWS_DEFAULT_REGION;
17565
- return { mode: "bedrock", label: region ? `Bedrock (${region})` : "Bedrock" };
17566
- }
17567
- if (truthy(merged.CLAUDE_CODE_USE_VERTEX)) return { mode: "vertex", label: "Vertex AI" };
17568
- if (merged.ANTHROPIC_API_KEY || merged.ANTHROPIC_AUTH_TOKEN) return { mode: "api-key", label: "an Anthropic API key" };
17569
- if (hasClaudeSubscriptionAuth()) return { mode: "subscription", label: "your Claude subscription" };
17570
- return { mode: "unknown", label: "its own login" };
17571
- }
17572
- function readClaudeSettingsEnv() {
17573
- try {
17574
- const raw = fs17.readFileSync(path18.join(os4.homedir(), ".claude", "settings.json"), "utf8");
17575
- const env3 = JSON.parse(raw).env ?? {};
17576
- return Object.fromEntries(Object.entries(env3).filter(([, v3]) => typeof v3 === "string"));
17577
- } catch {
17578
- return {};
17579
- }
17580
- }
17581
- var KEYCHAIN_OAUTH_SERVICE, _CLAUDE_CREDENTIALS_HOME;
17582
- var init_claude_cli_detect = __esm({
17583
- "src/core/claude-cli-detect.ts"() {
17584
- "use strict";
17585
- init_constants();
17586
- KEYCHAIN_OAUTH_SERVICE = "Claude Code-credentials";
17587
- _CLAUDE_CREDENTIALS_HOME = os4.homedir();
17588
- }
17589
- });
17590
-
17591
17637
  // src/providers/daemon-ownership.ts
17592
17638
  import fs18 from "fs";
17593
17639
  import os5 from "os";
@@ -68258,50 +68304,6 @@ var init_registry = __esm({
68258
68304
  }
68259
68305
  });
68260
68306
 
68261
- // src/agent/providers/default-provider.ts
68262
- var default_provider_exports = {};
68263
- __export(default_provider_exports, {
68264
- CLAUDE_CLI_PROVIDER: () => CLAUDE_CLI_PROVIDER,
68265
- LEGACY_DEFAULT_PROVIDER: () => LEGACY_DEFAULT_PROVIDER,
68266
- _resetDefaultProviderCacheForTesting: () => _resetDefaultProviderCacheForTesting,
68267
- hasExplicitBedrockConfig: () => hasExplicitBedrockConfig,
68268
- mainProviderIsImplicit: () => mainProviderIsImplicit,
68269
- resolveMainProviderName: () => resolveMainProviderName
68270
- });
68271
- function claudeCliInstalledCached() {
68272
- const now = Date.now();
68273
- if (!cliProbe || now - cliProbe.at > CLI_PROBE_TTL_MS) {
68274
- cliProbe = { at: now, installed: isClaudeCliInstalled() };
68275
- }
68276
- return cliProbe.installed;
68277
- }
68278
- function _resetDefaultProviderCacheForTesting() {
68279
- cliProbe = void 0;
68280
- }
68281
- function hasExplicitBedrockConfig(config) {
68282
- const b8 = config.providers?.bedrock;
68283
- if (b8 && (b8.bearer_token || b8.aws_access_key_id || b8.aws_profile || b8.aws_credential_export)) return true;
68284
- return !!config.provider?.bedrock_bearer_token;
68285
- }
68286
- function resolveMainProviderName(config, claudeInstalled = claudeCliInstalledCached()) {
68287
- if (config.agent?.main_provider) return config.agent.main_provider;
68288
- if (claudeInstalled) return CLAUDE_CLI_PROVIDER;
68289
- return LEGACY_DEFAULT_PROVIDER;
68290
- }
68291
- function mainProviderIsImplicit(config) {
68292
- return !config.agent?.main_provider;
68293
- }
68294
- var LEGACY_DEFAULT_PROVIDER, CLAUDE_CLI_PROVIDER, CLI_PROBE_TTL_MS, cliProbe;
68295
- var init_default_provider = __esm({
68296
- "src/agent/providers/default-provider.ts"() {
68297
- "use strict";
68298
- init_claude_cli_detect();
68299
- LEGACY_DEFAULT_PROVIDER = "bedrock";
68300
- CLAUDE_CLI_PROVIDER = "claude_cli";
68301
- CLI_PROBE_TTL_MS = 6e4;
68302
- }
68303
- });
68304
-
68305
68307
  // src/agent/model.ts
68306
68308
  var model_exports = {};
68307
68309
  __export(model_exports, {