@hasna/oldpal 0.1.7 → 0.1.9
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 +996 -44
- package/dist/index.js.map +14 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20450,12 +20450,12 @@ var exports_anthropic = {};
|
|
|
20450
20450
|
__export(exports_anthropic, {
|
|
20451
20451
|
AnthropicClient: () => AnthropicClient
|
|
20452
20452
|
});
|
|
20453
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
20454
|
-
import { homedir as
|
|
20455
|
-
import { join as
|
|
20453
|
+
import { readFileSync as readFileSync2, existsSync as existsSync4 } from "fs";
|
|
20454
|
+
import { homedir as homedir5 } from "os";
|
|
20455
|
+
import { join as join6 } from "path";
|
|
20456
20456
|
function loadApiKeyFromSecrets() {
|
|
20457
|
-
const secretsPath =
|
|
20458
|
-
if (
|
|
20457
|
+
const secretsPath = join6(homedir5(), ".secrets");
|
|
20458
|
+
if (existsSync4(secretsPath)) {
|
|
20459
20459
|
try {
|
|
20460
20460
|
const content = readFileSync2(secretsPath, "utf-8");
|
|
20461
20461
|
const match = content.match(/export\s+ANTHROPIC_API_KEY\s*=\s*["']?([^"'\n]+)["']?/);
|
|
@@ -29187,6 +29187,194 @@ class FilesystemTools {
|
|
|
29187
29187
|
};
|
|
29188
29188
|
}
|
|
29189
29189
|
|
|
29190
|
+
// packages/core/src/tools/web.ts
|
|
29191
|
+
class WebFetchTool {
|
|
29192
|
+
static tool = {
|
|
29193
|
+
name: "web_fetch",
|
|
29194
|
+
description: "Fetch content from a URL and return the text content. Useful for reading web pages, documentation, API responses, etc.",
|
|
29195
|
+
parameters: {
|
|
29196
|
+
type: "object",
|
|
29197
|
+
properties: {
|
|
29198
|
+
url: {
|
|
29199
|
+
type: "string",
|
|
29200
|
+
description: "The URL to fetch content from"
|
|
29201
|
+
},
|
|
29202
|
+
extract_type: {
|
|
29203
|
+
type: "string",
|
|
29204
|
+
description: 'What to extract: "text" for readable text, "html" for raw HTML, "json" for JSON response',
|
|
29205
|
+
enum: ["text", "html", "json"],
|
|
29206
|
+
default: "text"
|
|
29207
|
+
},
|
|
29208
|
+
timeout: {
|
|
29209
|
+
type: "number",
|
|
29210
|
+
description: "Timeout in milliseconds (default: 30000)"
|
|
29211
|
+
}
|
|
29212
|
+
},
|
|
29213
|
+
required: ["url"]
|
|
29214
|
+
}
|
|
29215
|
+
};
|
|
29216
|
+
static executor = async (input) => {
|
|
29217
|
+
const url = input.url;
|
|
29218
|
+
const extractType = input.extract_type || "text";
|
|
29219
|
+
const timeout = input.timeout || 30000;
|
|
29220
|
+
try {
|
|
29221
|
+
const parsedUrl = new URL(url);
|
|
29222
|
+
const hostname = parsedUrl.hostname;
|
|
29223
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.startsWith("172.")) {
|
|
29224
|
+
return "Error: Cannot fetch from local/private network addresses for security reasons";
|
|
29225
|
+
}
|
|
29226
|
+
const controller = new AbortController;
|
|
29227
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
29228
|
+
const response = await fetch(url, {
|
|
29229
|
+
signal: controller.signal,
|
|
29230
|
+
headers: {
|
|
29231
|
+
"User-Agent": "oldpal/1.0 (AI Assistant)",
|
|
29232
|
+
Accept: extractType === "json" ? "application/json" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
29233
|
+
}
|
|
29234
|
+
});
|
|
29235
|
+
clearTimeout(timeoutId);
|
|
29236
|
+
if (!response.ok) {
|
|
29237
|
+
return `Error: HTTP ${response.status} ${response.statusText}`;
|
|
29238
|
+
}
|
|
29239
|
+
const contentType = response.headers.get("content-type") || "";
|
|
29240
|
+
if (extractType === "json") {
|
|
29241
|
+
try {
|
|
29242
|
+
const json = await response.json();
|
|
29243
|
+
return JSON.stringify(json, null, 2);
|
|
29244
|
+
} catch {
|
|
29245
|
+
return "Error: Response is not valid JSON";
|
|
29246
|
+
}
|
|
29247
|
+
}
|
|
29248
|
+
const html = await response.text();
|
|
29249
|
+
if (extractType === "html") {
|
|
29250
|
+
const maxLength2 = 50000;
|
|
29251
|
+
if (html.length > maxLength2) {
|
|
29252
|
+
return html.slice(0, maxLength2) + `
|
|
29253
|
+
|
|
29254
|
+
[Content truncated...]`;
|
|
29255
|
+
}
|
|
29256
|
+
return html;
|
|
29257
|
+
}
|
|
29258
|
+
const text = extractReadableText(html);
|
|
29259
|
+
const maxLength = 30000;
|
|
29260
|
+
if (text.length > maxLength) {
|
|
29261
|
+
return text.slice(0, maxLength) + `
|
|
29262
|
+
|
|
29263
|
+
[Content truncated...]`;
|
|
29264
|
+
}
|
|
29265
|
+
return text || "No readable content found on page";
|
|
29266
|
+
} catch (error) {
|
|
29267
|
+
if (error instanceof Error) {
|
|
29268
|
+
if (error.name === "AbortError") {
|
|
29269
|
+
return `Error: Request timed out after ${timeout}ms`;
|
|
29270
|
+
}
|
|
29271
|
+
return `Error: ${error.message}`;
|
|
29272
|
+
}
|
|
29273
|
+
return `Error: ${String(error)}`;
|
|
29274
|
+
}
|
|
29275
|
+
};
|
|
29276
|
+
}
|
|
29277
|
+
|
|
29278
|
+
class WebSearchTool {
|
|
29279
|
+
static tool = {
|
|
29280
|
+
name: "web_search",
|
|
29281
|
+
description: "Search the web using DuckDuckGo and return results. Useful for finding current information, documentation, news, etc.",
|
|
29282
|
+
parameters: {
|
|
29283
|
+
type: "object",
|
|
29284
|
+
properties: {
|
|
29285
|
+
query: {
|
|
29286
|
+
type: "string",
|
|
29287
|
+
description: "The search query"
|
|
29288
|
+
},
|
|
29289
|
+
max_results: {
|
|
29290
|
+
type: "number",
|
|
29291
|
+
description: "Maximum number of results to return (default: 5, max: 10)"
|
|
29292
|
+
}
|
|
29293
|
+
},
|
|
29294
|
+
required: ["query"]
|
|
29295
|
+
}
|
|
29296
|
+
};
|
|
29297
|
+
static executor = async (input) => {
|
|
29298
|
+
const query = input.query;
|
|
29299
|
+
const maxResults = Math.min(input.max_results || 5, 10);
|
|
29300
|
+
try {
|
|
29301
|
+
const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
29302
|
+
const response = await fetch(searchUrl, {
|
|
29303
|
+
headers: {
|
|
29304
|
+
"User-Agent": "oldpal/1.0 (AI Assistant)",
|
|
29305
|
+
Accept: "text/html"
|
|
29306
|
+
}
|
|
29307
|
+
});
|
|
29308
|
+
if (!response.ok) {
|
|
29309
|
+
return `Error: Search request failed with HTTP ${response.status}`;
|
|
29310
|
+
}
|
|
29311
|
+
const html = await response.text();
|
|
29312
|
+
const results = parseDuckDuckGoResults(html, maxResults);
|
|
29313
|
+
if (results.length === 0) {
|
|
29314
|
+
return `No results found for "${query}"`;
|
|
29315
|
+
}
|
|
29316
|
+
let output = `Search results for "${query}":
|
|
29317
|
+
|
|
29318
|
+
`;
|
|
29319
|
+
for (let i = 0;i < results.length; i++) {
|
|
29320
|
+
const r = results[i];
|
|
29321
|
+
output += `${i + 1}. ${r.title}
|
|
29322
|
+
`;
|
|
29323
|
+
output += ` ${r.url}
|
|
29324
|
+
`;
|
|
29325
|
+
if (r.snippet) {
|
|
29326
|
+
output += ` ${r.snippet}
|
|
29327
|
+
`;
|
|
29328
|
+
}
|
|
29329
|
+
output += `
|
|
29330
|
+
`;
|
|
29331
|
+
}
|
|
29332
|
+
return output.trim();
|
|
29333
|
+
} catch (error) {
|
|
29334
|
+
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
29335
|
+
}
|
|
29336
|
+
};
|
|
29337
|
+
}
|
|
29338
|
+
function extractReadableText(html) {
|
|
29339
|
+
let text = html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<noscript[^>]*>[\s\S]*?<\/noscript>/gi, "").replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, "").replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, "").replace(/<header[^>]*>[\s\S]*?<\/header>/gi, "");
|
|
29340
|
+
text = text.replace(/<\/?(p|div|br|h[1-6]|li|tr|blockquote)[^>]*>/gi, `
|
|
29341
|
+
`).replace(/<\/?[^>]+>/g, " ").replace(/ /gi, " ").replace(/&/gi, "&").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, '"').replace(/'/gi, "'").replace(/\s+/g, " ").replace(/\n\s*\n/g, `
|
|
29342
|
+
|
|
29343
|
+
`).trim();
|
|
29344
|
+
return text;
|
|
29345
|
+
}
|
|
29346
|
+
function parseDuckDuckGoResults(html, maxResults) {
|
|
29347
|
+
const results = [];
|
|
29348
|
+
const resultRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>[\s\S]*?<a[^>]*class="result__snippet"[^>]*>([^<]*)/gi;
|
|
29349
|
+
let match;
|
|
29350
|
+
while ((match = resultRegex.exec(html)) !== null && results.length < maxResults) {
|
|
29351
|
+
const url = decodeURIComponent(match[1].replace(/\/l\/\?uddg=/, "").split("&")[0]);
|
|
29352
|
+
const title = match[2].trim();
|
|
29353
|
+
const snippet = match[3].trim().replace(/&[^;]+;/g, " ");
|
|
29354
|
+
if (url && title && !url.startsWith("//duckduckgo.com")) {
|
|
29355
|
+
results.push({ title, url, snippet });
|
|
29356
|
+
}
|
|
29357
|
+
}
|
|
29358
|
+
if (results.length === 0) {
|
|
29359
|
+
const simpleRegex = /<a[^>]*href="(https?:\/\/[^"]+)"[^>]*class="[^"]*result[^"]*"[^>]*>([^<]+)/gi;
|
|
29360
|
+
while ((match = simpleRegex.exec(html)) !== null && results.length < maxResults) {
|
|
29361
|
+
const url = match[1];
|
|
29362
|
+
const title = match[2].trim();
|
|
29363
|
+
if (url && title) {
|
|
29364
|
+
results.push({ title, url, snippet: "" });
|
|
29365
|
+
}
|
|
29366
|
+
}
|
|
29367
|
+
}
|
|
29368
|
+
return results;
|
|
29369
|
+
}
|
|
29370
|
+
|
|
29371
|
+
class WebTools {
|
|
29372
|
+
static registerAll(registry) {
|
|
29373
|
+
registry.register(WebFetchTool.tool, WebFetchTool.executor);
|
|
29374
|
+
registry.register(WebSearchTool.tool, WebSearchTool.executor);
|
|
29375
|
+
}
|
|
29376
|
+
}
|
|
29377
|
+
|
|
29190
29378
|
// packages/core/src/skills/loader.ts
|
|
29191
29379
|
import { join as join3 } from "path";
|
|
29192
29380
|
import { homedir as homedir2 } from "os";
|
|
@@ -29455,7 +29643,609 @@ class HookExecutor {
|
|
|
29455
29643
|
return null;
|
|
29456
29644
|
}
|
|
29457
29645
|
}
|
|
29646
|
+
// packages/core/src/commands/loader.ts
|
|
29647
|
+
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
29648
|
+
import { join as join4, basename, extname } from "path";
|
|
29649
|
+
import { homedir as homedir3 } from "os";
|
|
29650
|
+
|
|
29651
|
+
class CommandLoader {
|
|
29652
|
+
commands = new Map;
|
|
29653
|
+
cwd;
|
|
29654
|
+
constructor(cwd2) {
|
|
29655
|
+
this.cwd = cwd2 || process.cwd();
|
|
29656
|
+
}
|
|
29657
|
+
async loadAll() {
|
|
29658
|
+
this.commands.clear();
|
|
29659
|
+
const globalDir = join4(homedir3(), ".oldpal", "commands");
|
|
29660
|
+
await this.loadFromDirectory(globalDir, "global");
|
|
29661
|
+
const projectDir = join4(this.cwd, ".oldpal", "commands");
|
|
29662
|
+
await this.loadFromDirectory(projectDir, "project");
|
|
29663
|
+
}
|
|
29664
|
+
async loadFromDirectory(dir, source, prefix = "") {
|
|
29665
|
+
if (!existsSync2(dir))
|
|
29666
|
+
return;
|
|
29667
|
+
const entries = readdirSync(dir);
|
|
29668
|
+
for (const entry of entries) {
|
|
29669
|
+
const fullPath = join4(dir, entry);
|
|
29670
|
+
const stat = statSync(fullPath);
|
|
29671
|
+
if (stat.isDirectory()) {
|
|
29672
|
+
const newPrefix = prefix ? `${prefix}:${entry}` : entry;
|
|
29673
|
+
await this.loadFromDirectory(fullPath, source, newPrefix);
|
|
29674
|
+
} else if (stat.isFile() && extname(entry) === ".md") {
|
|
29675
|
+
const command = await this.loadCommandFile(fullPath, prefix);
|
|
29676
|
+
if (command) {
|
|
29677
|
+
this.commands.set(command.name, command);
|
|
29678
|
+
}
|
|
29679
|
+
}
|
|
29680
|
+
}
|
|
29681
|
+
}
|
|
29682
|
+
async loadCommandFile(filePath, prefix) {
|
|
29683
|
+
try {
|
|
29684
|
+
const content = await Bun.file(filePath).text();
|
|
29685
|
+
const { frontmatter, body } = this.parseFrontmatter(content);
|
|
29686
|
+
const fileName = basename(filePath, ".md");
|
|
29687
|
+
const name = frontmatter.name || (prefix ? `${prefix}:${fileName}` : fileName);
|
|
29688
|
+
return {
|
|
29689
|
+
name,
|
|
29690
|
+
description: frontmatter.description || `Run the ${name} command`,
|
|
29691
|
+
tags: frontmatter.tags,
|
|
29692
|
+
allowedTools: frontmatter["allowed-tools"]?.split(",").map((t) => t.trim()),
|
|
29693
|
+
content: body,
|
|
29694
|
+
filePath,
|
|
29695
|
+
builtin: false
|
|
29696
|
+
};
|
|
29697
|
+
} catch (error) {
|
|
29698
|
+
console.error(`Failed to load command from ${filePath}:`, error);
|
|
29699
|
+
return null;
|
|
29700
|
+
}
|
|
29701
|
+
}
|
|
29702
|
+
parseFrontmatter(content) {
|
|
29703
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
29704
|
+
const match = content.match(frontmatterRegex);
|
|
29705
|
+
if (!match) {
|
|
29706
|
+
return { frontmatter: {}, body: content };
|
|
29707
|
+
}
|
|
29708
|
+
const [, yamlContent, body] = match;
|
|
29709
|
+
const frontmatter = {};
|
|
29710
|
+
const lines = yamlContent.split(`
|
|
29711
|
+
`);
|
|
29712
|
+
for (const line of lines) {
|
|
29713
|
+
const colonIndex = line.indexOf(":");
|
|
29714
|
+
if (colonIndex === -1)
|
|
29715
|
+
continue;
|
|
29716
|
+
const key = line.slice(0, colonIndex).trim();
|
|
29717
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
29718
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
29719
|
+
const arrayContent = value.slice(1, -1);
|
|
29720
|
+
frontmatter[key] = arrayContent.split(",").map((v) => v.trim());
|
|
29721
|
+
} else {
|
|
29722
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
29723
|
+
value = value.slice(1, -1);
|
|
29724
|
+
}
|
|
29725
|
+
frontmatter[key] = value;
|
|
29726
|
+
}
|
|
29727
|
+
}
|
|
29728
|
+
return { frontmatter, body: body.trim() };
|
|
29729
|
+
}
|
|
29730
|
+
register(command) {
|
|
29731
|
+
this.commands.set(command.name, command);
|
|
29732
|
+
}
|
|
29733
|
+
getCommand(name) {
|
|
29734
|
+
return this.commands.get(name);
|
|
29735
|
+
}
|
|
29736
|
+
getCommands() {
|
|
29737
|
+
return Array.from(this.commands.values());
|
|
29738
|
+
}
|
|
29739
|
+
hasCommand(name) {
|
|
29740
|
+
return this.commands.has(name);
|
|
29741
|
+
}
|
|
29742
|
+
findMatching(partial) {
|
|
29743
|
+
const lower = partial.toLowerCase();
|
|
29744
|
+
return this.getCommands().filter((cmd) => cmd.name.toLowerCase().startsWith(lower) || cmd.description.toLowerCase().includes(lower));
|
|
29745
|
+
}
|
|
29746
|
+
}
|
|
29747
|
+
// packages/core/src/commands/executor.ts
|
|
29748
|
+
class CommandExecutor {
|
|
29749
|
+
loader;
|
|
29750
|
+
constructor(loader) {
|
|
29751
|
+
this.loader = loader;
|
|
29752
|
+
}
|
|
29753
|
+
parseCommand(input) {
|
|
29754
|
+
const trimmed = input.trim();
|
|
29755
|
+
if (!trimmed.startsWith("/")) {
|
|
29756
|
+
return null;
|
|
29757
|
+
}
|
|
29758
|
+
const match = trimmed.match(/^\/(\S+)(?:\s+(.*))?$/);
|
|
29759
|
+
if (!match) {
|
|
29760
|
+
return null;
|
|
29761
|
+
}
|
|
29762
|
+
return {
|
|
29763
|
+
name: match[1],
|
|
29764
|
+
args: match[2] || ""
|
|
29765
|
+
};
|
|
29766
|
+
}
|
|
29767
|
+
isCommand(input) {
|
|
29768
|
+
return this.parseCommand(input) !== null;
|
|
29769
|
+
}
|
|
29770
|
+
async execute(input, context) {
|
|
29771
|
+
const parsed = this.parseCommand(input);
|
|
29772
|
+
if (!parsed) {
|
|
29773
|
+
return { handled: false };
|
|
29774
|
+
}
|
|
29775
|
+
const command = this.loader.getCommand(parsed.name);
|
|
29776
|
+
if (!command) {
|
|
29777
|
+
context.emit("text", `Unknown command: /${parsed.name}
|
|
29778
|
+
|
|
29779
|
+
Use /help to see available commands.
|
|
29780
|
+
`);
|
|
29781
|
+
context.emit("done");
|
|
29782
|
+
return { handled: true };
|
|
29783
|
+
}
|
|
29784
|
+
if (command.selfHandled && command.handler) {
|
|
29785
|
+
return command.handler(parsed.args, context);
|
|
29786
|
+
}
|
|
29787
|
+
const prompt = await this.preparePrompt(command, parsed.args);
|
|
29788
|
+
return {
|
|
29789
|
+
handled: false,
|
|
29790
|
+
prompt
|
|
29791
|
+
};
|
|
29792
|
+
}
|
|
29793
|
+
async preparePrompt(command, args) {
|
|
29794
|
+
let content = command.content;
|
|
29795
|
+
content = content.replace(/\$ARGUMENTS/g, args || "(no arguments provided)");
|
|
29796
|
+
content = await this.processShellCommands(content);
|
|
29797
|
+
return content;
|
|
29798
|
+
}
|
|
29799
|
+
async processShellCommands(content) {
|
|
29800
|
+
const lines = content.split(`
|
|
29801
|
+
`);
|
|
29802
|
+
const processedLines = [];
|
|
29803
|
+
for (const line of lines) {
|
|
29804
|
+
const trimmed = line.trim();
|
|
29805
|
+
if (trimmed.startsWith("!")) {
|
|
29806
|
+
const command = trimmed.slice(1).trim();
|
|
29807
|
+
const output = await this.executeShell(command);
|
|
29808
|
+
processedLines.push(`\`\`\`
|
|
29809
|
+
${output}
|
|
29810
|
+
\`\`\``);
|
|
29811
|
+
} else {
|
|
29812
|
+
processedLines.push(line);
|
|
29813
|
+
}
|
|
29814
|
+
}
|
|
29815
|
+
return processedLines.join(`
|
|
29816
|
+
`);
|
|
29817
|
+
}
|
|
29818
|
+
async executeShell(command) {
|
|
29819
|
+
try {
|
|
29820
|
+
const proc = Bun.spawn(["bash", "-c", command], {
|
|
29821
|
+
stdout: "pipe",
|
|
29822
|
+
stderr: "pipe"
|
|
29823
|
+
});
|
|
29824
|
+
const [stdout, stderr] = await Promise.all([
|
|
29825
|
+
new Response(proc.stdout).text(),
|
|
29826
|
+
new Response(proc.stderr).text()
|
|
29827
|
+
]);
|
|
29828
|
+
const exitCode = await proc.exited;
|
|
29829
|
+
if (exitCode !== 0 && stderr) {
|
|
29830
|
+
return `Error (exit ${exitCode}):
|
|
29831
|
+
${stderr}`;
|
|
29832
|
+
}
|
|
29833
|
+
return stdout.trim() || "(no output)";
|
|
29834
|
+
} catch (error) {
|
|
29835
|
+
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
29836
|
+
}
|
|
29837
|
+
}
|
|
29838
|
+
getSuggestions(partial) {
|
|
29839
|
+
if (!partial.startsWith("/")) {
|
|
29840
|
+
return [];
|
|
29841
|
+
}
|
|
29842
|
+
const name = partial.slice(1).toLowerCase();
|
|
29843
|
+
return this.loader.findMatching(name);
|
|
29844
|
+
}
|
|
29845
|
+
}
|
|
29846
|
+
// packages/core/src/commands/builtin.ts
|
|
29847
|
+
import { join as join5 } from "path";
|
|
29848
|
+
import { homedir as homedir4 } from "os";
|
|
29849
|
+
import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
|
|
29850
|
+
|
|
29851
|
+
class BuiltinCommands {
|
|
29852
|
+
tokenUsage = {
|
|
29853
|
+
inputTokens: 0,
|
|
29854
|
+
outputTokens: 0,
|
|
29855
|
+
totalTokens: 0,
|
|
29856
|
+
maxContextTokens: 200000
|
|
29857
|
+
};
|
|
29858
|
+
registerAll(loader) {
|
|
29859
|
+
loader.register(this.helpCommand(loader));
|
|
29860
|
+
loader.register(this.clearCommand());
|
|
29861
|
+
loader.register(this.statusCommand());
|
|
29862
|
+
loader.register(this.compactCommand());
|
|
29863
|
+
loader.register(this.configCommand());
|
|
29864
|
+
loader.register(this.initCommand());
|
|
29865
|
+
loader.register(this.costCommand());
|
|
29866
|
+
loader.register(this.modelCommand());
|
|
29867
|
+
loader.register(this.memoryCommand());
|
|
29868
|
+
loader.register(this.bugCommand());
|
|
29869
|
+
loader.register(this.prCommand());
|
|
29870
|
+
loader.register(this.reviewCommand());
|
|
29871
|
+
}
|
|
29872
|
+
updateTokenUsage(usage) {
|
|
29873
|
+
Object.assign(this.tokenUsage, usage);
|
|
29874
|
+
}
|
|
29875
|
+
getTokenUsage() {
|
|
29876
|
+
return { ...this.tokenUsage };
|
|
29877
|
+
}
|
|
29878
|
+
helpCommand(loader) {
|
|
29879
|
+
return {
|
|
29880
|
+
name: "help",
|
|
29881
|
+
description: "Show available slash commands",
|
|
29882
|
+
builtin: true,
|
|
29883
|
+
selfHandled: true,
|
|
29884
|
+
content: "",
|
|
29885
|
+
handler: async (args, context) => {
|
|
29886
|
+
const commands = loader.getCommands();
|
|
29887
|
+
const builtinCmds = commands.filter((c) => c.builtin);
|
|
29888
|
+
const customCmds = commands.filter((c) => !c.builtin);
|
|
29889
|
+
let message = `
|
|
29890
|
+
**Available Slash Commands**
|
|
29891
|
+
|
|
29892
|
+
`;
|
|
29893
|
+
if (builtinCmds.length > 0) {
|
|
29894
|
+
message += `**Built-in Commands:**
|
|
29895
|
+
`;
|
|
29896
|
+
for (const cmd of builtinCmds.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
29897
|
+
message += ` /${cmd.name} - ${cmd.description}
|
|
29898
|
+
`;
|
|
29899
|
+
}
|
|
29900
|
+
message += `
|
|
29901
|
+
`;
|
|
29902
|
+
}
|
|
29903
|
+
if (customCmds.length > 0) {
|
|
29904
|
+
message += `**Custom Commands:**
|
|
29905
|
+
`;
|
|
29906
|
+
for (const cmd of customCmds.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
29907
|
+
message += ` /${cmd.name} - ${cmd.description}
|
|
29908
|
+
`;
|
|
29909
|
+
}
|
|
29910
|
+
message += `
|
|
29911
|
+
`;
|
|
29912
|
+
}
|
|
29913
|
+
message += `**Tips:**
|
|
29914
|
+
`;
|
|
29915
|
+
message += ` - Create custom commands in .oldpal/commands/*.md
|
|
29916
|
+
`;
|
|
29917
|
+
message += ` - Global commands go in ~/.oldpal/commands/*.md
|
|
29918
|
+
`;
|
|
29919
|
+
message += ` - Use /init to create a starter command
|
|
29920
|
+
`;
|
|
29921
|
+
context.emit("text", message);
|
|
29922
|
+
context.emit("done");
|
|
29923
|
+
return { handled: true };
|
|
29924
|
+
}
|
|
29925
|
+
};
|
|
29926
|
+
}
|
|
29927
|
+
clearCommand() {
|
|
29928
|
+
return {
|
|
29929
|
+
name: "clear",
|
|
29930
|
+
description: "Clear conversation history and start fresh",
|
|
29931
|
+
builtin: true,
|
|
29932
|
+
selfHandled: true,
|
|
29933
|
+
content: "",
|
|
29934
|
+
handler: async (args, context) => {
|
|
29935
|
+
context.clearMessages();
|
|
29936
|
+
this.tokenUsage.inputTokens = 0;
|
|
29937
|
+
this.tokenUsage.outputTokens = 0;
|
|
29938
|
+
this.tokenUsage.totalTokens = 0;
|
|
29939
|
+
context.emit("text", `Conversation cleared. Starting fresh.
|
|
29940
|
+
`);
|
|
29941
|
+
context.emit("done");
|
|
29942
|
+
return { handled: true, clearConversation: true };
|
|
29943
|
+
}
|
|
29944
|
+
};
|
|
29945
|
+
}
|
|
29946
|
+
statusCommand() {
|
|
29947
|
+
return {
|
|
29948
|
+
name: "status",
|
|
29949
|
+
description: "Show current session status and token usage",
|
|
29950
|
+
builtin: true,
|
|
29951
|
+
selfHandled: true,
|
|
29952
|
+
content: "",
|
|
29953
|
+
handler: async (args, context) => {
|
|
29954
|
+
const usage = this.tokenUsage;
|
|
29955
|
+
const usedPercent = Math.round(usage.totalTokens / usage.maxContextTokens * 100);
|
|
29956
|
+
let message = `
|
|
29957
|
+
**Session Status**
|
|
29958
|
+
|
|
29959
|
+
`;
|
|
29960
|
+
message += `**Working Directory:** ${context.cwd}
|
|
29961
|
+
`;
|
|
29962
|
+
message += `**Session ID:** ${context.sessionId}
|
|
29963
|
+
`;
|
|
29964
|
+
message += `**Messages:** ${context.messages.length}
|
|
29965
|
+
`;
|
|
29966
|
+
message += `**Available Tools:** ${context.tools.length}
|
|
29967
|
+
|
|
29968
|
+
`;
|
|
29969
|
+
message += `**Token Usage:**
|
|
29970
|
+
`;
|
|
29971
|
+
message += ` Input: ${usage.inputTokens.toLocaleString()}
|
|
29972
|
+
`;
|
|
29973
|
+
message += ` Output: ${usage.outputTokens.toLocaleString()}
|
|
29974
|
+
`;
|
|
29975
|
+
message += ` Total: ${usage.totalTokens.toLocaleString()} / ${usage.maxContextTokens.toLocaleString()} (${usedPercent}%)
|
|
29976
|
+
`;
|
|
29977
|
+
if (usage.cacheReadTokens || usage.cacheWriteTokens) {
|
|
29978
|
+
message += ` Cache Read: ${(usage.cacheReadTokens || 0).toLocaleString()}
|
|
29979
|
+
`;
|
|
29980
|
+
message += ` Cache Write: ${(usage.cacheWriteTokens || 0).toLocaleString()}
|
|
29981
|
+
`;
|
|
29982
|
+
}
|
|
29983
|
+
const barLength = 30;
|
|
29984
|
+
const filledLength = Math.round(usedPercent / 100 * barLength);
|
|
29985
|
+
const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
|
|
29986
|
+
message += `
|
|
29987
|
+
[${bar}] ${usedPercent}%
|
|
29988
|
+
`;
|
|
29989
|
+
context.emit("text", message);
|
|
29990
|
+
context.emit("done");
|
|
29991
|
+
return { handled: true };
|
|
29992
|
+
}
|
|
29993
|
+
};
|
|
29994
|
+
}
|
|
29995
|
+
compactCommand() {
|
|
29996
|
+
return {
|
|
29997
|
+
name: "compact",
|
|
29998
|
+
description: "Summarize conversation to save context space",
|
|
29999
|
+
builtin: true,
|
|
30000
|
+
selfHandled: false,
|
|
30001
|
+
content: `Please summarize our conversation so far into a concise format that preserves:
|
|
30002
|
+
1. Key decisions made
|
|
30003
|
+
2. Important context about the codebase
|
|
30004
|
+
3. Current task/goal we're working on
|
|
30005
|
+
4. Any constraints or requirements mentioned
|
|
30006
|
+
|
|
30007
|
+
Format the summary as a brief bullet-point list. This summary will replace the conversation history to save context space.`
|
|
30008
|
+
};
|
|
30009
|
+
}
|
|
30010
|
+
configCommand() {
|
|
30011
|
+
return {
|
|
30012
|
+
name: "config",
|
|
30013
|
+
description: "Show current configuration",
|
|
30014
|
+
builtin: true,
|
|
30015
|
+
selfHandled: true,
|
|
30016
|
+
content: "",
|
|
30017
|
+
handler: async (args, context) => {
|
|
30018
|
+
const configPaths = [
|
|
30019
|
+
join5(context.cwd, ".oldpal", "config.json"),
|
|
30020
|
+
join5(homedir4(), ".oldpal", "config.json")
|
|
30021
|
+
];
|
|
30022
|
+
let message = `
|
|
30023
|
+
**Configuration**
|
|
30024
|
+
|
|
30025
|
+
`;
|
|
30026
|
+
message += `**Config File Locations:**
|
|
30027
|
+
`;
|
|
30028
|
+
for (const path of configPaths) {
|
|
30029
|
+
const exists = existsSync3(path);
|
|
30030
|
+
message += ` ${exists ? "\u2713" : "\u25CB"} ${path}
|
|
30031
|
+
`;
|
|
30032
|
+
}
|
|
30033
|
+
message += `
|
|
30034
|
+
**Commands Directories:**
|
|
30035
|
+
`;
|
|
30036
|
+
message += ` - Project: ${join5(context.cwd, ".oldpal", "commands")}
|
|
30037
|
+
`;
|
|
30038
|
+
message += ` - Global: ${join5(homedir4(), ".oldpal", "commands")}
|
|
30039
|
+
`;
|
|
30040
|
+
context.emit("text", message);
|
|
30041
|
+
context.emit("done");
|
|
30042
|
+
return { handled: true };
|
|
30043
|
+
}
|
|
30044
|
+
};
|
|
30045
|
+
}
|
|
30046
|
+
initCommand() {
|
|
30047
|
+
return {
|
|
30048
|
+
name: "init",
|
|
30049
|
+
description: "Initialize oldpal config and create example command",
|
|
30050
|
+
builtin: true,
|
|
30051
|
+
selfHandled: true,
|
|
30052
|
+
content: "",
|
|
30053
|
+
handler: async (args, context) => {
|
|
30054
|
+
const commandsDir = join5(context.cwd, ".oldpal", "commands");
|
|
30055
|
+
mkdirSync(commandsDir, { recursive: true });
|
|
30056
|
+
const exampleCommand = `---
|
|
30057
|
+
name: review
|
|
30058
|
+
description: Review code changes for issues and improvements
|
|
30059
|
+
tags: [code, review]
|
|
30060
|
+
---
|
|
30061
|
+
|
|
30062
|
+
# Code Review
|
|
30063
|
+
|
|
30064
|
+
Please review the current code changes and provide feedback on:
|
|
30065
|
+
|
|
30066
|
+
1. **Code Quality**
|
|
30067
|
+
- Readability and maintainability
|
|
30068
|
+
- Following project conventions
|
|
30069
|
+
- Proper error handling
|
|
30070
|
+
|
|
30071
|
+
2. **Potential Issues**
|
|
30072
|
+
- Security vulnerabilities
|
|
30073
|
+
- Performance concerns
|
|
30074
|
+
- Edge cases not handled
|
|
30075
|
+
|
|
30076
|
+
3. **Suggestions**
|
|
30077
|
+
- Improvements to consider
|
|
30078
|
+
- Best practices to apply
|
|
30079
|
+
- Documentation needs
|
|
30080
|
+
|
|
30081
|
+
If there are staged git changes, focus on those. Otherwise, ask what code to review.
|
|
30082
|
+
`;
|
|
30083
|
+
const examplePath = join5(commandsDir, "review.md");
|
|
30084
|
+
if (!existsSync3(examplePath)) {
|
|
30085
|
+
writeFileSync(examplePath, exampleCommand);
|
|
30086
|
+
}
|
|
30087
|
+
let message = `
|
|
30088
|
+
**Initialized oldpal**
|
|
30089
|
+
|
|
30090
|
+
`;
|
|
30091
|
+
message += `Created: ${commandsDir}
|
|
30092
|
+
`;
|
|
30093
|
+
message += `Example: ${examplePath}
|
|
30094
|
+
|
|
30095
|
+
`;
|
|
30096
|
+
message += `You can now:
|
|
30097
|
+
`;
|
|
30098
|
+
message += ` - Add custom commands to .oldpal/commands/
|
|
30099
|
+
`;
|
|
30100
|
+
message += ` - Use /review to try the example command
|
|
30101
|
+
`;
|
|
30102
|
+
message += ` - Run /help to see all available commands
|
|
30103
|
+
`;
|
|
30104
|
+
context.emit("text", message);
|
|
30105
|
+
context.emit("done");
|
|
30106
|
+
return { handled: true };
|
|
30107
|
+
}
|
|
30108
|
+
};
|
|
30109
|
+
}
|
|
30110
|
+
costCommand() {
|
|
30111
|
+
return {
|
|
30112
|
+
name: "cost",
|
|
30113
|
+
description: "Show estimated API cost for this session",
|
|
30114
|
+
builtin: true,
|
|
30115
|
+
selfHandled: true,
|
|
30116
|
+
content: "",
|
|
30117
|
+
handler: async (args, context) => {
|
|
30118
|
+
const usage = this.tokenUsage;
|
|
30119
|
+
const inputCostPer1M = 3;
|
|
30120
|
+
const outputCostPer1M = 15;
|
|
30121
|
+
const inputCost = usage.inputTokens / 1e6 * inputCostPer1M;
|
|
30122
|
+
const outputCost = usage.outputTokens / 1e6 * outputCostPer1M;
|
|
30123
|
+
const totalCost = inputCost + outputCost;
|
|
30124
|
+
const cacheReadCostPer1M = 0.3;
|
|
30125
|
+
const cacheSavings = usage.cacheReadTokens ? usage.cacheReadTokens / 1e6 * (inputCostPer1M - cacheReadCostPer1M) : 0;
|
|
30126
|
+
let message = `
|
|
30127
|
+
**Estimated Session Cost**
|
|
30128
|
+
|
|
30129
|
+
`;
|
|
30130
|
+
message += `Input tokens: ${usage.inputTokens.toLocaleString()} (~$${inputCost.toFixed(4)})
|
|
30131
|
+
`;
|
|
30132
|
+
message += `Output tokens: ${usage.outputTokens.toLocaleString()} (~$${outputCost.toFixed(4)})
|
|
30133
|
+
`;
|
|
30134
|
+
message += `**Total: ~$${totalCost.toFixed(4)}**
|
|
30135
|
+
`;
|
|
30136
|
+
if (cacheSavings > 0) {
|
|
30137
|
+
message += `
|
|
30138
|
+
Cache savings: ~$${cacheSavings.toFixed(4)}
|
|
30139
|
+
`;
|
|
30140
|
+
}
|
|
30141
|
+
message += `
|
|
30142
|
+
*Based on Claude 3.5 Sonnet pricing*
|
|
30143
|
+
`;
|
|
30144
|
+
context.emit("text", message);
|
|
30145
|
+
context.emit("done");
|
|
30146
|
+
return { handled: true };
|
|
30147
|
+
}
|
|
30148
|
+
};
|
|
30149
|
+
}
|
|
30150
|
+
modelCommand() {
|
|
30151
|
+
return {
|
|
30152
|
+
name: "model",
|
|
30153
|
+
description: "Show current model information",
|
|
30154
|
+
builtin: true,
|
|
30155
|
+
selfHandled: true,
|
|
30156
|
+
content: "",
|
|
30157
|
+
handler: async (args, context) => {
|
|
30158
|
+
let message = `
|
|
30159
|
+
**Model Information**
|
|
30160
|
+
|
|
30161
|
+
`;
|
|
30162
|
+
message += `Current model: claude-3-5-sonnet-20241022
|
|
30163
|
+
`;
|
|
30164
|
+
message += `Context window: 200,000 tokens
|
|
30165
|
+
`;
|
|
30166
|
+
message += `Max output: 8,192 tokens
|
|
30167
|
+
|
|
30168
|
+
`;
|
|
30169
|
+
message += `*Model selection coming in a future update*
|
|
30170
|
+
`;
|
|
30171
|
+
context.emit("text", message);
|
|
30172
|
+
context.emit("done");
|
|
30173
|
+
return { handled: true };
|
|
30174
|
+
}
|
|
30175
|
+
};
|
|
30176
|
+
}
|
|
30177
|
+
memoryCommand() {
|
|
30178
|
+
return {
|
|
30179
|
+
name: "memory",
|
|
30180
|
+
description: "Show conversation summary and key memories",
|
|
30181
|
+
builtin: true,
|
|
30182
|
+
selfHandled: false,
|
|
30183
|
+
content: `Please provide a summary of our conversation so far, including:
|
|
30184
|
+
|
|
30185
|
+
1. **Key Context** - What you know about this project/codebase
|
|
30186
|
+
2. **Current Task** - What we're working on
|
|
30187
|
+
3. **Decisions Made** - Any choices or agreements from our discussion
|
|
30188
|
+
4. **Open Items** - Things we mentioned but haven't addressed yet
|
|
30189
|
+
|
|
30190
|
+
Keep it concise but comprehensive.`
|
|
30191
|
+
};
|
|
30192
|
+
}
|
|
30193
|
+
bugCommand() {
|
|
30194
|
+
return {
|
|
30195
|
+
name: "bug",
|
|
30196
|
+
description: "Analyze and help fix a bug",
|
|
30197
|
+
builtin: true,
|
|
30198
|
+
selfHandled: false,
|
|
30199
|
+
content: `Help me debug an issue. $ARGUMENTS
|
|
30200
|
+
|
|
30201
|
+
Please:
|
|
30202
|
+
1. Understand the bug/error described
|
|
30203
|
+
2. Identify likely causes
|
|
30204
|
+
3. Search relevant code files
|
|
30205
|
+
4. Propose a fix with code changes
|
|
30206
|
+
|
|
30207
|
+
If no bug is described, ask me to describe the issue I'm experiencing.`
|
|
30208
|
+
};
|
|
30209
|
+
}
|
|
30210
|
+
prCommand() {
|
|
30211
|
+
return {
|
|
30212
|
+
name: "pr",
|
|
30213
|
+
description: "Create a pull request for current changes",
|
|
30214
|
+
builtin: true,
|
|
30215
|
+
selfHandled: false,
|
|
30216
|
+
content: `Help me create a pull request for the current changes.
|
|
30217
|
+
|
|
30218
|
+
1. First, check git status and staged changes
|
|
30219
|
+
2. Review the diff to understand what changed
|
|
30220
|
+
3. Write a clear PR title (max 72 chars)
|
|
30221
|
+
4. Write a description with:
|
|
30222
|
+
- Summary of changes
|
|
30223
|
+
- Motivation/context
|
|
30224
|
+
- Testing done
|
|
30225
|
+
- Any notes for reviewers
|
|
30226
|
+
|
|
30227
|
+
Then create the PR using the gh CLI.`
|
|
30228
|
+
};
|
|
30229
|
+
}
|
|
30230
|
+
reviewCommand() {
|
|
30231
|
+
return {
|
|
30232
|
+
name: "review",
|
|
30233
|
+
description: "Review code changes for issues",
|
|
30234
|
+
builtin: true,
|
|
30235
|
+
selfHandled: false,
|
|
30236
|
+
content: `Review the current code changes. $ARGUMENTS
|
|
30237
|
+
|
|
30238
|
+
Check for:
|
|
30239
|
+
1. **Bugs** - Logic errors, edge cases, null checks
|
|
30240
|
+
2. **Security** - Input validation, injection risks, secrets
|
|
30241
|
+
3. **Performance** - N+1 queries, unnecessary loops, memory leaks
|
|
30242
|
+
4. **Style** - Naming, formatting, code organization
|
|
30243
|
+
5. **Tests** - Coverage, edge cases, assertions
|
|
29458
30244
|
|
|
30245
|
+
If there are staged changes, review those. Otherwise, ask what to review.`
|
|
30246
|
+
};
|
|
30247
|
+
}
|
|
30248
|
+
}
|
|
29459
30249
|
// packages/core/src/llm/client.ts
|
|
29460
30250
|
async function createLLMClient(config) {
|
|
29461
30251
|
if (config.provider === "anthropic") {
|
|
@@ -29466,8 +30256,8 @@ async function createLLMClient(config) {
|
|
|
29466
30256
|
}
|
|
29467
30257
|
|
|
29468
30258
|
// packages/core/src/config.ts
|
|
29469
|
-
import { join as
|
|
29470
|
-
import { homedir as
|
|
30259
|
+
import { join as join7 } from "path";
|
|
30260
|
+
import { homedir as homedir6 } from "os";
|
|
29471
30261
|
var DEFAULT_CONFIG = {
|
|
29472
30262
|
llm: {
|
|
29473
30263
|
provider: "anthropic",
|
|
@@ -29497,13 +30287,13 @@ var DEFAULT_CONFIG = {
|
|
|
29497
30287
|
]
|
|
29498
30288
|
};
|
|
29499
30289
|
function getConfigDir() {
|
|
29500
|
-
return
|
|
30290
|
+
return join7(homedir6(), ".oldpal");
|
|
29501
30291
|
}
|
|
29502
30292
|
function getConfigPath(filename) {
|
|
29503
|
-
return
|
|
30293
|
+
return join7(getConfigDir(), filename);
|
|
29504
30294
|
}
|
|
29505
30295
|
function getProjectConfigDir(cwd2 = process.cwd()) {
|
|
29506
|
-
return
|
|
30296
|
+
return join7(cwd2, ".oldpal");
|
|
29507
30297
|
}
|
|
29508
30298
|
async function loadConfig(cwd2 = process.cwd()) {
|
|
29509
30299
|
const config = { ...DEFAULT_CONFIG };
|
|
@@ -29516,7 +30306,7 @@ async function loadConfig(cwd2 = process.cwd()) {
|
|
|
29516
30306
|
if (userConfig.voice)
|
|
29517
30307
|
config.voice = { ...config.voice, ...userConfig.voice };
|
|
29518
30308
|
}
|
|
29519
|
-
const projectConfigPath =
|
|
30309
|
+
const projectConfigPath = join7(getProjectConfigDir(cwd2), "settings.json");
|
|
29520
30310
|
const projectConfig = await loadJsonFile(projectConfigPath);
|
|
29521
30311
|
if (projectConfig) {
|
|
29522
30312
|
Object.assign(config, projectConfig);
|
|
@@ -29525,7 +30315,7 @@ async function loadConfig(cwd2 = process.cwd()) {
|
|
|
29525
30315
|
if (projectConfig.voice)
|
|
29526
30316
|
config.voice = { ...config.voice, ...projectConfig.voice };
|
|
29527
30317
|
}
|
|
29528
|
-
const localConfigPath =
|
|
30318
|
+
const localConfigPath = join7(getProjectConfigDir(cwd2), "settings.local.json");
|
|
29529
30319
|
const localConfig = await loadJsonFile(localConfigPath);
|
|
29530
30320
|
if (localConfig) {
|
|
29531
30321
|
Object.assign(config, localConfig);
|
|
@@ -29543,7 +30333,7 @@ async function loadHooksConfig(cwd2 = process.cwd()) {
|
|
|
29543
30333
|
if (userHooks?.hooks) {
|
|
29544
30334
|
mergeHooks(hooks, userHooks.hooks);
|
|
29545
30335
|
}
|
|
29546
|
-
const projectHooksPath =
|
|
30336
|
+
const projectHooksPath = join7(getProjectConfigDir(cwd2), "hooks.json");
|
|
29547
30337
|
const projectHooks = await loadJsonFile(projectHooksPath);
|
|
29548
30338
|
if (projectHooks?.hooks) {
|
|
29549
30339
|
mergeHooks(hooks, projectHooks.hooks);
|
|
@@ -29579,16 +30369,22 @@ class AgentLoop {
|
|
|
29579
30369
|
skillExecutor;
|
|
29580
30370
|
hookLoader;
|
|
29581
30371
|
hookExecutor;
|
|
30372
|
+
commandLoader;
|
|
30373
|
+
commandExecutor;
|
|
30374
|
+
builtinCommands;
|
|
29582
30375
|
llmClient = null;
|
|
29583
30376
|
config = null;
|
|
29584
30377
|
cwd;
|
|
30378
|
+
sessionId;
|
|
29585
30379
|
isRunning = false;
|
|
29586
30380
|
shouldStop = false;
|
|
29587
30381
|
onChunk;
|
|
29588
30382
|
onToolStart;
|
|
29589
30383
|
onToolEnd;
|
|
30384
|
+
onTokenUsage;
|
|
29590
30385
|
constructor(options = {}) {
|
|
29591
30386
|
this.cwd = options.cwd || process.cwd();
|
|
30387
|
+
this.sessionId = options.sessionId || generateId();
|
|
29592
30388
|
this.context = new AgentContext;
|
|
29593
30389
|
this.toolRegistry = new ToolRegistry;
|
|
29594
30390
|
this.connectorBridge = new ConnectorBridge;
|
|
@@ -29596,22 +30392,29 @@ class AgentLoop {
|
|
|
29596
30392
|
this.skillExecutor = new SkillExecutor;
|
|
29597
30393
|
this.hookLoader = new HookLoader;
|
|
29598
30394
|
this.hookExecutor = new HookExecutor;
|
|
30395
|
+
this.commandLoader = new CommandLoader(this.cwd);
|
|
30396
|
+
this.commandExecutor = new CommandExecutor(this.commandLoader);
|
|
30397
|
+
this.builtinCommands = new BuiltinCommands;
|
|
29599
30398
|
this.onChunk = options.onChunk;
|
|
29600
30399
|
this.onToolStart = options.onToolStart;
|
|
29601
30400
|
this.onToolEnd = options.onToolEnd;
|
|
30401
|
+
this.onTokenUsage = options.onTokenUsage;
|
|
29602
30402
|
}
|
|
29603
30403
|
async initialize() {
|
|
29604
30404
|
this.config = await loadConfig(this.cwd);
|
|
29605
30405
|
this.llmClient = await createLLMClient(this.config.llm);
|
|
29606
30406
|
this.toolRegistry.register(BashTool.tool, BashTool.executor);
|
|
29607
30407
|
FilesystemTools.registerAll(this.toolRegistry);
|
|
30408
|
+
WebTools.registerAll(this.toolRegistry);
|
|
29608
30409
|
await this.connectorBridge.discover(this.config.connectors);
|
|
29609
30410
|
this.connectorBridge.registerAll(this.toolRegistry);
|
|
29610
30411
|
await this.skillLoader.loadAll(this.cwd);
|
|
30412
|
+
await this.commandLoader.loadAll();
|
|
30413
|
+
this.builtinCommands.registerAll(this.commandLoader);
|
|
29611
30414
|
const hooksConfig = await loadHooksConfig(this.cwd);
|
|
29612
30415
|
this.hookLoader.load(hooksConfig);
|
|
29613
30416
|
await this.hookExecutor.execute(this.hookLoader.getHooks("SessionStart"), {
|
|
29614
|
-
session_id:
|
|
30417
|
+
session_id: this.sessionId,
|
|
29615
30418
|
hook_event_name: "SessionStart",
|
|
29616
30419
|
cwd: this.cwd
|
|
29617
30420
|
});
|
|
@@ -29627,7 +30430,7 @@ class AgentLoop {
|
|
|
29627
30430
|
this.shouldStop = false;
|
|
29628
30431
|
try {
|
|
29629
30432
|
const promptHookResult = await this.hookExecutor.execute(this.hookLoader.getHooks("UserPromptSubmit"), {
|
|
29630
|
-
session_id:
|
|
30433
|
+
session_id: this.sessionId,
|
|
29631
30434
|
hook_event_name: "UserPromptSubmit",
|
|
29632
30435
|
cwd: this.cwd,
|
|
29633
30436
|
prompt: userMessage
|
|
@@ -29636,6 +30439,18 @@ class AgentLoop {
|
|
|
29636
30439
|
this.emit({ type: "error", error: promptHookResult.stopReason || "Blocked by hook" });
|
|
29637
30440
|
return;
|
|
29638
30441
|
}
|
|
30442
|
+
if (userMessage.startsWith("/")) {
|
|
30443
|
+
const commandResult = await this.handleCommand(userMessage);
|
|
30444
|
+
if (commandResult.handled) {
|
|
30445
|
+
if (commandResult.clearConversation) {
|
|
30446
|
+
this.context = new AgentContext;
|
|
30447
|
+
}
|
|
30448
|
+
return;
|
|
30449
|
+
}
|
|
30450
|
+
if (commandResult.prompt) {
|
|
30451
|
+
userMessage = commandResult.prompt;
|
|
30452
|
+
}
|
|
30453
|
+
}
|
|
29639
30454
|
if (userMessage.startsWith("/")) {
|
|
29640
30455
|
const handled = await this.handleSkillInvocation(userMessage);
|
|
29641
30456
|
if (handled)
|
|
@@ -29716,6 +30531,30 @@ class AgentLoop {
|
|
|
29716
30531
|
}
|
|
29717
30532
|
return results;
|
|
29718
30533
|
}
|
|
30534
|
+
async handleCommand(message) {
|
|
30535
|
+
const context = {
|
|
30536
|
+
cwd: this.cwd,
|
|
30537
|
+
sessionId: this.sessionId,
|
|
30538
|
+
messages: this.context.getMessages(),
|
|
30539
|
+
tools: this.toolRegistry.getTools(),
|
|
30540
|
+
clearMessages: () => {
|
|
30541
|
+
this.context = new AgentContext;
|
|
30542
|
+
},
|
|
30543
|
+
addSystemMessage: (content) => {
|
|
30544
|
+
this.context.addSystemMessage(content);
|
|
30545
|
+
},
|
|
30546
|
+
emit: (type, content) => {
|
|
30547
|
+
if (type === "text" && content) {
|
|
30548
|
+
this.emit({ type: "text", content });
|
|
30549
|
+
} else if (type === "done") {
|
|
30550
|
+
this.emit({ type: "done" });
|
|
30551
|
+
} else if (type === "error" && content) {
|
|
30552
|
+
this.emit({ type: "error", error: content });
|
|
30553
|
+
}
|
|
30554
|
+
}
|
|
30555
|
+
};
|
|
30556
|
+
return this.commandExecutor.execute(message, context);
|
|
30557
|
+
}
|
|
29719
30558
|
async handleSkillInvocation(message) {
|
|
29720
30559
|
const match = message.match(/^\/(\S+)(?:\s+(.*))?$/);
|
|
29721
30560
|
if (!match)
|
|
@@ -29747,18 +30586,34 @@ class AgentLoop {
|
|
|
29747
30586
|
getSkills() {
|
|
29748
30587
|
return this.skillLoader.getSkills();
|
|
29749
30588
|
}
|
|
30589
|
+
getCommands() {
|
|
30590
|
+
return this.commandLoader.getCommands();
|
|
30591
|
+
}
|
|
30592
|
+
getTokenUsage() {
|
|
30593
|
+
return this.builtinCommands.getTokenUsage();
|
|
30594
|
+
}
|
|
30595
|
+
updateTokenUsage(usage) {
|
|
30596
|
+
this.builtinCommands.updateTokenUsage(usage);
|
|
30597
|
+
this.onTokenUsage?.(this.builtinCommands.getTokenUsage());
|
|
30598
|
+
}
|
|
29750
30599
|
isProcessing() {
|
|
29751
30600
|
return this.isRunning;
|
|
29752
30601
|
}
|
|
30602
|
+
getSessionId() {
|
|
30603
|
+
return this.sessionId;
|
|
30604
|
+
}
|
|
30605
|
+
clearConversation() {
|
|
30606
|
+
this.context = new AgentContext;
|
|
30607
|
+
}
|
|
29753
30608
|
}
|
|
29754
30609
|
|
|
29755
30610
|
// packages/core/src/index.ts
|
|
29756
30611
|
init_anthropic();
|
|
29757
30612
|
|
|
29758
30613
|
// packages/core/src/logger.ts
|
|
29759
|
-
import { existsSync as
|
|
29760
|
-
import { join as
|
|
29761
|
-
import { homedir as
|
|
30614
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, appendFileSync } from "fs";
|
|
30615
|
+
import { join as join8 } from "path";
|
|
30616
|
+
import { homedir as homedir7 } from "os";
|
|
29762
30617
|
|
|
29763
30618
|
class Logger {
|
|
29764
30619
|
logDir;
|
|
@@ -29766,14 +30621,14 @@ class Logger {
|
|
|
29766
30621
|
sessionId;
|
|
29767
30622
|
constructor(sessionId) {
|
|
29768
30623
|
this.sessionId = sessionId;
|
|
29769
|
-
this.logDir =
|
|
30624
|
+
this.logDir = join8(homedir7(), ".oldpal", "logs");
|
|
29770
30625
|
this.ensureDir(this.logDir);
|
|
29771
30626
|
const date = new Date().toISOString().split("T")[0];
|
|
29772
|
-
this.logFile =
|
|
30627
|
+
this.logFile = join8(this.logDir, `${date}.log`);
|
|
29773
30628
|
}
|
|
29774
30629
|
ensureDir(dir) {
|
|
29775
|
-
if (!
|
|
29776
|
-
|
|
30630
|
+
if (!existsSync5(dir)) {
|
|
30631
|
+
mkdirSync2(dir, { recursive: true });
|
|
29777
30632
|
}
|
|
29778
30633
|
}
|
|
29779
30634
|
write(level, message, data) {
|
|
@@ -29812,13 +30667,13 @@ class SessionStorage {
|
|
|
29812
30667
|
sessionId;
|
|
29813
30668
|
constructor(sessionId) {
|
|
29814
30669
|
this.sessionId = sessionId;
|
|
29815
|
-
this.sessionsDir =
|
|
30670
|
+
this.sessionsDir = join8(homedir7(), ".oldpal", "sessions");
|
|
29816
30671
|
this.ensureDir(this.sessionsDir);
|
|
29817
|
-
this.sessionFile =
|
|
30672
|
+
this.sessionFile = join8(this.sessionsDir, `${sessionId}.json`);
|
|
29818
30673
|
}
|
|
29819
30674
|
ensureDir(dir) {
|
|
29820
|
-
if (!
|
|
29821
|
-
|
|
30675
|
+
if (!existsSync5(dir)) {
|
|
30676
|
+
mkdirSync2(dir, { recursive: true });
|
|
29822
30677
|
}
|
|
29823
30678
|
}
|
|
29824
30679
|
save(data) {
|
|
@@ -29831,16 +30686,16 @@ class SessionStorage {
|
|
|
29831
30686
|
}
|
|
29832
30687
|
}
|
|
29833
30688
|
function initOldpalDir() {
|
|
29834
|
-
const baseDir =
|
|
30689
|
+
const baseDir = join8(homedir7(), ".oldpal");
|
|
29835
30690
|
const dirs = [
|
|
29836
30691
|
baseDir,
|
|
29837
|
-
|
|
29838
|
-
|
|
29839
|
-
|
|
30692
|
+
join8(baseDir, "sessions"),
|
|
30693
|
+
join8(baseDir, "logs"),
|
|
30694
|
+
join8(baseDir, "skills")
|
|
29840
30695
|
];
|
|
29841
30696
|
for (const dir of dirs) {
|
|
29842
|
-
if (!
|
|
29843
|
-
|
|
30697
|
+
if (!existsSync5(dir)) {
|
|
30698
|
+
mkdirSync2(dir, { recursive: true });
|
|
29844
30699
|
}
|
|
29845
30700
|
}
|
|
29846
30701
|
}
|
|
@@ -29977,6 +30832,20 @@ class EmbeddedClient {
|
|
|
29977
30832
|
getSessionId() {
|
|
29978
30833
|
return this.session.getSessionId();
|
|
29979
30834
|
}
|
|
30835
|
+
async getCommands() {
|
|
30836
|
+
if (!this.initialized) {
|
|
30837
|
+
await this.initialize();
|
|
30838
|
+
}
|
|
30839
|
+
return this.agent.getCommands();
|
|
30840
|
+
}
|
|
30841
|
+
getTokenUsage() {
|
|
30842
|
+
return this.agent.getTokenUsage();
|
|
30843
|
+
}
|
|
30844
|
+
clearConversation() {
|
|
30845
|
+
this.agent.clearConversation();
|
|
30846
|
+
this.messages = [];
|
|
30847
|
+
this.logger.info("Conversation cleared");
|
|
30848
|
+
}
|
|
29980
30849
|
}
|
|
29981
30850
|
// packages/terminal/src/components/Input.tsx
|
|
29982
30851
|
var import_react23 = __toESM(require_react(), 1);
|
|
@@ -30158,7 +31027,7 @@ function parseMarkdown(text) {
|
|
|
30158
31027
|
|
|
30159
31028
|
// packages/terminal/src/components/Messages.tsx
|
|
30160
31029
|
var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
|
|
30161
|
-
function Messages4({ messages, currentResponse, currentToolCall, lastToolResult }) {
|
|
31030
|
+
function Messages4({ messages, currentResponse, currentToolCall, lastToolResult, activityLog = [] }) {
|
|
30162
31031
|
const visibleMessages = messages.slice(-15);
|
|
30163
31032
|
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
30164
31033
|
flexDirection: "column",
|
|
@@ -30166,7 +31035,37 @@ function Messages4({ messages, currentResponse, currentToolCall, lastToolResult
|
|
|
30166
31035
|
visibleMessages.map((message) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(MessageBubble, {
|
|
30167
31036
|
message
|
|
30168
31037
|
}, message.id, false, undefined, this)),
|
|
30169
|
-
|
|
31038
|
+
activityLog.map((entry) => {
|
|
31039
|
+
if (entry.type === "tool_call" && entry.toolCall) {
|
|
31040
|
+
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
31041
|
+
marginY: 1,
|
|
31042
|
+
children: [
|
|
31043
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
31044
|
+
dimColor: true,
|
|
31045
|
+
children: "\u25D0 "
|
|
31046
|
+
}, undefined, false, undefined, this),
|
|
31047
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
31048
|
+
dimColor: true,
|
|
31049
|
+
children: formatToolCall(entry.toolCall)
|
|
31050
|
+
}, undefined, false, undefined, this)
|
|
31051
|
+
]
|
|
31052
|
+
}, entry.id, true, undefined, this);
|
|
31053
|
+
}
|
|
31054
|
+
if (entry.type === "tool_result" && entry.toolResult) {
|
|
31055
|
+
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
31056
|
+
marginLeft: 2,
|
|
31057
|
+
children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
31058
|
+
dimColor: true,
|
|
31059
|
+
children: [
|
|
31060
|
+
"\u2192 ",
|
|
31061
|
+
truncate(entry.toolResult.content, 100)
|
|
31062
|
+
]
|
|
31063
|
+
}, undefined, true, undefined, this)
|
|
31064
|
+
}, entry.id, false, undefined, this);
|
|
31065
|
+
}
|
|
31066
|
+
return null;
|
|
31067
|
+
}),
|
|
31068
|
+
currentToolCall && !activityLog.some((e) => e.toolCall?.id === currentToolCall.id) && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
30170
31069
|
marginY: 1,
|
|
30171
31070
|
children: [
|
|
30172
31071
|
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
@@ -30179,7 +31078,7 @@ function Messages4({ messages, currentResponse, currentToolCall, lastToolResult
|
|
|
30179
31078
|
}, undefined, false, undefined, this)
|
|
30180
31079
|
]
|
|
30181
31080
|
}, undefined, true, undefined, this),
|
|
30182
|
-
lastToolResult && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
31081
|
+
lastToolResult && !activityLog.some((e) => e.toolResult?.toolCallId === lastToolResult.toolCallId) && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
30183
31082
|
marginY: 1,
|
|
30184
31083
|
marginLeft: 2,
|
|
30185
31084
|
children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
@@ -30297,10 +31196,17 @@ function truncate(text, maxLength) {
|
|
|
30297
31196
|
|
|
30298
31197
|
// packages/terminal/src/components/Status.tsx
|
|
30299
31198
|
var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
|
|
30300
|
-
function Status({ isProcessing, cwd: cwd2, queueLength = 0 }) {
|
|
30301
|
-
const maxCwdLength =
|
|
31199
|
+
function Status({ isProcessing, cwd: cwd2, queueLength = 0, tokenUsage }) {
|
|
31200
|
+
const maxCwdLength = 30;
|
|
30302
31201
|
const displayCwd = cwd2.length > maxCwdLength ? "..." + cwd2.slice(-(maxCwdLength - 3)) : cwd2;
|
|
30303
31202
|
const queueInfo = queueLength > 0 ? ` | ${queueLength} queued` : "";
|
|
31203
|
+
let tokenInfo = "";
|
|
31204
|
+
if (tokenUsage && tokenUsage.totalTokens > 0) {
|
|
31205
|
+
const used = Math.round(tokenUsage.totalTokens / 1000);
|
|
31206
|
+
const max = Math.round(tokenUsage.maxContextTokens / 1000);
|
|
31207
|
+
const percent = Math.round(tokenUsage.totalTokens / tokenUsage.maxContextTokens * 100);
|
|
31208
|
+
tokenInfo = ` | ${used}k/${max}k (${percent}%)`;
|
|
31209
|
+
}
|
|
30304
31210
|
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
30305
31211
|
marginTop: 1,
|
|
30306
31212
|
borderStyle: "single",
|
|
@@ -30318,6 +31224,10 @@ function Status({ isProcessing, cwd: cwd2, queueLength = 0 }) {
|
|
|
30318
31224
|
dimColor: !isProcessing,
|
|
30319
31225
|
children: isProcessing ? "\u25CF processing" : "\u25CF ready"
|
|
30320
31226
|
}, undefined, false, undefined, this),
|
|
31227
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
31228
|
+
dimColor: true,
|
|
31229
|
+
children: tokenInfo
|
|
31230
|
+
}, undefined, false, undefined, this),
|
|
30321
31231
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
30322
31232
|
dimColor: true,
|
|
30323
31233
|
children: queueInfo
|
|
@@ -30326,7 +31236,8 @@ function Status({ isProcessing, cwd: cwd2, queueLength = 0 }) {
|
|
|
30326
31236
|
dimColor: true,
|
|
30327
31237
|
children: [
|
|
30328
31238
|
" | ",
|
|
30329
|
-
isProcessing ? "Esc to stop" : "Ctrl+C to exit"
|
|
31239
|
+
isProcessing ? "Esc to stop" : "Ctrl+C to exit",
|
|
31240
|
+
" | /help"
|
|
30330
31241
|
]
|
|
30331
31242
|
}, undefined, true, undefined, this)
|
|
30332
31243
|
]
|
|
@@ -30391,8 +31302,12 @@ function App2({ cwd: cwd2 }) {
|
|
|
30391
31302
|
const [isInitializing, setIsInitializing] = import_react25.useState(true);
|
|
30392
31303
|
const [error, setError] = import_react25.useState(null);
|
|
30393
31304
|
const [messageQueue, setMessageQueue] = import_react25.useState([]);
|
|
31305
|
+
const [activityLog, setActivityLog] = import_react25.useState([]);
|
|
31306
|
+
const [tokenUsage, setTokenUsage] = import_react25.useState();
|
|
30394
31307
|
const responseRef = import_react25.useRef("");
|
|
30395
31308
|
const clientRef = import_react25.useRef(null);
|
|
31309
|
+
const toolCallsRef = import_react25.useRef([]);
|
|
31310
|
+
const toolResultsRef = import_react25.useRef([]);
|
|
30396
31311
|
const processQueue = import_react25.useCallback(async () => {
|
|
30397
31312
|
if (!clientRef.current || messageQueue.length === 0)
|
|
30398
31313
|
return;
|
|
@@ -30407,9 +31322,12 @@ function App2({ cwd: cwd2 }) {
|
|
|
30407
31322
|
setMessages((prev) => [...prev, userMessage]);
|
|
30408
31323
|
setCurrentResponse("");
|
|
30409
31324
|
responseRef.current = "";
|
|
31325
|
+
toolCallsRef.current = [];
|
|
31326
|
+
toolResultsRef.current = [];
|
|
30410
31327
|
setError(null);
|
|
30411
31328
|
setCurrentToolCall(undefined);
|
|
30412
31329
|
setLastToolResult(undefined);
|
|
31330
|
+
setActivityLog([]);
|
|
30413
31331
|
setIsProcessing(true);
|
|
30414
31332
|
await clientRef.current.send(nextMessage);
|
|
30415
31333
|
}, [messageQueue]);
|
|
@@ -30423,31 +31341,60 @@ function App2({ cwd: cwd2 }) {
|
|
|
30423
31341
|
responseRef.current += chunk.content;
|
|
30424
31342
|
setCurrentResponse(responseRef.current);
|
|
30425
31343
|
} else if (chunk.type === "tool_use" && chunk.toolCall) {
|
|
31344
|
+
toolCallsRef.current.push(chunk.toolCall);
|
|
31345
|
+
setActivityLog((prev) => [
|
|
31346
|
+
...prev,
|
|
31347
|
+
{
|
|
31348
|
+
id: generateId(),
|
|
31349
|
+
type: "tool_call",
|
|
31350
|
+
toolCall: chunk.toolCall,
|
|
31351
|
+
timestamp: now()
|
|
31352
|
+
}
|
|
31353
|
+
]);
|
|
30426
31354
|
setCurrentToolCall(chunk.toolCall);
|
|
30427
31355
|
setLastToolResult(undefined);
|
|
30428
31356
|
} else if (chunk.type === "tool_result" && chunk.toolResult) {
|
|
31357
|
+
toolResultsRef.current.push(chunk.toolResult);
|
|
31358
|
+
setActivityLog((prev) => [
|
|
31359
|
+
...prev,
|
|
31360
|
+
{
|
|
31361
|
+
id: generateId(),
|
|
31362
|
+
type: "tool_result",
|
|
31363
|
+
toolResult: chunk.toolResult,
|
|
31364
|
+
timestamp: now()
|
|
31365
|
+
}
|
|
31366
|
+
]);
|
|
30429
31367
|
setLastToolResult(chunk.toolResult);
|
|
30430
31368
|
setCurrentToolCall(undefined);
|
|
30431
31369
|
} else if (chunk.type === "error" && chunk.error) {
|
|
30432
31370
|
setError(chunk.error);
|
|
30433
31371
|
setIsProcessing(false);
|
|
31372
|
+
} else if (chunk.type === "usage" && chunk.usage) {
|
|
31373
|
+
setTokenUsage(chunk.usage);
|
|
30434
31374
|
} else if (chunk.type === "done") {
|
|
30435
|
-
if (responseRef.current) {
|
|
31375
|
+
if (responseRef.current || toolCallsRef.current.length > 0) {
|
|
30436
31376
|
setMessages((prev) => [
|
|
30437
31377
|
...prev,
|
|
30438
31378
|
{
|
|
30439
31379
|
id: generateId(),
|
|
30440
31380
|
role: "assistant",
|
|
30441
31381
|
content: responseRef.current,
|
|
30442
|
-
timestamp: now()
|
|
31382
|
+
timestamp: now(),
|
|
31383
|
+
toolCalls: toolCallsRef.current.length > 0 ? [...toolCallsRef.current] : undefined,
|
|
31384
|
+
toolResults: toolResultsRef.current.length > 0 ? [...toolResultsRef.current] : undefined
|
|
30443
31385
|
}
|
|
30444
31386
|
]);
|
|
30445
31387
|
setCurrentResponse("");
|
|
30446
31388
|
responseRef.current = "";
|
|
31389
|
+
toolCallsRef.current = [];
|
|
31390
|
+
toolResultsRef.current = [];
|
|
30447
31391
|
}
|
|
30448
31392
|
setCurrentToolCall(undefined);
|
|
30449
31393
|
setLastToolResult(undefined);
|
|
30450
31394
|
setIsProcessing(false);
|
|
31395
|
+
if (newClient) {
|
|
31396
|
+
setTokenUsage(newClient.getTokenUsage());
|
|
31397
|
+
}
|
|
30451
31398
|
}
|
|
30452
31399
|
});
|
|
30453
31400
|
newClient.onError((err) => {
|
|
@@ -30550,9 +31497,12 @@ function App2({ cwd: cwd2 }) {
|
|
|
30550
31497
|
setMessages((prev) => [...prev, userMessage]);
|
|
30551
31498
|
setCurrentResponse("");
|
|
30552
31499
|
responseRef.current = "";
|
|
31500
|
+
toolCallsRef.current = [];
|
|
31501
|
+
toolResultsRef.current = [];
|
|
30553
31502
|
setError(null);
|
|
30554
31503
|
setCurrentToolCall(undefined);
|
|
30555
31504
|
setLastToolResult(undefined);
|
|
31505
|
+
setActivityLog([]);
|
|
30556
31506
|
setIsProcessing(true);
|
|
30557
31507
|
await client.send(trimmedInput);
|
|
30558
31508
|
}, [client, isProcessing]);
|
|
@@ -30573,7 +31523,8 @@ function App2({ cwd: cwd2 }) {
|
|
|
30573
31523
|
messages,
|
|
30574
31524
|
currentResponse: isProcessing ? currentResponse : undefined,
|
|
30575
31525
|
currentToolCall,
|
|
30576
|
-
lastToolResult
|
|
31526
|
+
lastToolResult,
|
|
31527
|
+
activityLog: isProcessing ? activityLog : []
|
|
30577
31528
|
}, undefined, false, undefined, this),
|
|
30578
31529
|
messageQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
|
|
30579
31530
|
marginY: 1,
|
|
@@ -30611,7 +31562,8 @@ function App2({ cwd: cwd2 }) {
|
|
|
30611
31562
|
/* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Status, {
|
|
30612
31563
|
isProcessing,
|
|
30613
31564
|
cwd: cwd2,
|
|
30614
|
-
queueLength: messageQueue.length
|
|
31565
|
+
queueLength: messageQueue.length,
|
|
31566
|
+
tokenUsage
|
|
30615
31567
|
}, undefined, false, undefined, this)
|
|
30616
31568
|
]
|
|
30617
31569
|
}, undefined, true, undefined, this);
|
|
@@ -30626,7 +31578,7 @@ var options = {
|
|
|
30626
31578
|
help: args.includes("--help") || args.includes("-h")
|
|
30627
31579
|
};
|
|
30628
31580
|
if (options.version) {
|
|
30629
|
-
console.log("oldpal v0.1.
|
|
31581
|
+
console.log("oldpal v0.1.9");
|
|
30630
31582
|
process.exit(0);
|
|
30631
31583
|
}
|
|
30632
31584
|
if (options.help) {
|
|
@@ -30657,4 +31609,4 @@ waitUntilExit().then(() => {
|
|
|
30657
31609
|
process.exit(0);
|
|
30658
31610
|
});
|
|
30659
31611
|
|
|
30660
|
-
//# debugId=
|
|
31612
|
+
//# debugId=307434E7D5151E5864756E2164756E21
|