jawere 1.4.0 → 1.5.0
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 +155 -58
- package/package.json +1 -1
- package/dist/agent.d.ts +0 -15
- package/dist/agent.js +0 -321
- package/dist/config.d.ts +0 -19
- package/dist/config.js +0 -53
- package/dist/convex-client.d.ts +0 -41
- package/dist/convex-client.js +0 -99
- package/dist/crypto.d.ts +0 -12
- package/dist/crypto.js +0 -79
- package/dist/index.d.ts +0 -1
- package/dist/prompt.d.ts +0 -9
- package/dist/prompt.js +0 -325
- package/dist/scanner.d.ts +0 -29
- package/dist/scanner.js +0 -520
- package/dist/spinner.d.ts +0 -23
- package/dist/spinner.js +0 -83
- package/dist/system-prompt.d.ts +0 -1
- package/dist/system-prompt.js +0 -115
- package/dist/tools.d.ts +0 -22
- package/dist/tools.js +0 -551
package/dist/index.js
CHANGED
|
@@ -13339,6 +13339,30 @@ var TOOL_DEFS = [
|
|
|
13339
13339
|
}
|
|
13340
13340
|
}
|
|
13341
13341
|
},
|
|
13342
|
+
{
|
|
13343
|
+
type: "function",
|
|
13344
|
+
function: {
|
|
13345
|
+
name: "diff",
|
|
13346
|
+
description: "Show a git diff of changes. Useful for reviewing what changed before committing. Supports --staged for staged changes, and optional path/file and base ref.",
|
|
13347
|
+
parameters: {
|
|
13348
|
+
type: "object",
|
|
13349
|
+
properties: {
|
|
13350
|
+
path: {
|
|
13351
|
+
type: "string",
|
|
13352
|
+
description: "Specific file or directory to diff (optional \u2014 diffs everything if omitted)"
|
|
13353
|
+
},
|
|
13354
|
+
staged: {
|
|
13355
|
+
type: "boolean",
|
|
13356
|
+
description: "Show staged changes (git diff --staged). Default: false (working tree)"
|
|
13357
|
+
},
|
|
13358
|
+
base: {
|
|
13359
|
+
type: "string",
|
|
13360
|
+
description: "Base ref to diff against (e.g. HEAD~1, main). Default: HEAD for staged, working tree otherwise"
|
|
13361
|
+
}
|
|
13362
|
+
}
|
|
13363
|
+
}
|
|
13364
|
+
}
|
|
13365
|
+
},
|
|
13342
13366
|
{
|
|
13343
13367
|
type: "function",
|
|
13344
13368
|
function: {
|
|
@@ -13757,6 +13781,14 @@ async function statTool(path, workDir) {
|
|
|
13757
13781
|
return `Error: [stat-failed] ${fullPath}: ${err.message}`;
|
|
13758
13782
|
}
|
|
13759
13783
|
}
|
|
13784
|
+
async function diffTool(path, staged, base, workDir) {
|
|
13785
|
+
const args = ["diff"];
|
|
13786
|
+
if (staged) args.push("--staged");
|
|
13787
|
+
if (base) args.push(base);
|
|
13788
|
+
if (path) args.push("--", path);
|
|
13789
|
+
else args.push("--", ".");
|
|
13790
|
+
return execBash(`git ${args.join(" ")}`, workDir, 30);
|
|
13791
|
+
}
|
|
13760
13792
|
async function executeTool(call, workDir) {
|
|
13761
13793
|
const { id, function: fn } = call;
|
|
13762
13794
|
let args;
|
|
@@ -13799,6 +13831,14 @@ async function executeTool(call, workDir) {
|
|
|
13799
13831
|
case "find":
|
|
13800
13832
|
result = await findTool(args.pattern, args.path, workDir);
|
|
13801
13833
|
break;
|
|
13834
|
+
case "diff":
|
|
13835
|
+
result = await diffTool(
|
|
13836
|
+
args.path,
|
|
13837
|
+
args.staged,
|
|
13838
|
+
args.base,
|
|
13839
|
+
workDir
|
|
13840
|
+
);
|
|
13841
|
+
break;
|
|
13802
13842
|
case "grep":
|
|
13803
13843
|
result = await grepTool(
|
|
13804
13844
|
args.pattern,
|
|
@@ -14265,13 +14305,14 @@ async function listSessions(convexUrl) {
|
|
|
14265
14305
|
|
|
14266
14306
|
// src/agent.ts
|
|
14267
14307
|
var MAX_TURNS = 500;
|
|
14268
|
-
var MAX_OUTPUT_TOKENS =
|
|
14308
|
+
var MAX_OUTPUT_TOKENS = 393216;
|
|
14269
14309
|
var COL = () => process.stdout.columns || 80;
|
|
14270
14310
|
var GRUVBOX_GREEN = "\x1B[38;2;184;187;3m";
|
|
14271
14311
|
var GRUVBOX_GRAY = "\x1B[38;2;146;131;116m";
|
|
14272
14312
|
var GRUVBOX_RED = "\x1B[38;2;251;73;52m";
|
|
14273
14313
|
var RESET2 = "\x1B[0m";
|
|
14274
14314
|
var FILE_TOOLS = /* @__PURE__ */ new Set(["read", "write", "edit", "stat"]);
|
|
14315
|
+
var SILENT_TOOLS = /* @__PURE__ */ new Set(["diff"]);
|
|
14275
14316
|
function toolDetail(name, args) {
|
|
14276
14317
|
switch (name) {
|
|
14277
14318
|
case "read": {
|
|
@@ -14296,6 +14337,7 @@ function toolDetail(name, args) {
|
|
|
14296
14337
|
}
|
|
14297
14338
|
}
|
|
14298
14339
|
function displayToolLine(name, args, ok, spin) {
|
|
14340
|
+
if (SILENT_TOOLS.has(name)) return;
|
|
14299
14341
|
if (spin?.running) {
|
|
14300
14342
|
spin.stop();
|
|
14301
14343
|
}
|
|
@@ -14463,86 +14505,120 @@ async function runAgent(userMessage, options = {}) {
|
|
|
14463
14505
|
return { text: msg2, sessionId, history: messages };
|
|
14464
14506
|
}
|
|
14465
14507
|
spin.update("Thinking\u2026");
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14508
|
+
let streamedContent = "";
|
|
14509
|
+
const streamedToolCalls = /* @__PURE__ */ new Map();
|
|
14510
|
+
let streamUsage;
|
|
14511
|
+
try {
|
|
14512
|
+
const stream = await withRetry(async () => {
|
|
14513
|
+
return client.chat.completions.create({
|
|
14514
|
+
model: config.model,
|
|
14515
|
+
messages,
|
|
14516
|
+
tools: TOOL_DEFS,
|
|
14517
|
+
tool_choice: "auto",
|
|
14518
|
+
temperature: 0.2,
|
|
14519
|
+
max_tokens: MAX_OUTPUT_TOKENS,
|
|
14520
|
+
stream: true,
|
|
14521
|
+
stream_options: { include_usage: true },
|
|
14522
|
+
// Enable thinking/reasoning — DeepSeek specific params
|
|
14523
|
+
...{
|
|
14524
|
+
thinking: { type: "enabled" },
|
|
14525
|
+
reasoning_effort: "max"
|
|
14526
|
+
}
|
|
14527
|
+
});
|
|
14479
14528
|
});
|
|
14480
|
-
|
|
14529
|
+
for await (const chunk of stream) {
|
|
14530
|
+
if (options.signal?.aborted) break;
|
|
14531
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
14532
|
+
if (!delta) {
|
|
14533
|
+
if (chunk.usage) {
|
|
14534
|
+
streamUsage = {
|
|
14535
|
+
input: chunk.usage.prompt_tokens || 0,
|
|
14536
|
+
output: chunk.usage.completion_tokens || 0,
|
|
14537
|
+
total: chunk.usage.total_tokens || 0
|
|
14538
|
+
};
|
|
14539
|
+
}
|
|
14540
|
+
continue;
|
|
14541
|
+
}
|
|
14542
|
+
if (delta.content) {
|
|
14543
|
+
streamedContent += delta.content;
|
|
14544
|
+
}
|
|
14545
|
+
if (delta.tool_calls) {
|
|
14546
|
+
for (const tc of delta.tool_calls) {
|
|
14547
|
+
const idx = tc.index ?? 0;
|
|
14548
|
+
if (!streamedToolCalls.has(idx)) {
|
|
14549
|
+
streamedToolCalls.set(idx, { id: "", name: "", arguments: "" });
|
|
14550
|
+
}
|
|
14551
|
+
const entry = streamedToolCalls.get(idx);
|
|
14552
|
+
if (tc.id) entry.id = tc.id;
|
|
14553
|
+
if (tc.function?.name) entry.name += tc.function.name;
|
|
14554
|
+
if (tc.function?.arguments) entry.arguments += tc.function.arguments;
|
|
14555
|
+
}
|
|
14556
|
+
}
|
|
14557
|
+
spin.update("Thinking\u2026");
|
|
14558
|
+
}
|
|
14559
|
+
} catch (err) {
|
|
14481
14560
|
if (err.name === "AbortError" || err.name === "Canceled") {
|
|
14482
|
-
|
|
14561
|
+
spin.stop();
|
|
14562
|
+
const msg2 = "\n[Cancelled by user]";
|
|
14563
|
+
return { text: msg2, sessionId, history: messages };
|
|
14483
14564
|
}
|
|
14484
14565
|
throw err;
|
|
14485
|
-
}
|
|
14486
|
-
if (
|
|
14566
|
+
}
|
|
14567
|
+
if (options.signal?.aborted) {
|
|
14487
14568
|
spin.stop();
|
|
14488
14569
|
const msg2 = "\n[Cancelled by user]";
|
|
14489
14570
|
return { text: msg2, sessionId, history: messages };
|
|
14490
14571
|
}
|
|
14491
|
-
const
|
|
14492
|
-
if (
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
() => appendAssistantMessage(config.convexUrl, sessionId, "(error: no response)", null),
|
|
14496
|
-
"appendAssistantMessage"
|
|
14497
|
-
);
|
|
14498
|
-
return { text: "Error: No response from model.", sessionId, history: messages };
|
|
14499
|
-
}
|
|
14500
|
-
const { message } = choice;
|
|
14501
|
-
const usage = response.usage ? {
|
|
14502
|
-
input: response.usage.prompt_tokens || 0,
|
|
14503
|
-
output: response.usage.completion_tokens || 0,
|
|
14504
|
-
total: response.usage.total_tokens || 0
|
|
14505
|
-
} : void 0;
|
|
14506
|
-
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
14507
|
-
const toolCallsMeta = message.tool_calls.map((tc) => ({
|
|
14572
|
+
const hasToolCalls = streamedToolCalls.size > 0;
|
|
14573
|
+
if (hasToolCalls) {
|
|
14574
|
+
const toolCallArray = Array.from(streamedToolCalls.entries()).sort(([a2], [b2]) => a2 - b2).map(([_2, tc]) => tc);
|
|
14575
|
+
const toolCallsMeta = toolCallArray.map((tc) => ({
|
|
14508
14576
|
id: tc.id,
|
|
14509
|
-
name: tc.
|
|
14510
|
-
arguments: tc.
|
|
14577
|
+
name: tc.name,
|
|
14578
|
+
arguments: tc.arguments
|
|
14511
14579
|
}));
|
|
14512
14580
|
safeCall(
|
|
14513
14581
|
() => appendAssistantMessage(
|
|
14514
14582
|
config.convexUrl,
|
|
14515
14583
|
sessionId,
|
|
14516
|
-
|
|
14584
|
+
streamedContent || null,
|
|
14517
14585
|
toolCallsMeta.length > 0 ? toolCallsMeta : null,
|
|
14518
|
-
|
|
14586
|
+
streamUsage
|
|
14519
14587
|
),
|
|
14520
14588
|
"appendAssistantMessage"
|
|
14521
14589
|
);
|
|
14590
|
+
const openaiToolCalls = toolCallArray.map((tc) => ({
|
|
14591
|
+
id: tc.id,
|
|
14592
|
+
type: "function",
|
|
14593
|
+
function: {
|
|
14594
|
+
name: tc.name,
|
|
14595
|
+
arguments: tc.arguments
|
|
14596
|
+
}
|
|
14597
|
+
}));
|
|
14522
14598
|
messages.push({
|
|
14523
14599
|
role: "assistant",
|
|
14524
|
-
content:
|
|
14525
|
-
tool_calls:
|
|
14600
|
+
content: streamedContent || null,
|
|
14601
|
+
tool_calls: openaiToolCalls
|
|
14526
14602
|
});
|
|
14527
|
-
for (const tc of
|
|
14603
|
+
for (const tc of toolCallArray) {
|
|
14528
14604
|
let args = {};
|
|
14529
14605
|
try {
|
|
14530
|
-
args = JSON.parse(tc.
|
|
14606
|
+
args = JSON.parse(tc.arguments);
|
|
14531
14607
|
} catch {
|
|
14532
14608
|
}
|
|
14533
|
-
spin.update(`Running ${tc.
|
|
14609
|
+
spin.update(`Running ${tc.name}\u2026`);
|
|
14534
14610
|
const result = await executeTool(
|
|
14535
14611
|
{
|
|
14536
14612
|
id: tc.id,
|
|
14537
14613
|
function: {
|
|
14538
|
-
name: tc.
|
|
14539
|
-
arguments: tc.
|
|
14614
|
+
name: tc.name,
|
|
14615
|
+
arguments: tc.arguments
|
|
14540
14616
|
}
|
|
14541
14617
|
},
|
|
14542
14618
|
config.workDir
|
|
14543
14619
|
);
|
|
14544
14620
|
const ok = !result.content.startsWith("Error");
|
|
14545
|
-
displayToolLine(tc.
|
|
14621
|
+
displayToolLine(tc.name, args, ok, spin);
|
|
14546
14622
|
messages.push({
|
|
14547
14623
|
role: "tool",
|
|
14548
14624
|
tool_call_id: result.tool_call_id,
|
|
@@ -14554,7 +14630,7 @@ async function runAgent(userMessage, options = {}) {
|
|
|
14554
14630
|
config.convexUrl,
|
|
14555
14631
|
sessionId,
|
|
14556
14632
|
result.tool_call_id,
|
|
14557
|
-
tc.
|
|
14633
|
+
tc.name,
|
|
14558
14634
|
result.content,
|
|
14559
14635
|
isError
|
|
14560
14636
|
),
|
|
@@ -14564,10 +14640,9 @@ async function runAgent(userMessage, options = {}) {
|
|
|
14564
14640
|
continue;
|
|
14565
14641
|
}
|
|
14566
14642
|
spin.stop();
|
|
14567
|
-
const
|
|
14568
|
-
const text = stripThinking(rawText) || "(empty response)";
|
|
14643
|
+
const text = stripThinking(streamedContent) || "(empty response)";
|
|
14569
14644
|
safeCall(
|
|
14570
|
-
() => appendAssistantMessage(config.convexUrl, sessionId, text, null,
|
|
14645
|
+
() => appendAssistantMessage(config.convexUrl, sessionId, text, null, streamUsage),
|
|
14571
14646
|
"appendAssistantMessage"
|
|
14572
14647
|
);
|
|
14573
14648
|
console.log("");
|
|
@@ -14871,20 +14946,32 @@ function getProjectInfo(workDir) {
|
|
|
14871
14946
|
}
|
|
14872
14947
|
return { name, version };
|
|
14873
14948
|
}
|
|
14874
|
-
async function scanCodebase(workDir) {
|
|
14949
|
+
async function scanCodebase(workDir, onProgress) {
|
|
14875
14950
|
const codebaseDir = resolve2(workDir, CODEBASE_DIR);
|
|
14876
14951
|
await mkdir3(codebaseDir, { recursive: true });
|
|
14952
|
+
onProgress?.("listing files");
|
|
14877
14953
|
const allFiles = await getAllFiles(workDir, workDir);
|
|
14878
14954
|
const files = allFiles.sort();
|
|
14955
|
+
onProgress?.(`found ${files.length} files`);
|
|
14956
|
+
onProgress?.("building tree");
|
|
14879
14957
|
const tree = buildTree(files);
|
|
14958
|
+
onProgress?.(`summarizing ${files.length} files`);
|
|
14880
14959
|
const summaries = {};
|
|
14881
|
-
|
|
14882
|
-
|
|
14960
|
+
let lastReport = 0;
|
|
14961
|
+
for (let i2 = 0; i2 < files.length; i2++) {
|
|
14962
|
+
const summary = await summarizeFile(resolve2(workDir, files[i2]));
|
|
14883
14963
|
if (summary) {
|
|
14884
|
-
summaries[
|
|
14964
|
+
summaries[files[i2]] = summary;
|
|
14965
|
+
}
|
|
14966
|
+
const now = Date.now();
|
|
14967
|
+
if (i2 - lastReport >= 10 || now - lastReport > 200) {
|
|
14968
|
+
onProgress?.(`summarizing ${i2 + 1}/${files.length}`);
|
|
14969
|
+
lastReport = i2;
|
|
14885
14970
|
}
|
|
14886
14971
|
}
|
|
14972
|
+
onProgress?.("reading project info");
|
|
14887
14973
|
const { name, version } = getProjectInfo(workDir);
|
|
14974
|
+
onProgress?.("hashing files");
|
|
14888
14975
|
const gitHash = await getGitHash(workDir);
|
|
14889
14976
|
const checksums = {
|
|
14890
14977
|
scannedAt: Date.now(),
|
|
@@ -14902,9 +14989,12 @@ async function scanCodebase(workDir) {
|
|
|
14902
14989
|
}
|
|
14903
14990
|
}
|
|
14904
14991
|
}
|
|
14992
|
+
onProgress?.("writing checksums");
|
|
14905
14993
|
await writeFile3(resolve2(workDir, CHECKSUMS_FILE), JSON.stringify(checksums, null, 2) + "\n", "utf-8");
|
|
14994
|
+
onProgress?.("writing tree.yaml");
|
|
14906
14995
|
const treeYaml = generateTreeYaml(name, version, tree, summaries);
|
|
14907
14996
|
await writeFile3(resolve2(workDir, TREE_FILE), treeYaml, "utf-8");
|
|
14997
|
+
onProgress?.("writing meta.json");
|
|
14908
14998
|
const meta = {
|
|
14909
14999
|
scannedAt: Date.now(),
|
|
14910
15000
|
fileCount: files.length,
|
|
@@ -14992,11 +15082,18 @@ async function runScanner(workDir, force = false) {
|
|
|
14992
15082
|
const meta = JSON.parse(
|
|
14993
15083
|
await readFile3(resolve2(workDir, META_FILE), "utf-8")
|
|
14994
15084
|
);
|
|
15085
|
+
process.stderr.write(` (cached)`);
|
|
14995
15086
|
return { fileCount: meta.fileCount, cached: true };
|
|
14996
15087
|
} catch {
|
|
14997
15088
|
}
|
|
14998
15089
|
}
|
|
14999
|
-
const
|
|
15090
|
+
const GRAY2 = "\x1B[38;2;146;131;116m";
|
|
15091
|
+
const RESET3 = "\x1B[0m";
|
|
15092
|
+
const { fileCount } = await scanCodebase(workDir, (phase, detail) => {
|
|
15093
|
+
const msg = detail || phase;
|
|
15094
|
+
process.stderr.write(`\r\x1B[K${GRAY2} scanning: ${msg}${RESET3}`);
|
|
15095
|
+
});
|
|
15096
|
+
process.stderr.write(`\r\x1B[K`);
|
|
15000
15097
|
return { fileCount, cached: false };
|
|
15001
15098
|
}
|
|
15002
15099
|
|
|
@@ -15351,10 +15448,10 @@ async function main() {
|
|
|
15351
15448
|
try {
|
|
15352
15449
|
const scanResult = await runScanner(config.workDir);
|
|
15353
15450
|
if (scanResult.cached) {
|
|
15354
|
-
process.stderr.write(` ${G_GRAY2}(
|
|
15451
|
+
process.stderr.write(` ${G_GRAY2}(${scanResult.fileCount} files)${R3}
|
|
15355
15452
|
`);
|
|
15356
15453
|
} else {
|
|
15357
|
-
process.stderr.write(
|
|
15454
|
+
process.stderr.write(`${G_GRAY2}Done \u2014 ${scanResult.fileCount} files indexed${R3}
|
|
15358
15455
|
`);
|
|
15359
15456
|
}
|
|
15360
15457
|
} catch (err) {
|
package/package.json
CHANGED
package/dist/agent.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
2
|
-
export interface AgentOptions {
|
|
3
|
-
sessionId?: string;
|
|
4
|
-
title?: string;
|
|
5
|
-
history?: ChatCompletionMessageParam[];
|
|
6
|
-
signal?: AbortSignal;
|
|
7
|
-
}
|
|
8
|
-
export interface AgentResult {
|
|
9
|
-
text: string;
|
|
10
|
-
sessionId: string;
|
|
11
|
-
history: ChatCompletionMessageParam[];
|
|
12
|
-
}
|
|
13
|
-
/** Print the assistant's FINAL response — the summary shown when all work is done. */
|
|
14
|
-
export declare function printAssistantResponse(text: string): void;
|
|
15
|
-
export declare function runAgent(userMessage: string, options?: AgentOptions): Promise<AgentResult>;
|