wave-agent-sdk 0.14.3 → 0.15.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/builtin/skills/settings/SKILLS.md +34 -6
- package/dist/agent.d.ts +0 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +0 -15
- package/dist/constants/toolLimits.d.ts +10 -0
- package/dist/constants/toolLimits.d.ts.map +1 -0
- package/dist/constants/toolLimits.js +9 -0
- package/dist/managers/aiManager.d.ts +3 -5
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +107 -104
- package/dist/managers/forkedAgentManager.d.ts +1 -0
- package/dist/managers/forkedAgentManager.d.ts.map +1 -1
- package/dist/managers/forkedAgentManager.js +1 -0
- package/dist/managers/hookManager.d.ts +0 -4
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +0 -25
- package/dist/managers/permissionManager.d.ts +1 -1
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +5 -5
- package/dist/managers/subagentManager.d.ts +1 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +1 -0
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +3 -4
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +10 -8
- package/dist/services/autoMemoryService.d.ts.map +1 -1
- package/dist/services/autoMemoryService.js +1 -0
- package/dist/services/hook.d.ts +0 -4
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +0 -10
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +4 -1
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +2 -45
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/types.d.ts +0 -3
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/agent.d.ts +0 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +1 -5
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +0 -1
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -2
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +16 -8
- package/dist/utils/editUtils.d.ts +5 -2
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +3 -57
- package/dist/utils/markdownParser.d.ts +8 -1
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +64 -11
- package/dist/utils/openaiClient.d.ts.map +1 -1
- package/dist/utils/openaiClient.js +0 -11
- package/dist/utils/stringUtils.d.ts +8 -0
- package/dist/utils/stringUtils.d.ts.map +1 -1
- package/dist/utils/stringUtils.js +45 -0
- package/package.json +1 -1
- package/src/agent.ts +0 -17
- package/src/constants/toolLimits.ts +12 -0
- package/src/managers/aiManager.ts +141 -148
- package/src/managers/forkedAgentManager.ts +3 -0
- package/src/managers/hookManager.ts +0 -32
- package/src/managers/permissionManager.ts +6 -6
- package/src/managers/subagentManager.ts +2 -0
- package/src/prompts/index.ts +3 -5
- package/src/services/aiService.ts +10 -12
- package/src/services/autoMemoryService.ts +1 -0
- package/src/services/hook.ts +0 -15
- package/src/services/session.ts +6 -1
- package/src/tools/bashTool.ts +2 -51
- package/src/tools/editTool.ts +1 -1
- package/src/tools/types.ts +0 -3
- package/src/types/agent.ts +0 -1
- package/src/types/hooks.ts +1 -7
- package/src/utils/constants.ts +2 -2
- package/src/utils/convertMessagesForAPI.ts +15 -8
- package/src/utils/editUtils.ts +3 -73
- package/src/utils/markdownParser.ts +85 -11
- package/src/utils/openaiClient.ts +0 -11
- package/src/utils/stringUtils.ts +43 -0
package/dist/utils/editUtils.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility functions for file editing tools
|
|
3
3
|
*/
|
|
4
|
-
import { formatLineNumberPrefix } from "./stringUtils.js";
|
|
5
4
|
/**
|
|
6
5
|
* Escape regular expression special characters
|
|
7
6
|
*/
|
|
@@ -9,61 +8,8 @@ export function escapeRegExp(string) {
|
|
|
9
8
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
11
|
+
* Returns a generic error message when old_string is not found.
|
|
13
12
|
*/
|
|
14
|
-
export function analyzeEditMismatch(
|
|
15
|
-
|
|
16
|
-
const searchLines = searchString.split("\n");
|
|
17
|
-
if (searchLines.length === 0 || contentLines.length === 0) {
|
|
18
|
-
return "old_string not found in file (empty search or content)";
|
|
19
|
-
}
|
|
20
|
-
let bestMatchIndex = -1;
|
|
21
|
-
let bestMatchScore = -1;
|
|
22
|
-
// Sliding window to find the best partial match
|
|
23
|
-
for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
|
|
24
|
-
let currentScore = 0;
|
|
25
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
26
|
-
if (contentLines[i + j] === searchLines[j]) {
|
|
27
|
-
currentScore++;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// Heuristic: prioritize matches where first or last lines match
|
|
31
|
-
if (contentLines[i] === searchLines[0])
|
|
32
|
-
currentScore += 0.5;
|
|
33
|
-
if (contentLines[i + searchLines.length - 1] ===
|
|
34
|
-
searchLines[searchLines.length - 1])
|
|
35
|
-
currentScore += 0.5;
|
|
36
|
-
// Also consider trimmed matches to catch indentation issues
|
|
37
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
38
|
-
if (contentLines[i + j].trim() === searchLines[j].trim() &&
|
|
39
|
-
contentLines[i + j] !== searchLines[j]) {
|
|
40
|
-
currentScore += 0.1;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (currentScore > bestMatchScore) {
|
|
44
|
-
bestMatchScore = currentScore;
|
|
45
|
-
bestMatchIndex = i;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
// If no decent match found (score <= 0), return generic message
|
|
49
|
-
if (bestMatchScore <= 0) {
|
|
50
|
-
return "old_string not found in file (no similar block found)";
|
|
51
|
-
}
|
|
52
|
-
// Generate detailed report
|
|
53
|
-
const reportLines = [
|
|
54
|
-
`old_string not found in file. Best partial match found at line ${bestMatchIndex + 1}:`,
|
|
55
|
-
];
|
|
56
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
57
|
-
const lineNum = bestMatchIndex + j + 1;
|
|
58
|
-
const actualLine = contentLines[bestMatchIndex + j];
|
|
59
|
-
const expectedLine = searchLines[j];
|
|
60
|
-
if (actualLine === expectedLine) {
|
|
61
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}${actualLine}`);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}- ${expectedLine}`);
|
|
65
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}+ ${actualLine}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return reportLines.join("\n");
|
|
13
|
+
export function analyzeEditMismatch() {
|
|
14
|
+
return "old_string not found in file";
|
|
69
15
|
}
|
|
@@ -27,7 +27,14 @@ export declare function parseBashCommands(content: string): {
|
|
|
27
27
|
processedContent: string;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* Truncate output if it exceeds the size limit.
|
|
31
|
+
* Writes to a temp file and returns a preview + file path if truncated.
|
|
32
|
+
*/
|
|
33
|
+
export declare function truncateOutput(output: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Replace bash command placeholders with their outputs.
|
|
36
|
+
* Uses function replacer to avoid $$, $&, $' corruption in shell output.
|
|
37
|
+
* Handles both inline (!`cmd`) and block (```! cmd ```) syntax.
|
|
31
38
|
*/
|
|
32
39
|
export declare function replaceBashCommandsWithOutput(content: string, results: BashCommandResult[]): string;
|
|
33
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/utils/markdownParser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/utils/markdownParser.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAQlE,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,CA8DA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CA4CtE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAYD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAyCA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBrD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,EAAE,GAC3B,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAc,GACtB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC9B"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
2
2
|
import { exec } from "child_process";
|
|
3
3
|
import { promisify } from "util";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { tmpdir } from "os";
|
|
6
|
+
import { SKILL_BASH_MAX_OUTPUT_CHARS, PREVIEW_SIZE_BYTES, } from "../constants/toolLimits.js";
|
|
4
7
|
const execAsync = promisify(exec);
|
|
5
8
|
/**
|
|
6
9
|
* Parse YAML frontmatter from markdown content
|
|
@@ -97,13 +100,38 @@ export function parseMarkdownFile(filePath) {
|
|
|
97
100
|
throw new Error(`Failed to parse markdown file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
98
101
|
}
|
|
99
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Block syntax pattern: ```! command ```
|
|
105
|
+
*/
|
|
106
|
+
const BLOCK_BASH_REGEX = /```!\s*\n?([\s\S]*?)\n?```/g;
|
|
107
|
+
/**
|
|
108
|
+
* Inline syntax pattern: !`command`
|
|
109
|
+
*/
|
|
110
|
+
const INLINE_BASH_REGEX = /!`([^`]+)`/g;
|
|
100
111
|
export function parseBashCommands(content) {
|
|
101
|
-
|
|
112
|
+
// Performance gate: skip expensive regex if no bash pattern exists
|
|
113
|
+
// Covers the common case where 93% of skills have no bash substitution
|
|
114
|
+
if (!content.includes("!`") && !content.includes("```!")) {
|
|
115
|
+
return { commands: [], processedContent: content };
|
|
116
|
+
}
|
|
102
117
|
const commands = [];
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
// Extract block commands
|
|
119
|
+
let blockMatch;
|
|
120
|
+
const blockRegex = new RegExp(BLOCK_BASH_REGEX.source, BLOCK_BASH_REGEX.flags);
|
|
121
|
+
while ((blockMatch = blockRegex.exec(content)) !== null) {
|
|
122
|
+
const cmd = blockMatch[1].trim();
|
|
123
|
+
if (cmd) {
|
|
124
|
+
commands.push(cmd);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Extract inline commands
|
|
128
|
+
let inlineMatch;
|
|
129
|
+
const inlineRegex = new RegExp(INLINE_BASH_REGEX.source, INLINE_BASH_REGEX.flags);
|
|
130
|
+
while ((inlineMatch = inlineRegex.exec(content)) !== null) {
|
|
131
|
+
const cmd = inlineMatch[1].trim();
|
|
132
|
+
if (cmd) {
|
|
133
|
+
commands.push(cmd);
|
|
134
|
+
}
|
|
107
135
|
}
|
|
108
136
|
// For now, return the content as-is. The actual command execution
|
|
109
137
|
// will be handled by the slash command manager
|
|
@@ -113,18 +141,43 @@ export function parseBashCommands(content) {
|
|
|
113
141
|
};
|
|
114
142
|
}
|
|
115
143
|
/**
|
|
116
|
-
*
|
|
144
|
+
* Truncate output if it exceeds the size limit.
|
|
145
|
+
* Writes to a temp file and returns a preview + file path if truncated.
|
|
146
|
+
*/
|
|
147
|
+
export function truncateOutput(output) {
|
|
148
|
+
if (output.length <= SKILL_BASH_MAX_OUTPUT_CHARS) {
|
|
149
|
+
return output;
|
|
150
|
+
}
|
|
151
|
+
const preview = output.slice(0, PREVIEW_SIZE_BYTES);
|
|
152
|
+
const tempDir = join(tmpdir(), "wave-skill-bash");
|
|
153
|
+
mkdirSync(tempDir, { recursive: true });
|
|
154
|
+
const tempFile = join(tempDir, `output-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`);
|
|
155
|
+
writeFileSync(tempFile, output, "utf-8");
|
|
156
|
+
return `${preview}\n\n[Output truncated (${output.length} chars). Full output saved to: ${tempFile}]`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Replace bash command placeholders with their outputs.
|
|
160
|
+
* Uses function replacer to avoid $$, $&, $' corruption in shell output.
|
|
161
|
+
* Handles both inline (!`cmd`) and block (```! cmd ```) syntax.
|
|
117
162
|
*/
|
|
118
163
|
export function replaceBashCommandsWithOutput(content, results) {
|
|
119
|
-
const bashCommandRegex = /!`([^`]+)`/g;
|
|
120
164
|
let processedContent = content;
|
|
121
165
|
let commandIndex = 0;
|
|
122
|
-
|
|
166
|
+
// Replace block syntax first: ```! command ```
|
|
167
|
+
processedContent = processedContent.replace(BLOCK_BASH_REGEX, () => {
|
|
168
|
+
if (commandIndex < results.length) {
|
|
169
|
+
const result = results[commandIndex++];
|
|
170
|
+
return truncateOutput(result.output);
|
|
171
|
+
}
|
|
172
|
+
return "";
|
|
173
|
+
});
|
|
174
|
+
// Replace inline syntax: !`command`
|
|
175
|
+
processedContent = processedContent.replace(INLINE_BASH_REGEX, () => {
|
|
123
176
|
if (commandIndex < results.length) {
|
|
124
177
|
const result = results[commandIndex++];
|
|
125
|
-
return result.output;
|
|
178
|
+
return truncateOutput(result.output);
|
|
126
179
|
}
|
|
127
|
-
return
|
|
180
|
+
return "";
|
|
128
181
|
});
|
|
129
182
|
return processedContent;
|
|
130
183
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;
|
|
1
|
+
{"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;YAqIN,oBAAoB;CAqCpC"}
|
|
@@ -108,27 +108,16 @@ export class OpenAIClient {
|
|
|
108
108
|
error.status = response.status;
|
|
109
109
|
error.body = errorBody;
|
|
110
110
|
if (response.status === 429 && attempt < maxRetries) {
|
|
111
|
-
const responseHeaders = {};
|
|
112
|
-
response.headers.forEach((value, key) => {
|
|
113
|
-
responseHeaders[key] = value;
|
|
114
|
-
});
|
|
115
111
|
logger.warn("OpenAI API 429 Too Many Requests, retrying...", {
|
|
116
112
|
attempt: attempt + 1,
|
|
117
113
|
status: response.status,
|
|
118
|
-
responseHeaders,
|
|
119
114
|
});
|
|
120
115
|
lastError = error;
|
|
121
116
|
continue;
|
|
122
117
|
}
|
|
123
|
-
const responseHeaders = {};
|
|
124
|
-
response.headers.forEach((value, key) => {
|
|
125
|
-
responseHeaders[key] = value;
|
|
126
|
-
});
|
|
127
118
|
logger.error("OpenAI API Error:", {
|
|
128
119
|
status: response.status,
|
|
129
120
|
statusText: response.statusText,
|
|
130
|
-
requestHeaders: headers,
|
|
131
|
-
responseHeaders,
|
|
132
121
|
errorBody,
|
|
133
122
|
});
|
|
134
123
|
throw error;
|
|
@@ -23,6 +23,14 @@ export declare const stripAnsiColors: (text: string) => string;
|
|
|
23
23
|
* @returns Formatted line number prefix
|
|
24
24
|
*/
|
|
25
25
|
export declare function formatLineNumberPrefix(lineNumber: number): string;
|
|
26
|
+
/**
|
|
27
|
+
* Attempt to recover truncated JSON (e.g., missing closing braces due to max tokens).
|
|
28
|
+
* Tracks brace depth and only recovers if there are unclosed `{` braces.
|
|
29
|
+
* Will NOT recover if there are unclosed `[` brackets (can't guess the content).
|
|
30
|
+
* @param jsonStr Potentially truncated JSON string
|
|
31
|
+
* @returns Recovered JSON string, or the original if unrecoverable
|
|
32
|
+
*/
|
|
33
|
+
export declare function recoverTruncatedJson(jsonStr: string): string;
|
|
26
34
|
/**
|
|
27
35
|
* Efficiently get the last N lines of a string without splitting the whole string.
|
|
28
36
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../src/utils/stringUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBxB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAK9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAehE"}
|
|
1
|
+
{"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../src/utils/stringUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBxB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAK9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkC5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAehE"}
|
|
@@ -77,6 +77,51 @@ export const stripAnsiColors = (text) => {
|
|
|
77
77
|
export function formatLineNumberPrefix(lineNumber) {
|
|
78
78
|
return `${lineNumber.toString().padStart(6)}\t`;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Attempt to recover truncated JSON (e.g., missing closing braces due to max tokens).
|
|
82
|
+
* Tracks brace depth and only recovers if there are unclosed `{` braces.
|
|
83
|
+
* Will NOT recover if there are unclosed `[` brackets (can't guess the content).
|
|
84
|
+
* @param jsonStr Potentially truncated JSON string
|
|
85
|
+
* @returns Recovered JSON string, or the original if unrecoverable
|
|
86
|
+
*/
|
|
87
|
+
export function recoverTruncatedJson(jsonStr) {
|
|
88
|
+
let braceDepth = 0;
|
|
89
|
+
let bracketDepth = 0;
|
|
90
|
+
let inString = false;
|
|
91
|
+
let escaped = false;
|
|
92
|
+
for (const ch of jsonStr) {
|
|
93
|
+
if (escaped) {
|
|
94
|
+
escaped = false;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (ch === "\\" && inString) {
|
|
98
|
+
escaped = true;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (ch === '"') {
|
|
102
|
+
inString = !inString;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!inString) {
|
|
106
|
+
if (ch === "{")
|
|
107
|
+
braceDepth++;
|
|
108
|
+
if (ch === "}")
|
|
109
|
+
braceDepth--;
|
|
110
|
+
if (ch === "[")
|
|
111
|
+
bracketDepth++;
|
|
112
|
+
if (ch === "]")
|
|
113
|
+
bracketDepth--;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Build recovery suffix
|
|
117
|
+
let suffix = "";
|
|
118
|
+
if (inString)
|
|
119
|
+
suffix += '"'; // Close unclosed string
|
|
120
|
+
if (braceDepth > 0 && bracketDepth === 0) {
|
|
121
|
+
suffix += "}".repeat(braceDepth);
|
|
122
|
+
}
|
|
123
|
+
return suffix ? jsonStr + suffix : jsonStr;
|
|
124
|
+
}
|
|
80
125
|
/**
|
|
81
126
|
* Efficiently get the last N lines of a string without splitting the whole string.
|
|
82
127
|
*/
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -218,13 +218,6 @@ export class Agent {
|
|
|
218
218
|
}
|
|
219
219
|
};
|
|
220
220
|
|
|
221
|
-
// Wire up CWD change callback from AIManager to sync Agent's workdir
|
|
222
|
-
this.aiManager.setOnCwdChange((newCwd) => {
|
|
223
|
-
this.workdir = newCwd;
|
|
224
|
-
this.container.register("Workdir", newCwd);
|
|
225
|
-
this.options.callbacks?.onWorkdirChange?.(newCwd);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
221
|
// Wire up message queue to process when agent becomes idle
|
|
229
222
|
this.messageQueue.onMessageEnqueued = () => {
|
|
230
223
|
// If the AI is NOT loading and command is not running, trigger dequeue
|
|
@@ -287,16 +280,6 @@ export class Agent {
|
|
|
287
280
|
return this.workdir;
|
|
288
281
|
}
|
|
289
282
|
|
|
290
|
-
/**
|
|
291
|
-
* Set the working directory
|
|
292
|
-
* @param newCwd - The new working directory
|
|
293
|
-
*/
|
|
294
|
-
public setWorkdir(newCwd: string): void {
|
|
295
|
-
this.workdir = newCwd;
|
|
296
|
-
this.container.register("Workdir", newCwd);
|
|
297
|
-
this.options.callbacks?.onWorkdirChange?.(newCwd);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
283
|
/** Get project memory content */
|
|
301
284
|
public get projectMemory(): string {
|
|
302
285
|
return this._projectMemoryContent;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool output size limits matching Claude Code patterns.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** System-wide default max result size in characters. */
|
|
6
|
+
export const DEFAULT_MAX_RESULT_SIZE_CHARS = 50_000;
|
|
7
|
+
|
|
8
|
+
/** Per-command cap for skill bash substitution (inline/block). */
|
|
9
|
+
export const SKILL_BASH_MAX_OUTPUT_CHARS = 30_000;
|
|
10
|
+
|
|
11
|
+
/** Preview size in characters when output is persisted to disk. */
|
|
12
|
+
export const PREVIEW_SIZE_BYTES = 2_048;
|