fluxflow-cli 2.6.4 → 2.6.6
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/fluxflow.js +200 -136
- package/package.json +2 -2
package/dist/fluxflow.js
CHANGED
|
@@ -12,6 +12,7 @@ var __export = (target, all) => {
|
|
|
12
12
|
// src/utils/paths.js
|
|
13
13
|
var paths_exports = {};
|
|
14
14
|
__export(paths_exports, {
|
|
15
|
+
ACTIVE_TX_FILE: () => ACTIVE_TX_FILE,
|
|
15
16
|
BACKUPS_DIR: () => BACKUPS_DIR,
|
|
16
17
|
CONTEXT_FILE: () => CONTEXT_FILE,
|
|
17
18
|
DATA_DIR: () => DATA_DIR,
|
|
@@ -32,7 +33,7 @@ import os from "os";
|
|
|
32
33
|
import path from "path";
|
|
33
34
|
import fs from "fs";
|
|
34
35
|
import crypto from "crypto";
|
|
35
|
-
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
|
|
36
|
+
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE, BACKUPS_DIR, LEDGER_FILE, ACTIVE_TX_FILE, PATHS_FILE, CONTEXT_FILE, PARSER_DIR;
|
|
36
37
|
var init_paths = __esm({
|
|
37
38
|
"src/utils/paths.js"() {
|
|
38
39
|
FLUXFLOW_DIR = path.join(os.homedir(), ".fluxflow");
|
|
@@ -75,6 +76,7 @@ var init_paths = __esm({
|
|
|
75
76
|
TEMP_MEM_CHAT_FILE = path.join(SECRET_DIR, "temp-memory-chat.json");
|
|
76
77
|
BACKUPS_DIR = path.join(DATA_DIR, "backups");
|
|
77
78
|
LEDGER_FILE = path.join(SECRET_DIR, "ledger.json");
|
|
79
|
+
ACTIVE_TX_FILE = path.join(SECRET_DIR, "active_tx.json");
|
|
78
80
|
PATHS_FILE = path.join(SECRET_DIR, "path.json");
|
|
79
81
|
CONTEXT_FILE = path.join(SECRET_DIR, "context.json");
|
|
80
82
|
PARSER_DIR = path.join(DATA_DIR, "parsers");
|
|
@@ -2146,7 +2148,7 @@ Access to internal tools. MUST use the exact syntax on a new line: [tool:functio
|
|
|
2146
2148
|
|
|
2147
2149
|
**TOOL USAGE POLICY:**
|
|
2148
2150
|
- **MAX 3 TOOL CALLS PER TURN. Next Turn, verify tool results, plan next**
|
|
2149
|
-
${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many changes \u2190 **
|
|
2151
|
+
${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many changes \u2190 **HIGHLY PREFERRED**\n- Tool execution denied? MUST use 'Ask' tool immediately to ask for reason/changes. NEVER END RESPONSE OR PROCEED BLINDLY \u2190 **MANDATORY**\n- FileMap >> ReadFile for understandling files efficiently\n- Want a spefific word/varible to find across project? SearchKeyword >> Guessing/ReadFile" : ""}- No brute force, no spamming of tools
|
|
2150
2152
|
${mode === "Flux" ? "- **File Tools >> Code in chat**\n" : ""}
|
|
2151
2153
|
- COMMUNICATION TOOLS -
|
|
2152
2154
|
1. [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish. Suggest best options; don't ask for preferences
|
|
@@ -2157,11 +2159,11 @@ ${mode === "Flux" ? "- **File Tools >> Code in chat**\n" : ""}
|
|
|
2157
2159
|
|
|
2158
2160
|
${mode === "Flux" ? `- PROJECT TOOLS (path = relative to CWD, path separator: '/') -
|
|
2159
2161
|
1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. User gives image/doc: VIEW FIRST` : `No Multimodal support`}` : `Supports images/docs. User gives image/doc: VIEW FIRST`}
|
|
2160
|
-
2. [tool:functions.FileMap(path="path/file")]. Shows file structure, dependency, functions, variable maps. Token Efficient than ReadFile
|
|
2162
|
+
2. [tool:functions.FileMap(path="path/file")]. Shows file structure, dependency, functions, variable maps. Token Efficient than ReadFile
|
|
2161
2163
|
3. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
|
|
2162
2164
|
4. [tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 10)]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile >> guessing. **MUST VERIFY DIFF**
|
|
2163
2165
|
5. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. Verify Imports
|
|
2164
|
-
6. [tool:functions.SearchKeyword(keyword="...", file="optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file
|
|
2166
|
+
6. [tool:functions.SearchKeyword(keyword="...", file="optional")]. Global project search. If 'file' is provided, searches only that file. Finds definitions/logic without reading every file. Usage: Can search for relevent lines/logic area to read specifically for edit
|
|
2165
2167
|
7. [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `${isPtyAvailable ? "Interactive " : ""}WINDOWS POWERSHELL ONLY` : `${isPtyAvailable ? "Interactive " : ""}WINDOWS CMD ONLY` : `${isPtyAvailable ? "Interactive " : ""}BASH`} command. Destructive/Irreversible ops -> Ask user. **TOOL DENY RULE APPLIES**. **1 CALL LIMIT OR 3 CONSECUTIVE RUN TOOL ONLY**
|
|
2166
2168
|
8. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. PROACTIVE A4 PAGE BREAKS MUST IN CSS. HTML/CSS for PREMIUM layout
|
|
2167
2169
|
9. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word document
|
|
@@ -3422,6 +3424,51 @@ Current date and Time: ${(/* @__PURE__ */ new Date()).toLocaleString([], { year:
|
|
|
3422
3424
|
// src/utils/revert.js
|
|
3423
3425
|
import fs6 from "fs-extra";
|
|
3424
3426
|
import path5 from "path";
|
|
3427
|
+
async function performRestoration(change, tx) {
|
|
3428
|
+
try {
|
|
3429
|
+
if (change.type === "create") {
|
|
3430
|
+
if (await fs6.pathExists(change.filePath)) {
|
|
3431
|
+
await fs6.chmod(change.filePath, 438).catch(() => {
|
|
3432
|
+
});
|
|
3433
|
+
await fs6.remove(change.filePath);
|
|
3434
|
+
}
|
|
3435
|
+
} else if (change.type === "update") {
|
|
3436
|
+
if (!change.backupFile) return;
|
|
3437
|
+
const backupPath = path5.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
3438
|
+
if (await fs6.pathExists(backupPath)) {
|
|
3439
|
+
const encrypted = await fs6.readFile(backupPath, "utf8");
|
|
3440
|
+
const decrypted = decryptAes(encrypted);
|
|
3441
|
+
if (await fs6.pathExists(change.filePath)) {
|
|
3442
|
+
await fs6.chmod(change.filePath, 438).catch(() => {
|
|
3443
|
+
});
|
|
3444
|
+
}
|
|
3445
|
+
await fs6.writeFile(change.filePath, decrypted, "utf8");
|
|
3446
|
+
} else {
|
|
3447
|
+
console.warn(`[RevertManager] Backup file missing: ${backupPath}`);
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
} catch (err) {
|
|
3451
|
+
throw new Error(`Restoration failed for ${path5.basename(change.filePath)}: ${err.message}`);
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
async function restoreWithRetry(change, tx, maxAttempts = 7) {
|
|
3455
|
+
let attempt = 0;
|
|
3456
|
+
while (attempt < maxAttempts) {
|
|
3457
|
+
try {
|
|
3458
|
+
await performRestoration(change, tx);
|
|
3459
|
+
return true;
|
|
3460
|
+
} catch (err) {
|
|
3461
|
+
attempt++;
|
|
3462
|
+
if (attempt >= maxAttempts) {
|
|
3463
|
+
console.error(`[RevertManager] Permanent failure: ${change.filePath}. ${err.message}`);
|
|
3464
|
+
return false;
|
|
3465
|
+
}
|
|
3466
|
+
const delay = Math.min(100 * Math.pow(2, attempt - 1), 5e3);
|
|
3467
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
return false;
|
|
3471
|
+
}
|
|
3425
3472
|
var currentTransaction, RevertManager;
|
|
3426
3473
|
var init_revert = __esm({
|
|
3427
3474
|
"src/utils/revert.js"() {
|
|
@@ -3430,9 +3477,6 @@ var init_revert = __esm({
|
|
|
3430
3477
|
fs6.ensureDirSync(BACKUPS_DIR);
|
|
3431
3478
|
currentTransaction = null;
|
|
3432
3479
|
RevertManager = {
|
|
3433
|
-
/**
|
|
3434
|
-
* Initializes a new transaction before a prompt starts processing.
|
|
3435
|
-
*/
|
|
3436
3480
|
async startTransaction(chatId, promptText) {
|
|
3437
3481
|
currentTransaction = {
|
|
3438
3482
|
id: `tx_prompt_${Date.now()}`,
|
|
@@ -3442,122 +3486,101 @@ var init_revert = __esm({
|
|
|
3442
3486
|
changes: [],
|
|
3443
3487
|
reverted: false
|
|
3444
3488
|
};
|
|
3489
|
+
writeEncryptedJson(ACTIVE_TX_FILE, currentTransaction);
|
|
3445
3490
|
},
|
|
3446
|
-
/**
|
|
3447
|
-
* Records a file change under the active prompt transaction.
|
|
3448
|
-
*/
|
|
3449
3491
|
async recordFileChange(absolutePath, forcedContent = null) {
|
|
3450
3492
|
if (!currentTransaction) return;
|
|
3451
3493
|
try {
|
|
3452
3494
|
const alreadyBackedUp = currentTransaction.changes.some((c) => c.filePath === absolutePath);
|
|
3453
3495
|
if (alreadyBackedUp) return;
|
|
3454
3496
|
const fileExists = await fs6.pathExists(absolutePath);
|
|
3455
|
-
let type = fileExists
|
|
3456
|
-
if (!fileExists && !forcedContent) type = "create";
|
|
3497
|
+
let type = fileExists || forcedContent ? "update" : "create";
|
|
3457
3498
|
let backupFile = null;
|
|
3458
|
-
if (
|
|
3459
|
-
type = "update";
|
|
3499
|
+
if (type === "update") {
|
|
3460
3500
|
const fileName = path5.basename(absolutePath);
|
|
3461
3501
|
backupFile = `${currentTransaction.id}_${fileName}.bak`;
|
|
3462
3502
|
const chatBackupDir = path5.join(BACKUPS_DIR, currentTransaction.chatId);
|
|
3463
3503
|
await fs6.ensureDir(chatBackupDir);
|
|
3464
3504
|
const backupPath = path5.join(chatBackupDir, backupFile);
|
|
3465
|
-
let content;
|
|
3466
|
-
if (
|
|
3467
|
-
content
|
|
3505
|
+
let content = forcedContent !== null ? forcedContent : await fs6.readFile(absolutePath, "utf8").catch(() => null);
|
|
3506
|
+
if (content !== null) {
|
|
3507
|
+
writeEncryptedJson(backupPath, { data: encryptAes(content) });
|
|
3468
3508
|
} else {
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
} catch (readErr) {
|
|
3472
|
-
console.warn(`[RevertManager] Could not read file for backup: ${absolutePath}. ${readErr.message}`);
|
|
3473
|
-
type = "create";
|
|
3474
|
-
backupFile = null;
|
|
3475
|
-
}
|
|
3476
|
-
}
|
|
3477
|
-
if (backupFile) {
|
|
3478
|
-
const encrypted = encryptAes(content);
|
|
3479
|
-
await fs6.writeFile(backupPath, encrypted, "utf8");
|
|
3509
|
+
type = "create";
|
|
3510
|
+
backupFile = null;
|
|
3480
3511
|
}
|
|
3481
3512
|
}
|
|
3482
|
-
currentTransaction.changes.push({
|
|
3483
|
-
|
|
3484
|
-
type,
|
|
3485
|
-
backupFile
|
|
3486
|
-
});
|
|
3513
|
+
currentTransaction.changes.push({ filePath: absolutePath, type, backupFile });
|
|
3514
|
+
writeEncryptedJson(ACTIVE_TX_FILE, currentTransaction);
|
|
3487
3515
|
} catch (err) {
|
|
3488
|
-
console.error(`[RevertManager] Error recording file change for ${absolutePath}:`, err.message);
|
|
3489
3516
|
}
|
|
3490
3517
|
},
|
|
3491
|
-
/**
|
|
3492
|
-
* Finalizes the transaction and saves it to ledger.json.
|
|
3493
|
-
*/
|
|
3494
3518
|
async commitTransaction() {
|
|
3495
3519
|
if (!currentTransaction) return;
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3520
|
+
try {
|
|
3521
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
3522
|
+
ledger.push(currentTransaction);
|
|
3523
|
+
if (ledger.length > 512e3) {
|
|
3524
|
+
const removed = ledger.shift();
|
|
3525
|
+
if (removed.changes) {
|
|
3526
|
+
for (const change of removed.changes) {
|
|
3527
|
+
if (change.backupFile) {
|
|
3528
|
+
await fs6.remove(path5.join(BACKUPS_DIR, removed.chatId, change.backupFile)).catch(() => {
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3505
3531
|
}
|
|
3506
3532
|
}
|
|
3507
3533
|
}
|
|
3534
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
3535
|
+
await fs6.remove(ACTIVE_TX_FILE).catch(() => {
|
|
3536
|
+
});
|
|
3537
|
+
} catch (err) {
|
|
3538
|
+
} finally {
|
|
3539
|
+
currentTransaction = null;
|
|
3540
|
+
}
|
|
3541
|
+
},
|
|
3542
|
+
async recoverCrashedTransaction() {
|
|
3543
|
+
try {
|
|
3544
|
+
if (await fs6.pathExists(ACTIVE_TX_FILE)) {
|
|
3545
|
+
const orphanedTx = readEncryptedJson(ACTIVE_TX_FILE, null);
|
|
3546
|
+
if (orphanedTx?.changes?.length > 0) {
|
|
3547
|
+
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
3548
|
+
if (!ledger.some((t) => t.id === orphanedTx.id)) {
|
|
3549
|
+
ledger.push(orphanedTx);
|
|
3550
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3553
|
+
await fs6.remove(ACTIVE_TX_FILE).catch(() => {
|
|
3554
|
+
});
|
|
3555
|
+
}
|
|
3556
|
+
} catch (e) {
|
|
3508
3557
|
}
|
|
3509
|
-
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
3510
|
-
currentTransaction = null;
|
|
3511
3558
|
},
|
|
3512
|
-
/**
|
|
3513
|
-
* Reverts the codebase to a state immediately before the target transaction.
|
|
3514
|
-
* Reverts the target transaction and all subsequent ones in reverse sequential order.
|
|
3515
|
-
* Returns the target prompt text so it can be loaded back into the user input.
|
|
3516
|
-
*/
|
|
3517
3559
|
async rollbackToBefore(txId) {
|
|
3518
|
-
|
|
3560
|
+
let ledger = readEncryptedJson(LEDGER_FILE, null);
|
|
3519
3561
|
if (!ledger) throw new Error("No transaction ledger found.");
|
|
3520
3562
|
const targetIndex = ledger.findIndex((t) => t.id === txId);
|
|
3521
3563
|
if (targetIndex === -1) throw new Error(`Transaction [${txId}] not found.`);
|
|
3522
3564
|
const chatId = ledger[targetIndex].chatId;
|
|
3523
3565
|
const targetPrompt = ledger[targetIndex].prompt;
|
|
3524
3566
|
const toRevert = ledger.slice(targetIndex).filter((t) => t.chatId === chatId && !t.reverted).reverse();
|
|
3567
|
+
console.log(`[RevertManager] Starting sequential rollback of ${toRevert.length} transactions...`);
|
|
3525
3568
|
for (const tx of toRevert) {
|
|
3526
3569
|
for (const change of [...tx.changes].reverse()) {
|
|
3527
|
-
|
|
3528
|
-
if (await fs6.pathExists(change.filePath)) {
|
|
3529
|
-
await fs6.remove(change.filePath);
|
|
3530
|
-
}
|
|
3531
|
-
} else if (change.type === "update") {
|
|
3532
|
-
const backupPath = path5.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
3533
|
-
if (await fs6.pathExists(backupPath)) {
|
|
3534
|
-
const encrypted = await fs6.readFile(backupPath, "utf8");
|
|
3535
|
-
const decrypted = decryptAes(encrypted);
|
|
3536
|
-
await fs6.writeFile(change.filePath, decrypted, "utf8");
|
|
3537
|
-
}
|
|
3538
|
-
}
|
|
3570
|
+
await restoreWithRetry(change, tx);
|
|
3539
3571
|
}
|
|
3540
|
-
tx.reverted = true;
|
|
3541
|
-
}
|
|
3542
|
-
for (const tx of toRevert) {
|
|
3543
3572
|
for (const change of tx.changes) {
|
|
3544
3573
|
if (change.backupFile) {
|
|
3545
3574
|
const backupPath = path5.join(BACKUPS_DIR, tx.chatId, change.backupFile);
|
|
3546
|
-
await fs6.remove(backupPath)
|
|
3575
|
+
await fs6.remove(backupPath).catch(() => {
|
|
3576
|
+
});
|
|
3547
3577
|
}
|
|
3548
3578
|
}
|
|
3579
|
+
ledger = ledger.filter((t) => t.id !== tx.id);
|
|
3580
|
+
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
3549
3581
|
}
|
|
3550
|
-
|
|
3551
|
-
writeEncryptedJson(LEDGER_FILE, updatedLedger);
|
|
3552
|
-
return {
|
|
3553
|
-
success: true,
|
|
3554
|
-
chatId,
|
|
3555
|
-
targetPrompt
|
|
3556
|
-
};
|
|
3582
|
+
return { success: true, chatId, targetPrompt };
|
|
3557
3583
|
},
|
|
3558
|
-
/**
|
|
3559
|
-
* Gets all non-reverted prompt transactions for a specific chat.
|
|
3560
|
-
*/
|
|
3561
3584
|
async getChatHistory(chatId) {
|
|
3562
3585
|
try {
|
|
3563
3586
|
const ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
@@ -3566,19 +3589,12 @@ var init_revert = __esm({
|
|
|
3566
3589
|
return [];
|
|
3567
3590
|
}
|
|
3568
3591
|
},
|
|
3569
|
-
/**
|
|
3570
|
-
* Cleans up all transaction logs and backups associated with a deleted chat.
|
|
3571
|
-
*/
|
|
3572
3592
|
async deleteChatBackups(chatId) {
|
|
3573
3593
|
try {
|
|
3574
|
-
|
|
3575
|
-
await fs6.remove(chatBackupDir);
|
|
3594
|
+
await fs6.remove(path5.join(BACKUPS_DIR, chatId));
|
|
3576
3595
|
let ledger = readEncryptedJson(LEDGER_FILE, []);
|
|
3577
|
-
const
|
|
3578
|
-
|
|
3579
|
-
if (ledger.length !== originalLength) {
|
|
3580
|
-
writeEncryptedJson(LEDGER_FILE, ledger);
|
|
3581
|
-
}
|
|
3596
|
+
const clean = ledger.filter((t) => t.chatId !== chatId);
|
|
3597
|
+
if (ledger.length !== clean.length) writeEncryptedJson(LEDGER_FILE, clean);
|
|
3582
3598
|
} catch (e) {
|
|
3583
3599
|
}
|
|
3584
3600
|
}
|
|
@@ -5579,46 +5595,70 @@ var init_parsers = __esm({
|
|
|
5579
5595
|
import fs18 from "fs-extra";
|
|
5580
5596
|
import path17 from "path";
|
|
5581
5597
|
import { createRequire } from "module";
|
|
5598
|
+
function sanitize(text, limit = 50) {
|
|
5599
|
+
if (!text) return "";
|
|
5600
|
+
const clean = text.replace(/\s+/g, " ").trim();
|
|
5601
|
+
return clean.length > limit ? clean.substring(0, limit - 3) + "..." : clean;
|
|
5602
|
+
}
|
|
5582
5603
|
function getDisplayName(node) {
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
return tagName2 ? tagName2.text : null;
|
|
5588
|
-
}
|
|
5589
|
-
const tagName = node.children.find((c) => c.type === "tag_name");
|
|
5590
|
-
return tagName ? tagName.text : null;
|
|
5604
|
+
const type = node.type;
|
|
5605
|
+
if (type === "if_statement") {
|
|
5606
|
+
const cond = node.childForFieldName("condition");
|
|
5607
|
+
return cond ? `if (${sanitize(cond.text, 40)})` : "if";
|
|
5591
5608
|
}
|
|
5592
|
-
if (
|
|
5593
|
-
|
|
5594
|
-
const
|
|
5595
|
-
return
|
|
5609
|
+
if (type === "else_clause") return "else";
|
|
5610
|
+
if (type === "while_statement" || type === "do_statement") {
|
|
5611
|
+
const cond = node.childForFieldName("condition");
|
|
5612
|
+
return `${type.split("_")[0]} (${cond ? sanitize(cond.text, 40) : ""})`;
|
|
5596
5613
|
}
|
|
5597
|
-
if (
|
|
5598
|
-
|
|
5614
|
+
if (type === "for_statement" || type === "for_in_statement" || type === "for_of_statement") {
|
|
5615
|
+
const text = node.text.split("\n")[0];
|
|
5616
|
+
const match = text.match(/for\s*(?:await\s*)?\((.*)\)/);
|
|
5617
|
+
if (match) return `for (${sanitize(match[1], 40)})`;
|
|
5618
|
+
return "for";
|
|
5599
5619
|
}
|
|
5600
|
-
if (
|
|
5601
|
-
const
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5620
|
+
if (type === "switch_statement") {
|
|
5621
|
+
const val = node.childForFieldName("value");
|
|
5622
|
+
return `switch (${val ? sanitize(val.text, 40) : ""})`;
|
|
5623
|
+
}
|
|
5624
|
+
if (type === "try_statement") return "try";
|
|
5625
|
+
if (type === "catch_clause") return "catch";
|
|
5626
|
+
if (type === "element" || type === "script_element" || type === "style_element" || type === "jsx_element" || type === "jsx_self_closing_element") {
|
|
5627
|
+
const opening = node.childForFieldName("opening_element") || node.childForFieldName("start_tag") || node.children.find((c) => c.type === "start_tag") || node;
|
|
5628
|
+
const tagName = opening.childForFieldName("name") || opening.childForFieldName("tag_name") || opening.children.find((c) => c.type === "tag_name");
|
|
5629
|
+
return tagName ? `<${sanitize(tagName.text, 30)}>` : null;
|
|
5630
|
+
}
|
|
5631
|
+
if (["import_declaration", "import_from_statement", "import_statement", "preproc_include"].includes(type)) {
|
|
5632
|
+
return sanitize(node.text.split("\n")[0], 60);
|
|
5633
|
+
}
|
|
5634
|
+
if (type === "pair") {
|
|
5635
|
+
const key = node.childForFieldName("key");
|
|
5636
|
+
return key ? sanitize(key.text.replace(/["']/g, ""), 40) : null;
|
|
5637
|
+
}
|
|
5638
|
+
if (type === "assignment_expression") {
|
|
5639
|
+
const left = node.childForFieldName("left");
|
|
5640
|
+
return left ? `${sanitize(left.text, 30)} = ...` : null;
|
|
5641
|
+
}
|
|
5642
|
+
if (type === "variable_declarator") {
|
|
5643
|
+
const id = node.childForFieldName("name") || node.children.find((c) => ["identifier", "object_pattern", "array_pattern"].includes(c.type));
|
|
5644
|
+
return id ? sanitize(id.text, 40) : null;
|
|
5606
5645
|
}
|
|
5607
|
-
const nameNode = node.childForFieldName("name") || node.children.find((c) =>
|
|
5646
|
+
const nameNode = node.childForFieldName("name") || node.childForFieldName("declarator") || node.children.find((c) => ["identifier", "type_identifier", "field_identifier", "property_identifier", "shorthand_property_identifier"].includes(c.type));
|
|
5608
5647
|
if (nameNode) {
|
|
5609
|
-
if (nameNode.type
|
|
5610
|
-
const
|
|
5611
|
-
|
|
5648
|
+
if (nameNode.type.includes("declarator")) {
|
|
5649
|
+
const id = nameNode.descendantsOfType("identifier")[0] || nameNode.descendantsOfType("field_identifier")[0];
|
|
5650
|
+
if (id) return sanitize(id.text, 40);
|
|
5612
5651
|
}
|
|
5613
|
-
return nameNode.text;
|
|
5652
|
+
return sanitize(nameNode.text, 40);
|
|
5614
5653
|
}
|
|
5615
|
-
if (
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5654
|
+
if (["arrow_function", "function_expression", "function_declaration"].includes(type)) {
|
|
5655
|
+
let p = node.parent;
|
|
5656
|
+
while (p && p.type !== "program") {
|
|
5657
|
+
const pName = getDisplayName(p);
|
|
5658
|
+
if (pName) return pName;
|
|
5659
|
+
if (!PASSTHROUGH_TYPES.has(p.type)) break;
|
|
5660
|
+
p = p.parent;
|
|
5661
|
+
}
|
|
5622
5662
|
}
|
|
5623
5663
|
return null;
|
|
5624
5664
|
}
|
|
@@ -5639,36 +5679,43 @@ function getNextInterestingNodes(node) {
|
|
|
5639
5679
|
function toCamelCase(str) {
|
|
5640
5680
|
return str.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
|
|
5641
5681
|
}
|
|
5642
|
-
function traverse(node, depth = 0, isLast = true, prefix = "") {
|
|
5643
|
-
const MAX_DEPTH =
|
|
5682
|
+
function traverse(node, depth = 0, isLast = true, prefix = "", parentName = null) {
|
|
5683
|
+
const MAX_DEPTH = 12;
|
|
5644
5684
|
if (depth > MAX_DEPTH) return "";
|
|
5645
5685
|
const type = node.type;
|
|
5686
|
+
const name = getDisplayName(node);
|
|
5646
5687
|
const isInteresting = INTERESTING_TYPES.has(type) || depth === 0;
|
|
5688
|
+
const children = getNextInterestingNodes(node);
|
|
5689
|
+
const isPassthrough = isInteresting && depth > 0 && (PASSTHROUGH_TYPES.has(type) && children.length > 0 || name !== null && name === parentName && children.length > 0);
|
|
5647
5690
|
let result = "";
|
|
5648
5691
|
let nextPrefix = prefix;
|
|
5649
|
-
|
|
5692
|
+
let nextDepth = depth;
|
|
5693
|
+
let nextParentName = parentName;
|
|
5694
|
+
if (isInteresting && !isPassthrough) {
|
|
5650
5695
|
const startLine = node.startPosition.row + 1;
|
|
5651
5696
|
const endLine = node.endPosition.row + 1;
|
|
5652
|
-
const name = getDisplayName(node);
|
|
5653
5697
|
const camelType = toCamelCase(type);
|
|
5654
5698
|
const label = name ? `${camelType} [${name}]` : camelType;
|
|
5655
5699
|
if (depth === 0) {
|
|
5656
5700
|
result += `\u{1F4C1} ROOT (Lines: ${startLine}-${endLine})
|
|
5657
5701
|
`;
|
|
5702
|
+
nextPrefix = prefix;
|
|
5658
5703
|
} else {
|
|
5659
5704
|
result += `${prefix}${isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${label} (Lines: ${startLine}-${endLine})
|
|
5660
5705
|
`;
|
|
5661
5706
|
nextPrefix += isLast ? " " : "\u2502 ";
|
|
5662
5707
|
}
|
|
5708
|
+
nextDepth = depth + 1;
|
|
5709
|
+
nextParentName = name;
|
|
5663
5710
|
}
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
const
|
|
5667
|
-
result += traverse(child,
|
|
5711
|
+
children.forEach((child, index) => {
|
|
5712
|
+
const isLastChildInLoop = index === children.length - 1;
|
|
5713
|
+
const effectiveIsLast = isPassthrough ? isLast && isLastChildInLoop : isLastChildInLoop;
|
|
5714
|
+
result += traverse(child, nextDepth, effectiveIsLast, nextPrefix, nextParentName);
|
|
5668
5715
|
});
|
|
5669
5716
|
return result;
|
|
5670
5717
|
}
|
|
5671
|
-
var require2, TreeSitter, isParserInitialized, INTERESTING_TYPES, file_map;
|
|
5718
|
+
var require2, TreeSitter, isParserInitialized, INTERESTING_TYPES, PASSTHROUGH_TYPES, file_map;
|
|
5672
5719
|
var init_file_map = __esm({
|
|
5673
5720
|
"src/tools/file_map.js"() {
|
|
5674
5721
|
init_parsers();
|
|
@@ -5682,15 +5729,21 @@ var init_file_map = __esm({
|
|
|
5682
5729
|
"function_declaration",
|
|
5683
5730
|
"method_definition",
|
|
5684
5731
|
"arrow_function",
|
|
5732
|
+
"function_expression",
|
|
5685
5733
|
"if_statement",
|
|
5734
|
+
"else_clause",
|
|
5686
5735
|
"for_statement",
|
|
5736
|
+
"for_in_statement",
|
|
5737
|
+
"for_of_statement",
|
|
5687
5738
|
"while_statement",
|
|
5688
5739
|
"do_statement",
|
|
5689
5740
|
"switch_statement",
|
|
5690
5741
|
"try_statement",
|
|
5691
|
-
"
|
|
5692
|
-
"
|
|
5742
|
+
"catch_clause",
|
|
5743
|
+
"variable_declarator",
|
|
5693
5744
|
"export_statement",
|
|
5745
|
+
"lexical_declaration",
|
|
5746
|
+
"variable_declaration",
|
|
5694
5747
|
"interface_declaration",
|
|
5695
5748
|
"type_alias_declaration",
|
|
5696
5749
|
"enum_declaration",
|
|
@@ -5705,6 +5758,8 @@ var init_file_map = __esm({
|
|
|
5705
5758
|
"preproc_include",
|
|
5706
5759
|
"method_declaration",
|
|
5707
5760
|
"constructor_declaration",
|
|
5761
|
+
"assignment_expression",
|
|
5762
|
+
"pair",
|
|
5708
5763
|
// C/C++
|
|
5709
5764
|
"class_specifier",
|
|
5710
5765
|
"struct_specifier",
|
|
@@ -5715,6 +5770,7 @@ var init_file_map = __esm({
|
|
|
5715
5770
|
"script_element",
|
|
5716
5771
|
"style_element"
|
|
5717
5772
|
]);
|
|
5773
|
+
PASSTHROUGH_TYPES = /* @__PURE__ */ new Set(["export_statement", "lexical_declaration", "variable_declaration", "variable_declarator", "pair", "assignment_expression"]);
|
|
5718
5774
|
file_map = async (args) => {
|
|
5719
5775
|
let filePath;
|
|
5720
5776
|
try {
|
|
@@ -5763,7 +5819,7 @@ var init_file_map = __esm({
|
|
|
5763
5819
|
parser.setLanguage(Lang);
|
|
5764
5820
|
const sourceCode = await fs18.readFile(absolutePath, "utf8");
|
|
5765
5821
|
const tree = parser.parse(sourceCode);
|
|
5766
|
-
const map = traverse(tree.rootNode);
|
|
5822
|
+
const map = traverse(tree.rootNode, 0, true, " ");
|
|
5767
5823
|
return `\u{1F4C4} File Map for: ${filePath}
|
|
5768
5824
|
${map}`;
|
|
5769
5825
|
} catch (err) {
|
|
@@ -7938,7 +7994,14 @@ ${activeSummaryBlock}${thinkingLevel != "Fast" && aiProvider === "Google" ? `${m
|
|
|
7938
7994
|
activeBufferType = null;
|
|
7939
7995
|
remaining = combined.substring(endIdx + endTag.length);
|
|
7940
7996
|
} else {
|
|
7941
|
-
|
|
7997
|
+
const MAX_BUFFER = 512;
|
|
7998
|
+
if (combined.length > MAX_BUFFER) {
|
|
7999
|
+
msgs.push({ type: "text", content: combined });
|
|
8000
|
+
toolCallBuffer = "";
|
|
8001
|
+
} else {
|
|
8002
|
+
toolCallBuffer = combined;
|
|
8003
|
+
}
|
|
8004
|
+
remaining = "";
|
|
7942
8005
|
break;
|
|
7943
8006
|
}
|
|
7944
8007
|
}
|
|
@@ -10636,6 +10699,7 @@ function App({ args = [] }) {
|
|
|
10636
10699
|
cleanupOldLogs(LOGS_DIR);
|
|
10637
10700
|
performVersionCheck(false, freshSettings);
|
|
10638
10701
|
await initUsage();
|
|
10702
|
+
await RevertManager.recoverCrashedTransaction();
|
|
10639
10703
|
if (parsedArgs.resume) {
|
|
10640
10704
|
const h = await loadHistory();
|
|
10641
10705
|
const id = parsedArgs.resume;
|
|
@@ -12535,7 +12599,7 @@ Selection: ${val}`,
|
|
|
12535
12599
|
if (result.success) {
|
|
12536
12600
|
const { targetPrompt } = result;
|
|
12537
12601
|
deleteChatSummary(chatId);
|
|
12538
|
-
const targetIdx = messages.
|
|
12602
|
+
const targetIdx = messages.findLastIndex(
|
|
12539
12603
|
(m) => m.role === "user" && m.text && (m.text.startsWith(targetPrompt) || m.text.includes(targetPrompt))
|
|
12540
12604
|
);
|
|
12541
12605
|
let newMsgs = [...messages];
|