tarsk 0.4.29 → 0.4.31
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.
- package/dist/index.js +746 -349
- package/dist/public/assets/{account-view-YvC0mymF.js → account-view-Cdp8xegU.js} +1 -1
- package/dist/public/assets/alert-dialog-DAJFcjdR.js +1 -0
- package/dist/public/assets/api-BYFUablr.js +1 -0
- package/dist/public/assets/{browser-tab-CCXMlmPO.js → browser-tab-Ban23pgA.js} +1 -1
- package/dist/public/assets/chat-input-container-Bc7nCdKX.js +21 -0
- package/dist/public/assets/context-menu-D93N09Jw.js +1 -0
- package/dist/public/assets/conversation-history-view-qm_qW0aD.js +1 -0
- package/dist/public/assets/{dialogs-config-B91VQpxo.js → dialogs-config-VlhyoYms.js} +14 -14
- package/dist/public/assets/diff-view-DUmzPmed.js +3 -0
- package/dist/public/assets/explorer-tab-view-Bbboiq-d.js +2 -0
- package/dist/public/assets/explorer-tree-CX03Vh31.js +1 -0
- package/dist/public/assets/{explorer-view-BCJqE1-z.js → explorer-view-CMcJFEtT.js} +1 -1
- package/dist/public/assets/history-view-Cub-F9g6.js +1 -0
- package/dist/public/assets/index-C-dv630o.css +1 -0
- package/dist/public/assets/index-DaJT5K7g.js +29 -0
- package/dist/public/assets/{markdown-renderer-9nzN0Pk3.js → markdown-renderer-BPXg5AUu.js} +4 -4
- package/dist/public/assets/{mcp-server-card-BSw_FlEC.js → mcp-server-card-BCZmpcVY.js} +1 -1
- package/dist/public/assets/onboarding-BPUo1aJX.js +1 -0
- package/dist/public/assets/onboarding-dialog-vqz8baom.js +1 -0
- package/dist/public/assets/page-toolbar-CU9dGLvm.js +1 -0
- package/dist/public/assets/project-settings-view-BAs5RYWR.js +1 -0
- package/dist/public/assets/providers-list-view-67A5O5vd.js +1 -0
- package/dist/public/assets/radio-group-CRwVSJCp.js +1 -0
- package/dist/public/assets/react-vendor-CtZx3FWA.js +22 -0
- package/dist/public/assets/{resizable-CEv7JjTI.js → resizable-AKojmHeo.js} +1 -1
- package/dist/public/assets/{run-stop-button-CrjPMC0m.js → run-stop-button-DYoC8i6e.js} +2 -2
- package/dist/public/assets/settings-general-view-mu1Qq8cl.js +1 -0
- package/dist/public/assets/{settings-instructions-view-C23spY9Y.js → settings-instructions-view-DQRSZId7.js} +1 -1
- package/dist/public/assets/{settings-mcp-servers-view-ZHar6YbE.js → settings-mcp-servers-view-BqJMRVZJ.js} +4 -4
- package/dist/public/assets/settings-models-skeleton-qdDMv5hS.js +1 -0
- package/dist/public/assets/settings-models-view-DSrdZZfF.js +1 -0
- package/dist/public/assets/settings-rules-view-Dt_lfKVv.js +8 -0
- package/dist/public/assets/{settings-skills-view-D60tD-OE.js → settings-skills-view-Djrk38ol.js} +2 -2
- package/dist/public/assets/{settings-slash-commands-view-DR-pzulT.js → settings-slash-commands-view-Cm5cy2My.js} +1 -1
- package/dist/public/assets/{settings-subagents-view-InXmwmw9.js → settings-subagents-view-CsGwbSvQ.js} +2 -2
- package/dist/public/assets/settings-view-DuTfugUO.js +2 -0
- package/dist/public/assets/{side-panel-container-CO3qgRvc.js → side-panel-container-Cg99BH1l.js} +2 -2
- package/dist/public/assets/skeleton-B1fuNMHm.js +1 -0
- package/dist/public/assets/{standard-list-item-DyALhVYe.js → standard-list-item-0m99qNoa.js} +1 -1
- package/dist/public/assets/{store-D28g9VUj.js → store-DUqJt-K-.js} +1 -1
- package/dist/public/assets/{tab-context-C3z7YU59.js → tab-context-BYpxvaoz.js} +1 -1
- package/dist/public/assets/tabs-ywSKq3qp.js +1 -0
- package/dist/public/assets/{terminal-panel-EifoA6G0.js → terminal-panel-C9XWZHaD.js} +2 -2
- package/dist/public/assets/textarea-DuuNwegn.js +1 -0
- package/dist/public/assets/todos-view-CRzNrsfP.js +1 -0
- package/dist/public/assets/{use-font-size-BCtvz0bm.js → use-font-size-D2A0_bAi.js} +1 -1
- package/dist/public/assets/{use-toast-BZ79E_dX.js → use-toast-BF5WtiOJ.js} +1 -1
- package/dist/public/assets/{utils-Bhu11Tpg.js → utils-CheqpoJ4.js} +1 -1
- package/dist/public/index.html +21 -21
- package/package.json +2 -2
- package/dist/public/assets/alert-dialog-BFhUZsPe.js +0 -1
- package/dist/public/assets/api-DSvSyBH5.js +0 -1
- package/dist/public/assets/chat-input-container-VwmGKJFJ.js +0 -21
- package/dist/public/assets/context-menu-B6K8j1ha.js +0 -1
- package/dist/public/assets/conversation-history-view-DrrLyMbg.js +0 -1
- package/dist/public/assets/diff-view-C09yOc5d.js +0 -3
- package/dist/public/assets/explorer-tab-view-B1DukGdo.js +0 -2
- package/dist/public/assets/explorer-tree-DCeud6YI.js +0 -1
- package/dist/public/assets/history-view-Dj4NiScy.js +0 -1
- package/dist/public/assets/index-7TFkb0ll.css +0 -1
- package/dist/public/assets/index-BLCecayZ.js +0 -29
- package/dist/public/assets/onboarding-ClUE_I5q.js +0 -1
- package/dist/public/assets/onboarding-dialog-C2jig8mT.js +0 -1
- package/dist/public/assets/page-toolbar-DnVFnCgq.js +0 -1
- package/dist/public/assets/project-settings-view-DWn0ty7b.js +0 -1
- package/dist/public/assets/providers-list-view-B0DqNJYK.js +0 -1
- package/dist/public/assets/radio-group-CM_Wwam0.js +0 -1
- package/dist/public/assets/react-vendor-nPkCWaAR.js +0 -22
- package/dist/public/assets/settings-general-view-CwQYmnI2.js +0 -1
- package/dist/public/assets/settings-models-view-Cg6WQ4cy.js +0 -1
- package/dist/public/assets/settings-rules-view-zAx5JL4w.js +0 -8
- package/dist/public/assets/settings-view-DLRDBuwH.js +0 -2
- package/dist/public/assets/skeleton-CXoVAzC1.js +0 -1
- package/dist/public/assets/tabs-sXgL2DZz.js +0 -1
- package/dist/public/assets/textarea-Bp3p1-25.js +0 -1
- package/dist/public/assets/todos-view-DRL4px6A.js +0 -1
- /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:
|
|
146
|
+
PATH: path6,
|
|
57
147
|
SHELL: process.env.SHELL ?? "/bin/zsh"
|
|
58
148
|
};
|
|
59
149
|
if (additionalEnv) {
|
|
60
|
-
|
|
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
|
|
103
|
-
import { homedir as
|
|
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 =
|
|
107
|
-
const dataDir =
|
|
108
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 &&
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
2736
|
+
exists: existsSync5,
|
|
2629
2737
|
stat: statSync2,
|
|
2630
|
-
readdir:
|
|
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
|
|
2878
|
-
import { existsSync as
|
|
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 =
|
|
2972
|
-
if (!
|
|
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 =
|
|
2981
|
-
if (!
|
|
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
|
|
3042
|
-
import { existsSync as
|
|
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 =
|
|
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 =
|
|
3076
|
-
if (!
|
|
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 =
|
|
3096
|
-
if (!
|
|
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 ?
|
|
3254
|
+
const relativePath = prefix ? join6(prefix, entry.name) : entry.name;
|
|
3147
3255
|
if (entry.isDirectory()) {
|
|
3148
|
-
const subFiles = await listReferencesRecursive(
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
5026
|
+
tarskDebugLog(`[code-search] invalidated thread index after ${toolName}`);
|
|
4907
5027
|
} catch (error) {
|
|
4908
|
-
|
|
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
|
-
|
|
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
|
|
5488
|
-
import { homedir as
|
|
5489
|
-
var APP_SUPPORT_DIR =
|
|
5490
|
-
var DATA_DIR =
|
|
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
|
|
5501
|
-
import { join as
|
|
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 =
|
|
5636
|
+
const packageJsonPath = join10(this.projectPath, "package.json");
|
|
5513
5637
|
const info = { description: "" };
|
|
5514
|
-
if (
|
|
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 ||
|
|
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 ||
|
|
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 ||
|
|
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 (
|
|
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 (
|
|
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 (
|
|
5740
|
+
} else if (existsSync8(join10(this.projectPath, "pubspec.yaml"))) {
|
|
5617
5741
|
info.projectType = "Flutter";
|
|
5618
|
-
} else if (
|
|
5742
|
+
} else if (existsSync8(join10(this.projectPath, "go.mod"))) {
|
|
5619
5743
|
info.projectType = "Go";
|
|
5620
|
-
} else if (
|
|
5744
|
+
} else if (existsSync8(join10(this.projectPath, "Cargo.toml"))) {
|
|
5621
5745
|
info.projectType = "Rust";
|
|
5622
|
-
} else if (
|
|
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 (
|
|
5748
|
+
} else if (existsSync8(join10(this.projectPath, "Gemfile"))) {
|
|
5625
5749
|
info.projectType = "Ruby";
|
|
5626
|
-
} else if (
|
|
5750
|
+
} else if (existsSync8(join10(this.projectPath, "composer.json"))) {
|
|
5627
5751
|
info.projectType = "PHP";
|
|
5628
|
-
} else if (
|
|
5752
|
+
} else if (existsSync8(join10(this.projectPath, "pom.xml")) || existsSync8(join10(this.projectPath, "build.xml"))) {
|
|
5629
5753
|
info.projectType = "Java";
|
|
5630
|
-
} else if (
|
|
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 (
|
|
5759
|
+
if (existsSync8(join10(this.projectPath, "bun.lockb"))) {
|
|
5636
5760
|
info.packageManager = "Bun";
|
|
5637
|
-
} else if (
|
|
5761
|
+
} else if (existsSync8(join10(this.projectPath, "bun.lock"))) {
|
|
5638
5762
|
info.packageManager = "Bun";
|
|
5639
|
-
} else if (
|
|
5763
|
+
} else if (existsSync8(join10(this.projectPath, "pnpm-lock.yaml"))) {
|
|
5640
5764
|
info.packageManager = "pnpm";
|
|
5641
|
-
} else if (
|
|
5765
|
+
} else if (existsSync8(join10(this.projectPath, "yarn.lock"))) {
|
|
5642
5766
|
info.packageManager = "Yarn";
|
|
5643
|
-
} else if (
|
|
5767
|
+
} else if (existsSync8(join10(this.projectPath, "package-lock.json"))) {
|
|
5644
5768
|
info.packageManager = "npm";
|
|
5645
|
-
} else if (
|
|
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
|
|
5709
|
-
import { existsSync as
|
|
5710
|
-
import { homedir as
|
|
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
|
|
5876
|
+
return join11(homedir5(), ".agents", "rules");
|
|
5753
5877
|
}
|
|
5754
5878
|
function getProjectRulesDir(threadPath) {
|
|
5755
|
-
return
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
6884
|
-
import { existsSync as
|
|
6885
|
-
import { homedir as
|
|
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
|
|
7096
|
+
return join13(homedir6(), ".agents", "skills");
|
|
6932
7097
|
}
|
|
6933
7098
|
function getProjectSkillsDir(threadPath) {
|
|
6934
|
-
return
|
|
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 (
|
|
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 (
|
|
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 =
|
|
6988
|
-
const skillFilePath =
|
|
6989
|
-
if (!
|
|
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
|
|
7169
|
-
import { existsSync as
|
|
7170
|
-
import { homedir as
|
|
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
|
|
7391
|
+
return join14(homedir7(), ".agents", "agents");
|
|
7227
7392
|
}
|
|
7228
7393
|
function getProjectAgentsDir(threadPath) {
|
|
7229
|
-
return
|
|
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 (
|
|
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 (
|
|
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 =
|
|
7262
|
-
const agentFilePath =
|
|
7263
|
-
if (!
|
|
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
|
|
7614
|
+
import { join as join15 } from "path";
|
|
7450
7615
|
|
|
7451
7616
|
// src/features/project-todos/project-todos.database.ts
|
|
7452
7617
|
init_database();
|
|
@@ -8256,7 +8421,7 @@ $ ${validationScript}`
|
|
|
8256
8421
|
console.log("[ChatRoute] Validation script passed");
|
|
8257
8422
|
const passEvent = {
|
|
8258
8423
|
type: "thinking",
|
|
8259
|
-
content: `[Validated]
|
|
8424
|
+
content: `[Validated] Validated (exit code 0)${result.output ? `
|
|
8260
8425
|
${result.output}` : ""}`
|
|
8261
8426
|
};
|
|
8262
8427
|
processingStateManager.pushEvent(threadId, passEvent);
|
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10339
|
-
models
|
|
10340
|
-
|
|
10341
|
-
|
|
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 =
|
|
10370
|
-
const bEnabled =
|
|
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
|
|
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
|
|
11638
|
+
import { join as join16 } from "path";
|
|
11249
11639
|
async function detectPackageManager(projectPath) {
|
|
11250
11640
|
try {
|
|
11251
|
-
const packageJsonPath =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
11392
|
-
import { existsSync as
|
|
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 =
|
|
11411
|
-
const entryAbsPath =
|
|
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 =
|
|
11440
|
-
const entryAbsPath =
|
|
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 =
|
|
11476
|
-
const absPath =
|
|
11477
|
-
const exists =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
11765
|
-
const skillAbsPath =
|
|
11766
|
-
const skillFileRelPath =
|
|
11767
|
-
const skillFileAbsPath =
|
|
11768
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
12096
|
-
import { join as
|
|
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 =
|
|
12819
|
-
if (
|
|
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 =
|
|
12977
|
-
if (!
|
|
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 =
|
|
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 =
|
|
13077
|
-
const newPath =
|
|
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 (
|
|
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
|
|
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(
|
|
14086
|
+
await access3(join20(currentPath, "package.json"));
|
|
13696
14087
|
const relativePath = relative5(rootPath, currentPath);
|
|
13697
14088
|
let installCommand = "";
|
|
13698
14089
|
try {
|
|
13699
|
-
await access3(
|
|
14090
|
+
await access3(join20(currentPath, "yarn.lock"));
|
|
13700
14091
|
installCommand = "yarn install";
|
|
13701
14092
|
} catch {
|
|
13702
14093
|
try {
|
|
13703
|
-
await access3(
|
|
14094
|
+
await access3(join20(currentPath, "bun.lock"));
|
|
13704
14095
|
installCommand = "bun install";
|
|
13705
14096
|
} catch {
|
|
13706
14097
|
try {
|
|
13707
|
-
await access3(
|
|
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 =
|
|
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 :
|
|
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
|
|
14819
|
-
import { existsSync as
|
|
14820
|
-
import { homedir as
|
|
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
|
|
15255
|
+
return join22(homedir8(), ".agents", "commands");
|
|
14865
15256
|
}
|
|
14866
15257
|
function getProjectCommandsDir(threadPath) {
|
|
14867
|
-
return
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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 (!
|
|
15351
|
+
if (!existsSync14(dir)) {
|
|
14961
15352
|
await mkdir3(dir, { recursive: true });
|
|
14962
15353
|
}
|
|
14963
15354
|
const filename = `${name}.md`;
|
|
14964
|
-
const filePath =
|
|
14965
|
-
if (
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
|
16161
|
-
import { join as
|
|
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 (
|
|
16596
|
+
if (existsSync15(join24(projectPath, "bun.lockb")) || existsSync15(join24(projectPath, "bun.lock"))) {
|
|
16206
16597
|
return "bun";
|
|
16207
16598
|
}
|
|
16208
|
-
if (
|
|
16599
|
+
if (existsSync15(join24(projectPath, "pnpm-lock.yaml"))) {
|
|
16209
16600
|
return "pnpm";
|
|
16210
16601
|
}
|
|
16211
|
-
if (
|
|
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 =
|
|
16231
|
-
if (
|
|
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 (
|
|
16636
|
+
if (existsSync15(join24(projectPath, "lerna.json"))) {
|
|
16246
16637
|
return "lerna";
|
|
16247
16638
|
}
|
|
16248
|
-
if (
|
|
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 =
|
|
16290
|
-
if (
|
|
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 =
|
|
16306
|
-
if (!
|
|
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 =
|
|
16332
|
-
if (
|
|
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 =
|
|
16352
|
-
if (!
|
|
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 =
|
|
16366
|
-
if (
|
|
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 =
|
|
16387
|
-
if (
|
|
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:
|
|
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(
|
|
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:
|
|
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 =
|
|
16426
|
-
if (
|
|
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 =
|
|
16821
|
+
const folder = join24("apps", entry.name);
|
|
16431
16822
|
workspaces.push({
|
|
16432
16823
|
name: entry.name,
|
|
16433
|
-
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 =
|
|
16468
|
-
if (
|
|
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:
|
|
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(
|
|
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
|
|
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 ?
|
|
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(
|
|
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(
|
|
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
|
|
17237
|
-
import { existsSync as
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
17509
|
-
const agentAbsPath =
|
|
17510
|
-
const agentFileRelPath =
|
|
17511
|
-
const agentFileAbsPath =
|
|
17512
|
-
if (
|
|
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 =
|
|
17579
|
-
const skillAbsPath =
|
|
17580
|
-
const skillFileRelPath =
|
|
17581
|
-
const skillFileAbsPath =
|
|
17582
|
-
if (
|
|
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
|
|
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
|
|
18265
|
-
import { isAbsolute as isAbsolute3, normalize as normalize2, resolve as resolve3, join as
|
|
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 =
|
|
18523
|
-
if (!
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19681
|
+
tarskDebugWrite(`[generate-commit-message] resolved path: ${absolutePath}
|
|
19292
19682
|
`);
|
|
19293
|
-
if (!
|
|
19294
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19338
|
-
|
|
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
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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
|
|
20770
|
-
|
|
20771
|
-
|
|
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
|
|
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 =
|
|
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 ??
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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());
|