fraude-code 0.1.1 → 0.1.2
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/LICENSE +21 -0
- package/dist/index.js +130 -56
- package/package.json +4 -2
- package/src/commands/COMMANDS.ts +2 -0
- package/src/commands/update.ts +36 -0
- package/src/components/IntroComponent.tsx +18 -0
- package/src/index.tsx +9 -0
- package/src/store/useSettingsStore.ts +5 -1
- package/src/utils/updateCheck.ts +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matthew Branning
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.js
CHANGED
|
@@ -419,6 +419,7 @@ var init_useSettingsStore = __esm(() => {
|
|
|
419
419
|
useSettingsStore = create()((set) => {
|
|
420
420
|
return {
|
|
421
421
|
...DEFAULTS,
|
|
422
|
+
updateAvailable: null,
|
|
422
423
|
setOllamaUrl: (url) => {
|
|
423
424
|
try {
|
|
424
425
|
UpdateSettings({ ollamaUrl: url });
|
|
@@ -434,7 +435,8 @@ var init_useSettingsStore = __esm(() => {
|
|
|
434
435
|
} catch (e) {
|
|
435
436
|
console.error("Failed to sync settings:", e);
|
|
436
437
|
}
|
|
437
|
-
}
|
|
438
|
+
},
|
|
439
|
+
setUpdateAvailable: (version) => set({ updateAvailable: version })
|
|
438
440
|
};
|
|
439
441
|
});
|
|
440
442
|
useSettingsStore_default = useSettingsStore;
|
|
@@ -173992,9 +173994,51 @@ var command2 = {
|
|
|
173992
173994
|
}
|
|
173993
173995
|
};
|
|
173994
173996
|
var visualize_default = command2;
|
|
173997
|
+
// package.json
|
|
173998
|
+
var version = "0.1.2";
|
|
173999
|
+
|
|
174000
|
+
// src/utils/updateCheck.ts
|
|
174001
|
+
import semver from "semver";
|
|
174002
|
+
async function checkForUpdate(currentVersion) {
|
|
174003
|
+
try {
|
|
174004
|
+
const response = await fetch("https://registry.npmjs.org/fraude-code/latest");
|
|
174005
|
+
if (!response.ok)
|
|
174006
|
+
return null;
|
|
174007
|
+
const data = await response.json();
|
|
174008
|
+
const latestVersion = data.version;
|
|
174009
|
+
if (semver.gt(latestVersion, currentVersion)) {
|
|
174010
|
+
return latestVersion;
|
|
174011
|
+
}
|
|
174012
|
+
} catch (error) {}
|
|
174013
|
+
return null;
|
|
174014
|
+
}
|
|
174015
|
+
|
|
174016
|
+
// src/commands/update.ts
|
|
174017
|
+
init_useFraudeStore();
|
|
174018
|
+
var { updateOutput: updateOutput18 } = useFraudeStore_default.getState();
|
|
174019
|
+
var updateCommand = {
|
|
174020
|
+
name: "update",
|
|
174021
|
+
description: "Check for the latest version of FraudeCode",
|
|
174022
|
+
usage: "/update",
|
|
174023
|
+
action: async () => {
|
|
174024
|
+
updateOutput18("log", "Checking for updates...");
|
|
174025
|
+
const latest = await checkForUpdate(version);
|
|
174026
|
+
if (!latest) {
|
|
174027
|
+
updateOutput18("log", "\uD83C\uDF89 You are already using the latest version of FraudeCode (v" + version + ").");
|
|
174028
|
+
return;
|
|
174029
|
+
}
|
|
174030
|
+
updateOutput18("log", "\uD83D\uDE80 A new version of FraudeCode is available: v" + latest);
|
|
174031
|
+
updateOutput18("log", "-----------------------------------------");
|
|
174032
|
+
updateOutput18("log", "To update to the latest version, run:");
|
|
174033
|
+
updateOutput18("log", " npm install -g fraude-code");
|
|
174034
|
+
updateOutput18("log", "-----------------------------------------");
|
|
174035
|
+
}
|
|
174036
|
+
};
|
|
174037
|
+
var update_default = updateCommand;
|
|
173995
174038
|
|
|
173996
174039
|
// src/commands/COMMANDS.ts
|
|
173997
174040
|
var COMMANDS = [
|
|
174041
|
+
update_default,
|
|
173998
174042
|
usage_default,
|
|
173999
174043
|
log_default,
|
|
174000
174044
|
serve_default,
|
|
@@ -174278,7 +174322,7 @@ init_useFraudeStore();
|
|
|
174278
174322
|
import { tool } from "ai";
|
|
174279
174323
|
import { z as z3 } from "zod";
|
|
174280
174324
|
import path11 from "path";
|
|
174281
|
-
var { updateOutput:
|
|
174325
|
+
var { updateOutput: updateOutput19 } = useFraudeStore_default.getState();
|
|
174282
174326
|
var FRAUDE_DIR = path11.join(process.cwd(), ".fraude");
|
|
174283
174327
|
var PLAN_FILE = path11.join(FRAUDE_DIR, "plan.md");
|
|
174284
174328
|
async function ensureDir() {
|
|
@@ -174318,7 +174362,7 @@ Operations:
|
|
|
174318
174362
|
switch (operation) {
|
|
174319
174363
|
case "read": {
|
|
174320
174364
|
const plan = await readPlan();
|
|
174321
|
-
|
|
174365
|
+
updateOutput19("toolCall", JSON.stringify({
|
|
174322
174366
|
action: "Read Plan",
|
|
174323
174367
|
details: `${plan.split(`
|
|
174324
174368
|
`).length} lines`,
|
|
@@ -174330,7 +174374,7 @@ Operations:
|
|
|
174330
174374
|
if (!content)
|
|
174331
174375
|
throw new Error("Content required for write operation");
|
|
174332
174376
|
await writePlan(content);
|
|
174333
|
-
|
|
174377
|
+
updateOutput19("toolCall", JSON.stringify({
|
|
174334
174378
|
action: "Wrote Plan",
|
|
174335
174379
|
details: `${content.split(`
|
|
174336
174380
|
`).length} lines`,
|
|
@@ -174344,7 +174388,7 @@ Operations:
|
|
|
174344
174388
|
const existing = await readPlan();
|
|
174345
174389
|
await writePlan(existing + `
|
|
174346
174390
|
` + content);
|
|
174347
|
-
|
|
174391
|
+
updateOutput19("toolCall", JSON.stringify({
|
|
174348
174392
|
action: "Appended to Plan",
|
|
174349
174393
|
details: `+${content.split(`
|
|
174350
174394
|
`).length} lines`,
|
|
@@ -174357,7 +174401,7 @@ Operations:
|
|
|
174357
174401
|
|
|
174358
174402
|
*No plan yet.*
|
|
174359
174403
|
`);
|
|
174360
|
-
|
|
174404
|
+
updateOutput19("toolCall", JSON.stringify({
|
|
174361
174405
|
action: "Cleared Plan",
|
|
174362
174406
|
details: "Reset to empty",
|
|
174363
174407
|
result: "\u2713"
|
|
@@ -174391,7 +174435,7 @@ Task context includes:
|
|
|
174391
174435
|
`;
|
|
174392
174436
|
|
|
174393
174437
|
// src/agent/tools/todoTool.ts
|
|
174394
|
-
var { updateOutput:
|
|
174438
|
+
var { updateOutput: updateOutput20 } = useFraudeStore_default.getState();
|
|
174395
174439
|
var FRAUDE_DIR2 = path12.join(process.cwd(), ".fraude");
|
|
174396
174440
|
var TODOS_FILE = path12.join(FRAUDE_DIR2, "todos.json");
|
|
174397
174441
|
async function readTodos() {
|
|
@@ -174440,7 +174484,7 @@ var todoTool = tool2({
|
|
|
174440
174484
|
};
|
|
174441
174485
|
state2.todos.push(newTodo);
|
|
174442
174486
|
await writeTodos(state2);
|
|
174443
|
-
|
|
174487
|
+
updateOutput20("toolCall", JSON.stringify({
|
|
174444
174488
|
action: "Added Task",
|
|
174445
174489
|
details: description,
|
|
174446
174490
|
result: newTodo.id
|
|
@@ -174459,7 +174503,7 @@ var todoTool = tool2({
|
|
|
174459
174503
|
todo.notes.push(note);
|
|
174460
174504
|
todo.updatedAt = now;
|
|
174461
174505
|
await writeTodos(state2);
|
|
174462
|
-
|
|
174506
|
+
updateOutput20("toolCall", JSON.stringify({
|
|
174463
174507
|
action: "Updated Task",
|
|
174464
174508
|
details: todo.description,
|
|
174465
174509
|
result: status || "note added"
|
|
@@ -174477,7 +174521,7 @@ var todoTool = tool2({
|
|
|
174477
174521
|
todo.notes.push(`[Done] ${note}`);
|
|
174478
174522
|
todo.updatedAt = now;
|
|
174479
174523
|
await writeTodos(state2);
|
|
174480
|
-
|
|
174524
|
+
updateOutput20("toolCall", JSON.stringify({
|
|
174481
174525
|
action: "Completed Task",
|
|
174482
174526
|
details: todo.description,
|
|
174483
174527
|
result: "\u2713"
|
|
@@ -174491,7 +174535,7 @@ var todoTool = tool2({
|
|
|
174491
174535
|
inProgress: state2.todos.filter((t) => t.status === "in-progress").length,
|
|
174492
174536
|
completed: state2.todos.filter((t) => t.status === "completed").length
|
|
174493
174537
|
};
|
|
174494
|
-
|
|
174538
|
+
updateOutput20("toolCall", JSON.stringify({
|
|
174495
174539
|
action: "Listed Tasks",
|
|
174496
174540
|
details: `${summary.pending} pending, ${summary.inProgress} in-progress`,
|
|
174497
174541
|
result: `${summary.total} total`
|
|
@@ -174502,7 +174546,7 @@ var todoTool = tool2({
|
|
|
174502
174546
|
const before = state2.todos.length;
|
|
174503
174547
|
state2.todos = state2.todos.filter((t) => t.status !== "completed");
|
|
174504
174548
|
await writeTodos(state2);
|
|
174505
|
-
|
|
174549
|
+
updateOutput20("toolCall", JSON.stringify({
|
|
174506
174550
|
action: "Cleared Completed",
|
|
174507
174551
|
details: `Removed ${before - state2.todos.length} tasks`,
|
|
174508
174552
|
result: "\u2713"
|
|
@@ -174557,7 +174601,7 @@ Usage:
|
|
|
174557
174601
|
- The limit parameter is the number of lines to read (inclusive).`;
|
|
174558
174602
|
|
|
174559
174603
|
// src/agent/tools/readTool.ts
|
|
174560
|
-
var { updateOutput:
|
|
174604
|
+
var { updateOutput: updateOutput21 } = useFraudeStore_default.getState();
|
|
174561
174605
|
var readTool = tool3({
|
|
174562
174606
|
description: read_default,
|
|
174563
174607
|
strict: true,
|
|
@@ -174577,7 +174621,7 @@ var readTool = tool3({
|
|
|
174577
174621
|
const file = Bun.file(filePath);
|
|
174578
174622
|
const isStaged = pendingChanges_default.getChanges().some((c) => c.path === filePath);
|
|
174579
174623
|
if (!isStaged && !await file.exists()) {
|
|
174580
|
-
|
|
174624
|
+
updateOutput21("toolCall", JSON.stringify({
|
|
174581
174625
|
action: "Error Reading " + projectPath(filePath),
|
|
174582
174626
|
details: "File doesn't exist",
|
|
174583
174627
|
result: ""
|
|
@@ -174590,7 +174634,7 @@ var readTool = tool3({
|
|
|
174590
174634
|
const lastLine = Math.min(offset + limit, lines.length);
|
|
174591
174635
|
const result = lines.slice(offset, lastLine).join(`
|
|
174592
174636
|
`);
|
|
174593
|
-
|
|
174637
|
+
updateOutput21("toolCall", JSON.stringify({
|
|
174594
174638
|
action: "Analyzing " + projectPath(filePath),
|
|
174595
174639
|
details: "#L" + (offset + 1) + "-" + lastLine,
|
|
174596
174640
|
result
|
|
@@ -174661,7 +174705,7 @@ Usage notes:
|
|
|
174661
174705
|
</bad-example>`;
|
|
174662
174706
|
|
|
174663
174707
|
// src/agent/tools/bashTool.ts
|
|
174664
|
-
var { updateOutput:
|
|
174708
|
+
var { updateOutput: updateOutput22 } = useFraudeStore_default.getState();
|
|
174665
174709
|
var bashTool = tool4({
|
|
174666
174710
|
description: bash_default,
|
|
174667
174711
|
strict: true,
|
|
@@ -174693,7 +174737,7 @@ Output: Creates directory 'foo'`)
|
|
|
174693
174737
|
throw new Error("Command blocked by safety policy");
|
|
174694
174738
|
}
|
|
174695
174739
|
try {
|
|
174696
|
-
|
|
174740
|
+
updateOutput22("toolCall", JSON.stringify({
|
|
174697
174741
|
action: "Executing Bash",
|
|
174698
174742
|
details: command3,
|
|
174699
174743
|
result: ""
|
|
@@ -174712,7 +174756,7 @@ Output: Creates directory 'foo'`)
|
|
|
174712
174756
|
}
|
|
174713
174757
|
const [stdout, stderr] = await Promise.all([outputPromise, errorPromise]);
|
|
174714
174758
|
const exitCode = await proc.exited;
|
|
174715
|
-
|
|
174759
|
+
updateOutput22("toolCall", JSON.stringify({
|
|
174716
174760
|
action: "Bash",
|
|
174717
174761
|
details: command3,
|
|
174718
174762
|
result: stdout.trim()
|
|
@@ -174747,7 +174791,7 @@ var grep_default = `Search for a chunk of text in the codebase using grep. Use t
|
|
|
174747
174791
|
- Use this tool when you need to find files containing specific patterns`;
|
|
174748
174792
|
|
|
174749
174793
|
// src/agent/tools/grepTool.ts
|
|
174750
|
-
var { updateOutput:
|
|
174794
|
+
var { updateOutput: updateOutput23 } = useFraudeStore_default.getState();
|
|
174751
174795
|
var grepTool = tool5({
|
|
174752
174796
|
description: grep_default,
|
|
174753
174797
|
strict: true,
|
|
@@ -174761,7 +174805,7 @@ var grepTool = tool5({
|
|
|
174761
174805
|
path: path14,
|
|
174762
174806
|
include
|
|
174763
174807
|
}) => {
|
|
174764
|
-
|
|
174808
|
+
updateOutput23("toolCall", JSON.stringify({
|
|
174765
174809
|
action: "Searching For " + pattern,
|
|
174766
174810
|
details: path14
|
|
174767
174811
|
}), { dontOverride: true });
|
|
@@ -174801,7 +174845,7 @@ var grepTool = tool5({
|
|
|
174801
174845
|
}
|
|
174802
174846
|
}
|
|
174803
174847
|
results.sort((a, b) => b.mtime - a.mtime);
|
|
174804
|
-
|
|
174848
|
+
updateOutput23("toolCall", JSON.stringify({
|
|
174805
174849
|
action: "Found " + results.length + " Match(es)",
|
|
174806
174850
|
details: pattern
|
|
174807
174851
|
}), { dontOverride: true });
|
|
@@ -174955,7 +174999,7 @@ var glob_default = `- Fast file pattern matching tool that works with any codeba
|
|
|
174955
174999
|
|
|
174956
175000
|
// src/agent/tools/globTool.ts
|
|
174957
175001
|
var {Glob } = globalThis.Bun;
|
|
174958
|
-
var { updateOutput:
|
|
175002
|
+
var { updateOutput: updateOutput24 } = useFraudeStore_default.getState();
|
|
174959
175003
|
var globTool = tool6({
|
|
174960
175004
|
description: glob_default,
|
|
174961
175005
|
strict: true,
|
|
@@ -174964,7 +175008,7 @@ var globTool = tool6({
|
|
|
174964
175008
|
path: z8.string().optional().describe(`The directory to search in. If not specified, the current directory will be searched. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.`)
|
|
174965
175009
|
}),
|
|
174966
175010
|
execute: async ({ pattern, path: path14 }) => {
|
|
174967
|
-
|
|
175011
|
+
updateOutput24("toolCall", JSON.stringify({
|
|
174968
175012
|
action: "Searching Files in " + path14,
|
|
174969
175013
|
details: pattern
|
|
174970
175014
|
}), { dontOverride: true });
|
|
@@ -174983,7 +175027,7 @@ var globTool = tool6({
|
|
|
174983
175027
|
break;
|
|
174984
175028
|
}
|
|
174985
175029
|
}
|
|
174986
|
-
|
|
175030
|
+
updateOutput24("toolCall", JSON.stringify({
|
|
174987
175031
|
action: "Found " + files.length + " Files",
|
|
174988
175032
|
details: pattern
|
|
174989
175033
|
}));
|
|
@@ -175030,7 +175074,7 @@ TypeScript, JavaScript, Python, Rust, Go, C/C++, JSON, CSS, HTML
|
|
|
175030
175074
|
`;
|
|
175031
175075
|
|
|
175032
175076
|
// src/agent/tools/lspTool.ts
|
|
175033
|
-
var { updateOutput:
|
|
175077
|
+
var { updateOutput: updateOutput25 } = useFraudeStore_default.getState();
|
|
175034
175078
|
function findSymbolPosition(content, symbolName, occurrence = 1) {
|
|
175035
175079
|
const lines = content.split(`
|
|
175036
175080
|
`);
|
|
@@ -175318,7 +175362,7 @@ ${lines.join(`
|
|
|
175318
175362
|
default:
|
|
175319
175363
|
return "Unknown command.";
|
|
175320
175364
|
}
|
|
175321
|
-
|
|
175365
|
+
updateOutput25("toolCall", JSON.stringify({
|
|
175322
175366
|
action: `LSP: ${command3}`,
|
|
175323
175367
|
details: `${projectPath(filePath)} ${symbol ? `(${symbol})` : ""}`,
|
|
175324
175368
|
result
|
|
@@ -175340,14 +175384,14 @@ var researchSubAgentTool = tool8({
|
|
|
175340
175384
|
question: z10.string().describe("The specific question about the code to answer.")
|
|
175341
175385
|
}),
|
|
175342
175386
|
execute: async ({ question }) => {
|
|
175343
|
-
const { updateOutput:
|
|
175344
|
-
|
|
175387
|
+
const { updateOutput: updateOutput26, researchCache } = useFraudeStore_default.getState();
|
|
175388
|
+
updateOutput26("toolCall", JSON.stringify({
|
|
175345
175389
|
action: "Searching for context",
|
|
175346
175390
|
details: question,
|
|
175347
175391
|
result: ""
|
|
175348
175392
|
}), { dontOverride: true });
|
|
175349
175393
|
if (researchCache?.[question]) {
|
|
175350
|
-
|
|
175394
|
+
updateOutput26("toolCall", JSON.stringify({
|
|
175351
175395
|
action: "Explored context",
|
|
175352
175396
|
details: question,
|
|
175353
175397
|
result: researchCache[question]
|
|
@@ -175363,7 +175407,7 @@ var researchSubAgentTool = tool8({
|
|
|
175363
175407
|
useIsolatedContext: true
|
|
175364
175408
|
});
|
|
175365
175409
|
const result = await subagent.chat(question);
|
|
175366
|
-
|
|
175410
|
+
updateOutput26("toolCall", JSON.stringify({
|
|
175367
175411
|
action: "Explored context",
|
|
175368
175412
|
details: question,
|
|
175369
175413
|
result: result.text
|
|
@@ -175479,7 +175523,7 @@ Usage:
|
|
|
175479
175523
|
- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`;
|
|
175480
175524
|
|
|
175481
175525
|
// src/agent/tools/writeTool.ts
|
|
175482
|
-
var { updateOutput:
|
|
175526
|
+
var { updateOutput: updateOutput26 } = useFraudeStore_default.getState();
|
|
175483
175527
|
var writeTool = tool9({
|
|
175484
175528
|
description: write_default,
|
|
175485
175529
|
strict: true,
|
|
@@ -175490,7 +175534,7 @@ var writeTool = tool9({
|
|
|
175490
175534
|
execute: async ({ path: path15, content }) => {
|
|
175491
175535
|
const change = await pendingChanges_default.addChange(path15, content, "write");
|
|
175492
175536
|
const stats = pendingChanges_default.getDiffStats(change.diff);
|
|
175493
|
-
|
|
175537
|
+
updateOutput26("toolCall", JSON.stringify({
|
|
175494
175538
|
action: "Created File",
|
|
175495
175539
|
details: path15,
|
|
175496
175540
|
result: `(+${stats.added} / -${stats.removed})`
|
|
@@ -175515,7 +175559,7 @@ Usage:
|
|
|
175515
175559
|
- If removing, new content should be empty.`;
|
|
175516
175560
|
|
|
175517
175561
|
// src/agent/tools/editTool.ts
|
|
175518
|
-
var { updateOutput:
|
|
175562
|
+
var { updateOutput: updateOutput27 } = useFraudeStore_default.getState();
|
|
175519
175563
|
var editTool = tool10({
|
|
175520
175564
|
description: edit_default,
|
|
175521
175565
|
strict: true,
|
|
@@ -175532,7 +175576,7 @@ var editTool = tool10({
|
|
|
175532
175576
|
const newFileContent = fileContent.replace(old_content, new_content);
|
|
175533
175577
|
const change = await pendingChanges_default.addChange(path15, newFileContent, "edit");
|
|
175534
175578
|
const stats = pendingChanges_default.getDiffStats(change.diff);
|
|
175535
|
-
|
|
175579
|
+
updateOutput27("toolCall", JSON.stringify({
|
|
175536
175580
|
action: "Edited File",
|
|
175537
175581
|
details: path15,
|
|
175538
175582
|
result: `(+${stats.added} / -${stats.removed})`
|
|
@@ -175616,7 +175660,7 @@ init_useFraudeStore();
|
|
|
175616
175660
|
import { exec as exec2 } from "child_process";
|
|
175617
175661
|
import { promisify } from "util";
|
|
175618
175662
|
var execAsync = promisify(exec2);
|
|
175619
|
-
var { updateOutput:
|
|
175663
|
+
var { updateOutput: updateOutput28 } = useFraudeStore_default.getState();
|
|
175620
175664
|
var testRunnerTool = tool11({
|
|
175621
175665
|
description: `Run a shell command to verify the codebase state, INCLUDING pending changes.
|
|
175622
175666
|
Crucial for testing changes before they are permanently applied.
|
|
@@ -175632,7 +175676,7 @@ var testRunnerTool = tool11({
|
|
|
175632
175676
|
command: z13.string().describe("The shell command to run (e.g., 'bun test tests/my.test.ts', 'python3 tests/test_app.py')")
|
|
175633
175677
|
}),
|
|
175634
175678
|
execute: async ({ command: command3 }) => {
|
|
175635
|
-
|
|
175679
|
+
updateOutput28("toolCall", JSON.stringify({
|
|
175636
175680
|
action: "Running Test on Pending State",
|
|
175637
175681
|
details: command3,
|
|
175638
175682
|
result: "..."
|
|
@@ -175646,7 +175690,7 @@ ${stdout}
|
|
|
175646
175690
|
|
|
175647
175691
|
STDERR:
|
|
175648
175692
|
${stderr}`;
|
|
175649
|
-
|
|
175693
|
+
updateOutput28("toolCall", JSON.stringify({
|
|
175650
175694
|
action: "Test Result",
|
|
175651
175695
|
details: command3,
|
|
175652
175696
|
result: stdout.slice(0, 100) + (stdout.length > 100 ? "..." : "")
|
|
@@ -175661,7 +175705,7 @@ ${error.stdout}
|
|
|
175661
175705
|
|
|
175662
175706
|
STDERR:
|
|
175663
175707
|
${error.stderr}`;
|
|
175664
|
-
|
|
175708
|
+
updateOutput28("toolCall", JSON.stringify({
|
|
175665
175709
|
action: "Test Failed",
|
|
175666
175710
|
details: command3,
|
|
175667
175711
|
result: "Exit Code: " + error.code
|
|
@@ -175679,7 +175723,7 @@ var testRunnerTool_default = testRunnerTool;
|
|
|
175679
175723
|
init_useFraudeStore();
|
|
175680
175724
|
import { tool as tool12 } from "ai";
|
|
175681
175725
|
import { z as z14 } from "zod";
|
|
175682
|
-
var { updateOutput:
|
|
175726
|
+
var { updateOutput: updateOutput29 } = useFraudeStore_default.getState();
|
|
175683
175727
|
var testTool = tool12({
|
|
175684
175728
|
description: `Create OR UPDATE a TEMPORARY test file to verify changes.
|
|
175685
175729
|
This file will NOT be saved to the project permanently and will NOT appear in the user's pending changes list.
|
|
@@ -175694,7 +175738,7 @@ var testTool = tool12({
|
|
|
175694
175738
|
const change = await pendingChanges_default.addChange(path15, content, "write", {
|
|
175695
175739
|
hidden: true
|
|
175696
175740
|
});
|
|
175697
|
-
|
|
175741
|
+
updateOutput29("toolCall", JSON.stringify({
|
|
175698
175742
|
action: "Created Temporary Test",
|
|
175699
175743
|
details: path15,
|
|
175700
175744
|
result: "(Hidden from pending changes)"
|
|
@@ -175911,7 +175955,7 @@ function getAskAgent() {
|
|
|
175911
175955
|
var askAgent_default = getAskAgent;
|
|
175912
175956
|
|
|
175913
175957
|
// src/utils/queryHandler.ts
|
|
175914
|
-
var { updateOutput:
|
|
175958
|
+
var { updateOutput: updateOutput30 } = useFraudeStore_default.getState();
|
|
175915
175959
|
var checkAbort = () => {
|
|
175916
175960
|
const abortController = useFraudeStore_default.getState().abortController;
|
|
175917
175961
|
if (abortController?.signal.aborted) {
|
|
@@ -175962,7 +176006,7 @@ var planMode = async (query) => {
|
|
|
175962
176006
|
while (!nextTask.done && nextTask.task) {
|
|
175963
176007
|
checkAbort();
|
|
175964
176008
|
let taskContext = getTaskContext(nextTask.task);
|
|
175965
|
-
|
|
176009
|
+
updateOutput30("log", "Working on task: " + nextTask.task.description);
|
|
175966
176010
|
const response2 = await getWorkerSubAgent().stream(taskContext, {
|
|
175967
176011
|
abortSignal: abortController.signal
|
|
175968
176012
|
});
|
|
@@ -175975,11 +176019,11 @@ var planMode = async (query) => {
|
|
|
175975
176019
|
}
|
|
175976
176020
|
const getUpdatedTask = await getTodoById(nextTask.task.id);
|
|
175977
176021
|
if (!getUpdatedTask) {
|
|
175978
|
-
|
|
176022
|
+
updateOutput30("error", "Task not found");
|
|
175979
176023
|
continue;
|
|
175980
176024
|
}
|
|
175981
176025
|
taskContext = getTaskContext(getUpdatedTask);
|
|
175982
|
-
|
|
176026
|
+
updateOutput30("log", "Reviewing changes for task: " + nextTask.task.description);
|
|
175983
176027
|
const reviewResponse = await getReviewerSubAgent().stream(taskContext, {
|
|
175984
176028
|
abortSignal: abortController.signal
|
|
175985
176029
|
});
|
|
@@ -176010,7 +176054,7 @@ async function QueryHandler(query) {
|
|
|
176010
176054
|
if (query === "exit") {
|
|
176011
176055
|
process.exit(0);
|
|
176012
176056
|
}
|
|
176013
|
-
|
|
176057
|
+
updateOutput30("command", query);
|
|
176014
176058
|
if (query.startsWith("/")) {
|
|
176015
176059
|
useFraudeStore_default.setState({
|
|
176016
176060
|
status: 2
|
|
@@ -176054,9 +176098,9 @@ async function QueryHandler(query) {
|
|
|
176054
176098
|
}
|
|
176055
176099
|
if (pendingChanges_default.hasChanges()) {
|
|
176056
176100
|
useFraudeStore_default.setState({ status: 3, statusText: "Reviewing Changes" });
|
|
176057
|
-
|
|
176101
|
+
updateOutput30("confirmation", "");
|
|
176058
176102
|
} else {
|
|
176059
|
-
|
|
176103
|
+
updateOutput30("done", `Task Completed in ${(useFraudeStore_default.getState().elapsedTime / 10).toFixed(1)}s`);
|
|
176060
176104
|
}
|
|
176061
176105
|
} catch (e) {
|
|
176062
176106
|
if (e?.name === "AbortError" || e?.message === "Aborted") {
|
|
@@ -176920,10 +176964,10 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
176920
176964
|
return 3;
|
|
176921
176965
|
}
|
|
176922
176966
|
if ("TERM_PROGRAM" in env) {
|
|
176923
|
-
const
|
|
176967
|
+
const version2 = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
176924
176968
|
switch (env.TERM_PROGRAM) {
|
|
176925
176969
|
case "iTerm.app": {
|
|
176926
|
-
return
|
|
176970
|
+
return version2 >= 3 ? 3 : 2;
|
|
176927
176971
|
}
|
|
176928
176972
|
case "Apple_Terminal": {
|
|
176929
176973
|
return 2;
|
|
@@ -178872,10 +178916,7 @@ init_useFraudeStore();
|
|
|
178872
178916
|
// src/components/IntroComponent.tsx
|
|
178873
178917
|
import { Box as Box18, Text as Text18 } from "ink";
|
|
178874
178918
|
import Gradient from "ink-gradient";
|
|
178875
|
-
|
|
178876
|
-
var version = "0.1.1";
|
|
178877
|
-
|
|
178878
|
-
// src/components/IntroComponent.tsx
|
|
178919
|
+
init_useSettingsStore();
|
|
178879
178920
|
import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
|
|
178880
178921
|
var INTRO_THEME = {
|
|
178881
178922
|
primary: "#FFB6C1",
|
|
@@ -178978,7 +179019,35 @@ function IntroComponent() {
|
|
|
178978
179019
|
"to start your journey..."
|
|
178979
179020
|
]
|
|
178980
179021
|
}, undefined, true, undefined, this)
|
|
178981
|
-
}, undefined, false, undefined, this)
|
|
179022
|
+
}, undefined, false, undefined, this),
|
|
179023
|
+
useSettingsStore_default((state2) => state2.updateAvailable) && /* @__PURE__ */ jsxDEV20(Box18, {
|
|
179024
|
+
marginTop: 1,
|
|
179025
|
+
borderStyle: "round",
|
|
179026
|
+
borderColor: "yellow",
|
|
179027
|
+
paddingX: 1,
|
|
179028
|
+
children: [
|
|
179029
|
+
/* @__PURE__ */ jsxDEV20(Text18, {
|
|
179030
|
+
color: "yellow",
|
|
179031
|
+
children: [
|
|
179032
|
+
"Update available!",
|
|
179033
|
+
" ",
|
|
179034
|
+
/* @__PURE__ */ jsxDEV20(Text18, {
|
|
179035
|
+
bold: true,
|
|
179036
|
+
children: [
|
|
179037
|
+
"v",
|
|
179038
|
+
useSettingsStore_default((state2) => state2.updateAvailable)
|
|
179039
|
+
]
|
|
179040
|
+
}, undefined, true, undefined, this),
|
|
179041
|
+
" ",
|
|
179042
|
+
"is now live."
|
|
179043
|
+
]
|
|
179044
|
+
}, undefined, true, undefined, this),
|
|
179045
|
+
/* @__PURE__ */ jsxDEV20(Text18, {
|
|
179046
|
+
dimColor: true,
|
|
179047
|
+
children: " Run `npm install -g fraude-code` to update."
|
|
179048
|
+
}, undefined, false, undefined, this)
|
|
179049
|
+
]
|
|
179050
|
+
}, undefined, true, undefined, this)
|
|
178982
179051
|
]
|
|
178983
179052
|
}, undefined, true, undefined, this)
|
|
178984
179053
|
]
|
|
@@ -179047,7 +179116,7 @@ var LoaderComponent_default = LoaderComponent;
|
|
|
179047
179116
|
// src/components/App.tsx
|
|
179048
179117
|
import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
|
|
179049
179118
|
function App() {
|
|
179050
|
-
const { status, started, updateOutput:
|
|
179119
|
+
const { status, started, updateOutput: updateOutput31 } = useFraudeStore_default();
|
|
179051
179120
|
const [exitPending, setExitPending] = useState5(false);
|
|
179052
179121
|
useInput3((input, key) => {
|
|
179053
179122
|
if (key.return && !started) {
|
|
@@ -179066,7 +179135,7 @@ function App() {
|
|
|
179066
179135
|
if (key.escape && status === 1) {
|
|
179067
179136
|
useFraudeStore_default.getState().interruptAgent();
|
|
179068
179137
|
logger_default("User pressed escape - interrupting agent");
|
|
179069
|
-
|
|
179138
|
+
updateOutput31("interrupted", (useFraudeStore_default.getState().elapsedTime / 10).toFixed(1));
|
|
179070
179139
|
}
|
|
179071
179140
|
});
|
|
179072
179141
|
return !started ? /* @__PURE__ */ jsxDEV22(IntroComponent, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV22(Box20, {
|
|
@@ -179297,6 +179366,11 @@ async function main() {
|
|
|
179297
179366
|
await commands_default.loadPlugins();
|
|
179298
179367
|
syncModels();
|
|
179299
179368
|
const { waitUntilExit } = render(/* @__PURE__ */ jsxDEV23(App, {}, undefined, false, undefined, this), { exitOnCtrlC: false });
|
|
179369
|
+
checkForUpdate(version).then((newVersion) => {
|
|
179370
|
+
if (newVersion) {
|
|
179371
|
+
useSettingsStore_default.getState().setUpdateAvailable(newVersion);
|
|
179372
|
+
}
|
|
179373
|
+
});
|
|
179300
179374
|
getKnowledgeOrchestrator().indexProject(process.cwd()).catch((e) => logger_default(`Background indexing failed: ${e}`));
|
|
179301
179375
|
const exitHandler = () => {
|
|
179302
179376
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraude-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "FraudeCode - An AI coding agent powered by Graph + Vector memory",
|
|
5
5
|
"author": "Matthew Branning",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/bun": "latest",
|
|
35
35
|
"@types/diff": "^8.0.0",
|
|
36
|
-
"@types/react": "^19.2.7"
|
|
36
|
+
"@types/react": "^19.2.7",
|
|
37
|
+
"@types/semver": "^7.7.1"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
40
|
"typescript": "^5"
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"react": "^19.2.4",
|
|
68
69
|
"react-devtools-core": "^7.0.1",
|
|
69
70
|
"react-dom": "^19.2.4",
|
|
71
|
+
"semver": "^7.7.4",
|
|
70
72
|
"vscode-jsonrpc": "^8.2.1",
|
|
71
73
|
"vscode-languageserver-protocol": "^3.17.5",
|
|
72
74
|
"vscode-languageserver-types": "^3.17.5",
|
package/src/commands/COMMANDS.ts
CHANGED
|
@@ -15,8 +15,10 @@ import rememberCommand from "./remember";
|
|
|
15
15
|
import knowledgeCommand from "./knowledge";
|
|
16
16
|
import forgetCommand from "./forget";
|
|
17
17
|
import visualizeCommand from "./visualize";
|
|
18
|
+
import updateCommand from "./update";
|
|
18
19
|
|
|
19
20
|
const COMMANDS: Command[] = [
|
|
21
|
+
updateCommand,
|
|
20
22
|
usageCommand,
|
|
21
23
|
logCommand,
|
|
22
24
|
serveCommand,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Command } from "@/types/CommandDefinition";
|
|
2
|
+
import { version } from "../../package.json";
|
|
3
|
+
import { checkForUpdate } from "../utils/updateCheck";
|
|
4
|
+
import useFraudeStore from "@/store/useFraudeStore";
|
|
5
|
+
const { updateOutput } = useFraudeStore.getState();
|
|
6
|
+
|
|
7
|
+
const updateCommand: Command = {
|
|
8
|
+
name: "update",
|
|
9
|
+
description: "Check for the latest version of FraudeCode",
|
|
10
|
+
usage: "/update",
|
|
11
|
+
action: async () => {
|
|
12
|
+
updateOutput("log", "Checking for updates...");
|
|
13
|
+
const latest = await checkForUpdate(version);
|
|
14
|
+
|
|
15
|
+
if (!latest) {
|
|
16
|
+
updateOutput(
|
|
17
|
+
"log",
|
|
18
|
+
"🎉 You are already using the latest version of FraudeCode (v" +
|
|
19
|
+
version +
|
|
20
|
+
").",
|
|
21
|
+
);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
updateOutput(
|
|
26
|
+
"log",
|
|
27
|
+
"🚀 A new version of FraudeCode is available: v" + latest,
|
|
28
|
+
);
|
|
29
|
+
updateOutput("log", "-----------------------------------------");
|
|
30
|
+
updateOutput("log", "To update to the latest version, run:");
|
|
31
|
+
updateOutput("log", " npm install -g fraude-code");
|
|
32
|
+
updateOutput("log", "-----------------------------------------");
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default updateCommand;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Box, Text } from "ink";
|
|
2
2
|
import Gradient from "ink-gradient";
|
|
3
3
|
import { version } from "../../package.json";
|
|
4
|
+
import useSettingsStore from "../store/useSettingsStore";
|
|
4
5
|
|
|
5
6
|
const INTRO_THEME = {
|
|
6
7
|
primary: "#FFB6C1",
|
|
@@ -66,6 +67,23 @@ export default function IntroComponent() {
|
|
|
66
67
|
to start your journey...
|
|
67
68
|
</Text>
|
|
68
69
|
</Box>
|
|
70
|
+
{useSettingsStore((state) => state.updateAvailable) && (
|
|
71
|
+
<Box
|
|
72
|
+
marginTop={1}
|
|
73
|
+
borderStyle="round"
|
|
74
|
+
borderColor="yellow"
|
|
75
|
+
paddingX={1}
|
|
76
|
+
>
|
|
77
|
+
<Text color="yellow">
|
|
78
|
+
Update available!{" "}
|
|
79
|
+
<Text bold>
|
|
80
|
+
v{useSettingsStore((state) => state.updateAvailable)}
|
|
81
|
+
</Text>{" "}
|
|
82
|
+
is now live.
|
|
83
|
+
</Text>
|
|
84
|
+
<Text dimColor> Run `npm install -g fraude-code` to update.</Text>
|
|
85
|
+
</Box>
|
|
86
|
+
)}
|
|
69
87
|
</Box>
|
|
70
88
|
</Box>
|
|
71
89
|
);
|
package/src/index.tsx
CHANGED
|
@@ -11,6 +11,8 @@ import CerebrasClient from "@/services/cerebras";
|
|
|
11
11
|
import GoogleClient from "@/services/google";
|
|
12
12
|
import CommandCenter from "@/commands";
|
|
13
13
|
import { getKnowledgeOrchestrator } from "@/services/knowledgeOrchestrator";
|
|
14
|
+
import { checkForUpdate } from "./utils/updateCheck";
|
|
15
|
+
import { version } from "../package.json";
|
|
14
16
|
|
|
15
17
|
// Global error handlers to catch and suppress AbortErrors
|
|
16
18
|
process.on("unhandledRejection", (reason) => {
|
|
@@ -81,6 +83,13 @@ async function main() {
|
|
|
81
83
|
syncModels();
|
|
82
84
|
const { waitUntilExit } = render(<App />, { exitOnCtrlC: false });
|
|
83
85
|
|
|
86
|
+
// Asynchronous update check
|
|
87
|
+
checkForUpdate(version).then((newVersion) => {
|
|
88
|
+
if (newVersion) {
|
|
89
|
+
useSettingsStore.getState().setUpdateAvailable(newVersion);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
84
93
|
// Background index the project (fire-and-forget)
|
|
85
94
|
getKnowledgeOrchestrator()
|
|
86
95
|
.indexProject(process.cwd())
|
|
@@ -5,15 +5,18 @@ import { SettingsSchema, type Config } from "../config/schema";
|
|
|
5
5
|
interface SettingsActions {
|
|
6
6
|
setOllamaUrl: (url: string) => void;
|
|
7
7
|
syncWithSettings: () => void;
|
|
8
|
+
setUpdateAvailable: (version: string | null) => void;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
type SettingsState = Config &
|
|
11
|
+
type SettingsState = Config &
|
|
12
|
+
SettingsActions & { updateAvailable: string | null };
|
|
11
13
|
|
|
12
14
|
const DEFAULTS = SettingsSchema.parse({});
|
|
13
15
|
|
|
14
16
|
const useSettingsStore = create<SettingsState>()((set) => {
|
|
15
17
|
return {
|
|
16
18
|
...DEFAULTS,
|
|
19
|
+
updateAvailable: null,
|
|
17
20
|
|
|
18
21
|
setOllamaUrl: (url) => {
|
|
19
22
|
try {
|
|
@@ -32,6 +35,7 @@ const useSettingsStore = create<SettingsState>()((set) => {
|
|
|
32
35
|
console.error("Failed to sync settings:", e);
|
|
33
36
|
}
|
|
34
37
|
},
|
|
38
|
+
setUpdateAvailable: (version) => set({ updateAvailable: version }),
|
|
35
39
|
} as SettingsState;
|
|
36
40
|
});
|
|
37
41
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
export async function checkForUpdate(
|
|
3
|
+
currentVersion: string,
|
|
4
|
+
): Promise<string | null> {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(
|
|
7
|
+
"https://registry.npmjs.org/fraude-code/latest",
|
|
8
|
+
);
|
|
9
|
+
if (!response.ok) return null;
|
|
10
|
+
const data = (await response.json()) as { version: string };
|
|
11
|
+
const latestVersion = data.version;
|
|
12
|
+
|
|
13
|
+
if (semver.gt(latestVersion, currentVersion)) {
|
|
14
|
+
return latestVersion;
|
|
15
|
+
}
|
|
16
|
+
} catch (error) {
|
|
17
|
+
// Silently fail to not disrupt user experience
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|