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