tarsk 0.4.28 → 0.4.30

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 (92) hide show
  1. package/dist/index.js +774 -373
  2. package/dist/public/assets/{account-view-DcpSNB3N.js → account-view-wqPOnMfW.js} +1 -1
  3. package/dist/public/assets/alert-dialog-Dj0hDlZC.js +1 -0
  4. package/dist/public/assets/api-RbLAI1bg.js +1 -0
  5. package/dist/public/assets/{browser-tab-CiAz6nc1.js → browser-tab-BjqSmZHm.js} +1 -1
  6. package/dist/public/assets/chat-input-container-BNOl7YtC.js +21 -0
  7. package/dist/public/assets/codicon-ngg6Pgfi.ttf +0 -0
  8. package/dist/public/assets/context-menu-XD6khGRr.js +1 -0
  9. package/dist/public/assets/conversation-history-view-BRSNoBYn.js +1 -0
  10. package/dist/public/assets/css.worker-DyDu5ynT.js +89 -0
  11. package/dist/public/assets/{dialogs-config-vkfELnGl.js → dialogs-config-BXDglGdB.js} +14 -14
  12. package/dist/public/assets/diff-view-DiNlWcSj.js +3 -0
  13. package/dist/public/assets/explorer-tab-view-DbMBihAH.js +2 -0
  14. package/dist/public/assets/{explorer-tree-DTFYhczJ.js → explorer-tree-D0P-HUYS.js} +1 -1
  15. package/dist/public/assets/{explorer-view-C0KcZ8NQ.js → explorer-view-CL_9lhkq.js} +1 -1
  16. package/dist/public/assets/history-view-i7fGKCkc.js +1 -0
  17. package/dist/public/assets/html.worker-IWNXhnIC.js +502 -0
  18. package/dist/public/assets/index-BeLCtY82.css +1 -0
  19. package/dist/public/assets/index-CZZ6Jb9i.js +29 -0
  20. package/dist/public/assets/json.worker-c4h5s80L.js +58 -0
  21. package/dist/public/assets/markdown-renderer-CPSKOcqK.js +10 -0
  22. package/dist/public/assets/mcp-server-card-DFATg_Ie.js +1 -0
  23. package/dist/public/assets/monaco-BGyhgQtx.js +1209 -0
  24. package/dist/public/assets/monaco-Br_kD0ds.css +1 -0
  25. package/dist/public/assets/onboarding-5CTkrfwe.js +1 -0
  26. package/dist/public/assets/onboarding-dialog-gcZ9aKKp.js +1 -0
  27. package/dist/public/assets/page-toolbar-CbwENcML.js +1 -0
  28. package/dist/public/assets/project-settings-view-CRRJPGNL.js +1 -0
  29. package/dist/public/assets/providers-list-view-D3CIB4ou.js +1 -0
  30. package/dist/public/assets/radio-group-qCcnwXV3.js +1 -0
  31. package/dist/public/assets/react-vendor-Bpg1hd5i.js +22 -0
  32. package/dist/public/assets/resizable-BLhzHL_f.js +1 -0
  33. package/dist/public/assets/{run-stop-button-DZ4JFwdL.js → run-stop-button-CIuDOHFg.js} +2 -2
  34. package/dist/public/assets/settings-general-view-7Y0c9534.js +1 -0
  35. package/dist/public/assets/{settings-instructions-view-DWzAH2yN.js → settings-instructions-view-B-uTQrNZ.js} +1 -1
  36. package/dist/public/assets/settings-mcp-servers-view-nAMQQWHb.js +5 -0
  37. package/dist/public/assets/settings-models-skeleton-CffyGIvJ.js +1 -0
  38. package/dist/public/assets/settings-models-view-CMZh5LlR.js +1 -0
  39. package/dist/public/assets/settings-rules-view-BaNccq1v.js +8 -0
  40. package/dist/public/assets/{settings-skills-view-DV40_L1o.js → settings-skills-view-DBX7obT7.js} +2 -2
  41. package/dist/public/assets/{settings-slash-commands-view-BEk3BgOY.js → settings-slash-commands-view-BoT1nCir.js} +1 -1
  42. package/dist/public/assets/{settings-subagents-view-d3P4ylDX.js → settings-subagents-view-Cy87X2bs.js} +2 -2
  43. package/dist/public/assets/settings-view-CS-RnV6J.js +2 -0
  44. package/dist/public/assets/side-panel-container-B33_hnhc.js +2 -0
  45. package/dist/public/assets/skeleton-n47_ST9G.js +1 -0
  46. package/dist/public/assets/standard-list-item-BLTOBGFa.js +1 -0
  47. package/dist/public/assets/store-B9rEO6q-.js +4 -0
  48. package/dist/public/assets/{tab-context-DWD20a4z.js → tab-context-BUUT3x3d.js} +1 -1
  49. package/dist/public/assets/tabs--5y6mYhG.js +1 -0
  50. package/dist/public/assets/{terminal-panel-CkIe2d2K.js → terminal-panel-BCHLDUbD.js} +2 -2
  51. package/dist/public/assets/textarea-CwXpBxom.js +1 -0
  52. package/dist/public/assets/todos-view-k0k8R9NT.js +1 -0
  53. package/dist/public/assets/ts.worker-BwM5Ha3L.js +67719 -0
  54. package/dist/public/assets/use-font-size-BJl84s49.js +1 -0
  55. package/dist/public/assets/{use-toast-yY7qQuQP.js → use-toast-C5s-Xnwi.js} +1 -1
  56. package/dist/public/assets/{utils-BKss67Vg.js → utils-CDrGT12s.js} +1 -1
  57. package/dist/public/assets/{whisper-wasm-B7iuRPFr.js → whisper-wasm-C_Ot631g.js} +1 -1
  58. package/dist/public/index.html +24 -22
  59. package/package.json +2 -2
  60. package/dist/public/assets/alert-dialog-CQRWdGnn.js +0 -1
  61. package/dist/public/assets/api-CH5gAPs5.js +0 -1
  62. package/dist/public/assets/chat-input-container-C6U_WFFu.js +0 -21
  63. package/dist/public/assets/context-menu-A9p22S7d.js +0 -1
  64. package/dist/public/assets/conversation-history-view-CD_uVRNY.js +0 -1
  65. package/dist/public/assets/diff-view-CjbcDB6m.js +0 -3
  66. package/dist/public/assets/explorer-tab-view-BfycKUUW.js +0 -2
  67. package/dist/public/assets/history-view-Dn0hQIKU.js +0 -1
  68. package/dist/public/assets/index-Bdde81Uo.css +0 -1
  69. package/dist/public/assets/index-DKQVo4Vz.js +0 -29
  70. package/dist/public/assets/markdown-renderer-CNuyXHcy.js +0 -10
  71. package/dist/public/assets/mcp-server-card-DBEBe3Qh.js +0 -1
  72. package/dist/public/assets/monaco-SWcefg0q.js +0 -11
  73. package/dist/public/assets/onboarding-DslO5AS6.js +0 -1
  74. package/dist/public/assets/onboarding-dialog-CE-GhoDt.js +0 -1
  75. package/dist/public/assets/page-toolbar-CloU_Kvo.js +0 -1
  76. package/dist/public/assets/project-settings-view-CxD9JZoB.js +0 -1
  77. package/dist/public/assets/providers-list-view-CNxVBJlM.js +0 -1
  78. package/dist/public/assets/radio-group-Co0Lg6se.js +0 -1
  79. package/dist/public/assets/react-vendor-DyE9sO8V.js +0 -22
  80. package/dist/public/assets/resizable-dToeUeVD.js +0 -1
  81. package/dist/public/assets/settings-mcp-servers-view-q6gGMMVX.js +0 -5
  82. package/dist/public/assets/settings-models-view-BDDFQWWC.js +0 -1
  83. package/dist/public/assets/settings-rules-view-DsEwgDFr.js +0 -8
  84. package/dist/public/assets/settings-view-ClTMPafQ.js +0 -2
  85. package/dist/public/assets/side-panel-container-BAYoMt7B.js +0 -2
  86. package/dist/public/assets/skeleton-DveUQR4w.js +0 -1
  87. package/dist/public/assets/standard-list-item-BLlgm1qW.js +0 -1
  88. package/dist/public/assets/store-BcwWHqYr.js +0 -4
  89. package/dist/public/assets/tabs-CgvpwOBj.js +0 -1
  90. package/dist/public/assets/textarea-C2UIAa7y.js +0 -1
  91. package/dist/public/assets/todos-view-C-awG1dZ.js +0 -1
  92. /package/dist/public/assets/{dist-Bjt_i1zi.js → dist-CAVGqbBm.js} +0 -0
package/dist/index.js CHANGED
@@ -9,18 +9,106 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
+ // src/core/tarsk-debug.ts
13
+ function isTarskDebugLoggingEnabled() {
14
+ return process.env.TARSK_DEBUG === "1" && process.env.VITEST !== "true";
15
+ }
16
+ function tarskDebugLog(...args2) {
17
+ if (isTarskDebugLoggingEnabled()) {
18
+ console.log(...args2);
19
+ }
20
+ }
21
+ function tarskDebugWarn(...args2) {
22
+ if (isTarskDebugLoggingEnabled()) {
23
+ console.warn(...args2);
24
+ }
25
+ }
26
+ function tarskDebugWrite(message) {
27
+ if (isTarskDebugLoggingEnabled()) {
28
+ process.stdout.write(message);
29
+ }
30
+ }
31
+ var init_tarsk_debug = __esm({
32
+ "src/core/tarsk-debug.ts"() {
33
+ "use strict";
34
+ }
35
+ });
36
+
12
37
  // src/core/utils.ts
13
38
  var utils_exports = {};
14
39
  __export(utils_exports, {
40
+ buildSpawnPath: () => buildSpawnPath,
15
41
  delay: () => delay,
42
+ getVitePlusRuntimePaths: () => getVitePlusRuntimePaths,
43
+ mergePath: () => mergePath,
16
44
  spawnProcess: () => spawnProcess,
17
45
  spawnShell: () => spawnShell,
18
46
  spawnSyncProcess: () => spawnSyncProcess
19
47
  });
48
+ import { existsSync, readdirSync } from "node:fs";
49
+ import { homedir } from "node:os";
50
+ import { join } from "node:path";
20
51
  import { spawn, spawnSync, execSync } from "child_process";
21
52
  function delay(ms) {
22
53
  return new Promise((resolve6) => setTimeout(resolve6, ms));
23
54
  }
55
+ function mergePath(parentPath, shellPath) {
56
+ const parent = (parentPath ?? "").split(":").filter(Boolean);
57
+ const shell = (shellPath ?? "").split(":").filter(Boolean);
58
+ const shellSet = new Set(shell);
59
+ const parentOnly = parent.filter((segment) => !shellSet.has(segment));
60
+ const seen = /* @__PURE__ */ new Set();
61
+ const merged = [];
62
+ for (const segment of [...parentOnly, ...shell]) {
63
+ if (!seen.has(segment)) {
64
+ seen.add(segment);
65
+ merged.push(segment);
66
+ }
67
+ }
68
+ return merged.join(":");
69
+ }
70
+ function getVitePlusRuntimePaths() {
71
+ if (cachedVitePlusRuntimePaths !== null) {
72
+ return cachedVitePlusRuntimePaths;
73
+ }
74
+ const roots = [];
75
+ const home = homedir();
76
+ if (home) {
77
+ roots.push(join(home, ".vite-plus", "js_runtime", "node"));
78
+ }
79
+ if (process.platform === "win32" && process.env.LOCALAPPDATA) {
80
+ roots.push(join(process.env.LOCALAPPDATA, "vite-plus", "js_runtime", "node"));
81
+ }
82
+ const paths = [];
83
+ for (const runtimeRoot of roots) {
84
+ if (!existsSync(runtimeRoot)) {
85
+ continue;
86
+ }
87
+ try {
88
+ for (const entry of readdirSync(runtimeRoot, { withFileTypes: true })) {
89
+ if (!entry.isDirectory() || entry.name.endsWith(".lock")) {
90
+ continue;
91
+ }
92
+ const binDir = join(runtimeRoot, entry.name, "bin");
93
+ if (existsSync(binDir)) {
94
+ paths.push(binDir);
95
+ }
96
+ }
97
+ } catch {
98
+ }
99
+ }
100
+ paths.sort((a, b) => b.localeCompare(a, void 0, { numeric: true }));
101
+ cachedVitePlusRuntimePaths = paths;
102
+ return cachedVitePlusRuntimePaths;
103
+ }
104
+ function buildSpawnPath(parentPath, shellPath) {
105
+ const merged = mergePath(parentPath, shellPath);
106
+ const runtimePaths = getVitePlusRuntimePaths();
107
+ if (runtimePaths.length === 0) {
108
+ return merged;
109
+ }
110
+ return mergePath(runtimePaths.join(":"), merged);
111
+ }
24
112
  function getFullPath() {
25
113
  if (resolvedPath !== null) {
26
114
  return resolvedPath;
@@ -51,13 +139,16 @@ function getFullPath() {
51
139
  return resolvedPath;
52
140
  }
53
141
  function createProcessEnv(additionalEnv) {
142
+ const shellPath = additionalEnv?.PATH ?? getFullPath();
143
+ const path6 = buildSpawnPath(process.env.PATH, shellPath);
54
144
  const baseEnv = {
55
145
  ...process.env,
56
- PATH: getFullPath(),
146
+ PATH: path6,
57
147
  SHELL: process.env.SHELL ?? "/bin/zsh"
58
148
  };
59
149
  if (additionalEnv) {
60
- return { ...baseEnv, ...additionalEnv };
150
+ const { PATH: _shellPath, ...rest } = additionalEnv;
151
+ return { ...baseEnv, ...rest, PATH: path6 };
61
152
  }
62
153
  return baseEnv;
63
154
  }
@@ -80,11 +171,12 @@ function spawnSyncProcess(command, args2, options = {}) {
80
171
  env: createProcessEnv(options.env)
81
172
  });
82
173
  }
83
- var resolvedPath;
174
+ var resolvedPath, cachedVitePlusRuntimePaths;
84
175
  var init_utils = __esm({
85
176
  "src/core/utils.ts"() {
86
177
  "use strict";
87
178
  resolvedPath = null;
179
+ cachedVitePlusRuntimePaths = null;
88
180
  }
89
181
  });
90
182
 
@@ -99,18 +191,18 @@ __export(database_exports, {
99
191
  initializeSchema: () => initializeSchema
100
192
  });
101
193
  import { createClient } from "@libsql/client";
102
- import { join as join2 } from "path";
103
- import { homedir as homedir2 } from "os";
194
+ import { join as join3 } from "path";
195
+ import { homedir as homedir3 } from "os";
104
196
  import { mkdirSync } from "fs";
105
197
  function getDatabasePath() {
106
- const appSupportDir = join2(homedir2(), "Library", "Application Support", "Tarsk");
107
- const dataDir = join2(appSupportDir, "data");
108
- return join2(dataDir, "tarsk.db");
198
+ const appSupportDir = join3(homedir3(), "Library", "Application Support", "Tarsk");
199
+ const dataDir = join3(appSupportDir, "data");
200
+ return join3(dataDir, "tarsk.db");
109
201
  }
110
202
  async function initializeDatabase() {
111
203
  const dbPath = getDatabasePath();
112
204
  try {
113
- const dataDir = join2(homedir2(), "Library", "Application Support", "Tarsk", "data");
205
+ const dataDir = join3(homedir3(), "Library", "Application Support", "Tarsk", "data");
114
206
  mkdirSync(dataDir, { recursive: true });
115
207
  const db = createClient({
116
208
  url: `file:${dbPath}`
@@ -287,7 +379,9 @@ async function runMigrations(db) {
287
379
  (col) => col.name === "conversationId"
288
380
  );
289
381
  if (!hasConversationId) {
290
- console.log("[db] Running migration: Adding conversationId column to conversation_history");
382
+ tarskDebugLog(
383
+ "[db] Running migration: Adding conversationId column to conversation_history"
384
+ );
291
385
  await db.execute(
292
386
  `ALTER TABLE conversation_history ADD COLUMN conversationId TEXT NOT NULL DEFAULT ''`
293
387
  );
@@ -311,25 +405,27 @@ async function runMigrations(db) {
311
405
  (col) => col.name === "output_tokens"
312
406
  );
313
407
  if (!hasStatusColumn) {
314
- console.log("[db] Running migration: Adding status column to conversation_history");
408
+ tarskDebugLog("[db] Running migration: Adding status column to conversation_history");
315
409
  await db.execute(
316
410
  `ALTER TABLE conversation_history ADD COLUMN status TEXT NOT NULL DEFAULT 'active'`
317
411
  );
318
412
  }
319
413
  if (!hasInputTokensColumn) {
320
- console.log("[db] Running migration: Adding input_tokens column to conversation_history");
414
+ tarskDebugLog("[db] Running migration: Adding input_tokens column to conversation_history");
321
415
  await db.execute(
322
416
  `ALTER TABLE conversation_history ADD COLUMN input_tokens INTEGER DEFAULT 0`
323
417
  );
324
418
  }
325
419
  if (!hasOutputTokensColumn) {
326
- console.log("[db] Running migration: Adding output_tokens column to conversation_history");
420
+ tarskDebugLog(
421
+ "[db] Running migration: Adding output_tokens column to conversation_history"
422
+ );
327
423
  await db.execute(
328
424
  `ALTER TABLE conversation_history ADD COLUMN output_tokens INTEGER DEFAULT 0`
329
425
  );
330
426
  }
331
427
  if (hasPromptIdColumn || hasMessageTypeColumn || hasSequenceIdColumn) {
332
- console.log(
428
+ tarskDebugLog(
333
429
  "[db] Running migration: Dropping prompt_id, message_type, and sequence_id columns from conversation_history"
334
430
  );
335
431
  await db.execute(`
@@ -366,7 +462,7 @@ async function runMigrations(db) {
366
462
  if (tableInfo.rows.length > 0) {
367
463
  const tableSql2 = tableInfo.rows[0].sql;
368
464
  if (!tableSql2.includes("ON DELETE CASCADE")) {
369
- console.log(
465
+ tarskDebugLog(
370
466
  "[db] Running migration: Adding ON DELETE CASCADE to conversation_history.threadId foreign key"
371
467
  );
372
468
  await db.execute(`
@@ -446,7 +542,7 @@ async function runMigrations(db) {
446
542
  if (threadsTableInfo.rows.length > 0) {
447
543
  const tableSql2 = threadsTableInfo.rows[0].sql;
448
544
  if (!tableSql2.includes("ON DELETE CASCADE")) {
449
- console.log(
545
+ tarskDebugLog(
450
546
  "[db] Running migration: Adding ON DELETE CASCADE to threads.projectId foreign key"
451
547
  );
452
548
  await db.execute(`DROP TABLE IF EXISTS threads_new`);
@@ -513,45 +609,45 @@ async function runMigrations(db) {
513
609
  (col) => col.name === "status"
514
610
  );
515
611
  if (!hasCurrentConversationId) {
516
- console.log("[db] Running migration: Adding currentConversationId column to threads");
612
+ tarskDebugLog("[db] Running migration: Adding currentConversationId column to threads");
517
613
  await db.execute(`ALTER TABLE threads ADD COLUMN currentConversationId TEXT`);
518
614
  }
519
615
  if (!hasStatusColumn) {
520
- console.log("[db] Running migration: Adding status column to threads");
616
+ tarskDebugLog("[db] Running migration: Adding status column to threads");
521
617
  await db.execute(`ALTER TABLE threads ADD COLUMN status TEXT NOT NULL DEFAULT 'active'`);
522
618
  }
523
619
  const hasDiffComments = threadsInfo.rows.some(
524
620
  (col) => col.name === "diffComments"
525
621
  );
526
622
  if (!hasDiffComments) {
527
- console.log("[db] Running migration: Adding diffComments column to threads");
623
+ tarskDebugLog("[db] Running migration: Adding diffComments column to threads");
528
624
  await db.execute(`ALTER TABLE threads ADD COLUMN diffComments TEXT`);
529
625
  }
530
626
  const hasModel = threadsInfo.rows.some(
531
627
  (col) => col.name === "model"
532
628
  );
533
629
  if (!hasModel) {
534
- console.log("[db] Running migration: Adding model column to threads");
630
+ tarskDebugLog("[db] Running migration: Adding model column to threads");
535
631
  await db.execute(`ALTER TABLE threads ADD COLUMN model TEXT`);
536
632
  }
537
633
  const hasModelProvider = threadsInfo.rows.some(
538
634
  (col) => col.name === "modelProvider"
539
635
  );
540
636
  if (!hasModelProvider) {
541
- console.log("[db] Running migration: Adding modelProvider column to threads");
637
+ tarskDebugLog("[db] Running migration: Adding modelProvider column to threads");
542
638
  await db.execute(`ALTER TABLE threads ADD COLUMN modelProvider TEXT`);
543
639
  }
544
640
  const hasModelColumn = threadsInfo.rows.some(
545
641
  (col) => col.name === "model"
546
642
  );
547
643
  if (hasModelColumn) {
548
- console.log("[db] Running migration: Updating existing model data to include provider");
644
+ tarskDebugLog("[db] Running migration: Updating existing model data to include provider");
549
645
  await db.execute(`
550
646
  UPDATE threads
551
647
  SET modelProvider = 'unknown'
552
648
  WHERE model IS NOT NULL AND modelProvider IS NULL
553
649
  `);
554
- console.log(
650
+ tarskDebugLog(
555
651
  "[db] Updated rows:",
556
652
  (await db.execute("SELECT id, model, modelProvider FROM threads")).rows
557
653
  );
@@ -562,7 +658,7 @@ async function runMigrations(db) {
562
658
  (col) => col.name === "request_imageMode"
563
659
  );
564
660
  if (!hasImageMode) {
565
- console.log(
661
+ tarskDebugLog(
566
662
  "[db] Running migration: Adding request_imageMode column to conversation_history"
567
663
  );
568
664
  await db.execute(
@@ -573,7 +669,7 @@ async function runMigrations(db) {
573
669
  (col) => col.name === "response_imageUrl"
574
670
  );
575
671
  if (!hasImageUrl) {
576
- console.log(
672
+ tarskDebugLog(
577
673
  "[db] Running migration: Adding response_imageUrl column to conversation_history"
578
674
  );
579
675
  await db.execute(`ALTER TABLE conversation_history ADD COLUMN response_imageUrl TEXT`);
@@ -583,14 +679,14 @@ async function runMigrations(db) {
583
679
  (col) => col.name === "threadId"
584
680
  );
585
681
  if (!hasThreadIdColumn) {
586
- console.log("[db] Running migration: Adding threadId column to project_todos");
682
+ tarskDebugLog("[db] Running migration: Adding threadId column to project_todos");
587
683
  await db.execute(`ALTER TABLE project_todos ADD COLUMN threadId TEXT`);
588
684
  }
589
685
  const gitStatusCacheExists = await db.execute(
590
686
  `SELECT name FROM sqlite_master WHERE type='table' AND name='git_status_cache'`
591
687
  );
592
688
  if (gitStatusCacheExists.rows.length === 0) {
593
- console.log("[db] Running migration: Creating git_status_cache table");
689
+ tarskDebugLog("[db] Running migration: Creating git_status_cache table");
594
690
  await db.execute(`
595
691
  CREATE TABLE git_status_cache (
596
692
  threadId TEXT PRIMARY KEY,
@@ -603,7 +699,7 @@ async function runMigrations(db) {
603
699
  `SELECT name FROM sqlite_master WHERE type='table' AND name='code_files'`
604
700
  );
605
701
  if (codeFilesExists.rows.length === 0) {
606
- console.log("[db] Running migration: Creating code search tables");
702
+ tarskDebugLog("[db] Running migration: Creating code search tables");
607
703
  await db.execute(`
608
704
  CREATE TABLE code_files (
609
705
  id INTEGER PRIMARY KEY,
@@ -634,7 +730,7 @@ async function runMigrations(db) {
634
730
  (col) => col.name === "planPrompt"
635
731
  );
636
732
  if (!hasPlanPrompt) {
637
- console.log("[db] Running migration: Adding AI prompt columns to projects");
733
+ tarskDebugLog("[db] Running migration: Adding AI prompt columns to projects");
638
734
  await db.execute(`ALTER TABLE projects ADD COLUMN planPrompt TEXT`);
639
735
  await db.execute(`ALTER TABLE projects ADD COLUMN testPrompt TEXT`);
640
736
  await db.execute(`ALTER TABLE projects ADD COLUMN reviewPrompt TEXT`);
@@ -644,14 +740,14 @@ async function runMigrations(db) {
644
740
  (col) => col.name === "passes"
645
741
  );
646
742
  if (!hasTodoPasses) {
647
- console.log("[db] Running migration: Adding passes column to todos");
743
+ tarskDebugLog("[db] Running migration: Adding passes column to todos");
648
744
  await db.execute(`ALTER TABLE todos ADD COLUMN passes INTEGER NOT NULL DEFAULT 0`);
649
745
  }
650
746
  const hasRalphMode = convInfo.rows.some(
651
747
  (col) => col.name === "request_ralphMode"
652
748
  );
653
749
  if (!hasRalphMode) {
654
- console.log(
750
+ tarskDebugLog(
655
751
  "[db] Running migration: Adding request_ralphMode column to conversation_history"
656
752
  );
657
753
  await db.execute(
@@ -662,14 +758,14 @@ async function runMigrations(db) {
662
758
  (col) => col.name === "validationScript"
663
759
  );
664
760
  if (!hasValidationScript) {
665
- console.log("[db] Running migration: Adding validationScript column to projects");
761
+ tarskDebugLog("[db] Running migration: Adding validationScript column to projects");
666
762
  await db.execute(`ALTER TABLE projects ADD COLUMN validationScript TEXT`);
667
763
  }
668
764
  const projectScriptsExists = await db.execute(
669
765
  `SELECT name FROM sqlite_master WHERE type='table' AND name='project_scripts'`
670
766
  );
671
767
  if (projectScriptsExists.rows.length === 0) {
672
- console.log("[db] Running migration: Creating project_scripts table");
768
+ tarskDebugLog("[db] Running migration: Creating project_scripts table");
673
769
  await db.execute(`
674
770
  CREATE TABLE project_scripts (
675
771
  id TEXT PRIMARY KEY,
@@ -692,7 +788,7 @@ async function runMigrations(db) {
692
788
  );
693
789
  const tableSql = projectScriptsInfo.rows[0];
694
790
  if (projectScriptsInfo.rows.length > 0 && typeof tableSql["sql"] === "string" && tableSql["sql"].includes('UNIQUE("projectId", "name")')) {
695
- console.log("[db] Running migration: Fixing project_scripts UNIQUE constraint");
791
+ tarskDebugLog("[db] Running migration: Fixing project_scripts UNIQUE constraint");
696
792
  await db.execute(`DROP TABLE IF EXISTS project_scripts`);
697
793
  await db.execute(`
698
794
  CREATE TABLE project_scripts (
@@ -732,6 +828,7 @@ var dbInstance;
732
828
  var init_database = __esm({
733
829
  "src/database/database.ts"() {
734
830
  "use strict";
831
+ init_tarsk_debug();
735
832
  dbInstance = null;
736
833
  }
737
834
  });
@@ -822,6 +919,15 @@ function isValidPackageManager(value) {
822
919
  return typeof value === "string" && PACKAGE_MANAGER_IDS.includes(value);
823
920
  }
824
921
 
922
+ // ../shared/dist/token-utils.js
923
+ var CHARS_PER_TOKEN = 4;
924
+ function estimateTokenCount(text) {
925
+ if (!text) {
926
+ return 0;
927
+ }
928
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
929
+ }
930
+
825
931
  // src/server.ts
826
932
  import fs3 from "fs";
827
933
  import { Hono as Hono23 } from "hono";
@@ -836,18 +942,18 @@ import { streamSimple } from "@mariozechner/pi-ai";
836
942
  import { resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
837
943
 
838
944
  // src/tools/bash.ts
945
+ init_tarsk_debug();
839
946
  init_utils();
840
947
  import { randomBytes } from "node:crypto";
841
- import { createWriteStream, existsSync as existsSync2 } from "node:fs";
948
+ import { createWriteStream, existsSync as existsSync3 } from "node:fs";
842
949
  import { tmpdir } from "node:os";
843
- import { join } from "node:path";
950
+ import { join as join2 } from "node:path";
844
951
  import { Type } from "@sinclair/typebox";
845
952
 
846
953
  // src/tools/shell.ts
847
954
  init_utils();
848
- init_utils();
849
955
  import { execSync as execSync2 } from "node:child_process";
850
- import { existsSync } from "node:fs";
956
+ import { existsSync as existsSync2 } from "node:fs";
851
957
  var cachedShellConfig = null;
852
958
  var cachedLoginShellEnv = null;
853
959
  function findBashOnPath() {
@@ -859,7 +965,7 @@ function findBashOnPath() {
859
965
  });
860
966
  if (syncResult.status === 0 && typeof syncResult.stdout === "string") {
861
967
  const firstMatch = syncResult.stdout.trim().split(/\r?\n/)[0];
862
- if (firstMatch && existsSync(firstMatch)) {
968
+ if (firstMatch && existsSync2(firstMatch)) {
863
969
  return firstMatch;
864
970
  }
865
971
  }
@@ -893,7 +999,7 @@ function getShellConfig() {
893
999
  paths.push(`${process.env["ProgramFiles(x86)"]}\\Git\\bin\\bash.exe`);
894
1000
  }
895
1001
  for (const p of paths) {
896
- if (existsSync(p)) {
1002
+ if (existsSync2(p)) {
897
1003
  cachedShellConfig = { shell: p, args: ["-c"] };
898
1004
  return cachedShellConfig;
899
1005
  }
@@ -905,7 +1011,7 @@ function getShellConfig() {
905
1011
  }
906
1012
  throw new Error("No bash shell found. Install Git for Windows or add bash to PATH.");
907
1013
  }
908
- if (existsSync("/bin/bash")) {
1014
+ if (existsSync2("/bin/bash")) {
909
1015
  cachedShellConfig = { shell: "/bin/bash", args: ["-c"] };
910
1016
  return cachedShellConfig;
911
1017
  }
@@ -944,6 +1050,7 @@ function getLoginShellEnv() {
944
1050
  const value = line.slice(separatorIndex + 1);
945
1051
  loginEnv[key] = value;
946
1052
  }
1053
+ loginEnv.PATH = buildSpawnPath(process.env.PATH, loginEnv.PATH);
947
1054
  cachedLoginShellEnv = loginEnv;
948
1055
  return cachedLoginShellEnv;
949
1056
  } catch {
@@ -1137,7 +1244,7 @@ function truncateLine(line, maxChars = GREP_MAX_LINE_LENGTH) {
1137
1244
 
1138
1245
  // src/tools/bash.ts
1139
1246
  function getTempFilePath() {
1140
- return join(tmpdir(), `tarsk-bash-${randomBytes(8).toString("hex")}.log`);
1247
+ return join2(tmpdir(), `tarsk-bash-${randomBytes(8).toString("hex")}.log`);
1141
1248
  }
1142
1249
  var bashSchema = Type.Object({
1143
1250
  command: Type.String({ description: "Bash command to execute" }),
@@ -1147,7 +1254,7 @@ var defaultBashOperations = {
1147
1254
  exec: (command, cwd, { onData, signal, timeout, env }) => {
1148
1255
  return new Promise((resolve6, reject) => {
1149
1256
  const { shell, args: args2 } = getShellConfig();
1150
- if (!existsSync2(cwd)) {
1257
+ if (!existsSync3(cwd)) {
1151
1258
  reject(new Error(`Working directory does not exist: ${cwd}`));
1152
1259
  return;
1153
1260
  }
@@ -1210,7 +1317,7 @@ function createBashTool(cwd, options) {
1210
1317
  execute: async (_toolCallId, { command, timeout }, signal, onUpdate) => {
1211
1318
  const resolvedCommand = commandPrefix ? `${commandPrefix}
1212
1319
  ${command}` : command;
1213
- console.log(`[ai] bash-start: ${resolvedCommand}`);
1320
+ tarskDebugLog(`[ai] bash-start: ${resolvedCommand}`);
1214
1321
  return new Promise((resolve6, reject) => {
1215
1322
  let tempFilePath;
1216
1323
  let tempFileStream;
@@ -1245,7 +1352,7 @@ ${command}` : command;
1245
1352
  }
1246
1353
  };
1247
1354
  ops.exec(resolvedCommand, cwd, { onData: handleData, signal, timeout, env: getShellEnv() }).then(({ exitCode }) => {
1248
- console.log(`[ai] bash-end: ${resolvedCommand}`);
1355
+ tarskDebugLog(`[ai] bash-end: ${resolvedCommand}`);
1249
1356
  if (tempFileStream) tempFileStream.end();
1250
1357
  const fullOutput = Buffer.concat(chunks).toString("utf-8");
1251
1358
  const truncation = truncateTail(fullOutput);
@@ -1278,7 +1385,7 @@ Command exited with code ${exitCode}`;
1278
1385
  resolve6({ content: [{ type: "text", text: outputText }], details });
1279
1386
  }
1280
1387
  }).catch((err) => {
1281
- console.log(`[ai] bash-end: ${resolvedCommand}`);
1388
+ tarskDebugLog(`[ai] bash-end: ${resolvedCommand}`);
1282
1389
  if (tempFileStream) tempFileStream.end();
1283
1390
  const output = Buffer.concat(chunks).toString("utf-8");
1284
1391
  if (err.message === "aborted") {
@@ -1610,7 +1717,7 @@ var editTool = createEditTool(process.cwd());
1610
1717
 
1611
1718
  // src/tools/find.ts
1612
1719
  import { Type as Type3 } from "@sinclair/typebox";
1613
- import { existsSync as existsSync3 } from "fs";
1720
+ import { existsSync as existsSync4 } from "fs";
1614
1721
  import os2 from "node:os";
1615
1722
  import path from "path";
1616
1723
  import { globSync } from "glob";
@@ -1625,7 +1732,7 @@ var findSchema = Type3.Object({
1625
1732
  });
1626
1733
  var DEFAULT_LIMIT = 1e3;
1627
1734
  var defaultFindOperations = {
1628
- exists: existsSync3,
1735
+ exists: existsSync4,
1629
1736
  glob: async (pattern, searchCwd, { ignore: ignore2, limit }) => {
1630
1737
  const results = [];
1631
1738
  try {
@@ -2000,9 +2107,10 @@ import { Type as Type5 } from "@sinclair/typebox";
2000
2107
 
2001
2108
  // src/tools/code-search-indexer.ts
2002
2109
  init_database();
2110
+ init_tarsk_debug();
2003
2111
  import { readFileSync as readFileSync2 } from "fs";
2004
2112
  import { readFile, opendir } from "fs/promises";
2005
- import { join as join3, relative as relative2, extname } from "path";
2113
+ import { join as join4, relative as relative2, extname } from "path";
2006
2114
  import ignore from "ignore";
2007
2115
  var SKIP_DIRS = /* @__PURE__ */ new Set([
2008
2116
  "node_modules",
@@ -2075,7 +2183,7 @@ var BATCH_SIZE = 50;
2075
2183
  function readGitignore(dirPath) {
2076
2184
  const ig = ignore();
2077
2185
  try {
2078
- const content = readFileSync2(join3(dirPath, ".gitignore"), "utf8");
2186
+ const content = readFileSync2(join4(dirPath, ".gitignore"), "utf8");
2079
2187
  ig.add(content);
2080
2188
  } catch {
2081
2189
  }
@@ -2106,7 +2214,7 @@ async function collectFiles(rootPath, signal) {
2106
2214
  }
2107
2215
  for await (const entry of dirHandle) {
2108
2216
  if (signal?.aborted) break;
2109
- const entryPath = join3(dirPath, entry.name);
2217
+ const entryPath = join4(dirPath, entry.name);
2110
2218
  const relPath = relative2(rootPath, entryPath);
2111
2219
  if (entry.isDirectory()) {
2112
2220
  if (SKIP_DIRS.has(entry.name)) continue;
@@ -2129,7 +2237,7 @@ async function ensureThreadIndex(db, threadId, threadPath, signal) {
2129
2237
  threadId
2130
2238
  ]);
2131
2239
  if (meta.rows.length > 0) return;
2132
- console.log(`[code-search] indexing ${threadId}: scanning files...`);
2240
+ tarskDebugLog(`[code-search] indexing ${threadId}: scanning files...`);
2133
2241
  const start = Date.now();
2134
2242
  const files = await collectFiles(threadPath, signal);
2135
2243
  if (signal?.aborted) return;
@@ -2167,7 +2275,7 @@ async function ensureThreadIndex(db, threadId, threadPath, signal) {
2167
2275
  "INSERT OR REPLACE INTO code_index_meta (thread_id, indexed_at, file_count) VALUES (?, ?, ?)",
2168
2276
  [threadId, now, fileCount]
2169
2277
  );
2170
- console.log(`[code-search] indexed ${fileCount} files in ${Date.now() - start}ms`);
2278
+ tarskDebugLog(`[code-search] indexed ${fileCount} files in ${Date.now() - start}ms`);
2171
2279
  }
2172
2280
  async function clearThreadIndex(db, threadId) {
2173
2281
  await db.execute(
@@ -2183,7 +2291,7 @@ async function invalidateThreadIndex(threadId) {
2183
2291
  }
2184
2292
 
2185
2293
  // src/tools/code-search.ts
2186
- var DEFAULT_LIMIT3 = 100;
2294
+ var DEFAULT_LIMIT3 = 30;
2187
2295
  var codeSearchSchema = Type5.Object({
2188
2296
  query: Type5.Optional(
2189
2297
  Type5.String({
@@ -2197,7 +2305,7 @@ var codeSearchSchema = Type5.Object({
2197
2305
  ),
2198
2306
  filePath: Type5.Optional(
2199
2307
  Type5.String({
2200
- description: "Search by file path pattern, e.g. 'camp.page.ts', 'src/app/camp', or 'src/**/camp/*.ts'. Supports glob wildcards (* and **). Returns all lines from matching files."
2308
+ description: "Search by file path pattern, e.g. 'camp.page.ts', 'src/app/camp', or 'src/**/camp/*.ts'. Supports glob wildcards (* and **). Returns file paths only, no content."
2201
2309
  })
2202
2310
  ),
2203
2311
  fileGlob: Type5.Optional(
@@ -2332,10 +2440,12 @@ function formatOutput(rows, tokens, regex, limit, multiline = false) {
2332
2440
  const matchLimitReached = rows.length >= limit ? rows.length : void 0;
2333
2441
  for (const { file_path, content } of rows) {
2334
2442
  const matchingLines = regex ? findLinesByRegex(content, regex, multiline) : findLinesByTokens(content, tokens);
2443
+ if (matchingLines.length === 0) continue;
2444
+ outputLines.push(`${file_path}:`);
2335
2445
  for (const { line, text } of matchingLines) {
2336
2446
  const { text: truncated, wasTruncated } = truncateLine(text.replace(/\r/g, ""));
2337
2447
  if (wasTruncated) linesTruncated = true;
2338
- outputLines.push(`${file_path}:${line}: ${truncated}`);
2448
+ outputLines.push(` ${line}: ${truncated}`);
2339
2449
  }
2340
2450
  }
2341
2451
  return { outputLines, linesTruncated, matchLimitReached };
@@ -2443,24 +2553,15 @@ function createCodeSearchTool(cwd, threadId) {
2443
2553
  if (filePath && !query && !pattern) {
2444
2554
  const likePattern = filePathToLike(filePath);
2445
2555
  const result = await db.execute(
2446
- `SELECT file_path, content FROM code_files
2556
+ `SELECT file_path FROM code_files
2447
2557
  WHERE thread_id = ?
2448
2558
  AND file_path LIKE ? ESCAPE '\\'
2449
2559
  LIMIT ? OFFSET ?`,
2450
2560
  [threadId, likePattern, limit, offset]
2451
2561
  );
2452
2562
  const rows2 = result.rows;
2453
- const { outputLines: outputLines2, linesTruncated: linesTruncated2, matchLimitReached: matchLimitReached2 } = formatOutput(
2454
- rows2,
2455
- [],
2456
- null,
2457
- limit
2458
- );
2459
- if (outputLines2.length === 0) {
2460
- const names = rows2.map((r) => r.file_path).join("\n");
2461
- return buildResult(names ? names.split("\n") : [], false, void 0, limit, offset);
2462
- }
2463
- return buildResult(outputLines2, linesTruncated2, matchLimitReached2, limit, offset);
2563
+ const names = rows2.map((r) => r.file_path);
2564
+ return buildResult(names, false, void 0, limit, offset);
2464
2565
  }
2465
2566
  if (filePath && (query || pattern)) {
2466
2567
  const likePattern = filePathToLike(filePath);
@@ -2490,7 +2591,7 @@ function createCodeSearchTool(cwd, threadId) {
2490
2591
  const args2 = likeFilter ? [threadId, likeFilter] : [threadId];
2491
2592
  const result = await db.execute(sql, args2);
2492
2593
  const allRows = result.rows;
2493
- const outputLines2 = [];
2594
+ const fileGroups = [];
2494
2595
  let linesTruncated2 = false;
2495
2596
  let matchedFiles = 0;
2496
2597
  for (const { file_path, content } of allRows) {
@@ -2499,10 +2600,18 @@ function createCodeSearchTool(cwd, threadId) {
2499
2600
  matchedFiles++;
2500
2601
  if (matchedFiles <= offset) continue;
2501
2602
  if (matchedFiles > offset + limit) break;
2502
- for (const { line, text } of matchingLines) {
2503
- const { text: truncated, wasTruncated } = truncateLine(text.replace(/\r/g, ""));
2603
+ fileGroups.push({ filePath: file_path, lines: matchingLines });
2604
+ for (const { text } of matchingLines) {
2605
+ const { wasTruncated } = truncateLine(text.replace(/\r/g, ""));
2504
2606
  if (wasTruncated) linesTruncated2 = true;
2505
- outputLines2.push(`${file_path}:${line}: ${truncated}`);
2607
+ }
2608
+ }
2609
+ const outputLines2 = [];
2610
+ for (const group of fileGroups) {
2611
+ outputLines2.push(`${group.filePath}:`);
2612
+ for (const { line, text } of group.lines) {
2613
+ const { text: truncated } = truncateLine(text.replace(/\r/g, ""));
2614
+ outputLines2.push(` ${line}: ${truncated}`);
2506
2615
  }
2507
2616
  }
2508
2617
  const matchLimitReached2 = matchedFiles > offset + limit ? matchedFiles : void 0;
@@ -2612,7 +2721,7 @@ var codeSearchTool = createCodeSearchTool(
2612
2721
 
2613
2722
  // src/tools/ls.ts
2614
2723
  import { Type as Type6 } from "@sinclair/typebox";
2615
- import { existsSync as existsSync4, readdirSync, statSync as statSync2 } from "fs";
2724
+ import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2616
2725
  import nodePath from "path";
2617
2726
  var lsSchema = Type6.Object({
2618
2727
  path: Type6.Optional(
@@ -2624,9 +2733,9 @@ var lsSchema = Type6.Object({
2624
2733
  });
2625
2734
  var DEFAULT_LIMIT4 = 500;
2626
2735
  var defaultLsOperations = {
2627
- exists: existsSync4,
2736
+ exists: existsSync5,
2628
2737
  stat: statSync2,
2629
- readdir: readdirSync
2738
+ readdir: readdirSync2
2630
2739
  };
2631
2740
  function createLsTool(cwd, options) {
2632
2741
  const ops = options?.operations ?? defaultLsOperations;
@@ -2873,8 +2982,8 @@ var writeTool = createWriteTool(process.cwd());
2873
2982
  // src/tools/skill-tool.ts
2874
2983
  init_utils();
2875
2984
  import { readdir } from "fs/promises";
2876
- import { join as join4, extname as extname2 } from "path";
2877
- import { existsSync as existsSync5, statSync as statSync3 } from "fs";
2985
+ import { join as join5, extname as extname2 } from "path";
2986
+ import { existsSync as existsSync6, statSync as statSync3 } from "fs";
2878
2987
  import { Type as Type9 } from "@sinclair/typebox";
2879
2988
  function getInterpreter(scriptPath) {
2880
2989
  const ext = extname2(scriptPath);
@@ -2967,8 +3076,8 @@ function createSkillScriptTool(skills, cwd) {
2967
3076
  details: void 0
2968
3077
  };
2969
3078
  }
2970
- const scriptsDir = join4(skill.skillPath, "scripts");
2971
- if (!existsSync5(scriptsDir)) {
3079
+ const scriptsDir = join5(skill.skillPath, "scripts");
3080
+ if (!existsSync6(scriptsDir)) {
2972
3081
  return {
2973
3082
  content: [
2974
3083
  { type: "text", text: `Skill '${skillName}' has no scripts directory` }
@@ -2976,8 +3085,8 @@ function createSkillScriptTool(skills, cwd) {
2976
3085
  details: void 0
2977
3086
  };
2978
3087
  }
2979
- const scriptPath = join4(scriptsDir, scriptName);
2980
- if (!existsSync5(scriptPath)) {
3088
+ const scriptPath = join5(scriptsDir, scriptName);
3089
+ if (!existsSync6(scriptPath)) {
2981
3090
  try {
2982
3091
  const availableScripts = await readdir(scriptsDir);
2983
3092
  return {
@@ -3037,12 +3146,12 @@ ${result.stderr}
3037
3146
 
3038
3147
  // src/tools/skill-reference-tool.ts
3039
3148
  import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
3040
- import { join as join5, normalize, relative as relative3 } from "path";
3041
- import { existsSync as existsSync6 } from "fs";
3149
+ import { join as join6, normalize, relative as relative3 } from "path";
3150
+ import { existsSync as existsSync7 } from "fs";
3042
3151
  import { Type as Type10 } from "@sinclair/typebox";
3043
3152
  function isPathSafe(basePath, requestedPath) {
3044
3153
  const normalized = normalize(requestedPath);
3045
- const fullPath = join5(basePath, normalized);
3154
+ const fullPath = join6(basePath, normalized);
3046
3155
  const relativePath = relative3(basePath, fullPath);
3047
3156
  return !relativePath.startsWith("..") && !relativePath.startsWith("/");
3048
3157
  }
@@ -3071,8 +3180,8 @@ function createSkillReferenceTool(skills) {
3071
3180
  details: void 0
3072
3181
  };
3073
3182
  }
3074
- const referencesDir = join5(skill.skillPath, "references");
3075
- if (!existsSync6(referencesDir)) {
3183
+ const referencesDir = join6(skill.skillPath, "references");
3184
+ if (!existsSync7(referencesDir)) {
3076
3185
  return {
3077
3186
  content: [
3078
3187
  { type: "text", text: `Skill '${skillName}' has no references directory` }
@@ -3091,8 +3200,8 @@ function createSkillReferenceTool(skills) {
3091
3200
  details: void 0
3092
3201
  };
3093
3202
  }
3094
- const fullPath = join5(referencesDir, referencePath);
3095
- if (!existsSync6(fullPath)) {
3203
+ const fullPath = join6(referencesDir, referencePath);
3204
+ if (!existsSync7(fullPath)) {
3096
3205
  try {
3097
3206
  const availableRefs = await listReferencesRecursive(referencesDir);
3098
3207
  return {
@@ -3142,9 +3251,9 @@ async function listReferencesRecursive(dir, prefix = "") {
3142
3251
  try {
3143
3252
  const entries = await readdir2(dir, { withFileTypes: true });
3144
3253
  for (const entry of entries) {
3145
- const relativePath = prefix ? join5(prefix, entry.name) : entry.name;
3254
+ const relativePath = prefix ? join6(prefix, entry.name) : entry.name;
3146
3255
  if (entry.isDirectory()) {
3147
- const subFiles = await listReferencesRecursive(join5(dir, entry.name), relativePath);
3256
+ const subFiles = await listReferencesRecursive(join6(dir, entry.name), relativePath);
3148
3257
  files.push(...subFiles);
3149
3258
  } else {
3150
3259
  files.push(relativePath);
@@ -3284,11 +3393,11 @@ async function clearTodosIfAllDone(db, threadId) {
3284
3393
 
3285
3394
  // src/features/ralph/ralph.progress.ts
3286
3395
  import { readFile as readFile3, appendFile, writeFile } from "fs/promises";
3287
- import { join as join6 } from "path";
3396
+ import { join as join7 } from "path";
3288
3397
  var PROGRESS_FILE = "progress.txt";
3289
3398
  async function readProgress(threadPath) {
3290
3399
  try {
3291
- return await readFile3(join6(threadPath, PROGRESS_FILE), "utf-8");
3400
+ return await readFile3(join7(threadPath, PROGRESS_FILE), "utf-8");
3292
3401
  } catch (err) {
3293
3402
  if (err.code === "ENOENT") {
3294
3403
  return "";
@@ -3297,7 +3406,7 @@ async function readProgress(threadPath) {
3297
3406
  }
3298
3407
  }
3299
3408
  async function appendProgress(threadPath, learnings) {
3300
- const filePath = join6(threadPath, PROGRESS_FILE);
3409
+ const filePath = join7(threadPath, PROGRESS_FILE);
3301
3410
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3302
3411
  const entry = `
3303
3412
  --- ${timestamp} ---
@@ -3538,12 +3647,13 @@ function createTodoTool(threadId, threadPath) {
3538
3647
  var todoTool = createTodoTool("");
3539
3648
 
3540
3649
  // src/features/mcp/mcp.config.ts
3650
+ init_tarsk_debug();
3541
3651
  import { readFile as readFile4, stat, access } from "fs/promises";
3542
- import { join as join7 } from "path";
3652
+ import { join as join8 } from "path";
3543
3653
  var MCP_CONFIG_PATHS = [".agents/mcp.json", "mcp.json"];
3544
3654
  async function loadMCPConfig(projectPath) {
3545
3655
  for (const configPath of MCP_CONFIG_PATHS) {
3546
- const fullPath = join7(projectPath, configPath);
3656
+ const fullPath = join8(projectPath, configPath);
3547
3657
  try {
3548
3658
  await access(fullPath);
3549
3659
  const fileStats = await stat(fullPath);
@@ -3557,7 +3667,7 @@ async function loadMCPConfig(projectPath) {
3557
3667
  console.warn(`[MCP] Invalid configuration structure in ${configPath}`);
3558
3668
  continue;
3559
3669
  }
3560
- console.log(
3670
+ tarskDebugLog(
3561
3671
  `[MCP] Loaded configuration from ${configPath} (${fileStats.mtime.toISOString()})`
3562
3672
  );
3563
3673
  return config;
@@ -3572,7 +3682,7 @@ async function loadMCPConfig(projectPath) {
3572
3682
  }
3573
3683
  async function getMCPConfigModificationTime(projectPath) {
3574
3684
  for (const configPath of MCP_CONFIG_PATHS) {
3575
- const fullPath = join7(projectPath, configPath);
3685
+ const fullPath = join8(projectPath, configPath);
3576
3686
  try {
3577
3687
  await access(fullPath);
3578
3688
  const fileStats = await stat(fullPath);
@@ -3638,6 +3748,7 @@ async function hasMCPConfigChanged(projectPath, lastModified) {
3638
3748
  }
3639
3749
 
3640
3750
  // src/features/mcp/mcp.manager.ts
3751
+ init_tarsk_debug();
3641
3752
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3642
3753
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3643
3754
  var MCPManagerImpl = class {
@@ -3726,7 +3837,7 @@ var MCPManagerImpl = class {
3726
3837
  async getServerTools(serverName, serverConfig, projectPath) {
3727
3838
  const instance = await this.getOrCreateServerInstance(serverName, serverConfig, projectPath);
3728
3839
  if (instance.state !== "connected") {
3729
- console.warn(`[MCP] Server ${serverName} not connected (state: ${instance.state})`);
3840
+ tarskDebugWarn(`[MCP] Server ${serverName} not connected (state: ${instance.state})`);
3730
3841
  return [];
3731
3842
  }
3732
3843
  return instance.tools;
@@ -3753,7 +3864,7 @@ var MCPManagerImpl = class {
3753
3864
  tools: []
3754
3865
  };
3755
3866
  try {
3756
- console.log(
3867
+ tarskDebugLog(
3757
3868
  `[MCP] Connecting to server ${serverName} with command: ${serverConfig.command} ${serverConfig.args.join(" ")}`
3758
3869
  );
3759
3870
  const transport = new StdioClientTransport({
@@ -3771,7 +3882,7 @@ var MCPManagerImpl = class {
3771
3882
  }
3772
3883
  );
3773
3884
  await client.connect(transport);
3774
- console.log(`[MCP] Connected to server ${serverName}`);
3885
+ tarskDebugLog(`[MCP] Connected to server ${serverName}`);
3775
3886
  const toolsResponse = await client.listTools();
3776
3887
  instance.tools = toolsResponse.tools.map((tool) => ({
3777
3888
  name: tool.name,
@@ -3781,11 +3892,13 @@ var MCPManagerImpl = class {
3781
3892
  }));
3782
3893
  instance.client = client;
3783
3894
  instance.state = "connected";
3784
- console.log(`[MCP] Connected to server ${serverName}, found ${instance.tools.length} tools`);
3895
+ tarskDebugLog(
3896
+ `[MCP] Connected to server ${serverName}, found ${instance.tools.length} tools`
3897
+ );
3785
3898
  } catch (error) {
3786
3899
  instance.state = "error";
3787
3900
  instance.error = error instanceof Error ? error.message : String(error);
3788
- console.log(`[MCP] Unable to connect to server ${serverName}: ${instance.error}`);
3901
+ tarskDebugLog(`[MCP] Unable to connect to server ${serverName}: ${instance.error}`);
3789
3902
  }
3790
3903
  return instance;
3791
3904
  }
@@ -4050,8 +4163,14 @@ var ModelManager = class {
4050
4163
  * @param provider - Provider name
4051
4164
  * @returns Array of Model objects that are enabled
4052
4165
  */
4166
+ async getEnabledModelIds(provider) {
4167
+ return this.metadataManager.getEnabledModels(provider);
4168
+ }
4169
+ async getEnabledImageModelIds(provider) {
4170
+ return this.metadataManager.getEnabledImageModels(provider);
4171
+ }
4053
4172
  async getEnabledModels(provider) {
4054
- const enabledModelIds = await this.metadataManager.getEnabledModels(provider);
4173
+ const enabledModelIds = await this.getEnabledModelIds(provider);
4055
4174
  if (enabledModelIds.length === 0) {
4056
4175
  return [];
4057
4176
  }
@@ -4635,6 +4754,7 @@ function createFindImagesTool(cwd) {
4635
4754
  }
4636
4755
 
4637
4756
  // src/tools/execute-browser-js.ts
4757
+ init_tarsk_debug();
4638
4758
  import { Type as Type15 } from "@sinclair/typebox";
4639
4759
  var runWebWorkerSchema = Type15.Object({
4640
4760
  intention: Type15.String({
@@ -4683,7 +4803,7 @@ function createRunWebWorkerTool(options) {
4683
4803
  description: buildDescription(options?.tools),
4684
4804
  parameters: runWebWorkerSchema,
4685
4805
  execute: async (toolCallId, { intention: _intention, code }, signal) => {
4686
- console.log(`[ai] run_js: executing script of length ${code.length}`);
4806
+ tarskDebugLog(`[ai] run_js: executing script of length ${code.length}`);
4687
4807
  if (signal?.aborted) {
4688
4808
  throw new Error("Operation aborted");
4689
4809
  }
@@ -4892,6 +5012,7 @@ function formatDeferredToolsList(deferredTools) {
4892
5012
  }
4893
5013
 
4894
5014
  // src/tools/index.ts
5015
+ init_tarsk_debug();
4895
5016
  var INDEX_INVALIDATING_TOOL_NAMES = /* @__PURE__ */ new Set(["bash", "edit", "write"]);
4896
5017
  function shouldInvalidateCodeSearchIndex(toolName) {
4897
5018
  return INDEX_INVALIDATING_TOOL_NAMES.has(toolName);
@@ -4902,9 +5023,9 @@ function shouldInvalidateCodeSearchIndexOnError(toolName) {
4902
5023
  async function invalidateCodeSearchIndexSafely(threadId, toolName) {
4903
5024
  try {
4904
5025
  await invalidateThreadIndex(threadId);
4905
- console.log(`[code-search] invalidated thread index after ${toolName}`);
5026
+ tarskDebugLog(`[code-search] invalidated thread index after ${toolName}`);
4906
5027
  } catch (error) {
4907
- console.warn(`[code-search] failed to invalidate thread index after ${toolName}:`, error);
5028
+ tarskDebugWarn(`[code-search] failed to invalidate thread index after ${toolName}:`, error);
4908
5029
  }
4909
5030
  }
4910
5031
  function wrapToolWithCodeSearchInvalidation(tool, threadId) {
@@ -4985,7 +5106,7 @@ async function createCodingTools(cwd, options) {
4985
5106
  deferredTools
4986
5107
  });
4987
5108
  tools.push(toolSearch);
4988
- console.log(
5109
+ tarskDebugLog(
4989
5110
  `[Tools] ${deferredTools.size} tool(s) deferred behind tool_search: ${Array.from(deferredTools.keys()).join(", ")}`
4990
5111
  );
4991
5112
  }
@@ -5047,7 +5168,11 @@ var PROVIDER_NAME_TO_PI = {
5047
5168
  codex: "openai-codex",
5048
5169
  mistral: "mistral"
5049
5170
  };
5050
- function determineApiType(apiUrl) {
5171
+ function determineApiType(providerName, apiUrl) {
5172
+ const slug = providerName.toLowerCase();
5173
+ if (slug === "azure" || apiUrl.includes("openai.azure.com")) {
5174
+ return "azure-openai-responses";
5175
+ }
5051
5176
  if (apiUrl.includes("/anthropic/")) return "anthropic-messages";
5052
5177
  if (apiUrl.includes("api.anthropic.com")) return "anthropic-messages";
5053
5178
  return "openai-completions";
@@ -5065,7 +5190,7 @@ function resolveModel(providerName, modelId, providerConfig) {
5065
5190
  if (!baseUrl) {
5066
5191
  throw new Error(`No API URL configured for provider: ${providerName}`);
5067
5192
  }
5068
- const apiType = determineApiType(baseUrl);
5193
+ const apiType = determineApiType(providerName, baseUrl);
5069
5194
  return {
5070
5195
  id: modelId,
5071
5196
  name: modelId,
@@ -5483,10 +5608,10 @@ function createAgentTool(options) {
5483
5608
  }
5484
5609
 
5485
5610
  // src/core/paths.ts
5486
- import { join as join8 } from "path";
5487
- import { homedir as homedir3 } from "os";
5488
- var APP_SUPPORT_DIR = join8(homedir3(), "Library", "Application Support", "Tarsk");
5489
- var DATA_DIR = join8(APP_SUPPORT_DIR, "data");
5611
+ import { join as join9 } from "path";
5612
+ import { homedir as homedir4 } from "os";
5613
+ var APP_SUPPORT_DIR = join9(homedir4(), "Library", "Application Support", "Tarsk");
5614
+ var DATA_DIR = join9(APP_SUPPORT_DIR, "data");
5490
5615
  function getDataDir() {
5491
5616
  return DATA_DIR;
5492
5617
  }
@@ -5496,8 +5621,8 @@ import { resolve } from "path";
5496
5621
  import { readFileSync as readFileSync4 } from "fs";
5497
5622
 
5498
5623
  // src/project-analyzer.ts
5499
- import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
5500
- import { join as join9 } from "path";
5624
+ import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
5625
+ import { join as join10 } from "path";
5501
5626
  var ProjectAnalyzer = class {
5502
5627
  projectPath;
5503
5628
  constructor(projectPath = process.cwd()) {
@@ -5508,9 +5633,9 @@ var ProjectAnalyzer = class {
5508
5633
  return this.generateDescription(info);
5509
5634
  }
5510
5635
  getProjectInfo() {
5511
- const packageJsonPath = join9(this.projectPath, "package.json");
5636
+ const packageJsonPath = join10(this.projectPath, "package.json");
5512
5637
  const info = { description: "" };
5513
- if (existsSync7(packageJsonPath)) {
5638
+ if (existsSync8(packageJsonPath)) {
5514
5639
  const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
5515
5640
  const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
5516
5641
  this.detectFramework(allDeps, info);
@@ -5550,15 +5675,15 @@ var ProjectAnalyzer = class {
5550
5675
  }
5551
5676
  }
5552
5677
  detectBuildTool(_scripts = {}, deps, info) {
5553
- if (deps.vite || existsSync7(join9(this.projectPath, "vite.config.js")) || existsSync7(join9(this.projectPath, "vite.config.ts"))) {
5678
+ if (deps.vite || existsSync8(join10(this.projectPath, "vite.config.js")) || existsSync8(join10(this.projectPath, "vite.config.ts"))) {
5554
5679
  info.buildTool = "Vite";
5555
5680
  return;
5556
5681
  }
5557
- if (deps.webpack || existsSync7(join9(this.projectPath, "webpack.config.js"))) {
5682
+ if (deps.webpack || existsSync8(join10(this.projectPath, "webpack.config.js"))) {
5558
5683
  info.buildTool = "Webpack";
5559
5684
  return;
5560
5685
  }
5561
- if (deps.rollup || existsSync7(join9(this.projectPath, "rollup.config.js"))) {
5686
+ if (deps.rollup || existsSync8(join10(this.projectPath, "rollup.config.js"))) {
5562
5687
  info.buildTool = "Rollup";
5563
5688
  return;
5564
5689
  }
@@ -5608,40 +5733,40 @@ var ProjectAnalyzer = class {
5608
5733
  info.uiLibraries = [...new Set(uiLibs)].filter(Boolean);
5609
5734
  }
5610
5735
  detectProjectType(info) {
5611
- if (existsSync7(join9(this.projectPath, ".xcodeproj")) || existsSync7(join9(this.projectPath, ".xcworkspace")) || existsSync7(join9(this.projectPath, "project.pbxproj"))) {
5736
+ if (existsSync8(join10(this.projectPath, ".xcodeproj")) || existsSync8(join10(this.projectPath, ".xcworkspace")) || existsSync8(join10(this.projectPath, "project.pbxproj"))) {
5612
5737
  info.projectType = "Xcode";
5613
- } else if (existsSync7(join9(this.projectPath, "build.gradle")) || existsSync7(join9(this.projectPath, "build.gradle.kts")) || existsSync7(join9(this.projectPath, "app/build.gradle")) || existsSync7(join9(this.projectPath, "settings.gradle"))) {
5738
+ } else if (existsSync8(join10(this.projectPath, "build.gradle")) || existsSync8(join10(this.projectPath, "build.gradle.kts")) || existsSync8(join10(this.projectPath, "app/build.gradle")) || existsSync8(join10(this.projectPath, "settings.gradle"))) {
5614
5739
  info.projectType = "Android Studio";
5615
- } else if (existsSync7(join9(this.projectPath, "pubspec.yaml"))) {
5740
+ } else if (existsSync8(join10(this.projectPath, "pubspec.yaml"))) {
5616
5741
  info.projectType = "Flutter";
5617
- } else if (existsSync7(join9(this.projectPath, "go.mod"))) {
5742
+ } else if (existsSync8(join10(this.projectPath, "go.mod"))) {
5618
5743
  info.projectType = "Go";
5619
- } else if (existsSync7(join9(this.projectPath, "Cargo.toml"))) {
5744
+ } else if (existsSync8(join10(this.projectPath, "Cargo.toml"))) {
5620
5745
  info.projectType = "Rust";
5621
- } else if (existsSync7(join9(this.projectPath, "requirements.txt")) || existsSync7(join9(this.projectPath, "pyproject.toml")) || existsSync7(join9(this.projectPath, "setup.py"))) {
5746
+ } else if (existsSync8(join10(this.projectPath, "requirements.txt")) || existsSync8(join10(this.projectPath, "pyproject.toml")) || existsSync8(join10(this.projectPath, "setup.py"))) {
5622
5747
  info.projectType = "Python";
5623
- } else if (existsSync7(join9(this.projectPath, "Gemfile"))) {
5748
+ } else if (existsSync8(join10(this.projectPath, "Gemfile"))) {
5624
5749
  info.projectType = "Ruby";
5625
- } else if (existsSync7(join9(this.projectPath, "composer.json"))) {
5750
+ } else if (existsSync8(join10(this.projectPath, "composer.json"))) {
5626
5751
  info.projectType = "PHP";
5627
- } else if (existsSync7(join9(this.projectPath, "pom.xml")) || existsSync7(join9(this.projectPath, "build.xml"))) {
5752
+ } else if (existsSync8(join10(this.projectPath, "pom.xml")) || existsSync8(join10(this.projectPath, "build.xml"))) {
5628
5753
  info.projectType = "Java";
5629
- } else if (existsSync7(join9(this.projectPath, ".csproj")) || existsSync7(join9(this.projectPath, "project.json"))) {
5754
+ } else if (existsSync8(join10(this.projectPath, ".csproj")) || existsSync8(join10(this.projectPath, "project.json"))) {
5630
5755
  info.projectType = ".NET";
5631
5756
  }
5632
5757
  }
5633
5758
  detectPackageManager(info) {
5634
- if (existsSync7(join9(this.projectPath, "bun.lockb"))) {
5759
+ if (existsSync8(join10(this.projectPath, "bun.lockb"))) {
5635
5760
  info.packageManager = "Bun";
5636
- } else if (existsSync7(join9(this.projectPath, "bun.lock"))) {
5761
+ } else if (existsSync8(join10(this.projectPath, "bun.lock"))) {
5637
5762
  info.packageManager = "Bun";
5638
- } else if (existsSync7(join9(this.projectPath, "pnpm-lock.yaml"))) {
5763
+ } else if (existsSync8(join10(this.projectPath, "pnpm-lock.yaml"))) {
5639
5764
  info.packageManager = "pnpm";
5640
- } else if (existsSync7(join9(this.projectPath, "yarn.lock"))) {
5765
+ } else if (existsSync8(join10(this.projectPath, "yarn.lock"))) {
5641
5766
  info.packageManager = "Yarn";
5642
- } else if (existsSync7(join9(this.projectPath, "package-lock.json"))) {
5767
+ } else if (existsSync8(join10(this.projectPath, "package-lock.json"))) {
5643
5768
  info.packageManager = "npm";
5644
- } else if (existsSync7(join9(this.projectPath, "npm-shrinkwrap.json"))) {
5769
+ } else if (existsSync8(join10(this.projectPath, "npm-shrinkwrap.json"))) {
5645
5770
  info.packageManager = "npm";
5646
5771
  }
5647
5772
  }
@@ -5704,9 +5829,9 @@ function analyzeProject(projectPath) {
5704
5829
 
5705
5830
  // src/features/rules/rules.manager.ts
5706
5831
  import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
5707
- import { join as join10, relative as relative4 } from "path";
5708
- import { existsSync as existsSync8 } from "fs";
5709
- import { homedir as homedir4 } from "os";
5832
+ import { join as join11, relative as relative4 } from "path";
5833
+ import { existsSync as existsSync9 } from "fs";
5834
+ import { homedir as homedir5 } from "os";
5710
5835
  function parseRuleFrontmatter(markdown) {
5711
5836
  const lines = markdown.split("\n");
5712
5837
  if (lines[0]?.trim() !== "---") {
@@ -5748,10 +5873,10 @@ function parseRuleFrontmatter(markdown) {
5748
5873
  return { metadata, content };
5749
5874
  }
5750
5875
  function getGlobalRulesDir() {
5751
- return join10(homedir4(), ".agents", "rules");
5876
+ return join11(homedir5(), ".agents", "rules");
5752
5877
  }
5753
5878
  function getProjectRulesDir(threadPath) {
5754
- return join10(threadPath, ".agents", "rules");
5879
+ return join11(threadPath, ".agents", "rules");
5755
5880
  }
5756
5881
  var RuleManager = class {
5757
5882
  /**
@@ -5761,14 +5886,14 @@ var RuleManager = class {
5761
5886
  async loadRules(threadPath) {
5762
5887
  const rules = /* @__PURE__ */ new Map();
5763
5888
  const globalDir = getGlobalRulesDir();
5764
- if (existsSync8(globalDir)) {
5889
+ if (existsSync9(globalDir)) {
5765
5890
  const globalRules = await this.loadRulesFromDir(globalDir, threadPath, "global");
5766
5891
  for (const rule of globalRules) {
5767
5892
  rules.set(rule.name, rule);
5768
5893
  }
5769
5894
  }
5770
5895
  const projectDir = getProjectRulesDir(threadPath);
5771
- if (existsSync8(projectDir)) {
5896
+ if (existsSync9(projectDir)) {
5772
5897
  const projectRules = await this.loadRulesFromDir(projectDir, threadPath, "project");
5773
5898
  for (const rule of projectRules) {
5774
5899
  rules.set(rule.name, rule);
@@ -5784,7 +5909,7 @@ var RuleManager = class {
5784
5909
  try {
5785
5910
  const entries = await readdir3(dir, { withFileTypes: true });
5786
5911
  for (const entry of entries) {
5787
- const fullPath = join10(dir, entry.name);
5912
+ const fullPath = join11(dir, entry.name);
5788
5913
  if (entry.isDirectory()) {
5789
5914
  const subRules = await this.loadRulesFromDir(fullPath, threadPath, scope);
5790
5915
  rules.push(...subRules);
@@ -5915,6 +6040,7 @@ var DevServerCache = class {
5915
6040
  var devServerCache = new DevServerCache();
5916
6041
 
5917
6042
  // src/agent/agent.prompt-loader.ts
6043
+ init_tarsk_debug();
5918
6044
  function buildDefaultPrompt(tools) {
5919
6045
  const toolList = tools.map((t) => t.name).join(", ");
5920
6046
  return `You are a helpful coding assistant. You have access to ${toolList} tools. Use them to explore and modify the codebase as needed. Skills are created and stored in .agents/skills/ . Use Mermaid for flowcharts, sequence diagrams, state diagrams, or graphs when appropriate. Do not use emojis.`;
@@ -5991,12 +6117,12 @@ function loadDeveloperContext(threadPath) {
5991
6117
  try {
5992
6118
  const agentsPath = resolve(threadPath, "agents.md");
5993
6119
  const agentsContent = readFileSync4(agentsPath, "utf-8").trim();
5994
- console.log("[ai] Successfully loaded agents.md from thread path for developer context");
6120
+ tarskDebugLog("[ai] Successfully loaded agents.md from thread path for developer context");
5995
6121
  return agentsContent;
5996
6122
  } catch (error) {
5997
6123
  const isFileNotFound = error && typeof error === "object" && "code" in error && error.code === "ENOENT";
5998
6124
  if (isFileNotFound) {
5999
- console.log("[ai] agents.md not found in thread path, skipping developer context");
6125
+ tarskDebugLog("[ai] agents.md not found in thread path, skipping developer context");
6000
6126
  } else {
6001
6127
  console.warn(
6002
6128
  "[ai] Error loading agents.md from thread path:",
@@ -6012,7 +6138,7 @@ async function loadRulesSection(threadPath) {
6012
6138
  const rules = await ruleManager.loadRules(threadPath);
6013
6139
  if (rules.length > 0) {
6014
6140
  const rulesSection = ruleManager.formatRulesForPrompt(rules);
6015
- console.log(`[ai] Loaded ${rules.length} rule(s) from .agents/rules directory`);
6141
+ tarskDebugLog(`[ai] Loaded ${rules.length} rule(s) from .agents/rules directory`);
6016
6142
  return rulesSection;
6017
6143
  }
6018
6144
  return "";
@@ -6038,20 +6164,20 @@ async function loadDevServerSection(threadPath) {
6038
6164
  // 3 second timeout
6039
6165
  });
6040
6166
  if (response.ok) {
6041
- console.log(`[ai] Dev server is running at ${cachedUrl} for thread ${threadId}`);
6167
+ tarskDebugLog(`[ai] Dev server is running at ${cachedUrl} for thread ${threadId}`);
6042
6168
  return `
6043
6169
 
6044
6170
  # Dev Server
6045
6171
 
6046
6172
  The dev server is running at ${cachedUrl}.`;
6047
6173
  } else {
6048
- console.log(
6174
+ tarskDebugLog(
6049
6175
  `[ai] Dev server at ${cachedUrl} responded with status ${response.status} for thread ${threadId}`
6050
6176
  );
6051
6177
  return "";
6052
6178
  }
6053
6179
  } catch (fetchError) {
6054
- console.log(
6180
+ tarskDebugLog(
6055
6181
  `[ai] Dev server at ${cachedUrl} is not reachable for thread ${threadId}:`,
6056
6182
  fetchError instanceof Error ? fetchError.message : String(fetchError)
6057
6183
  );
@@ -6080,6 +6206,43 @@ function loadProjectAnalysisSection(threadPath) {
6080
6206
  return "";
6081
6207
  }
6082
6208
  }
6209
+ async function loadPromptSections(threadPath, tools, skills, planMode, agents, deferredTools, ralphMode) {
6210
+ let systemPrompt = buildDefaultPrompt(tools);
6211
+ const agentsContent = loadDeveloperContext(threadPath);
6212
+ if (agentsContent) {
6213
+ systemPrompt += "\n\n# Developer Context\n\n" + agentsContent;
6214
+ }
6215
+ const projectAnalysisSection = loadProjectAnalysisSection(threadPath);
6216
+ if (projectAnalysisSection) {
6217
+ systemPrompt += projectAnalysisSection;
6218
+ }
6219
+ const devServerSection = await loadDevServerSection(threadPath);
6220
+ if (devServerSection) {
6221
+ systemPrompt += devServerSection;
6222
+ }
6223
+ if (planMode) {
6224
+ systemPrompt += PLAN_MODE_INSTRUCTIONS;
6225
+ }
6226
+ if (ralphMode) {
6227
+ systemPrompt += RALPH_MODE_INSTRUCTIONS;
6228
+ const progressContent = await readProgress(threadPath);
6229
+ if (progressContent.trim()) {
6230
+ systemPrompt += "\n\n# Prior Learnings (from progress.txt)\n\n" + progressContent;
6231
+ }
6232
+ }
6233
+ if (deferredTools && deferredTools.size > 0) {
6234
+ systemPrompt += formatDeferredToolsList(deferredTools);
6235
+ }
6236
+ const rules = await loadRulesSection(threadPath);
6237
+ const skillsSection = formatSkillsSection(skills ?? []);
6238
+ const subagentDefinitions = formatAgentsSection(agents ?? []);
6239
+ return {
6240
+ systemPrompt,
6241
+ rules,
6242
+ skills: skillsSection,
6243
+ subagentDefinitions
6244
+ };
6245
+ }
6083
6246
  function formatSkillsSection(skills) {
6084
6247
  if (!skills || skills.length === 0) {
6085
6248
  return "";
@@ -6101,7 +6264,7 @@ function formatSkillsSection(skills) {
6101
6264
  skillsSection += skill.instructions;
6102
6265
  skillsSection += "\n\n---\n\n";
6103
6266
  }
6104
- console.log(
6267
+ tarskDebugLog(
6105
6268
  `[ai] Injected ${skills.length} skill(s) into system prompt: ${skills.map((s) => s.name).join(", ")}`
6106
6269
  );
6107
6270
  return skillsSection;
@@ -6120,7 +6283,7 @@ function formatAgentsSection(agents) {
6120
6283
 
6121
6284
  `;
6122
6285
  }
6123
- console.log(
6286
+ tarskDebugLog(
6124
6287
  `[ai] Injected ${invocable.length} agent(s) into system prompt: ${invocable.map((a) => a.name).join(", ")}`
6125
6288
  );
6126
6289
  return section;
@@ -6529,6 +6692,8 @@ ${userPrompt}`;
6529
6692
  } else {
6530
6693
  console.log("[ai] \u26A0\uFE0F Agent ended with no text content and no tool calls.");
6531
6694
  const upstreamError = eventQueue.lastErrorMessage ? { message: eventQueue.lastErrorMessage } : void 0;
6695
+ const noResponseMessage = `The model ${model} from ${providerName} did not provide a response to your prompt. Check your API key and balance and try again.`;
6696
+ const content = upstreamError ? `${noResponseMessage} ${upstreamError.message}` : noResponseMessage;
6532
6697
  console.error("[ai] Agent ended without text content:", {
6533
6698
  request: promptRequest,
6534
6699
  upstreamError,
@@ -6537,7 +6702,7 @@ ${userPrompt}`;
6537
6702
  });
6538
6703
  yield {
6539
6704
  type: "error",
6540
- content: `The model ${model} from ${providerName} did not provide a response to your prompt. Check your API key and balance and try again.`,
6705
+ content,
6541
6706
  error: {
6542
6707
  code: "NO_CONTENT_NO_TOOLS",
6543
6708
  message: `The model ${model} from ${providerName} did not provide a response to your prompt.`,
@@ -6570,6 +6735,7 @@ ${userPrompt}`;
6570
6735
  };
6571
6736
 
6572
6737
  // src/agent/agent.processing-state-manager.ts
6738
+ init_tarsk_debug();
6573
6739
  var ProcessingStateManagerImpl = class {
6574
6740
  processingThreads = /* @__PURE__ */ new Set();
6575
6741
  eventBuffers = /* @__PURE__ */ new Map();
@@ -6578,7 +6744,7 @@ var ProcessingStateManagerImpl = class {
6578
6744
  setProcessing(threadId) {
6579
6745
  this.processingThreads.add(threadId);
6580
6746
  this.eventBuffers.set(threadId, []);
6581
- console.log(
6747
+ tarskDebugLog(
6582
6748
  `[ProcessingState] Thread ${threadId} started processing. Active: ${this.processingThreads.size}`
6583
6749
  );
6584
6750
  }
@@ -6588,7 +6754,7 @@ var ProcessingStateManagerImpl = class {
6588
6754
  abortThread(threadId) {
6589
6755
  const controller = this.abortControllers.get(threadId);
6590
6756
  if (!controller) return false;
6591
- console.log(`[ProcessingState] Aborting thread ${threadId} via stop endpoint`);
6757
+ tarskDebugLog(`[ProcessingState] Aborting thread ${threadId} via stop endpoint`);
6592
6758
  controller.abort();
6593
6759
  this.abortControllers.delete(threadId);
6594
6760
  return true;
@@ -6606,7 +6772,7 @@ var ProcessingStateManagerImpl = class {
6606
6772
  setTimeout(() => {
6607
6773
  this.eventBuffers.delete(threadId);
6608
6774
  }, 5e3);
6609
- console.log(
6775
+ tarskDebugLog(
6610
6776
  `[ProcessingState] Thread ${threadId} finished processing. Active: ${this.processingThreads.size}`
6611
6777
  );
6612
6778
  }
@@ -6650,14 +6816,14 @@ var ProcessingStateManagerImpl = class {
6650
6816
 
6651
6817
  // src/core/env-manager.ts
6652
6818
  import { promises as fs } from "fs";
6653
- import { join as join11 } from "path";
6819
+ import { join as join12 } from "path";
6654
6820
  function updateRuntimeEnv(values) {
6655
6821
  for (const [key, value] of Object.entries(values)) {
6656
6822
  process.env[key] = value;
6657
6823
  }
6658
6824
  }
6659
6825
  async function updateEnvFile(keyNames) {
6660
- const envPath = join11(process.cwd(), ".env");
6826
+ const envPath = join12(process.cwd(), ".env");
6661
6827
  let content = "";
6662
6828
  try {
6663
6829
  content = await fs.readFile(envPath, "utf-8");
@@ -6686,7 +6852,7 @@ async function updateEnvFile(keyNames) {
6686
6852
  await fs.writeFile(envPath, newLines.join("\n") + "\n", "utf-8");
6687
6853
  }
6688
6854
  async function readEnvFile() {
6689
- const envPath = join11(process.cwd(), ".env");
6855
+ const envPath = join12(process.cwd(), ".env");
6690
6856
  const envMap = {};
6691
6857
  try {
6692
6858
  const content = await fs.readFile(envPath, "utf-8");
@@ -6879,9 +7045,9 @@ import { randomUUID as randomUUID4 } from "crypto";
6879
7045
 
6880
7046
  // src/features/skills/skills.manager.ts
6881
7047
  import { readdir as readdir4, readFile as readFile6 } from "fs/promises";
6882
- import { join as join12 } from "path";
6883
- import { existsSync as existsSync9 } from "fs";
6884
- import { homedir as homedir5 } from "os";
7048
+ import { join as join13 } from "path";
7049
+ import { existsSync as existsSync10 } from "fs";
7050
+ import { homedir as homedir6 } from "os";
6885
7051
  function parseFrontmatter(markdown) {
6886
7052
  const lines = markdown.split("\n");
6887
7053
  if (lines[0]?.trim() !== "---") {
@@ -6927,10 +7093,10 @@ function parseFrontmatter(markdown) {
6927
7093
  return { metadata, content };
6928
7094
  }
6929
7095
  function getGlobalSkillsDir() {
6930
- return join12(homedir5(), ".agents", "skills");
7096
+ return join13(homedir6(), ".agents", "skills");
6931
7097
  }
6932
7098
  function getProjectSkillsDir(threadPath) {
6933
- return join12(threadPath, ".agents", "skills");
7099
+ return join13(threadPath, ".agents", "skills");
6934
7100
  }
6935
7101
  function validateSkillName(name) {
6936
7102
  if (!name || name.length === 0 || name.length > 64) {
@@ -6958,14 +7124,14 @@ var SkillManager = class {
6958
7124
  async loadSkills(threadPath) {
6959
7125
  const skills = /* @__PURE__ */ new Map();
6960
7126
  const globalDir = getGlobalSkillsDir();
6961
- if (existsSync9(globalDir)) {
7127
+ if (existsSync10(globalDir)) {
6962
7128
  const globalSkills = await this.loadSkillsFromDir(globalDir, "global");
6963
7129
  for (const skill of globalSkills) {
6964
7130
  skills.set(skill.name, skill);
6965
7131
  }
6966
7132
  }
6967
7133
  const projectDir = getProjectSkillsDir(threadPath);
6968
- if (existsSync9(projectDir)) {
7134
+ if (existsSync10(projectDir)) {
6969
7135
  const projectSkills = await this.loadSkillsFromDir(projectDir, "project");
6970
7136
  for (const skill of projectSkills) {
6971
7137
  skills.set(skill.name, skill);
@@ -6983,9 +7149,9 @@ var SkillManager = class {
6983
7149
  for (const entry of entries) {
6984
7150
  if (!entry.isDirectory()) continue;
6985
7151
  const skillDirName = entry.name;
6986
- const skillPath = join12(dir, skillDirName);
6987
- const skillFilePath = join12(skillPath, "SKILL.md");
6988
- if (!existsSync9(skillFilePath)) {
7152
+ const skillPath = join13(dir, skillDirName);
7153
+ const skillFilePath = join13(skillPath, "SKILL.md");
7154
+ if (!existsSync10(skillFilePath)) {
6989
7155
  console.warn(`Skipping skill directory ${skillDirName}: SKILL.md not found`);
6990
7156
  continue;
6991
7157
  }
@@ -7164,9 +7330,9 @@ async function activateSkills(allSkills, taskDescription, thread, options) {
7164
7330
 
7165
7331
  // src/features/agents/agents.manager.ts
7166
7332
  import { readdir as readdir5, readFile as readFile7 } from "fs/promises";
7167
- import { join as join13 } from "path";
7168
- import { existsSync as existsSync10 } from "fs";
7169
- import { homedir as homedir6 } from "os";
7333
+ import { join as join14 } from "path";
7334
+ import { existsSync as existsSync11 } from "fs";
7335
+ import { homedir as homedir7 } from "os";
7170
7336
  function parseFrontmatter2(markdown) {
7171
7337
  const lines = markdown.split("\n");
7172
7338
  if (lines[0]?.trim() !== "---") {
@@ -7222,10 +7388,10 @@ function validateDescription2(description) {
7222
7388
  return !!description && description.length > 0 && description.length <= 1024;
7223
7389
  }
7224
7390
  function getGlobalAgentsDir() {
7225
- return join13(homedir6(), ".agents", "agents");
7391
+ return join14(homedir7(), ".agents", "agents");
7226
7392
  }
7227
7393
  function getProjectAgentsDir(threadPath) {
7228
- return join13(threadPath, ".agents", "agents");
7394
+ return join14(threadPath, ".agents", "agents");
7229
7395
  }
7230
7396
  var AgentsManager = class {
7231
7397
  /**
@@ -7235,14 +7401,14 @@ var AgentsManager = class {
7235
7401
  async loadAgents(threadPath) {
7236
7402
  const agents = /* @__PURE__ */ new Map();
7237
7403
  const globalDir = getGlobalAgentsDir();
7238
- if (existsSync10(globalDir)) {
7404
+ if (existsSync11(globalDir)) {
7239
7405
  const globalAgents = await this.loadAgentsFromDir(globalDir, "global");
7240
7406
  for (const agent of globalAgents) {
7241
7407
  agents.set(agent.name, agent);
7242
7408
  }
7243
7409
  }
7244
7410
  const projectDir = getProjectAgentsDir(threadPath);
7245
- if (existsSync10(projectDir)) {
7411
+ if (existsSync11(projectDir)) {
7246
7412
  const projectAgents = await this.loadAgentsFromDir(projectDir, "project");
7247
7413
  for (const agent of projectAgents) {
7248
7414
  agents.set(agent.name, agent);
@@ -7257,9 +7423,9 @@ var AgentsManager = class {
7257
7423
  for (const entry of entries) {
7258
7424
  if (!entry.isDirectory()) continue;
7259
7425
  const agentDirName = entry.name;
7260
- const agentPath = join13(dir, agentDirName);
7261
- const agentFilePath = join13(agentPath, "AGENT.md");
7262
- if (!existsSync10(agentFilePath)) {
7426
+ const agentPath = join14(dir, agentDirName);
7427
+ const agentFilePath = join14(agentPath, "AGENT.md");
7428
+ if (!existsSync11(agentFilePath)) {
7263
7429
  console.warn(`[agents] Skipping agent directory ${agentDirName}: AGENT.md not found`);
7264
7430
  continue;
7265
7431
  }
@@ -7445,7 +7611,7 @@ function extractAssistantContent(events, fallback) {
7445
7611
  // src/features/chat/chat-post.route.ts
7446
7612
  init_database();
7447
7613
  import { readFile as readFile8, unlink } from "fs/promises";
7448
- import { join as join14 } from "path";
7614
+ import { join as join15 } from "path";
7449
7615
 
7450
7616
  // src/features/project-todos/project-todos.database.ts
7451
7617
  init_database();
@@ -8438,7 +8604,7 @@ ${result.output}`;
8438
8604
  try {
8439
8605
  const todo = await getTodoByThreadId(db, threadId);
8440
8606
  if (todo && todo.status === "Plan") {
8441
- const planFilePath = join14(threadPath, `${todo.id}-plan.md`);
8607
+ const planFilePath = join15(threadPath, `${todo.id}-plan.md`);
8442
8608
  try {
8443
8609
  const planContent = await readFile8(planFilePath, "utf-8");
8444
8610
  await updateTodo(db, todo.id, { description: planContent.trim() });
@@ -9690,8 +9856,226 @@ async function handleGetThreadUsageSummary(c, conversationManager, threadManager
9690
9856
  }
9691
9857
  }
9692
9858
 
9859
+ // src/features/conversations/context-breakdown.ts
9860
+ function serializeToolsForEstimate(tools) {
9861
+ return JSON.stringify(
9862
+ tools.map((tool) => ({
9863
+ name: tool.name,
9864
+ description: tool.description,
9865
+ parameters: tool.parameters
9866
+ }))
9867
+ );
9868
+ }
9869
+ function serializeConversationContent(messages) {
9870
+ const parts = [];
9871
+ for (const message of messages) {
9872
+ parts.push(message.request.message);
9873
+ if (message.request.attachments?.length) {
9874
+ for (const attachment of message.request.attachments) {
9875
+ parts.push(attachment.content);
9876
+ }
9877
+ }
9878
+ if (!message.response) {
9879
+ continue;
9880
+ }
9881
+ parts.push(message.response.content);
9882
+ for (const event of message.response.events) {
9883
+ if (typeof event.content === "string" && event.content.length > 0) {
9884
+ parts.push(event.content);
9885
+ }
9886
+ if (event.type === "toolcall_delta" && event.partial) {
9887
+ parts.push(JSON.stringify(event.partial));
9888
+ }
9889
+ }
9890
+ }
9891
+ return parts.join("\n");
9892
+ }
9893
+ async function resolveContextWindow(modelId, metadataManager) {
9894
+ if (!modelId) {
9895
+ return 128e3;
9896
+ }
9897
+ const parts = modelId.split("/");
9898
+ if (parts.length < 2) {
9899
+ return 128e3;
9900
+ }
9901
+ const provider = parts[0];
9902
+ const modelName = parts.slice(1).join("/");
9903
+ const modelManager = new ModelManager(metadataManager);
9904
+ try {
9905
+ const enabledModels = await modelManager.getEnabledModels(provider);
9906
+ const enabledModel = enabledModels.find(
9907
+ (model) => model.id === modelName || model.id === modelId
9908
+ );
9909
+ if (enabledModel?.contextWindow) {
9910
+ return enabledModel.contextWindow;
9911
+ }
9912
+ const availableModels = await modelManager.getAvailableModels(provider);
9913
+ const availableModel = availableModels.find(
9914
+ (model) => model.id === modelName || model.id === modelId
9915
+ );
9916
+ if (availableModel?.contextWindow) {
9917
+ return availableModel.contextWindow;
9918
+ }
9919
+ } catch {
9920
+ }
9921
+ return 128e3;
9922
+ }
9923
+ function getPeakInputTokens(messages) {
9924
+ let peakInput = 0;
9925
+ for (const message of messages) {
9926
+ if (!message.response) {
9927
+ continue;
9928
+ }
9929
+ const hasMessageUsage = message.response.events.some(
9930
+ (event) => event.type === "message" && event.message?.usage && ((event.message.usage.input ?? 0) > 0 || (event.message.usage.output ?? 0) > 0 || (event.message.usage.cacheRead ?? 0) > 0 || (event.message.usage.cacheWrite ?? 0) > 0)
9931
+ );
9932
+ for (const event of message.response.events) {
9933
+ if (hasMessageUsage) {
9934
+ if (event.type === "message" && event.message?.usage) {
9935
+ peakInput = Math.max(peakInput, event.message.usage.input ?? 0);
9936
+ }
9937
+ } else if (event.type === "toolcall_delta" && event.partial?.usage) {
9938
+ peakInput = Math.max(peakInput, event.partial.usage.input ?? 0);
9939
+ }
9940
+ }
9941
+ }
9942
+ return peakInput;
9943
+ }
9944
+ function resolveModelId(thread, messages) {
9945
+ const latestModel = messages.at(-1)?.request.model;
9946
+ if (!latestModel) {
9947
+ return void 0;
9948
+ }
9949
+ if (latestModel.includes("/")) {
9950
+ return latestModel;
9951
+ }
9952
+ const provider = thread.modelProvider;
9953
+ return provider ? `${provider.toLowerCase()}/${latestModel}` : latestModel;
9954
+ }
9955
+ async function computeContextBreakdown(threadId, conversationId, conversationManager, threadManager, metadataManager) {
9956
+ const thread = await threadManager.getThread(threadId);
9957
+ if (!thread) {
9958
+ return null;
9959
+ }
9960
+ const history = await conversationManager.getConversationHistory(threadId);
9961
+ if (!history) {
9962
+ return null;
9963
+ }
9964
+ const messages = history.messages.filter((message) => message.conversationId === conversationId);
9965
+ if (messages.length === 0) {
9966
+ return null;
9967
+ }
9968
+ const threadPath = thread.path;
9969
+ const latestMessage = messages[messages.length - 1];
9970
+ const planMode = latestMessage.request.planMode === true;
9971
+ const ralphMode = latestMessage.request.ralphMode === true;
9972
+ const skillManager2 = new SkillManager();
9973
+ const allSkills = await skillManager2.loadSkills(threadPath);
9974
+ const activatedSkills = await activateSkills(allSkills, latestMessage.request.message, thread);
9975
+ const agentsManager = new AgentsManager();
9976
+ const agents = await agentsManager.loadAgents(threadPath);
9977
+ const { tools, deferredToolNames } = await createCodingTools(threadPath, {
9978
+ skills: activatedSkills,
9979
+ threadId,
9980
+ threadPath,
9981
+ metadataManager
9982
+ });
9983
+ const promptSections = await loadPromptSections(
9984
+ threadPath,
9985
+ tools,
9986
+ activatedSkills,
9987
+ planMode,
9988
+ agents,
9989
+ deferredToolNames,
9990
+ ralphMode
9991
+ );
9992
+ const invocableAgents = agents.filter((agent) => !agent.disableModelInvocation);
9993
+ if (invocableAgents.length > 0) {
9994
+ const agentToolInstance = createAgentTool({
9995
+ agents: invocableAgents,
9996
+ baseTools: tools,
9997
+ metadataManager,
9998
+ parentModel: latestMessage.request.model,
9999
+ parentProvider: thread.modelProvider ?? "",
10000
+ defaultSystemPrompt: promptSections.systemPrompt,
10001
+ onEvent: () => {
10002
+ }
10003
+ });
10004
+ tools.push(agentToolInstance);
10005
+ }
10006
+ const categories = {
10007
+ systemPrompt: estimateTokenCount(promptSections.systemPrompt),
10008
+ toolDefinitions: estimateTokenCount(serializeToolsForEstimate(tools)),
10009
+ rules: estimateTokenCount(promptSections.rules),
10010
+ skills: estimateTokenCount(promptSections.skills),
10011
+ subagentDefinitions: estimateTokenCount(promptSections.subagentDefinitions),
10012
+ conversation: estimateTokenCount(serializeConversationContent(messages))
10013
+ };
10014
+ const estimatedTotal = categories.systemPrompt + categories.toolDefinitions + categories.rules + categories.skills + categories.subagentDefinitions + categories.conversation;
10015
+ const peakInput = getPeakInputTokens(messages);
10016
+ if (peakInput > 0 && estimatedTotal > 0) {
10017
+ const fixedTotal = categories.systemPrompt + categories.toolDefinitions + categories.rules + categories.skills + categories.subagentDefinitions;
10018
+ categories.conversation = Math.max(0, peakInput - fixedTotal);
10019
+ }
10020
+ const totalTokens = categories.systemPrompt + categories.toolDefinitions + categories.rules + categories.skills + categories.subagentDefinitions + categories.conversation;
10021
+ const modelId = resolveModelId(thread, messages);
10022
+ const contextWindow = await resolveContextWindow(modelId, metadataManager);
10023
+ const percentageFull = contextWindow > 0 ? Math.round(totalTokens / contextWindow * 100) : 0;
10024
+ return {
10025
+ categories,
10026
+ totalTokens,
10027
+ contextWindow,
10028
+ percentageFull,
10029
+ model: modelId
10030
+ };
10031
+ }
10032
+
10033
+ // src/features/conversations/context-breakdown.route.ts
10034
+ async function handleGetContextBreakdown(c, conversationManager, threadManager, metadataManager) {
10035
+ try {
10036
+ const threadId = c.req.param("threadId");
10037
+ const conversationId = c.req.param("conversationId");
10038
+ if (!threadId || typeof threadId !== "string") {
10039
+ return errorResponse(
10040
+ c,
10041
+ ErrorCodes.INVALID_REQUEST,
10042
+ "threadId is required and must be a string",
10043
+ 400
10044
+ );
10045
+ }
10046
+ if (!conversationId || typeof conversationId !== "string") {
10047
+ return errorResponse(
10048
+ c,
10049
+ ErrorCodes.INVALID_REQUEST,
10050
+ "conversationId is required and must be a string",
10051
+ 400
10052
+ );
10053
+ }
10054
+ const breakdown = await computeContextBreakdown(
10055
+ threadId,
10056
+ conversationId,
10057
+ conversationManager,
10058
+ threadManager,
10059
+ metadataManager
10060
+ );
10061
+ if (!breakdown) {
10062
+ return errorResponse(c, ErrorCodes.NO_CONVERSATION, "Conversation not found", 404);
10063
+ }
10064
+ return successResponse(c, breakdown);
10065
+ } catch (error) {
10066
+ console.error("[context-breakdown] Error getting context breakdown:", error);
10067
+ return errorResponse(
10068
+ c,
10069
+ ErrorCodes.INTERNAL_ERROR,
10070
+ "Failed to retrieve context breakdown",
10071
+ 500,
10072
+ error instanceof Error ? error.message : String(error)
10073
+ );
10074
+ }
10075
+ }
10076
+
9693
10077
  // src/features/conversations/conversations.routes.ts
9694
- function createConversationRoutes(conversationManager, threadManager) {
10078
+ function createConversationRoutes(conversationManager, threadManager, metadataManager) {
9695
10079
  const router = new Hono3();
9696
10080
  router.get("/:threadId", (c) => getAllConversations(c, conversationManager, threadManager));
9697
10081
  router.get("/:threadId/deleted", (c) => getDeletedConversations(c, conversationManager));
@@ -9707,6 +10091,10 @@ function createConversationRoutes(conversationManager, threadManager) {
9707
10091
  "/:threadId/:conversationId/usage",
9708
10092
  (c) => handleGetConversationUsage(c, conversationManager, threadManager)
9709
10093
  );
10094
+ router.get(
10095
+ "/:threadId/:conversationId/context",
10096
+ (c) => handleGetContextBreakdown(c, conversationManager, threadManager, metadataManager)
10097
+ );
9710
10098
  router.get(
9711
10099
  "/:threadId/:conversationId",
9712
10100
  (c) => getConversationById(c, conversationManager, threadManager)
@@ -9876,6 +10264,7 @@ function isEncryptedKey(value) {
9876
10264
  }
9877
10265
 
9878
10266
  // src/features/metadata/metadata.manager.ts
10267
+ init_tarsk_debug();
9879
10268
  var MetadataManager = class {
9880
10269
  db;
9881
10270
  /**
@@ -10061,7 +10450,7 @@ var MetadataManager = class {
10061
10450
  providerKeys[provider] = "";
10062
10451
  }
10063
10452
  } else {
10064
- console.log(
10453
+ tarskDebugLog(
10065
10454
  `[MetadataManager] Found plain-text key for ${provider}, will encrypt on save`
10066
10455
  );
10067
10456
  providerKeys[provider] = encryptedKey;
@@ -10069,7 +10458,7 @@ var MetadataManager = class {
10069
10458
  }
10070
10459
  }
10071
10460
  if (needsMigration) {
10072
- console.log("[MetadataManager] Migrating plain-text keys to encrypted format");
10461
+ tarskDebugLog("[MetadataManager] Migrating plain-text keys to encrypted format");
10073
10462
  await this.saveAllProviderKeys(providerKeys);
10074
10463
  }
10075
10464
  return {
@@ -10326,6 +10715,33 @@ var MetadataManager = class {
10326
10715
  import { Hono as Hono4 } from "hono";
10327
10716
 
10328
10717
  // src/features/models/models-get-available.route.ts
10718
+ function filterBySupportedTools(models, supportedTools, provider) {
10719
+ if (supportedTools === "true" && provider.toLowerCase() === "openrouter") {
10720
+ return models.filter((m) => m.supportedParameters?.tools === true);
10721
+ }
10722
+ return models;
10723
+ }
10724
+ function filterByUseCase(models, useCase) {
10725
+ if (useCase === "image") {
10726
+ return models.filter((m) => m.generatesImages === true);
10727
+ }
10728
+ if (useCase === "coding") {
10729
+ const filtered = models.filter((m) => {
10730
+ const name = m.name.toLowerCase().trim();
10731
+ const hasValidName = name !== "free" && name !== "auto";
10732
+ const hasCodingUse = Array.isArray(m.tarsk_use) && m.tarsk_use.includes("coding");
10733
+ return hasValidName && hasCodingUse;
10734
+ });
10735
+ if (filtered.length === 0) {
10736
+ return models.filter((m) => {
10737
+ const name = m.name.toLowerCase().trim();
10738
+ return name !== "free" && name !== "auto";
10739
+ });
10740
+ }
10741
+ return filtered;
10742
+ }
10743
+ return models;
10744
+ }
10329
10745
  async function handleGetAvailableModels(c, modelManager) {
10330
10746
  try {
10331
10747
  const provider = c.req.query("provider");
@@ -10334,42 +10750,17 @@ async function handleGetAvailableModels(c, modelManager) {
10334
10750
  if (!provider) {
10335
10751
  return c.json({ error: "provider query parameter is required" }, 400);
10336
10752
  }
10337
- let models = await modelManager.getAvailableModels(provider);
10338
- models.forEach((m) => {
10339
- if (m.coding_index === void 0 || m.coding_index === null) {
10340
- console.log(`Model ${m.name} (${m.id}) is missing coding_index`);
10341
- }
10342
- });
10343
- if (supportedTools === "true" && provider.toLowerCase() === "openrouter") {
10344
- models = models.filter((m) => m.supportedParameters?.tools === true);
10345
- }
10346
- if (useCase === "image") {
10347
- models = models.filter((m) => m.generatesImages === true);
10348
- } else if (useCase === "coding") {
10349
- models = models.filter((m) => {
10350
- const name = m.name.toLowerCase().trim();
10351
- const hasValidName = name !== "free" && name !== "auto";
10352
- const hasCodingUse = Array.isArray(m.tarsk_use) && m.tarsk_use.includes("coding");
10353
- return hasValidName && hasCodingUse;
10354
- });
10355
- if (models.length === 0) {
10356
- models = (await modelManager.getAvailableModels(provider)).filter((m) => {
10357
- const name = m.name.toLowerCase().trim();
10358
- return name !== "free" && name !== "auto";
10359
- });
10360
- if (supportedTools === "true" && provider.toLowerCase() === "openrouter") {
10361
- models = models.filter((m) => m.supportedParameters?.tools === true);
10362
- }
10363
- }
10364
- }
10365
- const enabledModels = await modelManager.getEnabledModels(provider);
10366
- const enabledModelIds = new Set(enabledModels.map((m) => m.id));
10753
+ const allModels = await modelManager.getAvailableModels(provider);
10754
+ let models = filterByUseCase(allModels, useCase);
10755
+ models = filterBySupportedTools(models, supportedTools, provider);
10756
+ const enabledModelIds = useCase === "image" ? await modelManager.getEnabledImageModelIds(provider) : await modelManager.getEnabledModelIds(provider);
10757
+ const enabledSet = new Set(enabledModelIds);
10367
10758
  models.sort((a, b) => {
10368
- const aEnabled = enabledModelIds.has(a.id) ? 0 : 1;
10369
- const bEnabled = enabledModelIds.has(b.id) ? 0 : 1;
10759
+ const aEnabled = enabledSet.has(a.id) ? 0 : 1;
10760
+ const bEnabled = enabledSet.has(b.id) ? 0 : 1;
10370
10761
  return aEnabled - bEnabled;
10371
10762
  });
10372
- return c.json({ provider, models, enabledModelIds: [...enabledModelIds] });
10763
+ return c.json({ provider, models, enabledModelIds });
10373
10764
  } catch (error) {
10374
10765
  const message = error instanceof Error ? error.message : "Unknown error";
10375
10766
  return c.json({ error: message }, 500);
@@ -10825,6 +11216,9 @@ async function handleDeleteProject(c, projectManager) {
10825
11216
  // src/features/projects/projects.open-with.ts
10826
11217
  init_utils();
10827
11218
  import open from "open";
11219
+ function formatOpenError(program, _rawError) {
11220
+ return `${program} could not be started. Maybe it is not installed.`;
11221
+ }
10828
11222
  function validateProgram(program) {
10829
11223
  if (!program) {
10830
11224
  return "Program is required";
@@ -10876,7 +11270,7 @@ var OpenWithHandler = class {
10876
11270
  } catch (error) {
10877
11271
  const message = error instanceof Error ? error.message : String(error);
10878
11272
  console.error("[openWith] open() error:", message);
10879
- throw new Error(`Failed to open ${program}: ${message}`);
11273
+ throw new Error(formatOpenError(program, error));
10880
11274
  }
10881
11275
  }
10882
11276
  /**
@@ -11003,7 +11397,7 @@ async function handleOpenProject(c, projectManager) {
11003
11397
  });
11004
11398
  } catch (error) {
11005
11399
  const errorMessage = error instanceof Error ? error.message : String(error);
11006
- return errorResponse(c, ErrorCodes.OPEN_PROGRAM_ERROR, errorMessage, 500);
11400
+ return errorResponse(c, ErrorCodes.OPEN_PROGRAM_ERROR, errorMessage, 422);
11007
11401
  }
11008
11402
  }
11009
11403
 
@@ -11241,10 +11635,10 @@ async function handleCheckRunning(c, projectManager) {
11241
11635
 
11242
11636
  // src/core/run-command-detector.ts
11243
11637
  import { readFile as readFile9 } from "fs/promises";
11244
- import { join as join15 } from "path";
11638
+ import { join as join16 } from "path";
11245
11639
  async function detectPackageManager(projectPath) {
11246
11640
  try {
11247
- const packageJsonPath = join15(projectPath, "package.json");
11641
+ const packageJsonPath = join16(projectPath, "package.json");
11248
11642
  const content = await readFile9(packageJsonPath, "utf-8");
11249
11643
  const packageJson = JSON.parse(content);
11250
11644
  if (packageJson.packageManager) {
@@ -11260,7 +11654,7 @@ async function detectPackageManager(projectPath) {
11260
11654
  }
11261
11655
  async function detectRunScripts(projectPath) {
11262
11656
  try {
11263
- const packageJsonPath = join15(projectPath, "package.json");
11657
+ const packageJsonPath = join16(projectPath, "package.json");
11264
11658
  const content = await readFile9(packageJsonPath, "utf-8");
11265
11659
  const packageJson = JSON.parse(content);
11266
11660
  const scripts = packageJson.scripts ?? {};
@@ -11307,7 +11701,7 @@ async function suggestRunCommand(projectPath) {
11307
11701
 
11308
11702
  // src/features/projects/projects-package-scripts.route.ts
11309
11703
  import { readFile as readFile10 } from "fs/promises";
11310
- import { join as join16 } from "path";
11704
+ import { join as join17 } from "path";
11311
11705
  import { glob } from "glob";
11312
11706
  function formatScriptName(scriptName) {
11313
11707
  return scriptName.replace(/[-:_]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
@@ -11335,7 +11729,7 @@ async function findPackageScripts(projectPath) {
11335
11729
  const packageManager = await detectPackageManager(projectPath);
11336
11730
  for (const filePath of packageJsonFiles) {
11337
11731
  try {
11338
- const fullPath = join16(projectPath, filePath);
11732
+ const fullPath = join17(projectPath, filePath);
11339
11733
  const content = await readFile10(fullPath, "utf-8");
11340
11734
  const packageJson = JSON.parse(content);
11341
11735
  if (packageJson.scripts) {
@@ -11384,8 +11778,8 @@ async function handleGetPackageScripts(c, projectManager) {
11384
11778
 
11385
11779
  // src/features/projects/projects-ai-files.route.ts
11386
11780
  import { readdir as readdir6, readFile as readFile11, writeFile as writeFile2, mkdir, access as access2, rm } from "fs/promises";
11387
- import { join as join17, extname as extname3, basename } from "path";
11388
- import { existsSync as existsSync11 } from "fs";
11781
+ import { join as join18, extname as extname3, basename } from "path";
11782
+ import { existsSync as existsSync12 } from "fs";
11389
11783
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
11390
11784
  ".git",
11391
11785
  "node_modules",
@@ -11403,8 +11797,8 @@ async function buildFullTree(dirPath, relativeDirPath) {
11403
11797
  try {
11404
11798
  const entries = await readdir6(dirPath, { withFileTypes: true });
11405
11799
  for (const entry of entries) {
11406
- const entryRelPath = join17(relativeDirPath, entry.name);
11407
- const entryAbsPath = join17(dirPath, entry.name);
11800
+ const entryRelPath = join18(relativeDirPath, entry.name);
11801
+ const entryAbsPath = join18(dirPath, entry.name);
11408
11802
  if (entry.isDirectory()) {
11409
11803
  const children = await buildFullTree(entryAbsPath, entryRelPath);
11410
11804
  nodes.push({
@@ -11432,8 +11826,8 @@ async function buildMarkdownFilteredTree(dirPath, relativeDirPath) {
11432
11826
  try {
11433
11827
  const entries = await readdir6(dirPath, { withFileTypes: true });
11434
11828
  for (const entry of entries) {
11435
- const entryRelPath = join17(relativeDirPath, entry.name);
11436
- const entryAbsPath = join17(dirPath, entry.name);
11829
+ const entryRelPath = join18(relativeDirPath, entry.name);
11830
+ const entryAbsPath = join18(dirPath, entry.name);
11437
11831
  if (entry.isDirectory()) {
11438
11832
  if (IGNORED_DIRS.has(entry.name)) continue;
11439
11833
  const children = await buildMarkdownFilteredTree(entryAbsPath, entryRelPath);
@@ -11468,9 +11862,9 @@ async function buildAIFileTree(projectPath) {
11468
11862
  { key: "agents", label: "Agents" }
11469
11863
  ];
11470
11864
  for (const { key, label } of agentsFolders) {
11471
- const relPath = join17(".agents", key);
11472
- const absPath = join17(projectPath, relPath);
11473
- const exists = existsSync11(absPath);
11865
+ const relPath = join18(".agents", key);
11866
+ const absPath = join18(projectPath, relPath);
11867
+ const exists = existsSync12(absPath);
11474
11868
  if (exists) {
11475
11869
  const children = await buildFullTree(absPath, relPath);
11476
11870
  nodes.push({
@@ -11504,7 +11898,7 @@ async function buildAIFileTree(projectPath) {
11504
11898
  if (entry.name === ".agents" || entry.name === "AGENTS.md" || IGNORED_DIRS.has(entry.name))
11505
11899
  continue;
11506
11900
  const entryRelPath = entry.name;
11507
- const entryAbsPath = join17(projectPath, entry.name);
11901
+ const entryAbsPath = join18(projectPath, entry.name);
11508
11902
  if (entry.isFile() && MARKDOWN_EXTS.has(extname3(entry.name))) {
11509
11903
  nodes.push({
11510
11904
  id: entryRelPath,
@@ -11531,7 +11925,7 @@ async function buildAIFileTree(projectPath) {
11531
11925
  }
11532
11926
  function validateFilePath(projectPath, filePath) {
11533
11927
  if (!filePath) return null;
11534
- const abs = join17(projectPath, filePath);
11928
+ const abs = join18(projectPath, filePath);
11535
11929
  if (!abs.startsWith(projectPath + "/") && abs !== projectPath) return null;
11536
11930
  return abs;
11537
11931
  }
@@ -11657,7 +12051,7 @@ async function handleSaveAIFile(c, projectManager) {
11657
12051
  if (!absPath) {
11658
12052
  return c.json({ error: { code: "BAD_REQUEST", message: "Invalid file path" } }, 400);
11659
12053
  }
11660
- const parentDir = join17(absPath, "..");
12054
+ const parentDir = join18(absPath, "..");
11661
12055
  await mkdir(parentDir, { recursive: true });
11662
12056
  await writeFile2(absPath, content, "utf-8");
11663
12057
  return c.json({ success: true, path: filePath });
@@ -11757,11 +12151,11 @@ async function handleCreateSkill(c, projectManager) {
11757
12151
  if (!project) {
11758
12152
  return errorResponse(c, ErrorCodes.PROJECT_NOT_FOUND, `Project not found: ${projectId}`, 404);
11759
12153
  }
11760
- const skillRelPath = join17(".agents", "skills", name);
11761
- const skillAbsPath = join17(project.path, skillRelPath);
11762
- const skillFileRelPath = join17(skillRelPath, "SKILL.md");
11763
- const skillFileAbsPath = join17(skillAbsPath, "SKILL.md");
11764
- if (existsSync11(skillAbsPath)) {
12154
+ const skillRelPath = join18(".agents", "skills", name);
12155
+ const skillAbsPath = join18(project.path, skillRelPath);
12156
+ const skillFileRelPath = join18(skillRelPath, "SKILL.md");
12157
+ const skillFileAbsPath = join18(skillAbsPath, "SKILL.md");
12158
+ if (existsSync12(skillAbsPath)) {
11765
12159
  return c.json(
11766
12160
  { error: { code: "CONFLICT", message: `Skill '${name}' already exists` } },
11767
12161
  409
@@ -11862,13 +12256,14 @@ function createProjectRoutes(projectManager, threadManager) {
11862
12256
 
11863
12257
  // src/features/projects/projects.manager.ts
11864
12258
  init_utils();
11865
- import { join as join20 } from "path";
12259
+ import { join as join21 } from "path";
11866
12260
  import { realpathSync as realpathSync2 } from "fs";
11867
12261
  import { rm as rm3 } from "fs/promises";
11868
12262
 
11869
12263
  // src/agent/agent.process-manager.ts
11870
12264
  init_utils();
11871
12265
  import { EventEmitter } from "events";
12266
+ init_tarsk_debug();
11872
12267
  var URL_PATTERNS = [
11873
12268
  // http(s)://localhost:PORT
11874
12269
  /https?:\/\/localhost[:/](\d+)/i,
@@ -11895,7 +12290,7 @@ var ProcessManager = class extends EventEmitter {
11895
12290
  * @returns AsyncGenerator that yields ProcessOutput events
11896
12291
  */
11897
12292
  async *runProcess(projectId, command, cwd, threadId) {
11898
- console.log(
12293
+ tarskDebugLog(
11899
12294
  "CLI ProcessManager: runProcess called for project:",
11900
12295
  projectId,
11901
12296
  "thread:",
@@ -11906,14 +12301,14 @@ var ProcessManager = class extends EventEmitter {
11906
12301
  cwd
11907
12302
  );
11908
12303
  if (this.processes.has(projectId)) {
11909
- console.log("CLI ProcessManager: Process already running for project:", projectId);
12304
+ tarskDebugLog("CLI ProcessManager: Process already running for project:", projectId);
11910
12305
  yield {
11911
12306
  type: "error",
11912
12307
  error: new Error("A process is already running for this project")
11913
12308
  };
11914
12309
  return;
11915
12310
  }
11916
- console.log("CLI ProcessManager: Starting new process for project:", projectId);
12311
+ tarskDebugLog("CLI ProcessManager: Starting new process for project:", projectId);
11917
12312
  this.queues.set(projectId, []);
11918
12313
  this.resolvers.set(projectId, []);
11919
12314
  const addToQueue = (output) => {
@@ -11940,7 +12335,7 @@ var ProcessManager = class extends EventEmitter {
11940
12335
  };
11941
12336
  try {
11942
12337
  const { shell, args: shellArgs } = getShellConfig();
11943
- console.log("CLI ProcessManager: Spawning process:", shell, "with command:", command);
12338
+ tarskDebugLog("CLI ProcessManager: Spawning process:", shell, "with command:", command);
11944
12339
  const childProcess = spawnProcess(shell, [...shellArgs, command], {
11945
12340
  cwd,
11946
12341
  env: Object.fromEntries(
@@ -11949,7 +12344,7 @@ var ProcessManager = class extends EventEmitter {
11949
12344
  stdio: ["ignore", "pipe", "pipe"]
11950
12345
  });
11951
12346
  this.processes.set(projectId, childProcess);
11952
- console.log("CLI ProcessManager: Process spawned with PID:", childProcess.pid);
12347
+ tarskDebugLog("CLI ProcessManager: Process spawned with PID:", childProcess.pid);
11953
12348
  let urlDetected = false;
11954
12349
  let urlBuffer = "";
11955
12350
  childProcess.stdout?.on("data", (data) => {
@@ -12083,13 +12478,13 @@ var ProcessManager = class extends EventEmitter {
12083
12478
  // src/features/projects/projects.creator.ts
12084
12479
  init_utils();
12085
12480
  import { randomUUID as randomUUID7 } from "crypto";
12086
- import { basename as basename2, join as join19, relative as relative5 } from "path";
12481
+ import { basename as basename2, join as join20, relative as relative5 } from "path";
12087
12482
  import { access as access3, stat as stat3, readdir as readdir8 } from "fs/promises";
12088
12483
 
12089
12484
  // src/features/scaffold/scaffold.runner.ts
12090
12485
  init_utils();
12091
- import { existsSync as existsSync12 } from "fs";
12092
- import { join as join18 } from "path";
12486
+ import { existsSync as existsSync13 } from "fs";
12487
+ import { join as join19 } from "path";
12093
12488
  import { mkdir as mkdir2, readdir as readdir7, stat as stat2, rename, rm as rm2, writeFile as writeFile3 } from "fs/promises";
12094
12489
  import { createInterface as createInterface2 } from "readline";
12095
12490
 
@@ -12811,8 +13206,8 @@ function loadCatalog() {
12811
13206
  }
12812
13207
  async function writeAgentsMd(projectPath, agentsMd) {
12813
13208
  if (!agentsMd) return;
12814
- const agentsPath = join18(projectPath, "AGENTS.md");
12815
- if (existsSync12(agentsPath)) return;
13209
+ const agentsPath = join19(projectPath, "AGENTS.md");
13210
+ if (existsSync13(agentsPath)) return;
12816
13211
  await writeFile3(agentsPath, agentsMd, "utf-8");
12817
13212
  }
12818
13213
  function getProjectName(name) {
@@ -12969,8 +13364,8 @@ async function* runCommandStreaming(cwd, command) {
12969
13364
  }
12970
13365
  }
12971
13366
  async function* createScaffoldedProjectStreaming(options) {
12972
- const projectPath = join18(options.parentDir, options.threadId);
12973
- if (!existsSync12(options.parentDir)) {
13367
+ const projectPath = join19(options.parentDir, options.threadId);
13368
+ if (!existsSync13(options.parentDir)) {
12974
13369
  yield {
12975
13370
  type: "result",
12976
13371
  result: {
@@ -13059,7 +13454,7 @@ async function* createScaffoldedProjectStreaming(options) {
13059
13454
  }
13060
13455
  try {
13061
13456
  const projectName2 = getProjectName(options.projectName);
13062
- const projectSubDir = join18(projectPath, projectName2);
13457
+ const projectSubDir = join19(projectPath, projectName2);
13063
13458
  try {
13064
13459
  const subDirStat = await stat2(projectSubDir);
13065
13460
  if (subDirStat.isDirectory()) {
@@ -13069,8 +13464,8 @@ async function* createScaffoldedProjectStreaming(options) {
13069
13464
  };
13070
13465
  const items = await readdir7(projectSubDir);
13071
13466
  for (const item of items) {
13072
- const oldPath = join18(projectSubDir, item);
13073
- const newPath = join18(projectPath, item);
13467
+ const oldPath = join19(projectSubDir, item);
13468
+ const newPath = join19(projectPath, item);
13074
13469
  await rename(oldPath, newPath);
13075
13470
  }
13076
13471
  await rm2(projectSubDir, { recursive: true, force: true });
@@ -13086,7 +13481,7 @@ async function* createScaffoldedProjectStreaming(options) {
13086
13481
  };
13087
13482
  }
13088
13483
  const installCwd = scaffoldOptions.projectPath;
13089
- if (existsSync12(installCwd)) {
13484
+ if (existsSync13(installCwd)) {
13090
13485
  const installCmd = getInstallCommand(options.packageManager);
13091
13486
  yield { type: "progress", message: `
13092
13487
  > ${installCmd}` };
@@ -13538,7 +13933,7 @@ var ProjectCreator = class {
13538
13933
  return name;
13539
13934
  }
13540
13935
  generateThreadPath(_projectId, threadId) {
13541
- return join19(this.rootFolder, threadId);
13936
+ return join20(this.rootFolder, threadId);
13542
13937
  }
13543
13938
  async *createProjectFromFolder() {
13544
13939
  await loadUtils();
@@ -13688,19 +14083,19 @@ var ProjectCreator = class {
13688
14083
  }
13689
14084
  async findAllPackageJsonFiles(rootPath, currentPath, setupScripts) {
13690
14085
  try {
13691
- await access3(join19(currentPath, "package.json"));
14086
+ await access3(join20(currentPath, "package.json"));
13692
14087
  const relativePath = relative5(rootPath, currentPath);
13693
14088
  let installCommand = "";
13694
14089
  try {
13695
- await access3(join19(currentPath, "yarn.lock"));
14090
+ await access3(join20(currentPath, "yarn.lock"));
13696
14091
  installCommand = "yarn install";
13697
14092
  } catch {
13698
14093
  try {
13699
- await access3(join19(currentPath, "bun.lock"));
14094
+ await access3(join20(currentPath, "bun.lock"));
13700
14095
  installCommand = "bun install";
13701
14096
  } catch {
13702
14097
  try {
13703
- await access3(join19(currentPath, "pnpm-lock.yaml"));
14098
+ await access3(join20(currentPath, "pnpm-lock.yaml"));
13704
14099
  installCommand = "pnpm install";
13705
14100
  } catch {
13706
14101
  installCommand = "npm install";
@@ -13717,7 +14112,7 @@ var ProjectCreator = class {
13717
14112
  try {
13718
14113
  const entries = await readdir8(currentPath);
13719
14114
  for (const entry of entries) {
13720
- const entryPath = join19(currentPath, entry);
14115
+ const entryPath = join20(currentPath, entry);
13721
14116
  try {
13722
14117
  const stats = await stat3(entryPath);
13723
14118
  if (stats.isDirectory() && !entry.startsWith(".") && entry !== "node_modules") {
@@ -14057,7 +14452,7 @@ var ProjectManagerImpl = class {
14057
14452
  const session = this.terminalSessionManager.getOrCreateSession(threadId, thread.path);
14058
14453
  let workingDir;
14059
14454
  if (cwd) {
14060
- workingDir = cwd.startsWith("/") ? cwd : join20(thread.path, cwd);
14455
+ workingDir = cwd.startsWith("/") ? cwd : join21(thread.path, cwd);
14061
14456
  this.terminalSessionManager.updateWorkingDirectory(threadId, workingDir);
14062
14457
  } else {
14063
14458
  workingDir = session.currentWorkingDirectory;
@@ -14811,9 +15206,9 @@ function createScaffoldRoutes(projectManager) {
14811
15206
 
14812
15207
  // src/features/slash-commands/slash-commands.manager.ts
14813
15208
  import { readdir as readdir9, readFile as readFile12, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
14814
- import { join as join21, basename as basename3, extname as extname4, relative as relative6 } from "path";
14815
- import { existsSync as existsSync13 } from "fs";
14816
- import { homedir as homedir7 } from "os";
15209
+ import { join as join22, basename as basename3, extname as extname4, relative as relative6 } from "path";
15210
+ import { existsSync as existsSync14 } from "fs";
15211
+ import { homedir as homedir8 } from "os";
14817
15212
  function slugify(filename) {
14818
15213
  return filename.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
14819
15214
  }
@@ -14857,10 +15252,10 @@ function parseFrontmatter3(markdown) {
14857
15252
  return { metadata, content };
14858
15253
  }
14859
15254
  function getGlobalCommandsDir() {
14860
- return join21(homedir7(), ".agents", "commands");
15255
+ return join22(homedir8(), ".agents", "commands");
14861
15256
  }
14862
15257
  function getProjectCommandsDir(threadPath) {
14863
- return join21(threadPath, ".agents", "commands");
15258
+ return join22(threadPath, ".agents", "commands");
14864
15259
  }
14865
15260
  var SlashCommandManager = class _SlashCommandManager {
14866
15261
  /**
@@ -14891,14 +15286,14 @@ var SlashCommandManager = class _SlashCommandManager {
14891
15286
  async loadCommands(threadPath) {
14892
15287
  const commands = /* @__PURE__ */ new Map();
14893
15288
  const globalDir = getGlobalCommandsDir();
14894
- if (existsSync13(globalDir)) {
15289
+ if (existsSync14(globalDir)) {
14895
15290
  const globalCommands = await this.loadCommandsFromDir(globalDir, threadPath, "global");
14896
15291
  for (const cmd of globalCommands) {
14897
15292
  commands.set(cmd.name, cmd);
14898
15293
  }
14899
15294
  }
14900
15295
  const projectDir = getProjectCommandsDir(threadPath);
14901
- if (existsSync13(projectDir)) {
15296
+ if (existsSync14(projectDir)) {
14902
15297
  const projectCommands = await this.loadCommandsFromDir(projectDir, threadPath, "project");
14903
15298
  for (const cmd of projectCommands) {
14904
15299
  if (!_SlashCommandManager.BUILT_IN_COMMANDS.has(cmd.name)) {
@@ -14922,7 +15317,7 @@ var SlashCommandManager = class _SlashCommandManager {
14922
15317
  const files = await readdir9(dir);
14923
15318
  for (const file of files) {
14924
15319
  if (!file.endsWith(".md")) continue;
14925
- const filePath = join21(dir, file);
15320
+ const filePath = join22(dir, file);
14926
15321
  const fileContent = await readFile12(filePath, "utf-8");
14927
15322
  const { metadata, content } = parseFrontmatter3(fileContent);
14928
15323
  const nameWithoutExt = basename3(file, extname4(file));
@@ -14953,12 +15348,12 @@ var SlashCommandManager = class _SlashCommandManager {
14953
15348
  if (!dir) {
14954
15349
  throw new Error("threadPath required for project-scoped commands");
14955
15350
  }
14956
- if (!existsSync13(dir)) {
15351
+ if (!existsSync14(dir)) {
14957
15352
  await mkdir3(dir, { recursive: true });
14958
15353
  }
14959
15354
  const filename = `${name}.md`;
14960
- const filePath = join21(dir, filename);
14961
- if (existsSync13(filePath)) {
15355
+ const filePath = join22(dir, filename);
15356
+ if (existsSync14(filePath)) {
14962
15357
  throw new Error(`Command already exists: ${name}`);
14963
15358
  }
14964
15359
  let markdown = "";
@@ -14992,7 +15387,7 @@ var SlashCommandManager = class _SlashCommandManager {
14992
15387
  * Update an existing command
14993
15388
  */
14994
15389
  async updateCommand(filePath, content, metadata) {
14995
- if (!existsSync13(filePath)) {
15390
+ if (!existsSync14(filePath)) {
14996
15391
  throw new Error(`Command file not found: ${filePath}`);
14997
15392
  }
14998
15393
  let markdown = "";
@@ -15019,7 +15414,7 @@ var SlashCommandManager = class _SlashCommandManager {
15019
15414
  * Delete a command
15020
15415
  */
15021
15416
  async deleteCommand(filePath) {
15022
- if (!existsSync13(filePath)) {
15417
+ if (!existsSync14(filePath)) {
15023
15418
  throw new Error(`Command file not found: ${filePath}`);
15024
15419
  }
15025
15420
  await unlink2(filePath);
@@ -15552,7 +15947,7 @@ function createRuleRoutes(router, projectManager) {
15552
15947
  // src/features/threads/threads.manager.ts
15553
15948
  init_utils();
15554
15949
  import { randomUUID as randomUUID8 } from "crypto";
15555
- import { join as join22 } from "path";
15950
+ import { join as join23 } from "path";
15556
15951
  import { execSync as execSync3 } from "child_process";
15557
15952
  import { rm as rm4, stat as stat4, mkdir as mkdir4 } from "fs/promises";
15558
15953
  init_database();
@@ -15959,7 +16354,7 @@ var ThreadManagerImpl = class {
15959
16354
  * - 7.4 - THE CLI SHALL ensure each Thread clone is stored in a unique directory path
15960
16355
  */
15961
16356
  generateThreadPath(_projectId, threadId) {
15962
- return join22(this.rootFolder, threadId);
16357
+ return join23(this.rootFolder, threadId);
15963
16358
  }
15964
16359
  /**
15965
16360
  * Generates a thread title if not provided
@@ -16153,8 +16548,8 @@ async function handleDeleteThread(c, threadManager) {
16153
16548
 
16154
16549
  // src/core/project-inspector.ts
16155
16550
  import { readFile as readFile13, readdir as readdir10 } from "fs/promises";
16156
- import { existsSync as existsSync14 } from "fs";
16157
- import { join as join23, basename as basename4, relative as relative7 } from "path";
16551
+ import { existsSync as existsSync15 } from "fs";
16552
+ import { join as join24, basename as basename4, relative as relative7 } from "path";
16158
16553
  import { glob as glob2 } from "glob";
16159
16554
 
16160
16555
  // src/features/project-scripts/project-scripts.database.ts
@@ -16198,13 +16593,13 @@ async function inspectProject(projectPath, projectId) {
16198
16593
  return scripts;
16199
16594
  }
16200
16595
  async function detectPackageManager2(projectPath) {
16201
- if (existsSync14(join23(projectPath, "bun.lockb")) || existsSync14(join23(projectPath, "bun.lock"))) {
16596
+ if (existsSync15(join24(projectPath, "bun.lockb")) || existsSync15(join24(projectPath, "bun.lock"))) {
16202
16597
  return "bun";
16203
16598
  }
16204
- if (existsSync14(join23(projectPath, "pnpm-lock.yaml"))) {
16599
+ if (existsSync15(join24(projectPath, "pnpm-lock.yaml"))) {
16205
16600
  return "pnpm";
16206
16601
  }
16207
- if (existsSync14(join23(projectPath, "yarn.lock"))) {
16602
+ if (existsSync15(join24(projectPath, "yarn.lock"))) {
16208
16603
  return "yarn";
16209
16604
  }
16210
16605
  try {
@@ -16223,8 +16618,8 @@ async function detectPackageManager2(projectPath) {
16223
16618
  return "npm";
16224
16619
  }
16225
16620
  async function detectMonoRepoType(projectPath) {
16226
- const hasPnpmWorkspace = existsSync14(join23(projectPath, "pnpm-workspace.yaml"));
16227
- if (existsSync14(join23(projectPath, "nx.json"))) {
16621
+ const hasPnpmWorkspace = existsSync15(join24(projectPath, "pnpm-workspace.yaml"));
16622
+ if (existsSync15(join24(projectPath, "nx.json"))) {
16228
16623
  return "nx";
16229
16624
  }
16230
16625
  const pkg = await readPackageJson(projectPath);
@@ -16238,10 +16633,10 @@ async function detectMonoRepoType(projectPath) {
16238
16633
  if (hasPnpmWorkspace) {
16239
16634
  return "pnpm";
16240
16635
  }
16241
- if (existsSync14(join23(projectPath, "lerna.json"))) {
16636
+ if (existsSync15(join24(projectPath, "lerna.json"))) {
16242
16637
  return "lerna";
16243
16638
  }
16244
- if (existsSync14(join23(projectPath, "turbo.json"))) {
16639
+ if (existsSync15(join24(projectPath, "turbo.json"))) {
16245
16640
  return "turbo";
16246
16641
  }
16247
16642
  const folderWorkspaces = await detectFolderBasedWorkspaces(projectPath);
@@ -16282,8 +16677,8 @@ async function resolvePackageJsonWorkspaces(projectPath) {
16282
16677
  });
16283
16678
  const workspaces = [];
16284
16679
  for (const folder of folders) {
16285
- const absPath = join23(projectPath, folder);
16286
- if (existsSync14(join23(absPath, "package.json"))) {
16680
+ const absPath = join24(projectPath, folder);
16681
+ if (existsSync15(join24(absPath, "package.json"))) {
16287
16682
  workspaces.push({
16288
16683
  name: basename4(folder),
16289
16684
  folder: absPath,
@@ -16298,8 +16693,8 @@ async function resolvePackageJsonWorkspaces(projectPath) {
16298
16693
  return workspaces;
16299
16694
  }
16300
16695
  async function resolvePnpmWorkspaces(projectPath) {
16301
- const yamlPath = join23(projectPath, "pnpm-workspace.yaml");
16302
- if (!existsSync14(yamlPath)) {
16696
+ const yamlPath = join24(projectPath, "pnpm-workspace.yaml");
16697
+ if (!existsSync15(yamlPath)) {
16303
16698
  return [{ name: "root", folder: projectPath, relativePath: "." }];
16304
16699
  }
16305
16700
  try {
@@ -16324,8 +16719,8 @@ async function resolvePnpmWorkspaces(projectPath) {
16324
16719
  });
16325
16720
  const workspaces = [];
16326
16721
  for (const folder of folders) {
16327
- const absPath = join23(projectPath, folder);
16328
- if (existsSync14(join23(absPath, "package.json"))) {
16722
+ const absPath = join24(projectPath, folder);
16723
+ if (existsSync15(join24(absPath, "package.json"))) {
16329
16724
  const wsPkg = await readPackageJson(absPath);
16330
16725
  workspaces.push({
16331
16726
  name: wsPkg?.name ?? basename4(folder),
@@ -16344,8 +16739,8 @@ async function resolvePnpmWorkspaces(projectPath) {
16344
16739
  }
16345
16740
  }
16346
16741
  async function resolveLernaWorkspaces(projectPath) {
16347
- const lernaPath = join23(projectPath, "lerna.json");
16348
- if (!existsSync14(lernaPath)) {
16742
+ const lernaPath = join24(projectPath, "lerna.json");
16743
+ if (!existsSync15(lernaPath)) {
16349
16744
  return [{ name: "root", folder: projectPath, relativePath: "." }];
16350
16745
  }
16351
16746
  try {
@@ -16358,8 +16753,8 @@ async function resolveLernaWorkspaces(projectPath) {
16358
16753
  });
16359
16754
  const workspaces = [];
16360
16755
  for (const folder of folders) {
16361
- const absPath = join23(projectPath, folder);
16362
- if (existsSync14(join23(absPath, "package.json"))) {
16756
+ const absPath = join24(projectPath, folder);
16757
+ if (existsSync15(join24(absPath, "package.json"))) {
16363
16758
  const wsPkg = await readPackageJson(absPath);
16364
16759
  workspaces.push({
16365
16760
  name: wsPkg?.name ?? basename4(folder),
@@ -16379,8 +16774,8 @@ async function resolveLernaWorkspaces(projectPath) {
16379
16774
  }
16380
16775
  async function resolveNxWorkspaces(projectPath) {
16381
16776
  const workspaces = [];
16382
- const workspaceJsonPath = join23(projectPath, "workspace.json");
16383
- if (existsSync14(workspaceJsonPath)) {
16777
+ const workspaceJsonPath = join24(projectPath, "workspace.json");
16778
+ if (existsSync15(workspaceJsonPath)) {
16384
16779
  try {
16385
16780
  const content = await readFile13(workspaceJsonPath, "utf-8");
16386
16781
  const wsJson = JSON.parse(content);
@@ -16389,7 +16784,7 @@ async function resolveNxWorkspaces(projectPath) {
16389
16784
  if (folder) {
16390
16785
  workspaces.push({
16391
16786
  name,
16392
- folder: join23(projectPath, folder),
16787
+ folder: join24(projectPath, folder),
16393
16788
  relativePath: folder
16394
16789
  });
16395
16790
  }
@@ -16404,13 +16799,13 @@ async function resolveNxWorkspaces(projectPath) {
16404
16799
  });
16405
16800
  for (const file of projectJsonFiles) {
16406
16801
  try {
16407
- const content = await readFile13(join23(projectPath, file), "utf-8");
16802
+ const content = await readFile13(join24(projectPath, file), "utf-8");
16408
16803
  const project = JSON.parse(content);
16409
16804
  if (project.name) {
16410
16805
  const folder = file.replace(/\/project\.json$/, "");
16411
16806
  workspaces.push({
16412
16807
  name: project.name,
16413
- folder: join23(projectPath, folder),
16808
+ folder: join24(projectPath, folder),
16414
16809
  relativePath: folder
16415
16810
  });
16416
16811
  }
@@ -16418,15 +16813,15 @@ async function resolveNxWorkspaces(projectPath) {
16418
16813
  }
16419
16814
  }
16420
16815
  if (workspaces.length > 0) return workspaces;
16421
- const appsDir = join23(projectPath, "apps");
16422
- if (existsSync14(appsDir)) {
16816
+ const appsDir = join24(projectPath, "apps");
16817
+ if (existsSync15(appsDir)) {
16423
16818
  const entries = await readdir10(appsDir, { withFileTypes: true });
16424
16819
  for (const entry of entries) {
16425
16820
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
16426
- const folder = join23("apps", entry.name);
16821
+ const folder = join24("apps", entry.name);
16427
16822
  workspaces.push({
16428
16823
  name: entry.name,
16429
- folder: join23(projectPath, folder),
16824
+ folder: join24(projectPath, folder),
16430
16825
  relativePath: folder
16431
16826
  });
16432
16827
  }
@@ -16460,13 +16855,13 @@ async function detectFolderBasedWorkspaces(projectPath) {
16460
16855
  const results = [];
16461
16856
  for (const entry of entries) {
16462
16857
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "build") {
16463
- const pkgPath = join23(projectPath, entry.name, "package.json");
16464
- if (existsSync14(pkgPath)) {
16858
+ const pkgPath = join24(projectPath, entry.name, "package.json");
16859
+ if (existsSync15(pkgPath)) {
16465
16860
  try {
16466
16861
  const content = await readFile13(pkgPath, "utf-8");
16467
16862
  const pkg = JSON.parse(content);
16468
16863
  if (pkg.dependencies || pkg.devDependencies || pkg.scripts) {
16469
- results.push({ name: entry.name, absPath: join23(projectPath, entry.name) });
16864
+ results.push({ name: entry.name, absPath: join24(projectPath, entry.name) });
16470
16865
  }
16471
16866
  } catch {
16472
16867
  }
@@ -16522,7 +16917,7 @@ function pmRunCommand(packageManager, scriptName) {
16522
16917
  }
16523
16918
  async function readPackageJson(dir) {
16524
16919
  try {
16525
- const content = await readFile13(join23(dir, "package.json"), "utf-8");
16920
+ const content = await readFile13(join24(dir, "package.json"), "utf-8");
16526
16921
  return JSON.parse(content);
16527
16922
  } catch {
16528
16923
  return null;
@@ -16744,7 +17139,7 @@ async function handleListThreadFiles(c, threadManager) {
16744
17139
 
16745
17140
  // src/features/threads/threads-explorer.route.ts
16746
17141
  import { readdir as readdir11, readFile as readFile14, rename as rename2, writeFile as writeFile5, mkdir as mkdir5, rm as rm5, access as access4 } from "fs/promises";
16747
- import { join as join24 } from "path";
17142
+ import { join as join25 } from "path";
16748
17143
  import { spawn as spawn2 } from "child_process";
16749
17144
  var Utils3 = null;
16750
17145
  var utilsLoaded3 = false;
@@ -16807,7 +17202,7 @@ async function handleListThreadExplorerDir(c, threadManager) {
16807
17202
  const entries = dirents.filter((d) => !(isRoot && d.name === ".git")).map((d) => ({
16808
17203
  name: d.name,
16809
17204
  type: d.isDirectory() ? "folder" : "file",
16810
- path: queryPath ? join24(queryPath, d.name) : d.name
17205
+ path: queryPath ? join25(queryPath, d.name) : d.name
16811
17206
  })).sort((a, b) => {
16812
17207
  if (a.type !== b.type) return a.type === "folder" ? -1 : 1;
16813
17208
  return a.name.localeCompare(b.name);
@@ -16953,7 +17348,7 @@ async function handleCreateExplorerFile(c, threadManager) {
16953
17348
  absParent = validated;
16954
17349
  }
16955
17350
  await mkdir5(absParent, { recursive: true });
16956
- await writeFile5(join24(absParent, name), "", "utf-8");
17351
+ await writeFile5(join25(absParent, name), "", "utf-8");
16957
17352
  const relPath = dirPath ? `${dirPath}/${name}` : name;
16958
17353
  return c.json({ success: true, path: relPath });
16959
17354
  } catch (error) {
@@ -17055,7 +17450,7 @@ async function handleCreateExplorerFolder(c, threadManager) {
17055
17450
  }
17056
17451
  absParent = validated;
17057
17452
  }
17058
- await mkdir5(join24(absParent, name), { recursive: true });
17453
+ await mkdir5(join25(absParent, name), { recursive: true });
17059
17454
  const relPath = dirPath ? `${dirPath}/${name}` : name;
17060
17455
  return c.json({ success: true, path: relPath });
17061
17456
  } catch (error) {
@@ -17127,7 +17522,7 @@ async function handleOpenThread(c, threadManager) {
17127
17522
  c,
17128
17523
  ErrorCodes.OPEN_PROGRAM_ERROR,
17129
17524
  `Unsupported program: ${program}`,
17130
- 500
17525
+ 422
17131
17526
  );
17132
17527
  }
17133
17528
  console.log(
@@ -17147,8 +17542,8 @@ async function handleOpenThread(c, threadManager) {
17147
17542
  return errorResponse(
17148
17543
  c,
17149
17544
  ErrorCodes.OPEN_PROGRAM_ERROR,
17150
- `Failed to open ${program}: ${message}`,
17151
- 500
17545
+ formatOpenError(program, openError),
17546
+ 422
17152
17547
  );
17153
17548
  }
17154
17549
  return successResponse(c, { success: true, message: `Thread opened in ${program}` });
@@ -17158,7 +17553,7 @@ async function handleOpenThread(c, threadManager) {
17158
17553
  c,
17159
17554
  ErrorCodes.OPEN_PROGRAM_ERROR,
17160
17555
  "Failed to open thread",
17161
- 500,
17556
+ 422,
17162
17557
  errorMessage
17163
17558
  );
17164
17559
  }
@@ -17229,12 +17624,12 @@ async function handleFixComments(c, threadManager) {
17229
17624
 
17230
17625
  // src/features/threads/threads-ai-files.route.ts
17231
17626
  import { readFile as readFile15, writeFile as writeFile7, mkdir as mkdir7, access as access5, rm as rm6 } from "fs/promises";
17232
- import { join as join26 } from "path";
17233
- import { existsSync as existsSync15 } from "fs";
17627
+ import { join as join27 } from "path";
17628
+ import { existsSync as existsSync16 } from "fs";
17234
17629
 
17235
17630
  // src/features/git/git-download-folder.ts
17236
17631
  import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
17237
- import { join as join25, dirname as dirname4 } from "path";
17632
+ import { join as join26, dirname as dirname4 } from "path";
17238
17633
  async function downloadGithubFolder(repoUrl, srcPath, destPath, options = {}) {
17239
17634
  const { token, ref } = options;
17240
17635
  const match = repoUrl.replace(/\.git$/, "").match(/github\.com\/([^/]+)\/([^/]+)/);
@@ -17270,7 +17665,7 @@ async function downloadGithubFolder(repoUrl, srcPath, destPath, options = {}) {
17270
17665
  await Promise.all(
17271
17666
  files.map(async (file) => {
17272
17667
  const relativePath = file.path.slice(prefix.length);
17273
- const localPath = join25(destPath, relativePath);
17668
+ const localPath = join26(destPath, relativePath);
17274
17669
  await mkdir6(dirname4(localPath), { recursive: true });
17275
17670
  const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${refParam}/${file.path}`;
17276
17671
  const fileRes = await fetch(rawUrl, { headers });
@@ -17412,7 +17807,7 @@ async function handleSaveThreadAIFile(c, threadManager) {
17412
17807
  if (!absPath) {
17413
17808
  return c.json({ error: { code: "BAD_REQUEST", message: "Invalid file path" } }, 400);
17414
17809
  }
17415
- const parentDir = join26(absPath, "..");
17810
+ const parentDir = join27(absPath, "..");
17416
17811
  await mkdir7(parentDir, { recursive: true });
17417
17812
  await writeFile7(absPath, content, "utf-8");
17418
17813
  return c.json({ success: true, path: filePath });
@@ -17501,11 +17896,11 @@ async function handleCreateThreadAgent(c, threadManager) {
17501
17896
  if (!thread) {
17502
17897
  return errorResponse(c, ErrorCodes.THREAD_NOT_FOUND, `Thread not found: ${threadId}`, 404);
17503
17898
  }
17504
- const agentRelPath = join26(".agents", "agents", name);
17505
- const agentAbsPath = join26(thread.path, agentRelPath);
17506
- const agentFileRelPath = join26(agentRelPath, "AGENT.md");
17507
- const agentFileAbsPath = join26(agentAbsPath, "AGENT.md");
17508
- if (existsSync15(agentAbsPath)) {
17899
+ const agentRelPath = join27(".agents", "agents", name);
17900
+ const agentAbsPath = join27(thread.path, agentRelPath);
17901
+ const agentFileRelPath = join27(agentRelPath, "AGENT.md");
17902
+ const agentFileAbsPath = join27(agentAbsPath, "AGENT.md");
17903
+ if (existsSync16(agentAbsPath)) {
17509
17904
  return c.json(
17510
17905
  { error: { code: "CONFLICT", message: `Agent '${name}' already exists` } },
17511
17906
  409
@@ -17571,11 +17966,11 @@ async function handleCreateThreadSkill(c, threadManager) {
17571
17966
  if (!thread) {
17572
17967
  return errorResponse(c, ErrorCodes.THREAD_NOT_FOUND, `Thread not found: ${threadId}`, 404);
17573
17968
  }
17574
- const skillRelPath = join26(".agents", "skills", name);
17575
- const skillAbsPath = join26(thread.path, skillRelPath);
17576
- const skillFileRelPath = join26(skillRelPath, "SKILL.md");
17577
- const skillFileAbsPath = join26(skillAbsPath, "SKILL.md");
17578
- if (existsSync15(skillAbsPath)) {
17969
+ const skillRelPath = join27(".agents", "skills", name);
17970
+ const skillAbsPath = join27(thread.path, skillRelPath);
17971
+ const skillFileRelPath = join27(skillRelPath, "SKILL.md");
17972
+ const skillFileAbsPath = join27(skillAbsPath, "SKILL.md");
17973
+ if (existsSync16(skillAbsPath)) {
17579
17974
  return c.json(
17580
17975
  { error: { code: "CONFLICT", message: `Skill '${name}' already exists` } },
17581
17976
  409
@@ -18253,12 +18648,12 @@ async function gitUserHandler(c) {
18253
18648
  }
18254
18649
 
18255
18650
  // src/features/git/git-status.route.ts
18256
- import { existsSync as existsSync17 } from "fs";
18651
+ import { existsSync as existsSync18 } from "fs";
18257
18652
 
18258
18653
  // src/features/git/git.utils.ts
18259
18654
  init_utils();
18260
- import { existsSync as existsSync16, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
18261
- import { isAbsolute as isAbsolute3, normalize as normalize2, resolve as resolve3, join as join27 } from "path";
18655
+ import { existsSync as existsSync17, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
18656
+ import { isAbsolute as isAbsolute3, normalize as normalize2, resolve as resolve3, join as join28 } from "path";
18262
18657
  import { completeSimple } from "@mariozechner/pi-ai";
18263
18658
  async function resolveModelAndKey(provider, modelId, metadataManager) {
18264
18659
  const providerConfig = await resolveProviderConfig(provider);
@@ -18515,8 +18910,8 @@ async function getUntrackedFilesDiff(gitRoot) {
18515
18910
  const parts = [];
18516
18911
  const maxFileSize = 1e5;
18517
18912
  for (const relPath of untrackedPaths) {
18518
- const fullPath = join27(gitRoot, relPath);
18519
- if (!existsSync16(fullPath)) continue;
18913
+ const fullPath = join28(gitRoot, relPath);
18914
+ if (!existsSync17(fullPath)) continue;
18520
18915
  try {
18521
18916
  if (statSync4(fullPath).isDirectory()) continue;
18522
18917
  const content = readFileSync5(fullPath, "utf-8");
@@ -19055,7 +19450,7 @@ async function gitStatusHandler(c, metadataManager) {
19055
19450
  return c.json({ error: "Thread path not found" }, 404);
19056
19451
  }
19057
19452
  const absolutePath = resolveThreadPath(repoPath);
19058
- if (!existsSync17(absolutePath)) {
19453
+ if (!existsSync18(absolutePath)) {
19059
19454
  return c.json(
19060
19455
  {
19061
19456
  error: `Thread repo path does not exist: ${absolutePath}. Check that the project folder is present.`
@@ -19259,22 +19654,21 @@ async function gitDiffHandler(c, metadataManager) {
19259
19654
  }
19260
19655
 
19261
19656
  // src/features/git/git-generate-commit-message.route.ts
19262
- import { existsSync as existsSync18 } from "fs";
19657
+ init_tarsk_debug();
19658
+ import { existsSync as existsSync19 } from "fs";
19263
19659
  async function gitGenerateCommitMessageHandler(c, metadataManager) {
19264
19660
  try {
19265
19661
  const threadId = c.req.param("threadId");
19266
- process.stdout.write(`[generate-commit-message] threadId=${threadId}
19662
+ tarskDebugWrite(`[generate-commit-message] threadId=${threadId}
19267
19663
  `);
19268
19664
  const thread = await metadataManager.loadThreads().then((threads) => threads.find((t) => t.id === threadId));
19269
19665
  if (!thread) {
19270
- process.stdout.write("[generate-commit-message] thread not found\n");
19666
+ tarskDebugWrite("[generate-commit-message] thread not found\n");
19271
19667
  return c.json({ error: "Thread not found" }, 404);
19272
- } else {
19273
- console.log(thread);
19274
19668
  }
19275
19669
  const repoPath = thread.path;
19276
19670
  if (!repoPath) {
19277
- process.stdout.write("[generate-commit-message] thread path missing\n");
19671
+ tarskDebugWrite("[generate-commit-message] thread path missing\n");
19278
19672
  return c.json({ error: "Thread path not found" }, 404);
19279
19673
  }
19280
19674
  const body = await c.req.json().catch(() => ({}));
@@ -19284,10 +19678,10 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19284
19678
  }
19285
19679
  const model = body.model ?? thread.model;
19286
19680
  const absolutePath = resolveThreadPath(repoPath);
19287
- process.stdout.write(`[generate-commit-message] resolved path: ${absolutePath}
19681
+ tarskDebugWrite(`[generate-commit-message] resolved path: ${absolutePath}
19288
19682
  `);
19289
- if (!existsSync18(absolutePath)) {
19290
- process.stdout.write(`[generate-commit-message] path does not exist: ${absolutePath}
19683
+ if (!existsSync19(absolutePath)) {
19684
+ tarskDebugWrite(`[generate-commit-message] path does not exist: ${absolutePath}
19291
19685
  `);
19292
19686
  return c.json(
19293
19687
  {
@@ -19299,11 +19693,11 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19299
19693
  let gitRoot;
19300
19694
  try {
19301
19695
  gitRoot = await getGitRoot(absolutePath);
19302
- process.stdout.write(`[generate-commit-message] git root: ${gitRoot}
19696
+ tarskDebugWrite(`[generate-commit-message] git root: ${gitRoot}
19303
19697
  `);
19304
19698
  } catch (e) {
19305
19699
  const msg = e instanceof Error ? e.message : String(e);
19306
- process.stdout.write(`[generate-commit-message] not a git repo: ${msg}
19700
+ tarskDebugWrite(`[generate-commit-message] not a git repo: ${msg}
19307
19701
  `);
19308
19702
  return c.json(
19309
19703
  {
@@ -19316,24 +19710,22 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19316
19710
  if (!diff.trim()) {
19317
19711
  const untrackedDiff = await getUntrackedFilesDiff(gitRoot);
19318
19712
  if (untrackedDiff) {
19319
- process.stdout.write(`[generate-commit-message] building diff for untracked files
19713
+ tarskDebugWrite(`[generate-commit-message] building diff for untracked files
19320
19714
  `);
19321
19715
  diff = untrackedDiff;
19322
19716
  }
19323
19717
  }
19324
19718
  if (!diff.trim()) {
19325
- process.stdout.write("[generate-commit-message] no changes to generate message for\n");
19719
+ tarskDebugWrite("[generate-commit-message] no changes to generate message for\n");
19326
19720
  return c.json({ error: "No changes to generate commit message for" }, 400);
19327
19721
  }
19328
- process.stdout.write(
19722
+ tarskDebugWrite(
19329
19723
  `[generate-commit-message] diff length=${diff.length} chars, generating message with AI
19330
19724
  `
19331
19725
  );
19332
19726
  const commitMessage = await generateCommitMessageWithAI(diff, metadataManager, model, provider);
19333
- process.stdout.write(
19334
- `[generate-commit-message] generated: ${commitMessage.replace(/\n/g, " ")}
19335
- `
19336
- );
19727
+ tarskDebugWrite(`[generate-commit-message] generated: ${commitMessage.replace(/\n/g, " ")}
19728
+ `);
19337
19729
  return c.json({ message: commitMessage });
19338
19730
  } catch (error) {
19339
19731
  const message = error instanceof Error ? error.message : "Failed to generate commit message";
@@ -19767,7 +20159,7 @@ async function gitGithubStatusHandler(c, metadataManager) {
19767
20159
  }
19768
20160
 
19769
20161
  // src/features/git/git-unified-status.route.ts
19770
- import { existsSync as existsSync19 } from "fs";
20162
+ import { existsSync as existsSync20 } from "fs";
19771
20163
  async function gitUnifiedStatusHandler(c, metadataManager, db) {
19772
20164
  try {
19773
20165
  const threadId = c.req.param("threadId");
@@ -19795,7 +20187,7 @@ async function gitUnifiedStatusHandler(c, metadataManager, db) {
19795
20187
  return c.json({ error: "Thread path not found" }, 404);
19796
20188
  }
19797
20189
  const absolutePath = resolveThreadPath(repoPath);
19798
- if (!existsSync19(absolutePath)) {
20190
+ if (!existsSync20(absolutePath)) {
19799
20191
  return c.json(
19800
20192
  {
19801
20193
  error: `Thread repo path does not exist: ${absolutePath}. Check that the project folder is present.`
@@ -20141,7 +20533,7 @@ async function gitCreateBranchHandler(c, metadataManager) {
20141
20533
  }
20142
20534
 
20143
20535
  // src/features/git/git-sync-branch.route.ts
20144
- import { existsSync as existsSync20 } from "fs";
20536
+ import { existsSync as existsSync21 } from "fs";
20145
20537
  async function gitSyncBranchHandler(c, metadataManager) {
20146
20538
  try {
20147
20539
  const threadId = c.req.param("threadId");
@@ -20158,7 +20550,7 @@ async function gitSyncBranchHandler(c, metadataManager) {
20158
20550
  }
20159
20551
  const absolutePath = resolveThreadPath(repoPath);
20160
20552
  console.log(`[sync-branch] Resolved path: ${absolutePath}`);
20161
- if (!existsSync20(absolutePath)) {
20553
+ if (!existsSync21(absolutePath)) {
20162
20554
  console.log(`[sync-branch] Path does not exist: ${absolutePath}`);
20163
20555
  return c.json(
20164
20556
  {
@@ -20762,9 +21154,12 @@ function createGitRoutes(metadataManager) {
20762
21154
  return gitGenerateCommitMessageHandler(c, metadataManager);
20763
21155
  });
20764
21156
  router.post("/commit/:threadId", async (c) => {
20765
- const db = await getDatabase();
20766
- await invalidateGitStatusCache(db, c.req.param("threadId"));
20767
- return gitCommitHandler(c, metadataManager);
21157
+ const response = await gitCommitHandler(c, metadataManager);
21158
+ if (response.status < 400) {
21159
+ const db = await getDatabase();
21160
+ await invalidateGitStatusCache(db, c.req.param("threadId"));
21161
+ }
21162
+ return response;
20768
21163
  });
20769
21164
  router.post("/push/:threadId", async (c) => {
20770
21165
  const db = await getDatabase();
@@ -20875,7 +21270,7 @@ function createUpdateRoutes(updater) {
20875
21270
  // src/features/mcp/mcp.routes.ts
20876
21271
  import { Hono as Hono13 } from "hono";
20877
21272
  import { readFile as readFile16, writeFile as writeFile8, mkdir as mkdir9, access as access6 } from "fs/promises";
20878
- import { join as join28, dirname as dirname6 } from "path";
21273
+ import { join as join29, dirname as dirname6 } from "path";
20879
21274
 
20880
21275
  // src/features/mcp/mcp.popular.json
20881
21276
  var mcp_popular_default = [
@@ -20986,7 +21381,7 @@ var mcp_popular_default = [
20986
21381
  var MCP_CONFIG_PATHS2 = [".agents/mcp.json", "mcp.json"];
20987
21382
  async function readMCPConfig(projectPath) {
20988
21383
  for (const configPath of MCP_CONFIG_PATHS2) {
20989
- const fullPath = join28(projectPath, configPath);
21384
+ const fullPath = join29(projectPath, configPath);
20990
21385
  try {
20991
21386
  await access6(fullPath);
20992
21387
  const content = await readFile16(fullPath, "utf-8");
@@ -21000,7 +21395,7 @@ async function readMCPConfig(projectPath) {
21000
21395
  }
21001
21396
  async function writeMCPConfig(projectPath, config) {
21002
21397
  const existing = await readMCPConfig(projectPath);
21003
- const targetPath = existing?.filePath ?? join28(projectPath, ".agents/mcp.json");
21398
+ const targetPath = existing?.filePath ?? join29(projectPath, ".agents/mcp.json");
21004
21399
  await mkdir9(dirname6(targetPath), { recursive: true });
21005
21400
  await writeFile8(targetPath, JSON.stringify(config, null, 2), "utf-8");
21006
21401
  }
@@ -21674,7 +22069,7 @@ async function clipboardWriteImage(c) {
21674
22069
  }
21675
22070
 
21676
22071
  // src/features/image/image-save.route.ts
21677
- import { join as join29 } from "path";
22072
+ import { join as join30 } from "path";
21678
22073
  var Utils5 = null;
21679
22074
  var utilsLoaded5 = false;
21680
22075
  async function loadUtils5() {
@@ -21711,7 +22106,7 @@ async function saveImage(c) {
21711
22106
  return c.json({ error: "imageUrl or imageData is required" }, 400);
21712
22107
  }
21713
22108
  const name = filename ?? `generated-image-${Date.now()}.png`;
21714
- const savePath = join29(Utils5.paths.downloads, name);
22109
+ const savePath = join30(Utils5.paths.downloads, name);
21715
22110
  await Bun.write(savePath, data);
21716
22111
  return c.json({ success: true, path: savePath });
21717
22112
  } catch (error) {
@@ -21853,7 +22248,10 @@ function createLogsRoutes() {
21853
22248
  return c.json({ ok: false, error: "invalid json" }, 400);
21854
22249
  }
21855
22250
  const { level = "INFO", context = "app", message = "", data } = body;
21856
- let line = `[VOICE] [${level}] [${context}] ${message}`;
22251
+ const levelText = String(level);
22252
+ const contextText = String(context);
22253
+ const messageText = String(message);
22254
+ let line = `[VOICE] [${levelText}] [${contextText}] ${messageText}`;
21857
22255
  if (data !== void 0 && data !== "") {
21858
22256
  try {
21859
22257
  line += ` | ${JSON.stringify(data)}`;
@@ -21947,7 +22345,10 @@ async function startTarskServer(options) {
21947
22345
  "/api/chat",
21948
22346
  createChatRoutes(threadManager, agentExecutor, conversationManager, processingStateManager)
21949
22347
  );
21950
- app.route("/api/conversations", createConversationRoutes(conversationManager, threadManager));
22348
+ app.route(
22349
+ "/api/conversations",
22350
+ createConversationRoutes(conversationManager, threadManager, metadataManager)
22351
+ );
21951
22352
  app.route("/api/providers", createProviderRoutes(metadataManager));
21952
22353
  app.route("/api/models", createModelRoutes(metadataManager));
21953
22354
  app.route("/api/mcp", createMCPRoutes());