tarsk 0.4.29 → 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 (74) hide show
  1. package/dist/index.js +745 -348
  2. package/dist/public/assets/{account-view-YvC0mymF.js → account-view-wqPOnMfW.js} +1 -1
  3. package/dist/public/assets/{alert-dialog-BFhUZsPe.js → alert-dialog-Dj0hDlZC.js} +1 -1
  4. package/dist/public/assets/{api-DSvSyBH5.js → api-RbLAI1bg.js} +1 -1
  5. package/dist/public/assets/{browser-tab-CCXMlmPO.js → browser-tab-BjqSmZHm.js} +1 -1
  6. package/dist/public/assets/chat-input-container-BNOl7YtC.js +21 -0
  7. package/dist/public/assets/context-menu-XD6khGRr.js +1 -0
  8. package/dist/public/assets/conversation-history-view-BRSNoBYn.js +1 -0
  9. package/dist/public/assets/{dialogs-config-B91VQpxo.js → dialogs-config-BXDglGdB.js} +14 -14
  10. package/dist/public/assets/diff-view-DiNlWcSj.js +3 -0
  11. package/dist/public/assets/{explorer-tab-view-B1DukGdo.js → explorer-tab-view-DbMBihAH.js} +2 -2
  12. package/dist/public/assets/{explorer-tree-DCeud6YI.js → explorer-tree-D0P-HUYS.js} +1 -1
  13. package/dist/public/assets/{explorer-view-BCJqE1-z.js → explorer-view-CL_9lhkq.js} +1 -1
  14. package/dist/public/assets/history-view-i7fGKCkc.js +1 -0
  15. package/dist/public/assets/index-BeLCtY82.css +1 -0
  16. package/dist/public/assets/index-CZZ6Jb9i.js +29 -0
  17. package/dist/public/assets/{markdown-renderer-9nzN0Pk3.js → markdown-renderer-CPSKOcqK.js} +3 -3
  18. package/dist/public/assets/mcp-server-card-DFATg_Ie.js +1 -0
  19. package/dist/public/assets/onboarding-5CTkrfwe.js +1 -0
  20. package/dist/public/assets/onboarding-dialog-gcZ9aKKp.js +1 -0
  21. package/dist/public/assets/{page-toolbar-DnVFnCgq.js → page-toolbar-CbwENcML.js} +1 -1
  22. package/dist/public/assets/project-settings-view-CRRJPGNL.js +1 -0
  23. package/dist/public/assets/providers-list-view-D3CIB4ou.js +1 -0
  24. package/dist/public/assets/radio-group-qCcnwXV3.js +1 -0
  25. package/dist/public/assets/react-vendor-Bpg1hd5i.js +22 -0
  26. package/dist/public/assets/{resizable-CEv7JjTI.js → resizable-BLhzHL_f.js} +1 -1
  27. package/dist/public/assets/{run-stop-button-CrjPMC0m.js → run-stop-button-CIuDOHFg.js} +2 -2
  28. package/dist/public/assets/settings-general-view-7Y0c9534.js +1 -0
  29. package/dist/public/assets/{settings-instructions-view-C23spY9Y.js → settings-instructions-view-B-uTQrNZ.js} +1 -1
  30. package/dist/public/assets/settings-mcp-servers-view-nAMQQWHb.js +5 -0
  31. package/dist/public/assets/settings-models-skeleton-CffyGIvJ.js +1 -0
  32. package/dist/public/assets/settings-models-view-CMZh5LlR.js +1 -0
  33. package/dist/public/assets/settings-rules-view-BaNccq1v.js +8 -0
  34. package/dist/public/assets/{settings-skills-view-D60tD-OE.js → settings-skills-view-DBX7obT7.js} +2 -2
  35. package/dist/public/assets/{settings-slash-commands-view-DR-pzulT.js → settings-slash-commands-view-BoT1nCir.js} +1 -1
  36. package/dist/public/assets/settings-subagents-view-Cy87X2bs.js +2 -0
  37. package/dist/public/assets/settings-view-CS-RnV6J.js +2 -0
  38. package/dist/public/assets/{side-panel-container-CO3qgRvc.js → side-panel-container-B33_hnhc.js} +2 -2
  39. package/dist/public/assets/{skeleton-CXoVAzC1.js → skeleton-n47_ST9G.js} +1 -1
  40. package/dist/public/assets/{standard-list-item-DyALhVYe.js → standard-list-item-BLTOBGFa.js} +1 -1
  41. package/dist/public/assets/{store-D28g9VUj.js → store-B9rEO6q-.js} +1 -1
  42. package/dist/public/assets/{tab-context-C3z7YU59.js → tab-context-BUUT3x3d.js} +1 -1
  43. package/dist/public/assets/{tabs-sXgL2DZz.js → tabs--5y6mYhG.js} +1 -1
  44. package/dist/public/assets/{terminal-panel-EifoA6G0.js → terminal-panel-BCHLDUbD.js} +2 -2
  45. package/dist/public/assets/{textarea-Bp3p1-25.js → textarea-CwXpBxom.js} +1 -1
  46. package/dist/public/assets/todos-view-k0k8R9NT.js +1 -0
  47. package/dist/public/assets/use-font-size-BJl84s49.js +1 -0
  48. package/dist/public/assets/{use-toast-BZ79E_dX.js → use-toast-C5s-Xnwi.js} +1 -1
  49. package/dist/public/assets/{utils-Bhu11Tpg.js → utils-CDrGT12s.js} +1 -1
  50. package/dist/public/index.html +21 -21
  51. package/package.json +2 -2
  52. package/dist/public/assets/chat-input-container-VwmGKJFJ.js +0 -21
  53. package/dist/public/assets/context-menu-B6K8j1ha.js +0 -1
  54. package/dist/public/assets/conversation-history-view-DrrLyMbg.js +0 -1
  55. package/dist/public/assets/diff-view-C09yOc5d.js +0 -3
  56. package/dist/public/assets/history-view-Dj4NiScy.js +0 -1
  57. package/dist/public/assets/index-7TFkb0ll.css +0 -1
  58. package/dist/public/assets/index-BLCecayZ.js +0 -29
  59. package/dist/public/assets/mcp-server-card-BSw_FlEC.js +0 -1
  60. package/dist/public/assets/onboarding-ClUE_I5q.js +0 -1
  61. package/dist/public/assets/onboarding-dialog-C2jig8mT.js +0 -1
  62. package/dist/public/assets/project-settings-view-DWn0ty7b.js +0 -1
  63. package/dist/public/assets/providers-list-view-B0DqNJYK.js +0 -1
  64. package/dist/public/assets/radio-group-CM_Wwam0.js +0 -1
  65. package/dist/public/assets/react-vendor-nPkCWaAR.js +0 -22
  66. package/dist/public/assets/settings-general-view-CwQYmnI2.js +0 -1
  67. package/dist/public/assets/settings-mcp-servers-view-ZHar6YbE.js +0 -5
  68. package/dist/public/assets/settings-models-view-Cg6WQ4cy.js +0 -1
  69. package/dist/public/assets/settings-rules-view-zAx5JL4w.js +0 -8
  70. package/dist/public/assets/settings-subagents-view-InXmwmw9.js +0 -2
  71. package/dist/public/assets/settings-view-DLRDBuwH.js +0 -2
  72. package/dist/public/assets/todos-view-DRL4px6A.js +0 -1
  73. package/dist/public/assets/use-font-size-BCtvz0bm.js +0 -1
  74. /package/dist/public/assets/{dist-D5DgwfYL.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(
@@ -2613,7 +2721,7 @@ var codeSearchTool = createCodeSearchTool(
2613
2721
 
2614
2722
  // src/tools/ls.ts
2615
2723
  import { Type as Type6 } from "@sinclair/typebox";
2616
- import { existsSync as existsSync4, readdirSync, statSync as statSync2 } from "fs";
2724
+ import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2617
2725
  import nodePath from "path";
2618
2726
  var lsSchema = Type6.Object({
2619
2727
  path: Type6.Optional(
@@ -2625,9 +2733,9 @@ var lsSchema = Type6.Object({
2625
2733
  });
2626
2734
  var DEFAULT_LIMIT4 = 500;
2627
2735
  var defaultLsOperations = {
2628
- exists: existsSync4,
2736
+ exists: existsSync5,
2629
2737
  stat: statSync2,
2630
- readdir: readdirSync
2738
+ readdir: readdirSync2
2631
2739
  };
2632
2740
  function createLsTool(cwd, options) {
2633
2741
  const ops = options?.operations ?? defaultLsOperations;
@@ -2874,8 +2982,8 @@ var writeTool = createWriteTool(process.cwd());
2874
2982
  // src/tools/skill-tool.ts
2875
2983
  init_utils();
2876
2984
  import { readdir } from "fs/promises";
2877
- import { join as join4, extname as extname2 } from "path";
2878
- 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";
2879
2987
  import { Type as Type9 } from "@sinclair/typebox";
2880
2988
  function getInterpreter(scriptPath) {
2881
2989
  const ext = extname2(scriptPath);
@@ -2968,8 +3076,8 @@ function createSkillScriptTool(skills, cwd) {
2968
3076
  details: void 0
2969
3077
  };
2970
3078
  }
2971
- const scriptsDir = join4(skill.skillPath, "scripts");
2972
- if (!existsSync5(scriptsDir)) {
3079
+ const scriptsDir = join5(skill.skillPath, "scripts");
3080
+ if (!existsSync6(scriptsDir)) {
2973
3081
  return {
2974
3082
  content: [
2975
3083
  { type: "text", text: `Skill '${skillName}' has no scripts directory` }
@@ -2977,8 +3085,8 @@ function createSkillScriptTool(skills, cwd) {
2977
3085
  details: void 0
2978
3086
  };
2979
3087
  }
2980
- const scriptPath = join4(scriptsDir, scriptName);
2981
- if (!existsSync5(scriptPath)) {
3088
+ const scriptPath = join5(scriptsDir, scriptName);
3089
+ if (!existsSync6(scriptPath)) {
2982
3090
  try {
2983
3091
  const availableScripts = await readdir(scriptsDir);
2984
3092
  return {
@@ -3038,12 +3146,12 @@ ${result.stderr}
3038
3146
 
3039
3147
  // src/tools/skill-reference-tool.ts
3040
3148
  import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
3041
- import { join as join5, normalize, relative as relative3 } from "path";
3042
- import { existsSync as existsSync6 } from "fs";
3149
+ import { join as join6, normalize, relative as relative3 } from "path";
3150
+ import { existsSync as existsSync7 } from "fs";
3043
3151
  import { Type as Type10 } from "@sinclair/typebox";
3044
3152
  function isPathSafe(basePath, requestedPath) {
3045
3153
  const normalized = normalize(requestedPath);
3046
- const fullPath = join5(basePath, normalized);
3154
+ const fullPath = join6(basePath, normalized);
3047
3155
  const relativePath = relative3(basePath, fullPath);
3048
3156
  return !relativePath.startsWith("..") && !relativePath.startsWith("/");
3049
3157
  }
@@ -3072,8 +3180,8 @@ function createSkillReferenceTool(skills) {
3072
3180
  details: void 0
3073
3181
  };
3074
3182
  }
3075
- const referencesDir = join5(skill.skillPath, "references");
3076
- if (!existsSync6(referencesDir)) {
3183
+ const referencesDir = join6(skill.skillPath, "references");
3184
+ if (!existsSync7(referencesDir)) {
3077
3185
  return {
3078
3186
  content: [
3079
3187
  { type: "text", text: `Skill '${skillName}' has no references directory` }
@@ -3092,8 +3200,8 @@ function createSkillReferenceTool(skills) {
3092
3200
  details: void 0
3093
3201
  };
3094
3202
  }
3095
- const fullPath = join5(referencesDir, referencePath);
3096
- if (!existsSync6(fullPath)) {
3203
+ const fullPath = join6(referencesDir, referencePath);
3204
+ if (!existsSync7(fullPath)) {
3097
3205
  try {
3098
3206
  const availableRefs = await listReferencesRecursive(referencesDir);
3099
3207
  return {
@@ -3143,9 +3251,9 @@ async function listReferencesRecursive(dir, prefix = "") {
3143
3251
  try {
3144
3252
  const entries = await readdir2(dir, { withFileTypes: true });
3145
3253
  for (const entry of entries) {
3146
- const relativePath = prefix ? join5(prefix, entry.name) : entry.name;
3254
+ const relativePath = prefix ? join6(prefix, entry.name) : entry.name;
3147
3255
  if (entry.isDirectory()) {
3148
- const subFiles = await listReferencesRecursive(join5(dir, entry.name), relativePath);
3256
+ const subFiles = await listReferencesRecursive(join6(dir, entry.name), relativePath);
3149
3257
  files.push(...subFiles);
3150
3258
  } else {
3151
3259
  files.push(relativePath);
@@ -3285,11 +3393,11 @@ async function clearTodosIfAllDone(db, threadId) {
3285
3393
 
3286
3394
  // src/features/ralph/ralph.progress.ts
3287
3395
  import { readFile as readFile3, appendFile, writeFile } from "fs/promises";
3288
- import { join as join6 } from "path";
3396
+ import { join as join7 } from "path";
3289
3397
  var PROGRESS_FILE = "progress.txt";
3290
3398
  async function readProgress(threadPath) {
3291
3399
  try {
3292
- return await readFile3(join6(threadPath, PROGRESS_FILE), "utf-8");
3400
+ return await readFile3(join7(threadPath, PROGRESS_FILE), "utf-8");
3293
3401
  } catch (err) {
3294
3402
  if (err.code === "ENOENT") {
3295
3403
  return "";
@@ -3298,7 +3406,7 @@ async function readProgress(threadPath) {
3298
3406
  }
3299
3407
  }
3300
3408
  async function appendProgress(threadPath, learnings) {
3301
- const filePath = join6(threadPath, PROGRESS_FILE);
3409
+ const filePath = join7(threadPath, PROGRESS_FILE);
3302
3410
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3303
3411
  const entry = `
3304
3412
  --- ${timestamp} ---
@@ -3539,12 +3647,13 @@ function createTodoTool(threadId, threadPath) {
3539
3647
  var todoTool = createTodoTool("");
3540
3648
 
3541
3649
  // src/features/mcp/mcp.config.ts
3650
+ init_tarsk_debug();
3542
3651
  import { readFile as readFile4, stat, access } from "fs/promises";
3543
- import { join as join7 } from "path";
3652
+ import { join as join8 } from "path";
3544
3653
  var MCP_CONFIG_PATHS = [".agents/mcp.json", "mcp.json"];
3545
3654
  async function loadMCPConfig(projectPath) {
3546
3655
  for (const configPath of MCP_CONFIG_PATHS) {
3547
- const fullPath = join7(projectPath, configPath);
3656
+ const fullPath = join8(projectPath, configPath);
3548
3657
  try {
3549
3658
  await access(fullPath);
3550
3659
  const fileStats = await stat(fullPath);
@@ -3558,7 +3667,7 @@ async function loadMCPConfig(projectPath) {
3558
3667
  console.warn(`[MCP] Invalid configuration structure in ${configPath}`);
3559
3668
  continue;
3560
3669
  }
3561
- console.log(
3670
+ tarskDebugLog(
3562
3671
  `[MCP] Loaded configuration from ${configPath} (${fileStats.mtime.toISOString()})`
3563
3672
  );
3564
3673
  return config;
@@ -3573,7 +3682,7 @@ async function loadMCPConfig(projectPath) {
3573
3682
  }
3574
3683
  async function getMCPConfigModificationTime(projectPath) {
3575
3684
  for (const configPath of MCP_CONFIG_PATHS) {
3576
- const fullPath = join7(projectPath, configPath);
3685
+ const fullPath = join8(projectPath, configPath);
3577
3686
  try {
3578
3687
  await access(fullPath);
3579
3688
  const fileStats = await stat(fullPath);
@@ -3639,6 +3748,7 @@ async function hasMCPConfigChanged(projectPath, lastModified) {
3639
3748
  }
3640
3749
 
3641
3750
  // src/features/mcp/mcp.manager.ts
3751
+ init_tarsk_debug();
3642
3752
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3643
3753
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3644
3754
  var MCPManagerImpl = class {
@@ -3727,7 +3837,7 @@ var MCPManagerImpl = class {
3727
3837
  async getServerTools(serverName, serverConfig, projectPath) {
3728
3838
  const instance = await this.getOrCreateServerInstance(serverName, serverConfig, projectPath);
3729
3839
  if (instance.state !== "connected") {
3730
- console.warn(`[MCP] Server ${serverName} not connected (state: ${instance.state})`);
3840
+ tarskDebugWarn(`[MCP] Server ${serverName} not connected (state: ${instance.state})`);
3731
3841
  return [];
3732
3842
  }
3733
3843
  return instance.tools;
@@ -3754,7 +3864,7 @@ var MCPManagerImpl = class {
3754
3864
  tools: []
3755
3865
  };
3756
3866
  try {
3757
- console.log(
3867
+ tarskDebugLog(
3758
3868
  `[MCP] Connecting to server ${serverName} with command: ${serverConfig.command} ${serverConfig.args.join(" ")}`
3759
3869
  );
3760
3870
  const transport = new StdioClientTransport({
@@ -3772,7 +3882,7 @@ var MCPManagerImpl = class {
3772
3882
  }
3773
3883
  );
3774
3884
  await client.connect(transport);
3775
- console.log(`[MCP] Connected to server ${serverName}`);
3885
+ tarskDebugLog(`[MCP] Connected to server ${serverName}`);
3776
3886
  const toolsResponse = await client.listTools();
3777
3887
  instance.tools = toolsResponse.tools.map((tool) => ({
3778
3888
  name: tool.name,
@@ -3782,11 +3892,13 @@ var MCPManagerImpl = class {
3782
3892
  }));
3783
3893
  instance.client = client;
3784
3894
  instance.state = "connected";
3785
- 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
+ );
3786
3898
  } catch (error) {
3787
3899
  instance.state = "error";
3788
3900
  instance.error = error instanceof Error ? error.message : String(error);
3789
- console.log(`[MCP] Unable to connect to server ${serverName}: ${instance.error}`);
3901
+ tarskDebugLog(`[MCP] Unable to connect to server ${serverName}: ${instance.error}`);
3790
3902
  }
3791
3903
  return instance;
3792
3904
  }
@@ -4051,8 +4163,14 @@ var ModelManager = class {
4051
4163
  * @param provider - Provider name
4052
4164
  * @returns Array of Model objects that are enabled
4053
4165
  */
4166
+ async getEnabledModelIds(provider) {
4167
+ return this.metadataManager.getEnabledModels(provider);
4168
+ }
4169
+ async getEnabledImageModelIds(provider) {
4170
+ return this.metadataManager.getEnabledImageModels(provider);
4171
+ }
4054
4172
  async getEnabledModels(provider) {
4055
- const enabledModelIds = await this.metadataManager.getEnabledModels(provider);
4173
+ const enabledModelIds = await this.getEnabledModelIds(provider);
4056
4174
  if (enabledModelIds.length === 0) {
4057
4175
  return [];
4058
4176
  }
@@ -4636,6 +4754,7 @@ function createFindImagesTool(cwd) {
4636
4754
  }
4637
4755
 
4638
4756
  // src/tools/execute-browser-js.ts
4757
+ init_tarsk_debug();
4639
4758
  import { Type as Type15 } from "@sinclair/typebox";
4640
4759
  var runWebWorkerSchema = Type15.Object({
4641
4760
  intention: Type15.String({
@@ -4684,7 +4803,7 @@ function createRunWebWorkerTool(options) {
4684
4803
  description: buildDescription(options?.tools),
4685
4804
  parameters: runWebWorkerSchema,
4686
4805
  execute: async (toolCallId, { intention: _intention, code }, signal) => {
4687
- console.log(`[ai] run_js: executing script of length ${code.length}`);
4806
+ tarskDebugLog(`[ai] run_js: executing script of length ${code.length}`);
4688
4807
  if (signal?.aborted) {
4689
4808
  throw new Error("Operation aborted");
4690
4809
  }
@@ -4893,6 +5012,7 @@ function formatDeferredToolsList(deferredTools) {
4893
5012
  }
4894
5013
 
4895
5014
  // src/tools/index.ts
5015
+ init_tarsk_debug();
4896
5016
  var INDEX_INVALIDATING_TOOL_NAMES = /* @__PURE__ */ new Set(["bash", "edit", "write"]);
4897
5017
  function shouldInvalidateCodeSearchIndex(toolName) {
4898
5018
  return INDEX_INVALIDATING_TOOL_NAMES.has(toolName);
@@ -4903,9 +5023,9 @@ function shouldInvalidateCodeSearchIndexOnError(toolName) {
4903
5023
  async function invalidateCodeSearchIndexSafely(threadId, toolName) {
4904
5024
  try {
4905
5025
  await invalidateThreadIndex(threadId);
4906
- console.log(`[code-search] invalidated thread index after ${toolName}`);
5026
+ tarskDebugLog(`[code-search] invalidated thread index after ${toolName}`);
4907
5027
  } catch (error) {
4908
- console.warn(`[code-search] failed to invalidate thread index after ${toolName}:`, error);
5028
+ tarskDebugWarn(`[code-search] failed to invalidate thread index after ${toolName}:`, error);
4909
5029
  }
4910
5030
  }
4911
5031
  function wrapToolWithCodeSearchInvalidation(tool, threadId) {
@@ -4986,7 +5106,7 @@ async function createCodingTools(cwd, options) {
4986
5106
  deferredTools
4987
5107
  });
4988
5108
  tools.push(toolSearch);
4989
- console.log(
5109
+ tarskDebugLog(
4990
5110
  `[Tools] ${deferredTools.size} tool(s) deferred behind tool_search: ${Array.from(deferredTools.keys()).join(", ")}`
4991
5111
  );
4992
5112
  }
@@ -5048,7 +5168,11 @@ var PROVIDER_NAME_TO_PI = {
5048
5168
  codex: "openai-codex",
5049
5169
  mistral: "mistral"
5050
5170
  };
5051
- 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
+ }
5052
5176
  if (apiUrl.includes("/anthropic/")) return "anthropic-messages";
5053
5177
  if (apiUrl.includes("api.anthropic.com")) return "anthropic-messages";
5054
5178
  return "openai-completions";
@@ -5066,7 +5190,7 @@ function resolveModel(providerName, modelId, providerConfig) {
5066
5190
  if (!baseUrl) {
5067
5191
  throw new Error(`No API URL configured for provider: ${providerName}`);
5068
5192
  }
5069
- const apiType = determineApiType(baseUrl);
5193
+ const apiType = determineApiType(providerName, baseUrl);
5070
5194
  return {
5071
5195
  id: modelId,
5072
5196
  name: modelId,
@@ -5484,10 +5608,10 @@ function createAgentTool(options) {
5484
5608
  }
5485
5609
 
5486
5610
  // src/core/paths.ts
5487
- import { join as join8 } from "path";
5488
- import { homedir as homedir3 } from "os";
5489
- var APP_SUPPORT_DIR = join8(homedir3(), "Library", "Application Support", "Tarsk");
5490
- 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");
5491
5615
  function getDataDir() {
5492
5616
  return DATA_DIR;
5493
5617
  }
@@ -5497,8 +5621,8 @@ import { resolve } from "path";
5497
5621
  import { readFileSync as readFileSync4 } from "fs";
5498
5622
 
5499
5623
  // src/project-analyzer.ts
5500
- import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
5501
- import { join as join9 } from "path";
5624
+ import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
5625
+ import { join as join10 } from "path";
5502
5626
  var ProjectAnalyzer = class {
5503
5627
  projectPath;
5504
5628
  constructor(projectPath = process.cwd()) {
@@ -5509,9 +5633,9 @@ var ProjectAnalyzer = class {
5509
5633
  return this.generateDescription(info);
5510
5634
  }
5511
5635
  getProjectInfo() {
5512
- const packageJsonPath = join9(this.projectPath, "package.json");
5636
+ const packageJsonPath = join10(this.projectPath, "package.json");
5513
5637
  const info = { description: "" };
5514
- if (existsSync7(packageJsonPath)) {
5638
+ if (existsSync8(packageJsonPath)) {
5515
5639
  const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
5516
5640
  const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
5517
5641
  this.detectFramework(allDeps, info);
@@ -5551,15 +5675,15 @@ var ProjectAnalyzer = class {
5551
5675
  }
5552
5676
  }
5553
5677
  detectBuildTool(_scripts = {}, deps, info) {
5554
- 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"))) {
5555
5679
  info.buildTool = "Vite";
5556
5680
  return;
5557
5681
  }
5558
- if (deps.webpack || existsSync7(join9(this.projectPath, "webpack.config.js"))) {
5682
+ if (deps.webpack || existsSync8(join10(this.projectPath, "webpack.config.js"))) {
5559
5683
  info.buildTool = "Webpack";
5560
5684
  return;
5561
5685
  }
5562
- if (deps.rollup || existsSync7(join9(this.projectPath, "rollup.config.js"))) {
5686
+ if (deps.rollup || existsSync8(join10(this.projectPath, "rollup.config.js"))) {
5563
5687
  info.buildTool = "Rollup";
5564
5688
  return;
5565
5689
  }
@@ -5609,40 +5733,40 @@ var ProjectAnalyzer = class {
5609
5733
  info.uiLibraries = [...new Set(uiLibs)].filter(Boolean);
5610
5734
  }
5611
5735
  detectProjectType(info) {
5612
- 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"))) {
5613
5737
  info.projectType = "Xcode";
5614
- } 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"))) {
5615
5739
  info.projectType = "Android Studio";
5616
- } else if (existsSync7(join9(this.projectPath, "pubspec.yaml"))) {
5740
+ } else if (existsSync8(join10(this.projectPath, "pubspec.yaml"))) {
5617
5741
  info.projectType = "Flutter";
5618
- } else if (existsSync7(join9(this.projectPath, "go.mod"))) {
5742
+ } else if (existsSync8(join10(this.projectPath, "go.mod"))) {
5619
5743
  info.projectType = "Go";
5620
- } else if (existsSync7(join9(this.projectPath, "Cargo.toml"))) {
5744
+ } else if (existsSync8(join10(this.projectPath, "Cargo.toml"))) {
5621
5745
  info.projectType = "Rust";
5622
- } 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"))) {
5623
5747
  info.projectType = "Python";
5624
- } else if (existsSync7(join9(this.projectPath, "Gemfile"))) {
5748
+ } else if (existsSync8(join10(this.projectPath, "Gemfile"))) {
5625
5749
  info.projectType = "Ruby";
5626
- } else if (existsSync7(join9(this.projectPath, "composer.json"))) {
5750
+ } else if (existsSync8(join10(this.projectPath, "composer.json"))) {
5627
5751
  info.projectType = "PHP";
5628
- } 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"))) {
5629
5753
  info.projectType = "Java";
5630
- } 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"))) {
5631
5755
  info.projectType = ".NET";
5632
5756
  }
5633
5757
  }
5634
5758
  detectPackageManager(info) {
5635
- if (existsSync7(join9(this.projectPath, "bun.lockb"))) {
5759
+ if (existsSync8(join10(this.projectPath, "bun.lockb"))) {
5636
5760
  info.packageManager = "Bun";
5637
- } else if (existsSync7(join9(this.projectPath, "bun.lock"))) {
5761
+ } else if (existsSync8(join10(this.projectPath, "bun.lock"))) {
5638
5762
  info.packageManager = "Bun";
5639
- } else if (existsSync7(join9(this.projectPath, "pnpm-lock.yaml"))) {
5763
+ } else if (existsSync8(join10(this.projectPath, "pnpm-lock.yaml"))) {
5640
5764
  info.packageManager = "pnpm";
5641
- } else if (existsSync7(join9(this.projectPath, "yarn.lock"))) {
5765
+ } else if (existsSync8(join10(this.projectPath, "yarn.lock"))) {
5642
5766
  info.packageManager = "Yarn";
5643
- } else if (existsSync7(join9(this.projectPath, "package-lock.json"))) {
5767
+ } else if (existsSync8(join10(this.projectPath, "package-lock.json"))) {
5644
5768
  info.packageManager = "npm";
5645
- } else if (existsSync7(join9(this.projectPath, "npm-shrinkwrap.json"))) {
5769
+ } else if (existsSync8(join10(this.projectPath, "npm-shrinkwrap.json"))) {
5646
5770
  info.packageManager = "npm";
5647
5771
  }
5648
5772
  }
@@ -5705,9 +5829,9 @@ function analyzeProject(projectPath) {
5705
5829
 
5706
5830
  // src/features/rules/rules.manager.ts
5707
5831
  import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
5708
- import { join as join10, relative as relative4 } from "path";
5709
- import { existsSync as existsSync8 } from "fs";
5710
- 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";
5711
5835
  function parseRuleFrontmatter(markdown) {
5712
5836
  const lines = markdown.split("\n");
5713
5837
  if (lines[0]?.trim() !== "---") {
@@ -5749,10 +5873,10 @@ function parseRuleFrontmatter(markdown) {
5749
5873
  return { metadata, content };
5750
5874
  }
5751
5875
  function getGlobalRulesDir() {
5752
- return join10(homedir4(), ".agents", "rules");
5876
+ return join11(homedir5(), ".agents", "rules");
5753
5877
  }
5754
5878
  function getProjectRulesDir(threadPath) {
5755
- return join10(threadPath, ".agents", "rules");
5879
+ return join11(threadPath, ".agents", "rules");
5756
5880
  }
5757
5881
  var RuleManager = class {
5758
5882
  /**
@@ -5762,14 +5886,14 @@ var RuleManager = class {
5762
5886
  async loadRules(threadPath) {
5763
5887
  const rules = /* @__PURE__ */ new Map();
5764
5888
  const globalDir = getGlobalRulesDir();
5765
- if (existsSync8(globalDir)) {
5889
+ if (existsSync9(globalDir)) {
5766
5890
  const globalRules = await this.loadRulesFromDir(globalDir, threadPath, "global");
5767
5891
  for (const rule of globalRules) {
5768
5892
  rules.set(rule.name, rule);
5769
5893
  }
5770
5894
  }
5771
5895
  const projectDir = getProjectRulesDir(threadPath);
5772
- if (existsSync8(projectDir)) {
5896
+ if (existsSync9(projectDir)) {
5773
5897
  const projectRules = await this.loadRulesFromDir(projectDir, threadPath, "project");
5774
5898
  for (const rule of projectRules) {
5775
5899
  rules.set(rule.name, rule);
@@ -5785,7 +5909,7 @@ var RuleManager = class {
5785
5909
  try {
5786
5910
  const entries = await readdir3(dir, { withFileTypes: true });
5787
5911
  for (const entry of entries) {
5788
- const fullPath = join10(dir, entry.name);
5912
+ const fullPath = join11(dir, entry.name);
5789
5913
  if (entry.isDirectory()) {
5790
5914
  const subRules = await this.loadRulesFromDir(fullPath, threadPath, scope);
5791
5915
  rules.push(...subRules);
@@ -5916,6 +6040,7 @@ var DevServerCache = class {
5916
6040
  var devServerCache = new DevServerCache();
5917
6041
 
5918
6042
  // src/agent/agent.prompt-loader.ts
6043
+ init_tarsk_debug();
5919
6044
  function buildDefaultPrompt(tools) {
5920
6045
  const toolList = tools.map((t) => t.name).join(", ");
5921
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.`;
@@ -5992,12 +6117,12 @@ function loadDeveloperContext(threadPath) {
5992
6117
  try {
5993
6118
  const agentsPath = resolve(threadPath, "agents.md");
5994
6119
  const agentsContent = readFileSync4(agentsPath, "utf-8").trim();
5995
- 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");
5996
6121
  return agentsContent;
5997
6122
  } catch (error) {
5998
6123
  const isFileNotFound = error && typeof error === "object" && "code" in error && error.code === "ENOENT";
5999
6124
  if (isFileNotFound) {
6000
- 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");
6001
6126
  } else {
6002
6127
  console.warn(
6003
6128
  "[ai] Error loading agents.md from thread path:",
@@ -6013,7 +6138,7 @@ async function loadRulesSection(threadPath) {
6013
6138
  const rules = await ruleManager.loadRules(threadPath);
6014
6139
  if (rules.length > 0) {
6015
6140
  const rulesSection = ruleManager.formatRulesForPrompt(rules);
6016
- console.log(`[ai] Loaded ${rules.length} rule(s) from .agents/rules directory`);
6141
+ tarskDebugLog(`[ai] Loaded ${rules.length} rule(s) from .agents/rules directory`);
6017
6142
  return rulesSection;
6018
6143
  }
6019
6144
  return "";
@@ -6039,20 +6164,20 @@ async function loadDevServerSection(threadPath) {
6039
6164
  // 3 second timeout
6040
6165
  });
6041
6166
  if (response.ok) {
6042
- console.log(`[ai] Dev server is running at ${cachedUrl} for thread ${threadId}`);
6167
+ tarskDebugLog(`[ai] Dev server is running at ${cachedUrl} for thread ${threadId}`);
6043
6168
  return `
6044
6169
 
6045
6170
  # Dev Server
6046
6171
 
6047
6172
  The dev server is running at ${cachedUrl}.`;
6048
6173
  } else {
6049
- console.log(
6174
+ tarskDebugLog(
6050
6175
  `[ai] Dev server at ${cachedUrl} responded with status ${response.status} for thread ${threadId}`
6051
6176
  );
6052
6177
  return "";
6053
6178
  }
6054
6179
  } catch (fetchError) {
6055
- console.log(
6180
+ tarskDebugLog(
6056
6181
  `[ai] Dev server at ${cachedUrl} is not reachable for thread ${threadId}:`,
6057
6182
  fetchError instanceof Error ? fetchError.message : String(fetchError)
6058
6183
  );
@@ -6081,6 +6206,43 @@ function loadProjectAnalysisSection(threadPath) {
6081
6206
  return "";
6082
6207
  }
6083
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
+ }
6084
6246
  function formatSkillsSection(skills) {
6085
6247
  if (!skills || skills.length === 0) {
6086
6248
  return "";
@@ -6102,7 +6264,7 @@ function formatSkillsSection(skills) {
6102
6264
  skillsSection += skill.instructions;
6103
6265
  skillsSection += "\n\n---\n\n";
6104
6266
  }
6105
- console.log(
6267
+ tarskDebugLog(
6106
6268
  `[ai] Injected ${skills.length} skill(s) into system prompt: ${skills.map((s) => s.name).join(", ")}`
6107
6269
  );
6108
6270
  return skillsSection;
@@ -6121,7 +6283,7 @@ function formatAgentsSection(agents) {
6121
6283
 
6122
6284
  `;
6123
6285
  }
6124
- console.log(
6286
+ tarskDebugLog(
6125
6287
  `[ai] Injected ${invocable.length} agent(s) into system prompt: ${invocable.map((a) => a.name).join(", ")}`
6126
6288
  );
6127
6289
  return section;
@@ -6530,6 +6692,8 @@ ${userPrompt}`;
6530
6692
  } else {
6531
6693
  console.log("[ai] \u26A0\uFE0F Agent ended with no text content and no tool calls.");
6532
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;
6533
6697
  console.error("[ai] Agent ended without text content:", {
6534
6698
  request: promptRequest,
6535
6699
  upstreamError,
@@ -6538,7 +6702,7 @@ ${userPrompt}`;
6538
6702
  });
6539
6703
  yield {
6540
6704
  type: "error",
6541
- 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,
6542
6706
  error: {
6543
6707
  code: "NO_CONTENT_NO_TOOLS",
6544
6708
  message: `The model ${model} from ${providerName} did not provide a response to your prompt.`,
@@ -6571,6 +6735,7 @@ ${userPrompt}`;
6571
6735
  };
6572
6736
 
6573
6737
  // src/agent/agent.processing-state-manager.ts
6738
+ init_tarsk_debug();
6574
6739
  var ProcessingStateManagerImpl = class {
6575
6740
  processingThreads = /* @__PURE__ */ new Set();
6576
6741
  eventBuffers = /* @__PURE__ */ new Map();
@@ -6579,7 +6744,7 @@ var ProcessingStateManagerImpl = class {
6579
6744
  setProcessing(threadId) {
6580
6745
  this.processingThreads.add(threadId);
6581
6746
  this.eventBuffers.set(threadId, []);
6582
- console.log(
6747
+ tarskDebugLog(
6583
6748
  `[ProcessingState] Thread ${threadId} started processing. Active: ${this.processingThreads.size}`
6584
6749
  );
6585
6750
  }
@@ -6589,7 +6754,7 @@ var ProcessingStateManagerImpl = class {
6589
6754
  abortThread(threadId) {
6590
6755
  const controller = this.abortControllers.get(threadId);
6591
6756
  if (!controller) return false;
6592
- console.log(`[ProcessingState] Aborting thread ${threadId} via stop endpoint`);
6757
+ tarskDebugLog(`[ProcessingState] Aborting thread ${threadId} via stop endpoint`);
6593
6758
  controller.abort();
6594
6759
  this.abortControllers.delete(threadId);
6595
6760
  return true;
@@ -6607,7 +6772,7 @@ var ProcessingStateManagerImpl = class {
6607
6772
  setTimeout(() => {
6608
6773
  this.eventBuffers.delete(threadId);
6609
6774
  }, 5e3);
6610
- console.log(
6775
+ tarskDebugLog(
6611
6776
  `[ProcessingState] Thread ${threadId} finished processing. Active: ${this.processingThreads.size}`
6612
6777
  );
6613
6778
  }
@@ -6651,14 +6816,14 @@ var ProcessingStateManagerImpl = class {
6651
6816
 
6652
6817
  // src/core/env-manager.ts
6653
6818
  import { promises as fs } from "fs";
6654
- import { join as join11 } from "path";
6819
+ import { join as join12 } from "path";
6655
6820
  function updateRuntimeEnv(values) {
6656
6821
  for (const [key, value] of Object.entries(values)) {
6657
6822
  process.env[key] = value;
6658
6823
  }
6659
6824
  }
6660
6825
  async function updateEnvFile(keyNames) {
6661
- const envPath = join11(process.cwd(), ".env");
6826
+ const envPath = join12(process.cwd(), ".env");
6662
6827
  let content = "";
6663
6828
  try {
6664
6829
  content = await fs.readFile(envPath, "utf-8");
@@ -6687,7 +6852,7 @@ async function updateEnvFile(keyNames) {
6687
6852
  await fs.writeFile(envPath, newLines.join("\n") + "\n", "utf-8");
6688
6853
  }
6689
6854
  async function readEnvFile() {
6690
- const envPath = join11(process.cwd(), ".env");
6855
+ const envPath = join12(process.cwd(), ".env");
6691
6856
  const envMap = {};
6692
6857
  try {
6693
6858
  const content = await fs.readFile(envPath, "utf-8");
@@ -6880,9 +7045,9 @@ import { randomUUID as randomUUID4 } from "crypto";
6880
7045
 
6881
7046
  // src/features/skills/skills.manager.ts
6882
7047
  import { readdir as readdir4, readFile as readFile6 } from "fs/promises";
6883
- import { join as join12 } from "path";
6884
- import { existsSync as existsSync9 } from "fs";
6885
- 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";
6886
7051
  function parseFrontmatter(markdown) {
6887
7052
  const lines = markdown.split("\n");
6888
7053
  if (lines[0]?.trim() !== "---") {
@@ -6928,10 +7093,10 @@ function parseFrontmatter(markdown) {
6928
7093
  return { metadata, content };
6929
7094
  }
6930
7095
  function getGlobalSkillsDir() {
6931
- return join12(homedir5(), ".agents", "skills");
7096
+ return join13(homedir6(), ".agents", "skills");
6932
7097
  }
6933
7098
  function getProjectSkillsDir(threadPath) {
6934
- return join12(threadPath, ".agents", "skills");
7099
+ return join13(threadPath, ".agents", "skills");
6935
7100
  }
6936
7101
  function validateSkillName(name) {
6937
7102
  if (!name || name.length === 0 || name.length > 64) {
@@ -6959,14 +7124,14 @@ var SkillManager = class {
6959
7124
  async loadSkills(threadPath) {
6960
7125
  const skills = /* @__PURE__ */ new Map();
6961
7126
  const globalDir = getGlobalSkillsDir();
6962
- if (existsSync9(globalDir)) {
7127
+ if (existsSync10(globalDir)) {
6963
7128
  const globalSkills = await this.loadSkillsFromDir(globalDir, "global");
6964
7129
  for (const skill of globalSkills) {
6965
7130
  skills.set(skill.name, skill);
6966
7131
  }
6967
7132
  }
6968
7133
  const projectDir = getProjectSkillsDir(threadPath);
6969
- if (existsSync9(projectDir)) {
7134
+ if (existsSync10(projectDir)) {
6970
7135
  const projectSkills = await this.loadSkillsFromDir(projectDir, "project");
6971
7136
  for (const skill of projectSkills) {
6972
7137
  skills.set(skill.name, skill);
@@ -6984,9 +7149,9 @@ var SkillManager = class {
6984
7149
  for (const entry of entries) {
6985
7150
  if (!entry.isDirectory()) continue;
6986
7151
  const skillDirName = entry.name;
6987
- const skillPath = join12(dir, skillDirName);
6988
- const skillFilePath = join12(skillPath, "SKILL.md");
6989
- if (!existsSync9(skillFilePath)) {
7152
+ const skillPath = join13(dir, skillDirName);
7153
+ const skillFilePath = join13(skillPath, "SKILL.md");
7154
+ if (!existsSync10(skillFilePath)) {
6990
7155
  console.warn(`Skipping skill directory ${skillDirName}: SKILL.md not found`);
6991
7156
  continue;
6992
7157
  }
@@ -7165,9 +7330,9 @@ async function activateSkills(allSkills, taskDescription, thread, options) {
7165
7330
 
7166
7331
  // src/features/agents/agents.manager.ts
7167
7332
  import { readdir as readdir5, readFile as readFile7 } from "fs/promises";
7168
- import { join as join13 } from "path";
7169
- import { existsSync as existsSync10 } from "fs";
7170
- 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";
7171
7336
  function parseFrontmatter2(markdown) {
7172
7337
  const lines = markdown.split("\n");
7173
7338
  if (lines[0]?.trim() !== "---") {
@@ -7223,10 +7388,10 @@ function validateDescription2(description) {
7223
7388
  return !!description && description.length > 0 && description.length <= 1024;
7224
7389
  }
7225
7390
  function getGlobalAgentsDir() {
7226
- return join13(homedir6(), ".agents", "agents");
7391
+ return join14(homedir7(), ".agents", "agents");
7227
7392
  }
7228
7393
  function getProjectAgentsDir(threadPath) {
7229
- return join13(threadPath, ".agents", "agents");
7394
+ return join14(threadPath, ".agents", "agents");
7230
7395
  }
7231
7396
  var AgentsManager = class {
7232
7397
  /**
@@ -7236,14 +7401,14 @@ var AgentsManager = class {
7236
7401
  async loadAgents(threadPath) {
7237
7402
  const agents = /* @__PURE__ */ new Map();
7238
7403
  const globalDir = getGlobalAgentsDir();
7239
- if (existsSync10(globalDir)) {
7404
+ if (existsSync11(globalDir)) {
7240
7405
  const globalAgents = await this.loadAgentsFromDir(globalDir, "global");
7241
7406
  for (const agent of globalAgents) {
7242
7407
  agents.set(agent.name, agent);
7243
7408
  }
7244
7409
  }
7245
7410
  const projectDir = getProjectAgentsDir(threadPath);
7246
- if (existsSync10(projectDir)) {
7411
+ if (existsSync11(projectDir)) {
7247
7412
  const projectAgents = await this.loadAgentsFromDir(projectDir, "project");
7248
7413
  for (const agent of projectAgents) {
7249
7414
  agents.set(agent.name, agent);
@@ -7258,9 +7423,9 @@ var AgentsManager = class {
7258
7423
  for (const entry of entries) {
7259
7424
  if (!entry.isDirectory()) continue;
7260
7425
  const agentDirName = entry.name;
7261
- const agentPath = join13(dir, agentDirName);
7262
- const agentFilePath = join13(agentPath, "AGENT.md");
7263
- if (!existsSync10(agentFilePath)) {
7426
+ const agentPath = join14(dir, agentDirName);
7427
+ const agentFilePath = join14(agentPath, "AGENT.md");
7428
+ if (!existsSync11(agentFilePath)) {
7264
7429
  console.warn(`[agents] Skipping agent directory ${agentDirName}: AGENT.md not found`);
7265
7430
  continue;
7266
7431
  }
@@ -7446,7 +7611,7 @@ function extractAssistantContent(events, fallback) {
7446
7611
  // src/features/chat/chat-post.route.ts
7447
7612
  init_database();
7448
7613
  import { readFile as readFile8, unlink } from "fs/promises";
7449
- import { join as join14 } from "path";
7614
+ import { join as join15 } from "path";
7450
7615
 
7451
7616
  // src/features/project-todos/project-todos.database.ts
7452
7617
  init_database();
@@ -8439,7 +8604,7 @@ ${result.output}`;
8439
8604
  try {
8440
8605
  const todo = await getTodoByThreadId(db, threadId);
8441
8606
  if (todo && todo.status === "Plan") {
8442
- const planFilePath = join14(threadPath, `${todo.id}-plan.md`);
8607
+ const planFilePath = join15(threadPath, `${todo.id}-plan.md`);
8443
8608
  try {
8444
8609
  const planContent = await readFile8(planFilePath, "utf-8");
8445
8610
  await updateTodo(db, todo.id, { description: planContent.trim() });
@@ -9691,8 +9856,226 @@ async function handleGetThreadUsageSummary(c, conversationManager, threadManager
9691
9856
  }
9692
9857
  }
9693
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
+
9694
10077
  // src/features/conversations/conversations.routes.ts
9695
- function createConversationRoutes(conversationManager, threadManager) {
10078
+ function createConversationRoutes(conversationManager, threadManager, metadataManager) {
9696
10079
  const router = new Hono3();
9697
10080
  router.get("/:threadId", (c) => getAllConversations(c, conversationManager, threadManager));
9698
10081
  router.get("/:threadId/deleted", (c) => getDeletedConversations(c, conversationManager));
@@ -9708,6 +10091,10 @@ function createConversationRoutes(conversationManager, threadManager) {
9708
10091
  "/:threadId/:conversationId/usage",
9709
10092
  (c) => handleGetConversationUsage(c, conversationManager, threadManager)
9710
10093
  );
10094
+ router.get(
10095
+ "/:threadId/:conversationId/context",
10096
+ (c) => handleGetContextBreakdown(c, conversationManager, threadManager, metadataManager)
10097
+ );
9711
10098
  router.get(
9712
10099
  "/:threadId/:conversationId",
9713
10100
  (c) => getConversationById(c, conversationManager, threadManager)
@@ -9877,6 +10264,7 @@ function isEncryptedKey(value) {
9877
10264
  }
9878
10265
 
9879
10266
  // src/features/metadata/metadata.manager.ts
10267
+ init_tarsk_debug();
9880
10268
  var MetadataManager = class {
9881
10269
  db;
9882
10270
  /**
@@ -10062,7 +10450,7 @@ var MetadataManager = class {
10062
10450
  providerKeys[provider] = "";
10063
10451
  }
10064
10452
  } else {
10065
- console.log(
10453
+ tarskDebugLog(
10066
10454
  `[MetadataManager] Found plain-text key for ${provider}, will encrypt on save`
10067
10455
  );
10068
10456
  providerKeys[provider] = encryptedKey;
@@ -10070,7 +10458,7 @@ var MetadataManager = class {
10070
10458
  }
10071
10459
  }
10072
10460
  if (needsMigration) {
10073
- console.log("[MetadataManager] Migrating plain-text keys to encrypted format");
10461
+ tarskDebugLog("[MetadataManager] Migrating plain-text keys to encrypted format");
10074
10462
  await this.saveAllProviderKeys(providerKeys);
10075
10463
  }
10076
10464
  return {
@@ -10327,6 +10715,33 @@ var MetadataManager = class {
10327
10715
  import { Hono as Hono4 } from "hono";
10328
10716
 
10329
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
+ }
10330
10745
  async function handleGetAvailableModels(c, modelManager) {
10331
10746
  try {
10332
10747
  const provider = c.req.query("provider");
@@ -10335,42 +10750,17 @@ async function handleGetAvailableModels(c, modelManager) {
10335
10750
  if (!provider) {
10336
10751
  return c.json({ error: "provider query parameter is required" }, 400);
10337
10752
  }
10338
- let models = await modelManager.getAvailableModels(provider);
10339
- models.forEach((m) => {
10340
- if (m.coding_index === void 0 || m.coding_index === null) {
10341
- console.log(`Model ${m.name} (${m.id}) is missing coding_index`);
10342
- }
10343
- });
10344
- if (supportedTools === "true" && provider.toLowerCase() === "openrouter") {
10345
- models = models.filter((m) => m.supportedParameters?.tools === true);
10346
- }
10347
- if (useCase === "image") {
10348
- models = models.filter((m) => m.generatesImages === true);
10349
- } else if (useCase === "coding") {
10350
- models = models.filter((m) => {
10351
- const name = m.name.toLowerCase().trim();
10352
- const hasValidName = name !== "free" && name !== "auto";
10353
- const hasCodingUse = Array.isArray(m.tarsk_use) && m.tarsk_use.includes("coding");
10354
- return hasValidName && hasCodingUse;
10355
- });
10356
- if (models.length === 0) {
10357
- models = (await modelManager.getAvailableModels(provider)).filter((m) => {
10358
- const name = m.name.toLowerCase().trim();
10359
- return name !== "free" && name !== "auto";
10360
- });
10361
- if (supportedTools === "true" && provider.toLowerCase() === "openrouter") {
10362
- models = models.filter((m) => m.supportedParameters?.tools === true);
10363
- }
10364
- }
10365
- }
10366
- const enabledModels = await modelManager.getEnabledModels(provider);
10367
- 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);
10368
10758
  models.sort((a, b) => {
10369
- const aEnabled = enabledModelIds.has(a.id) ? 0 : 1;
10370
- 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;
10371
10761
  return aEnabled - bEnabled;
10372
10762
  });
10373
- return c.json({ provider, models, enabledModelIds: [...enabledModelIds] });
10763
+ return c.json({ provider, models, enabledModelIds });
10374
10764
  } catch (error) {
10375
10765
  const message = error instanceof Error ? error.message : "Unknown error";
10376
10766
  return c.json({ error: message }, 500);
@@ -11245,10 +11635,10 @@ async function handleCheckRunning(c, projectManager) {
11245
11635
 
11246
11636
  // src/core/run-command-detector.ts
11247
11637
  import { readFile as readFile9 } from "fs/promises";
11248
- import { join as join15 } from "path";
11638
+ import { join as join16 } from "path";
11249
11639
  async function detectPackageManager(projectPath) {
11250
11640
  try {
11251
- const packageJsonPath = join15(projectPath, "package.json");
11641
+ const packageJsonPath = join16(projectPath, "package.json");
11252
11642
  const content = await readFile9(packageJsonPath, "utf-8");
11253
11643
  const packageJson = JSON.parse(content);
11254
11644
  if (packageJson.packageManager) {
@@ -11264,7 +11654,7 @@ async function detectPackageManager(projectPath) {
11264
11654
  }
11265
11655
  async function detectRunScripts(projectPath) {
11266
11656
  try {
11267
- const packageJsonPath = join15(projectPath, "package.json");
11657
+ const packageJsonPath = join16(projectPath, "package.json");
11268
11658
  const content = await readFile9(packageJsonPath, "utf-8");
11269
11659
  const packageJson = JSON.parse(content);
11270
11660
  const scripts = packageJson.scripts ?? {};
@@ -11311,7 +11701,7 @@ async function suggestRunCommand(projectPath) {
11311
11701
 
11312
11702
  // src/features/projects/projects-package-scripts.route.ts
11313
11703
  import { readFile as readFile10 } from "fs/promises";
11314
- import { join as join16 } from "path";
11704
+ import { join as join17 } from "path";
11315
11705
  import { glob } from "glob";
11316
11706
  function formatScriptName(scriptName) {
11317
11707
  return scriptName.replace(/[-:_]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
@@ -11339,7 +11729,7 @@ async function findPackageScripts(projectPath) {
11339
11729
  const packageManager = await detectPackageManager(projectPath);
11340
11730
  for (const filePath of packageJsonFiles) {
11341
11731
  try {
11342
- const fullPath = join16(projectPath, filePath);
11732
+ const fullPath = join17(projectPath, filePath);
11343
11733
  const content = await readFile10(fullPath, "utf-8");
11344
11734
  const packageJson = JSON.parse(content);
11345
11735
  if (packageJson.scripts) {
@@ -11388,8 +11778,8 @@ async function handleGetPackageScripts(c, projectManager) {
11388
11778
 
11389
11779
  // src/features/projects/projects-ai-files.route.ts
11390
11780
  import { readdir as readdir6, readFile as readFile11, writeFile as writeFile2, mkdir, access as access2, rm } from "fs/promises";
11391
- import { join as join17, extname as extname3, basename } from "path";
11392
- import { existsSync as existsSync11 } from "fs";
11781
+ import { join as join18, extname as extname3, basename } from "path";
11782
+ import { existsSync as existsSync12 } from "fs";
11393
11783
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
11394
11784
  ".git",
11395
11785
  "node_modules",
@@ -11407,8 +11797,8 @@ async function buildFullTree(dirPath, relativeDirPath) {
11407
11797
  try {
11408
11798
  const entries = await readdir6(dirPath, { withFileTypes: true });
11409
11799
  for (const entry of entries) {
11410
- const entryRelPath = join17(relativeDirPath, entry.name);
11411
- const entryAbsPath = join17(dirPath, entry.name);
11800
+ const entryRelPath = join18(relativeDirPath, entry.name);
11801
+ const entryAbsPath = join18(dirPath, entry.name);
11412
11802
  if (entry.isDirectory()) {
11413
11803
  const children = await buildFullTree(entryAbsPath, entryRelPath);
11414
11804
  nodes.push({
@@ -11436,8 +11826,8 @@ async function buildMarkdownFilteredTree(dirPath, relativeDirPath) {
11436
11826
  try {
11437
11827
  const entries = await readdir6(dirPath, { withFileTypes: true });
11438
11828
  for (const entry of entries) {
11439
- const entryRelPath = join17(relativeDirPath, entry.name);
11440
- const entryAbsPath = join17(dirPath, entry.name);
11829
+ const entryRelPath = join18(relativeDirPath, entry.name);
11830
+ const entryAbsPath = join18(dirPath, entry.name);
11441
11831
  if (entry.isDirectory()) {
11442
11832
  if (IGNORED_DIRS.has(entry.name)) continue;
11443
11833
  const children = await buildMarkdownFilteredTree(entryAbsPath, entryRelPath);
@@ -11472,9 +11862,9 @@ async function buildAIFileTree(projectPath) {
11472
11862
  { key: "agents", label: "Agents" }
11473
11863
  ];
11474
11864
  for (const { key, label } of agentsFolders) {
11475
- const relPath = join17(".agents", key);
11476
- const absPath = join17(projectPath, relPath);
11477
- const exists = existsSync11(absPath);
11865
+ const relPath = join18(".agents", key);
11866
+ const absPath = join18(projectPath, relPath);
11867
+ const exists = existsSync12(absPath);
11478
11868
  if (exists) {
11479
11869
  const children = await buildFullTree(absPath, relPath);
11480
11870
  nodes.push({
@@ -11508,7 +11898,7 @@ async function buildAIFileTree(projectPath) {
11508
11898
  if (entry.name === ".agents" || entry.name === "AGENTS.md" || IGNORED_DIRS.has(entry.name))
11509
11899
  continue;
11510
11900
  const entryRelPath = entry.name;
11511
- const entryAbsPath = join17(projectPath, entry.name);
11901
+ const entryAbsPath = join18(projectPath, entry.name);
11512
11902
  if (entry.isFile() && MARKDOWN_EXTS.has(extname3(entry.name))) {
11513
11903
  nodes.push({
11514
11904
  id: entryRelPath,
@@ -11535,7 +11925,7 @@ async function buildAIFileTree(projectPath) {
11535
11925
  }
11536
11926
  function validateFilePath(projectPath, filePath) {
11537
11927
  if (!filePath) return null;
11538
- const abs = join17(projectPath, filePath);
11928
+ const abs = join18(projectPath, filePath);
11539
11929
  if (!abs.startsWith(projectPath + "/") && abs !== projectPath) return null;
11540
11930
  return abs;
11541
11931
  }
@@ -11661,7 +12051,7 @@ async function handleSaveAIFile(c, projectManager) {
11661
12051
  if (!absPath) {
11662
12052
  return c.json({ error: { code: "BAD_REQUEST", message: "Invalid file path" } }, 400);
11663
12053
  }
11664
- const parentDir = join17(absPath, "..");
12054
+ const parentDir = join18(absPath, "..");
11665
12055
  await mkdir(parentDir, { recursive: true });
11666
12056
  await writeFile2(absPath, content, "utf-8");
11667
12057
  return c.json({ success: true, path: filePath });
@@ -11761,11 +12151,11 @@ async function handleCreateSkill(c, projectManager) {
11761
12151
  if (!project) {
11762
12152
  return errorResponse(c, ErrorCodes.PROJECT_NOT_FOUND, `Project not found: ${projectId}`, 404);
11763
12153
  }
11764
- const skillRelPath = join17(".agents", "skills", name);
11765
- const skillAbsPath = join17(project.path, skillRelPath);
11766
- const skillFileRelPath = join17(skillRelPath, "SKILL.md");
11767
- const skillFileAbsPath = join17(skillAbsPath, "SKILL.md");
11768
- 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)) {
11769
12159
  return c.json(
11770
12160
  { error: { code: "CONFLICT", message: `Skill '${name}' already exists` } },
11771
12161
  409
@@ -11866,13 +12256,14 @@ function createProjectRoutes(projectManager, threadManager) {
11866
12256
 
11867
12257
  // src/features/projects/projects.manager.ts
11868
12258
  init_utils();
11869
- import { join as join20 } from "path";
12259
+ import { join as join21 } from "path";
11870
12260
  import { realpathSync as realpathSync2 } from "fs";
11871
12261
  import { rm as rm3 } from "fs/promises";
11872
12262
 
11873
12263
  // src/agent/agent.process-manager.ts
11874
12264
  init_utils();
11875
12265
  import { EventEmitter } from "events";
12266
+ init_tarsk_debug();
11876
12267
  var URL_PATTERNS = [
11877
12268
  // http(s)://localhost:PORT
11878
12269
  /https?:\/\/localhost[:/](\d+)/i,
@@ -11899,7 +12290,7 @@ var ProcessManager = class extends EventEmitter {
11899
12290
  * @returns AsyncGenerator that yields ProcessOutput events
11900
12291
  */
11901
12292
  async *runProcess(projectId, command, cwd, threadId) {
11902
- console.log(
12293
+ tarskDebugLog(
11903
12294
  "CLI ProcessManager: runProcess called for project:",
11904
12295
  projectId,
11905
12296
  "thread:",
@@ -11910,14 +12301,14 @@ var ProcessManager = class extends EventEmitter {
11910
12301
  cwd
11911
12302
  );
11912
12303
  if (this.processes.has(projectId)) {
11913
- console.log("CLI ProcessManager: Process already running for project:", projectId);
12304
+ tarskDebugLog("CLI ProcessManager: Process already running for project:", projectId);
11914
12305
  yield {
11915
12306
  type: "error",
11916
12307
  error: new Error("A process is already running for this project")
11917
12308
  };
11918
12309
  return;
11919
12310
  }
11920
- console.log("CLI ProcessManager: Starting new process for project:", projectId);
12311
+ tarskDebugLog("CLI ProcessManager: Starting new process for project:", projectId);
11921
12312
  this.queues.set(projectId, []);
11922
12313
  this.resolvers.set(projectId, []);
11923
12314
  const addToQueue = (output) => {
@@ -11944,7 +12335,7 @@ var ProcessManager = class extends EventEmitter {
11944
12335
  };
11945
12336
  try {
11946
12337
  const { shell, args: shellArgs } = getShellConfig();
11947
- console.log("CLI ProcessManager: Spawning process:", shell, "with command:", command);
12338
+ tarskDebugLog("CLI ProcessManager: Spawning process:", shell, "with command:", command);
11948
12339
  const childProcess = spawnProcess(shell, [...shellArgs, command], {
11949
12340
  cwd,
11950
12341
  env: Object.fromEntries(
@@ -11953,7 +12344,7 @@ var ProcessManager = class extends EventEmitter {
11953
12344
  stdio: ["ignore", "pipe", "pipe"]
11954
12345
  });
11955
12346
  this.processes.set(projectId, childProcess);
11956
- console.log("CLI ProcessManager: Process spawned with PID:", childProcess.pid);
12347
+ tarskDebugLog("CLI ProcessManager: Process spawned with PID:", childProcess.pid);
11957
12348
  let urlDetected = false;
11958
12349
  let urlBuffer = "";
11959
12350
  childProcess.stdout?.on("data", (data) => {
@@ -12087,13 +12478,13 @@ var ProcessManager = class extends EventEmitter {
12087
12478
  // src/features/projects/projects.creator.ts
12088
12479
  init_utils();
12089
12480
  import { randomUUID as randomUUID7 } from "crypto";
12090
- 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";
12091
12482
  import { access as access3, stat as stat3, readdir as readdir8 } from "fs/promises";
12092
12483
 
12093
12484
  // src/features/scaffold/scaffold.runner.ts
12094
12485
  init_utils();
12095
- import { existsSync as existsSync12 } from "fs";
12096
- import { join as join18 } from "path";
12486
+ import { existsSync as existsSync13 } from "fs";
12487
+ import { join as join19 } from "path";
12097
12488
  import { mkdir as mkdir2, readdir as readdir7, stat as stat2, rename, rm as rm2, writeFile as writeFile3 } from "fs/promises";
12098
12489
  import { createInterface as createInterface2 } from "readline";
12099
12490
 
@@ -12815,8 +13206,8 @@ function loadCatalog() {
12815
13206
  }
12816
13207
  async function writeAgentsMd(projectPath, agentsMd) {
12817
13208
  if (!agentsMd) return;
12818
- const agentsPath = join18(projectPath, "AGENTS.md");
12819
- if (existsSync12(agentsPath)) return;
13209
+ const agentsPath = join19(projectPath, "AGENTS.md");
13210
+ if (existsSync13(agentsPath)) return;
12820
13211
  await writeFile3(agentsPath, agentsMd, "utf-8");
12821
13212
  }
12822
13213
  function getProjectName(name) {
@@ -12973,8 +13364,8 @@ async function* runCommandStreaming(cwd, command) {
12973
13364
  }
12974
13365
  }
12975
13366
  async function* createScaffoldedProjectStreaming(options) {
12976
- const projectPath = join18(options.parentDir, options.threadId);
12977
- if (!existsSync12(options.parentDir)) {
13367
+ const projectPath = join19(options.parentDir, options.threadId);
13368
+ if (!existsSync13(options.parentDir)) {
12978
13369
  yield {
12979
13370
  type: "result",
12980
13371
  result: {
@@ -13063,7 +13454,7 @@ async function* createScaffoldedProjectStreaming(options) {
13063
13454
  }
13064
13455
  try {
13065
13456
  const projectName2 = getProjectName(options.projectName);
13066
- const projectSubDir = join18(projectPath, projectName2);
13457
+ const projectSubDir = join19(projectPath, projectName2);
13067
13458
  try {
13068
13459
  const subDirStat = await stat2(projectSubDir);
13069
13460
  if (subDirStat.isDirectory()) {
@@ -13073,8 +13464,8 @@ async function* createScaffoldedProjectStreaming(options) {
13073
13464
  };
13074
13465
  const items = await readdir7(projectSubDir);
13075
13466
  for (const item of items) {
13076
- const oldPath = join18(projectSubDir, item);
13077
- const newPath = join18(projectPath, item);
13467
+ const oldPath = join19(projectSubDir, item);
13468
+ const newPath = join19(projectPath, item);
13078
13469
  await rename(oldPath, newPath);
13079
13470
  }
13080
13471
  await rm2(projectSubDir, { recursive: true, force: true });
@@ -13090,7 +13481,7 @@ async function* createScaffoldedProjectStreaming(options) {
13090
13481
  };
13091
13482
  }
13092
13483
  const installCwd = scaffoldOptions.projectPath;
13093
- if (existsSync12(installCwd)) {
13484
+ if (existsSync13(installCwd)) {
13094
13485
  const installCmd = getInstallCommand(options.packageManager);
13095
13486
  yield { type: "progress", message: `
13096
13487
  > ${installCmd}` };
@@ -13542,7 +13933,7 @@ var ProjectCreator = class {
13542
13933
  return name;
13543
13934
  }
13544
13935
  generateThreadPath(_projectId, threadId) {
13545
- return join19(this.rootFolder, threadId);
13936
+ return join20(this.rootFolder, threadId);
13546
13937
  }
13547
13938
  async *createProjectFromFolder() {
13548
13939
  await loadUtils();
@@ -13692,19 +14083,19 @@ var ProjectCreator = class {
13692
14083
  }
13693
14084
  async findAllPackageJsonFiles(rootPath, currentPath, setupScripts) {
13694
14085
  try {
13695
- await access3(join19(currentPath, "package.json"));
14086
+ await access3(join20(currentPath, "package.json"));
13696
14087
  const relativePath = relative5(rootPath, currentPath);
13697
14088
  let installCommand = "";
13698
14089
  try {
13699
- await access3(join19(currentPath, "yarn.lock"));
14090
+ await access3(join20(currentPath, "yarn.lock"));
13700
14091
  installCommand = "yarn install";
13701
14092
  } catch {
13702
14093
  try {
13703
- await access3(join19(currentPath, "bun.lock"));
14094
+ await access3(join20(currentPath, "bun.lock"));
13704
14095
  installCommand = "bun install";
13705
14096
  } catch {
13706
14097
  try {
13707
- await access3(join19(currentPath, "pnpm-lock.yaml"));
14098
+ await access3(join20(currentPath, "pnpm-lock.yaml"));
13708
14099
  installCommand = "pnpm install";
13709
14100
  } catch {
13710
14101
  installCommand = "npm install";
@@ -13721,7 +14112,7 @@ var ProjectCreator = class {
13721
14112
  try {
13722
14113
  const entries = await readdir8(currentPath);
13723
14114
  for (const entry of entries) {
13724
- const entryPath = join19(currentPath, entry);
14115
+ const entryPath = join20(currentPath, entry);
13725
14116
  try {
13726
14117
  const stats = await stat3(entryPath);
13727
14118
  if (stats.isDirectory() && !entry.startsWith(".") && entry !== "node_modules") {
@@ -14061,7 +14452,7 @@ var ProjectManagerImpl = class {
14061
14452
  const session = this.terminalSessionManager.getOrCreateSession(threadId, thread.path);
14062
14453
  let workingDir;
14063
14454
  if (cwd) {
14064
- workingDir = cwd.startsWith("/") ? cwd : join20(thread.path, cwd);
14455
+ workingDir = cwd.startsWith("/") ? cwd : join21(thread.path, cwd);
14065
14456
  this.terminalSessionManager.updateWorkingDirectory(threadId, workingDir);
14066
14457
  } else {
14067
14458
  workingDir = session.currentWorkingDirectory;
@@ -14815,9 +15206,9 @@ function createScaffoldRoutes(projectManager) {
14815
15206
 
14816
15207
  // src/features/slash-commands/slash-commands.manager.ts
14817
15208
  import { readdir as readdir9, readFile as readFile12, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
14818
- import { join as join21, basename as basename3, extname as extname4, relative as relative6 } from "path";
14819
- import { existsSync as existsSync13 } from "fs";
14820
- 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";
14821
15212
  function slugify(filename) {
14822
15213
  return filename.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
14823
15214
  }
@@ -14861,10 +15252,10 @@ function parseFrontmatter3(markdown) {
14861
15252
  return { metadata, content };
14862
15253
  }
14863
15254
  function getGlobalCommandsDir() {
14864
- return join21(homedir7(), ".agents", "commands");
15255
+ return join22(homedir8(), ".agents", "commands");
14865
15256
  }
14866
15257
  function getProjectCommandsDir(threadPath) {
14867
- return join21(threadPath, ".agents", "commands");
15258
+ return join22(threadPath, ".agents", "commands");
14868
15259
  }
14869
15260
  var SlashCommandManager = class _SlashCommandManager {
14870
15261
  /**
@@ -14895,14 +15286,14 @@ var SlashCommandManager = class _SlashCommandManager {
14895
15286
  async loadCommands(threadPath) {
14896
15287
  const commands = /* @__PURE__ */ new Map();
14897
15288
  const globalDir = getGlobalCommandsDir();
14898
- if (existsSync13(globalDir)) {
15289
+ if (existsSync14(globalDir)) {
14899
15290
  const globalCommands = await this.loadCommandsFromDir(globalDir, threadPath, "global");
14900
15291
  for (const cmd of globalCommands) {
14901
15292
  commands.set(cmd.name, cmd);
14902
15293
  }
14903
15294
  }
14904
15295
  const projectDir = getProjectCommandsDir(threadPath);
14905
- if (existsSync13(projectDir)) {
15296
+ if (existsSync14(projectDir)) {
14906
15297
  const projectCommands = await this.loadCommandsFromDir(projectDir, threadPath, "project");
14907
15298
  for (const cmd of projectCommands) {
14908
15299
  if (!_SlashCommandManager.BUILT_IN_COMMANDS.has(cmd.name)) {
@@ -14926,7 +15317,7 @@ var SlashCommandManager = class _SlashCommandManager {
14926
15317
  const files = await readdir9(dir);
14927
15318
  for (const file of files) {
14928
15319
  if (!file.endsWith(".md")) continue;
14929
- const filePath = join21(dir, file);
15320
+ const filePath = join22(dir, file);
14930
15321
  const fileContent = await readFile12(filePath, "utf-8");
14931
15322
  const { metadata, content } = parseFrontmatter3(fileContent);
14932
15323
  const nameWithoutExt = basename3(file, extname4(file));
@@ -14957,12 +15348,12 @@ var SlashCommandManager = class _SlashCommandManager {
14957
15348
  if (!dir) {
14958
15349
  throw new Error("threadPath required for project-scoped commands");
14959
15350
  }
14960
- if (!existsSync13(dir)) {
15351
+ if (!existsSync14(dir)) {
14961
15352
  await mkdir3(dir, { recursive: true });
14962
15353
  }
14963
15354
  const filename = `${name}.md`;
14964
- const filePath = join21(dir, filename);
14965
- if (existsSync13(filePath)) {
15355
+ const filePath = join22(dir, filename);
15356
+ if (existsSync14(filePath)) {
14966
15357
  throw new Error(`Command already exists: ${name}`);
14967
15358
  }
14968
15359
  let markdown = "";
@@ -14996,7 +15387,7 @@ var SlashCommandManager = class _SlashCommandManager {
14996
15387
  * Update an existing command
14997
15388
  */
14998
15389
  async updateCommand(filePath, content, metadata) {
14999
- if (!existsSync13(filePath)) {
15390
+ if (!existsSync14(filePath)) {
15000
15391
  throw new Error(`Command file not found: ${filePath}`);
15001
15392
  }
15002
15393
  let markdown = "";
@@ -15023,7 +15414,7 @@ var SlashCommandManager = class _SlashCommandManager {
15023
15414
  * Delete a command
15024
15415
  */
15025
15416
  async deleteCommand(filePath) {
15026
- if (!existsSync13(filePath)) {
15417
+ if (!existsSync14(filePath)) {
15027
15418
  throw new Error(`Command file not found: ${filePath}`);
15028
15419
  }
15029
15420
  await unlink2(filePath);
@@ -15556,7 +15947,7 @@ function createRuleRoutes(router, projectManager) {
15556
15947
  // src/features/threads/threads.manager.ts
15557
15948
  init_utils();
15558
15949
  import { randomUUID as randomUUID8 } from "crypto";
15559
- import { join as join22 } from "path";
15950
+ import { join as join23 } from "path";
15560
15951
  import { execSync as execSync3 } from "child_process";
15561
15952
  import { rm as rm4, stat as stat4, mkdir as mkdir4 } from "fs/promises";
15562
15953
  init_database();
@@ -15963,7 +16354,7 @@ var ThreadManagerImpl = class {
15963
16354
  * - 7.4 - THE CLI SHALL ensure each Thread clone is stored in a unique directory path
15964
16355
  */
15965
16356
  generateThreadPath(_projectId, threadId) {
15966
- return join22(this.rootFolder, threadId);
16357
+ return join23(this.rootFolder, threadId);
15967
16358
  }
15968
16359
  /**
15969
16360
  * Generates a thread title if not provided
@@ -16157,8 +16548,8 @@ async function handleDeleteThread(c, threadManager) {
16157
16548
 
16158
16549
  // src/core/project-inspector.ts
16159
16550
  import { readFile as readFile13, readdir as readdir10 } from "fs/promises";
16160
- import { existsSync as existsSync14 } from "fs";
16161
- 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";
16162
16553
  import { glob as glob2 } from "glob";
16163
16554
 
16164
16555
  // src/features/project-scripts/project-scripts.database.ts
@@ -16202,13 +16593,13 @@ async function inspectProject(projectPath, projectId) {
16202
16593
  return scripts;
16203
16594
  }
16204
16595
  async function detectPackageManager2(projectPath) {
16205
- if (existsSync14(join23(projectPath, "bun.lockb")) || existsSync14(join23(projectPath, "bun.lock"))) {
16596
+ if (existsSync15(join24(projectPath, "bun.lockb")) || existsSync15(join24(projectPath, "bun.lock"))) {
16206
16597
  return "bun";
16207
16598
  }
16208
- if (existsSync14(join23(projectPath, "pnpm-lock.yaml"))) {
16599
+ if (existsSync15(join24(projectPath, "pnpm-lock.yaml"))) {
16209
16600
  return "pnpm";
16210
16601
  }
16211
- if (existsSync14(join23(projectPath, "yarn.lock"))) {
16602
+ if (existsSync15(join24(projectPath, "yarn.lock"))) {
16212
16603
  return "yarn";
16213
16604
  }
16214
16605
  try {
@@ -16227,8 +16618,8 @@ async function detectPackageManager2(projectPath) {
16227
16618
  return "npm";
16228
16619
  }
16229
16620
  async function detectMonoRepoType(projectPath) {
16230
- const hasPnpmWorkspace = existsSync14(join23(projectPath, "pnpm-workspace.yaml"));
16231
- if (existsSync14(join23(projectPath, "nx.json"))) {
16621
+ const hasPnpmWorkspace = existsSync15(join24(projectPath, "pnpm-workspace.yaml"));
16622
+ if (existsSync15(join24(projectPath, "nx.json"))) {
16232
16623
  return "nx";
16233
16624
  }
16234
16625
  const pkg = await readPackageJson(projectPath);
@@ -16242,10 +16633,10 @@ async function detectMonoRepoType(projectPath) {
16242
16633
  if (hasPnpmWorkspace) {
16243
16634
  return "pnpm";
16244
16635
  }
16245
- if (existsSync14(join23(projectPath, "lerna.json"))) {
16636
+ if (existsSync15(join24(projectPath, "lerna.json"))) {
16246
16637
  return "lerna";
16247
16638
  }
16248
- if (existsSync14(join23(projectPath, "turbo.json"))) {
16639
+ if (existsSync15(join24(projectPath, "turbo.json"))) {
16249
16640
  return "turbo";
16250
16641
  }
16251
16642
  const folderWorkspaces = await detectFolderBasedWorkspaces(projectPath);
@@ -16286,8 +16677,8 @@ async function resolvePackageJsonWorkspaces(projectPath) {
16286
16677
  });
16287
16678
  const workspaces = [];
16288
16679
  for (const folder of folders) {
16289
- const absPath = join23(projectPath, folder);
16290
- if (existsSync14(join23(absPath, "package.json"))) {
16680
+ const absPath = join24(projectPath, folder);
16681
+ if (existsSync15(join24(absPath, "package.json"))) {
16291
16682
  workspaces.push({
16292
16683
  name: basename4(folder),
16293
16684
  folder: absPath,
@@ -16302,8 +16693,8 @@ async function resolvePackageJsonWorkspaces(projectPath) {
16302
16693
  return workspaces;
16303
16694
  }
16304
16695
  async function resolvePnpmWorkspaces(projectPath) {
16305
- const yamlPath = join23(projectPath, "pnpm-workspace.yaml");
16306
- if (!existsSync14(yamlPath)) {
16696
+ const yamlPath = join24(projectPath, "pnpm-workspace.yaml");
16697
+ if (!existsSync15(yamlPath)) {
16307
16698
  return [{ name: "root", folder: projectPath, relativePath: "." }];
16308
16699
  }
16309
16700
  try {
@@ -16328,8 +16719,8 @@ async function resolvePnpmWorkspaces(projectPath) {
16328
16719
  });
16329
16720
  const workspaces = [];
16330
16721
  for (const folder of folders) {
16331
- const absPath = join23(projectPath, folder);
16332
- if (existsSync14(join23(absPath, "package.json"))) {
16722
+ const absPath = join24(projectPath, folder);
16723
+ if (existsSync15(join24(absPath, "package.json"))) {
16333
16724
  const wsPkg = await readPackageJson(absPath);
16334
16725
  workspaces.push({
16335
16726
  name: wsPkg?.name ?? basename4(folder),
@@ -16348,8 +16739,8 @@ async function resolvePnpmWorkspaces(projectPath) {
16348
16739
  }
16349
16740
  }
16350
16741
  async function resolveLernaWorkspaces(projectPath) {
16351
- const lernaPath = join23(projectPath, "lerna.json");
16352
- if (!existsSync14(lernaPath)) {
16742
+ const lernaPath = join24(projectPath, "lerna.json");
16743
+ if (!existsSync15(lernaPath)) {
16353
16744
  return [{ name: "root", folder: projectPath, relativePath: "." }];
16354
16745
  }
16355
16746
  try {
@@ -16362,8 +16753,8 @@ async function resolveLernaWorkspaces(projectPath) {
16362
16753
  });
16363
16754
  const workspaces = [];
16364
16755
  for (const folder of folders) {
16365
- const absPath = join23(projectPath, folder);
16366
- if (existsSync14(join23(absPath, "package.json"))) {
16756
+ const absPath = join24(projectPath, folder);
16757
+ if (existsSync15(join24(absPath, "package.json"))) {
16367
16758
  const wsPkg = await readPackageJson(absPath);
16368
16759
  workspaces.push({
16369
16760
  name: wsPkg?.name ?? basename4(folder),
@@ -16383,8 +16774,8 @@ async function resolveLernaWorkspaces(projectPath) {
16383
16774
  }
16384
16775
  async function resolveNxWorkspaces(projectPath) {
16385
16776
  const workspaces = [];
16386
- const workspaceJsonPath = join23(projectPath, "workspace.json");
16387
- if (existsSync14(workspaceJsonPath)) {
16777
+ const workspaceJsonPath = join24(projectPath, "workspace.json");
16778
+ if (existsSync15(workspaceJsonPath)) {
16388
16779
  try {
16389
16780
  const content = await readFile13(workspaceJsonPath, "utf-8");
16390
16781
  const wsJson = JSON.parse(content);
@@ -16393,7 +16784,7 @@ async function resolveNxWorkspaces(projectPath) {
16393
16784
  if (folder) {
16394
16785
  workspaces.push({
16395
16786
  name,
16396
- folder: join23(projectPath, folder),
16787
+ folder: join24(projectPath, folder),
16397
16788
  relativePath: folder
16398
16789
  });
16399
16790
  }
@@ -16408,13 +16799,13 @@ async function resolveNxWorkspaces(projectPath) {
16408
16799
  });
16409
16800
  for (const file of projectJsonFiles) {
16410
16801
  try {
16411
- const content = await readFile13(join23(projectPath, file), "utf-8");
16802
+ const content = await readFile13(join24(projectPath, file), "utf-8");
16412
16803
  const project = JSON.parse(content);
16413
16804
  if (project.name) {
16414
16805
  const folder = file.replace(/\/project\.json$/, "");
16415
16806
  workspaces.push({
16416
16807
  name: project.name,
16417
- folder: join23(projectPath, folder),
16808
+ folder: join24(projectPath, folder),
16418
16809
  relativePath: folder
16419
16810
  });
16420
16811
  }
@@ -16422,15 +16813,15 @@ async function resolveNxWorkspaces(projectPath) {
16422
16813
  }
16423
16814
  }
16424
16815
  if (workspaces.length > 0) return workspaces;
16425
- const appsDir = join23(projectPath, "apps");
16426
- if (existsSync14(appsDir)) {
16816
+ const appsDir = join24(projectPath, "apps");
16817
+ if (existsSync15(appsDir)) {
16427
16818
  const entries = await readdir10(appsDir, { withFileTypes: true });
16428
16819
  for (const entry of entries) {
16429
16820
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
16430
- const folder = join23("apps", entry.name);
16821
+ const folder = join24("apps", entry.name);
16431
16822
  workspaces.push({
16432
16823
  name: entry.name,
16433
- folder: join23(projectPath, folder),
16824
+ folder: join24(projectPath, folder),
16434
16825
  relativePath: folder
16435
16826
  });
16436
16827
  }
@@ -16464,13 +16855,13 @@ async function detectFolderBasedWorkspaces(projectPath) {
16464
16855
  const results = [];
16465
16856
  for (const entry of entries) {
16466
16857
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "build") {
16467
- const pkgPath = join23(projectPath, entry.name, "package.json");
16468
- if (existsSync14(pkgPath)) {
16858
+ const pkgPath = join24(projectPath, entry.name, "package.json");
16859
+ if (existsSync15(pkgPath)) {
16469
16860
  try {
16470
16861
  const content = await readFile13(pkgPath, "utf-8");
16471
16862
  const pkg = JSON.parse(content);
16472
16863
  if (pkg.dependencies || pkg.devDependencies || pkg.scripts) {
16473
- results.push({ name: entry.name, absPath: join23(projectPath, entry.name) });
16864
+ results.push({ name: entry.name, absPath: join24(projectPath, entry.name) });
16474
16865
  }
16475
16866
  } catch {
16476
16867
  }
@@ -16526,7 +16917,7 @@ function pmRunCommand(packageManager, scriptName) {
16526
16917
  }
16527
16918
  async function readPackageJson(dir) {
16528
16919
  try {
16529
- const content = await readFile13(join23(dir, "package.json"), "utf-8");
16920
+ const content = await readFile13(join24(dir, "package.json"), "utf-8");
16530
16921
  return JSON.parse(content);
16531
16922
  } catch {
16532
16923
  return null;
@@ -16748,7 +17139,7 @@ async function handleListThreadFiles(c, threadManager) {
16748
17139
 
16749
17140
  // src/features/threads/threads-explorer.route.ts
16750
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";
16751
- import { join as join24 } from "path";
17142
+ import { join as join25 } from "path";
16752
17143
  import { spawn as spawn2 } from "child_process";
16753
17144
  var Utils3 = null;
16754
17145
  var utilsLoaded3 = false;
@@ -16811,7 +17202,7 @@ async function handleListThreadExplorerDir(c, threadManager) {
16811
17202
  const entries = dirents.filter((d) => !(isRoot && d.name === ".git")).map((d) => ({
16812
17203
  name: d.name,
16813
17204
  type: d.isDirectory() ? "folder" : "file",
16814
- path: queryPath ? join24(queryPath, d.name) : d.name
17205
+ path: queryPath ? join25(queryPath, d.name) : d.name
16815
17206
  })).sort((a, b) => {
16816
17207
  if (a.type !== b.type) return a.type === "folder" ? -1 : 1;
16817
17208
  return a.name.localeCompare(b.name);
@@ -16957,7 +17348,7 @@ async function handleCreateExplorerFile(c, threadManager) {
16957
17348
  absParent = validated;
16958
17349
  }
16959
17350
  await mkdir5(absParent, { recursive: true });
16960
- await writeFile5(join24(absParent, name), "", "utf-8");
17351
+ await writeFile5(join25(absParent, name), "", "utf-8");
16961
17352
  const relPath = dirPath ? `${dirPath}/${name}` : name;
16962
17353
  return c.json({ success: true, path: relPath });
16963
17354
  } catch (error) {
@@ -17059,7 +17450,7 @@ async function handleCreateExplorerFolder(c, threadManager) {
17059
17450
  }
17060
17451
  absParent = validated;
17061
17452
  }
17062
- await mkdir5(join24(absParent, name), { recursive: true });
17453
+ await mkdir5(join25(absParent, name), { recursive: true });
17063
17454
  const relPath = dirPath ? `${dirPath}/${name}` : name;
17064
17455
  return c.json({ success: true, path: relPath });
17065
17456
  } catch (error) {
@@ -17233,12 +17624,12 @@ async function handleFixComments(c, threadManager) {
17233
17624
 
17234
17625
  // src/features/threads/threads-ai-files.route.ts
17235
17626
  import { readFile as readFile15, writeFile as writeFile7, mkdir as mkdir7, access as access5, rm as rm6 } from "fs/promises";
17236
- import { join as join26 } from "path";
17237
- import { existsSync as existsSync15 } from "fs";
17627
+ import { join as join27 } from "path";
17628
+ import { existsSync as existsSync16 } from "fs";
17238
17629
 
17239
17630
  // src/features/git/git-download-folder.ts
17240
17631
  import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
17241
- import { join as join25, dirname as dirname4 } from "path";
17632
+ import { join as join26, dirname as dirname4 } from "path";
17242
17633
  async function downloadGithubFolder(repoUrl, srcPath, destPath, options = {}) {
17243
17634
  const { token, ref } = options;
17244
17635
  const match = repoUrl.replace(/\.git$/, "").match(/github\.com\/([^/]+)\/([^/]+)/);
@@ -17274,7 +17665,7 @@ async function downloadGithubFolder(repoUrl, srcPath, destPath, options = {}) {
17274
17665
  await Promise.all(
17275
17666
  files.map(async (file) => {
17276
17667
  const relativePath = file.path.slice(prefix.length);
17277
- const localPath = join25(destPath, relativePath);
17668
+ const localPath = join26(destPath, relativePath);
17278
17669
  await mkdir6(dirname4(localPath), { recursive: true });
17279
17670
  const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${refParam}/${file.path}`;
17280
17671
  const fileRes = await fetch(rawUrl, { headers });
@@ -17416,7 +17807,7 @@ async function handleSaveThreadAIFile(c, threadManager) {
17416
17807
  if (!absPath) {
17417
17808
  return c.json({ error: { code: "BAD_REQUEST", message: "Invalid file path" } }, 400);
17418
17809
  }
17419
- const parentDir = join26(absPath, "..");
17810
+ const parentDir = join27(absPath, "..");
17420
17811
  await mkdir7(parentDir, { recursive: true });
17421
17812
  await writeFile7(absPath, content, "utf-8");
17422
17813
  return c.json({ success: true, path: filePath });
@@ -17505,11 +17896,11 @@ async function handleCreateThreadAgent(c, threadManager) {
17505
17896
  if (!thread) {
17506
17897
  return errorResponse(c, ErrorCodes.THREAD_NOT_FOUND, `Thread not found: ${threadId}`, 404);
17507
17898
  }
17508
- const agentRelPath = join26(".agents", "agents", name);
17509
- const agentAbsPath = join26(thread.path, agentRelPath);
17510
- const agentFileRelPath = join26(agentRelPath, "AGENT.md");
17511
- const agentFileAbsPath = join26(agentAbsPath, "AGENT.md");
17512
- 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)) {
17513
17904
  return c.json(
17514
17905
  { error: { code: "CONFLICT", message: `Agent '${name}' already exists` } },
17515
17906
  409
@@ -17575,11 +17966,11 @@ async function handleCreateThreadSkill(c, threadManager) {
17575
17966
  if (!thread) {
17576
17967
  return errorResponse(c, ErrorCodes.THREAD_NOT_FOUND, `Thread not found: ${threadId}`, 404);
17577
17968
  }
17578
- const skillRelPath = join26(".agents", "skills", name);
17579
- const skillAbsPath = join26(thread.path, skillRelPath);
17580
- const skillFileRelPath = join26(skillRelPath, "SKILL.md");
17581
- const skillFileAbsPath = join26(skillAbsPath, "SKILL.md");
17582
- 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)) {
17583
17974
  return c.json(
17584
17975
  { error: { code: "CONFLICT", message: `Skill '${name}' already exists` } },
17585
17976
  409
@@ -18257,12 +18648,12 @@ async function gitUserHandler(c) {
18257
18648
  }
18258
18649
 
18259
18650
  // src/features/git/git-status.route.ts
18260
- import { existsSync as existsSync17 } from "fs";
18651
+ import { existsSync as existsSync18 } from "fs";
18261
18652
 
18262
18653
  // src/features/git/git.utils.ts
18263
18654
  init_utils();
18264
- import { existsSync as existsSync16, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
18265
- 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";
18266
18657
  import { completeSimple } from "@mariozechner/pi-ai";
18267
18658
  async function resolveModelAndKey(provider, modelId, metadataManager) {
18268
18659
  const providerConfig = await resolveProviderConfig(provider);
@@ -18519,8 +18910,8 @@ async function getUntrackedFilesDiff(gitRoot) {
18519
18910
  const parts = [];
18520
18911
  const maxFileSize = 1e5;
18521
18912
  for (const relPath of untrackedPaths) {
18522
- const fullPath = join27(gitRoot, relPath);
18523
- if (!existsSync16(fullPath)) continue;
18913
+ const fullPath = join28(gitRoot, relPath);
18914
+ if (!existsSync17(fullPath)) continue;
18524
18915
  try {
18525
18916
  if (statSync4(fullPath).isDirectory()) continue;
18526
18917
  const content = readFileSync5(fullPath, "utf-8");
@@ -19059,7 +19450,7 @@ async function gitStatusHandler(c, metadataManager) {
19059
19450
  return c.json({ error: "Thread path not found" }, 404);
19060
19451
  }
19061
19452
  const absolutePath = resolveThreadPath(repoPath);
19062
- if (!existsSync17(absolutePath)) {
19453
+ if (!existsSync18(absolutePath)) {
19063
19454
  return c.json(
19064
19455
  {
19065
19456
  error: `Thread repo path does not exist: ${absolutePath}. Check that the project folder is present.`
@@ -19263,22 +19654,21 @@ async function gitDiffHandler(c, metadataManager) {
19263
19654
  }
19264
19655
 
19265
19656
  // src/features/git/git-generate-commit-message.route.ts
19266
- import { existsSync as existsSync18 } from "fs";
19657
+ init_tarsk_debug();
19658
+ import { existsSync as existsSync19 } from "fs";
19267
19659
  async function gitGenerateCommitMessageHandler(c, metadataManager) {
19268
19660
  try {
19269
19661
  const threadId = c.req.param("threadId");
19270
- process.stdout.write(`[generate-commit-message] threadId=${threadId}
19662
+ tarskDebugWrite(`[generate-commit-message] threadId=${threadId}
19271
19663
  `);
19272
19664
  const thread = await metadataManager.loadThreads().then((threads) => threads.find((t) => t.id === threadId));
19273
19665
  if (!thread) {
19274
- process.stdout.write("[generate-commit-message] thread not found\n");
19666
+ tarskDebugWrite("[generate-commit-message] thread not found\n");
19275
19667
  return c.json({ error: "Thread not found" }, 404);
19276
- } else {
19277
- console.log(thread);
19278
19668
  }
19279
19669
  const repoPath = thread.path;
19280
19670
  if (!repoPath) {
19281
- process.stdout.write("[generate-commit-message] thread path missing\n");
19671
+ tarskDebugWrite("[generate-commit-message] thread path missing\n");
19282
19672
  return c.json({ error: "Thread path not found" }, 404);
19283
19673
  }
19284
19674
  const body = await c.req.json().catch(() => ({}));
@@ -19288,10 +19678,10 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19288
19678
  }
19289
19679
  const model = body.model ?? thread.model;
19290
19680
  const absolutePath = resolveThreadPath(repoPath);
19291
- process.stdout.write(`[generate-commit-message] resolved path: ${absolutePath}
19681
+ tarskDebugWrite(`[generate-commit-message] resolved path: ${absolutePath}
19292
19682
  `);
19293
- if (!existsSync18(absolutePath)) {
19294
- 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}
19295
19685
  `);
19296
19686
  return c.json(
19297
19687
  {
@@ -19303,11 +19693,11 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19303
19693
  let gitRoot;
19304
19694
  try {
19305
19695
  gitRoot = await getGitRoot(absolutePath);
19306
- process.stdout.write(`[generate-commit-message] git root: ${gitRoot}
19696
+ tarskDebugWrite(`[generate-commit-message] git root: ${gitRoot}
19307
19697
  `);
19308
19698
  } catch (e) {
19309
19699
  const msg = e instanceof Error ? e.message : String(e);
19310
- process.stdout.write(`[generate-commit-message] not a git repo: ${msg}
19700
+ tarskDebugWrite(`[generate-commit-message] not a git repo: ${msg}
19311
19701
  `);
19312
19702
  return c.json(
19313
19703
  {
@@ -19320,24 +19710,22 @@ async function gitGenerateCommitMessageHandler(c, metadataManager) {
19320
19710
  if (!diff.trim()) {
19321
19711
  const untrackedDiff = await getUntrackedFilesDiff(gitRoot);
19322
19712
  if (untrackedDiff) {
19323
- process.stdout.write(`[generate-commit-message] building diff for untracked files
19713
+ tarskDebugWrite(`[generate-commit-message] building diff for untracked files
19324
19714
  `);
19325
19715
  diff = untrackedDiff;
19326
19716
  }
19327
19717
  }
19328
19718
  if (!diff.trim()) {
19329
- 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");
19330
19720
  return c.json({ error: "No changes to generate commit message for" }, 400);
19331
19721
  }
19332
- process.stdout.write(
19722
+ tarskDebugWrite(
19333
19723
  `[generate-commit-message] diff length=${diff.length} chars, generating message with AI
19334
19724
  `
19335
19725
  );
19336
19726
  const commitMessage = await generateCommitMessageWithAI(diff, metadataManager, model, provider);
19337
- process.stdout.write(
19338
- `[generate-commit-message] generated: ${commitMessage.replace(/\n/g, " ")}
19339
- `
19340
- );
19727
+ tarskDebugWrite(`[generate-commit-message] generated: ${commitMessage.replace(/\n/g, " ")}
19728
+ `);
19341
19729
  return c.json({ message: commitMessage });
19342
19730
  } catch (error) {
19343
19731
  const message = error instanceof Error ? error.message : "Failed to generate commit message";
@@ -19771,7 +20159,7 @@ async function gitGithubStatusHandler(c, metadataManager) {
19771
20159
  }
19772
20160
 
19773
20161
  // src/features/git/git-unified-status.route.ts
19774
- import { existsSync as existsSync19 } from "fs";
20162
+ import { existsSync as existsSync20 } from "fs";
19775
20163
  async function gitUnifiedStatusHandler(c, metadataManager, db) {
19776
20164
  try {
19777
20165
  const threadId = c.req.param("threadId");
@@ -19799,7 +20187,7 @@ async function gitUnifiedStatusHandler(c, metadataManager, db) {
19799
20187
  return c.json({ error: "Thread path not found" }, 404);
19800
20188
  }
19801
20189
  const absolutePath = resolveThreadPath(repoPath);
19802
- if (!existsSync19(absolutePath)) {
20190
+ if (!existsSync20(absolutePath)) {
19803
20191
  return c.json(
19804
20192
  {
19805
20193
  error: `Thread repo path does not exist: ${absolutePath}. Check that the project folder is present.`
@@ -20145,7 +20533,7 @@ async function gitCreateBranchHandler(c, metadataManager) {
20145
20533
  }
20146
20534
 
20147
20535
  // src/features/git/git-sync-branch.route.ts
20148
- import { existsSync as existsSync20 } from "fs";
20536
+ import { existsSync as existsSync21 } from "fs";
20149
20537
  async function gitSyncBranchHandler(c, metadataManager) {
20150
20538
  try {
20151
20539
  const threadId = c.req.param("threadId");
@@ -20162,7 +20550,7 @@ async function gitSyncBranchHandler(c, metadataManager) {
20162
20550
  }
20163
20551
  const absolutePath = resolveThreadPath(repoPath);
20164
20552
  console.log(`[sync-branch] Resolved path: ${absolutePath}`);
20165
- if (!existsSync20(absolutePath)) {
20553
+ if (!existsSync21(absolutePath)) {
20166
20554
  console.log(`[sync-branch] Path does not exist: ${absolutePath}`);
20167
20555
  return c.json(
20168
20556
  {
@@ -20766,9 +21154,12 @@ function createGitRoutes(metadataManager) {
20766
21154
  return gitGenerateCommitMessageHandler(c, metadataManager);
20767
21155
  });
20768
21156
  router.post("/commit/:threadId", async (c) => {
20769
- const db = await getDatabase();
20770
- await invalidateGitStatusCache(db, c.req.param("threadId"));
20771
- 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;
20772
21163
  });
20773
21164
  router.post("/push/:threadId", async (c) => {
20774
21165
  const db = await getDatabase();
@@ -20879,7 +21270,7 @@ function createUpdateRoutes(updater) {
20879
21270
  // src/features/mcp/mcp.routes.ts
20880
21271
  import { Hono as Hono13 } from "hono";
20881
21272
  import { readFile as readFile16, writeFile as writeFile8, mkdir as mkdir9, access as access6 } from "fs/promises";
20882
- import { join as join28, dirname as dirname6 } from "path";
21273
+ import { join as join29, dirname as dirname6 } from "path";
20883
21274
 
20884
21275
  // src/features/mcp/mcp.popular.json
20885
21276
  var mcp_popular_default = [
@@ -20990,7 +21381,7 @@ var mcp_popular_default = [
20990
21381
  var MCP_CONFIG_PATHS2 = [".agents/mcp.json", "mcp.json"];
20991
21382
  async function readMCPConfig(projectPath) {
20992
21383
  for (const configPath of MCP_CONFIG_PATHS2) {
20993
- const fullPath = join28(projectPath, configPath);
21384
+ const fullPath = join29(projectPath, configPath);
20994
21385
  try {
20995
21386
  await access6(fullPath);
20996
21387
  const content = await readFile16(fullPath, "utf-8");
@@ -21004,7 +21395,7 @@ async function readMCPConfig(projectPath) {
21004
21395
  }
21005
21396
  async function writeMCPConfig(projectPath, config) {
21006
21397
  const existing = await readMCPConfig(projectPath);
21007
- const targetPath = existing?.filePath ?? join28(projectPath, ".agents/mcp.json");
21398
+ const targetPath = existing?.filePath ?? join29(projectPath, ".agents/mcp.json");
21008
21399
  await mkdir9(dirname6(targetPath), { recursive: true });
21009
21400
  await writeFile8(targetPath, JSON.stringify(config, null, 2), "utf-8");
21010
21401
  }
@@ -21678,7 +22069,7 @@ async function clipboardWriteImage(c) {
21678
22069
  }
21679
22070
 
21680
22071
  // src/features/image/image-save.route.ts
21681
- import { join as join29 } from "path";
22072
+ import { join as join30 } from "path";
21682
22073
  var Utils5 = null;
21683
22074
  var utilsLoaded5 = false;
21684
22075
  async function loadUtils5() {
@@ -21715,7 +22106,7 @@ async function saveImage(c) {
21715
22106
  return c.json({ error: "imageUrl or imageData is required" }, 400);
21716
22107
  }
21717
22108
  const name = filename ?? `generated-image-${Date.now()}.png`;
21718
- const savePath = join29(Utils5.paths.downloads, name);
22109
+ const savePath = join30(Utils5.paths.downloads, name);
21719
22110
  await Bun.write(savePath, data);
21720
22111
  return c.json({ success: true, path: savePath });
21721
22112
  } catch (error) {
@@ -21857,7 +22248,10 @@ function createLogsRoutes() {
21857
22248
  return c.json({ ok: false, error: "invalid json" }, 400);
21858
22249
  }
21859
22250
  const { level = "INFO", context = "app", message = "", data } = body;
21860
- 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}`;
21861
22255
  if (data !== void 0 && data !== "") {
21862
22256
  try {
21863
22257
  line += ` | ${JSON.stringify(data)}`;
@@ -21951,7 +22345,10 @@ async function startTarskServer(options) {
21951
22345
  "/api/chat",
21952
22346
  createChatRoutes(threadManager, agentExecutor, conversationManager, processingStateManager)
21953
22347
  );
21954
- app.route("/api/conversations", createConversationRoutes(conversationManager, threadManager));
22348
+ app.route(
22349
+ "/api/conversations",
22350
+ createConversationRoutes(conversationManager, threadManager, metadataManager)
22351
+ );
21955
22352
  app.route("/api/providers", createProviderRoutes(metadataManager));
21956
22353
  app.route("/api/models", createModelRoutes(metadataManager));
21957
22354
  app.route("/api/mcp", createMCPRoutes());