@zhijiewang/openharness 0.1.1 → 0.2.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/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/pull_request_template.md +24 -0
- package/CODE_OF_CONDUCT.md +43 -0
- package/README.md +160 -156
- package/SECURITY.md +21 -0
- package/dist/commands/index.d.ts +37 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +189 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +3 -2
- package/dist/components/App.js.map +1 -1
- package/dist/components/ErrorBoundary.d.ts +17 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +19 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +70 -18
- package/dist/components/Markdown.js.map +1 -1
- package/dist/components/Messages.d.ts.map +1 -1
- package/dist/components/Messages.js +10 -4
- package/dist/components/Messages.js.map +1 -1
- package/dist/components/PermissionPrompt.d.ts.map +1 -1
- package/dist/components/PermissionPrompt.js +25 -7
- package/dist/components/PermissionPrompt.js.map +1 -1
- package/dist/components/REPL.d.ts.map +1 -1
- package/dist/components/REPL.js +60 -6
- package/dist/components/REPL.js.map +1 -1
- package/dist/components/Spinner.d.ts +3 -2
- package/dist/components/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner.js +22 -4
- package/dist/components/Spinner.js.map +1 -1
- package/dist/components/TextInput.d.ts.map +1 -1
- package/dist/components/TextInput.js +4 -1
- package/dist/components/TextInput.js.map +1 -1
- package/dist/git/index.d.ts +47 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +151 -0
- package/dist/git/index.js.map +1 -0
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +2 -1
- package/dist/harness/session.js.map +1 -1
- package/dist/main.js +88 -2
- package/dist/main.js.map +1 -1
- package/dist/providers/openai.js +11 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.js +11 -1
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/query.d.ts +15 -11
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +196 -80
- package/dist/query.js.map +1 -1
- package/dist/services/StreamingToolExecutor.d.ts +25 -0
- package/dist/services/StreamingToolExecutor.d.ts.map +1 -0
- package/dist/services/StreamingToolExecutor.js +107 -0
- package/dist/services/StreamingToolExecutor.js.map +1 -0
- package/dist/tools/AgentTool/index.d.ts +15 -0
- package/dist/tools/AgentTool/index.d.ts.map +1 -0
- package/dist/tools/AgentTool/index.js +30 -0
- package/dist/tools/AgentTool/index.js.map +1 -0
- package/dist/tools/AskUserTool/index.d.ts +15 -0
- package/dist/tools/AskUserTool/index.d.ts.map +1 -0
- package/dist/tools/AskUserTool/index.js +30 -0
- package/dist/tools/AskUserTool/index.js.map +1 -0
- package/dist/tools/EnterPlanModeTool/index.d.ts +6 -0
- package/dist/tools/EnterPlanModeTool/index.d.ts.map +1 -0
- package/dist/tools/EnterPlanModeTool/index.js +37 -0
- package/dist/tools/EnterPlanModeTool/index.js.map +1 -0
- package/dist/tools/ExitPlanModeTool/index.d.ts +6 -0
- package/dist/tools/ExitPlanModeTool/index.d.ts.map +1 -0
- package/dist/tools/ExitPlanModeTool/index.js +21 -0
- package/dist/tools/ExitPlanModeTool/index.js.map +1 -0
- package/dist/tools/NotebookEditTool/index.d.ts +18 -0
- package/dist/tools/NotebookEditTool/index.d.ts.map +1 -0
- package/dist/tools/NotebookEditTool/index.js +61 -0
- package/dist/tools/NotebookEditTool/index.js.map +1 -0
- package/dist/tools/SkillTool/index.d.ts +15 -0
- package/dist/tools/SkillTool/index.d.ts.map +1 -0
- package/dist/tools/SkillTool/index.js +49 -0
- package/dist/tools/SkillTool/index.js.map +1 -0
- package/dist/tools/TaskCreateTool/index.d.ts +15 -0
- package/dist/tools/TaskCreateTool/index.d.ts.map +1 -0
- package/dist/tools/TaskCreateTool/index.js +54 -0
- package/dist/tools/TaskCreateTool/index.js.map +1 -0
- package/dist/tools/TaskListTool/index.d.ts +6 -0
- package/dist/tools/TaskListTool/index.d.ts.map +1 -0
- package/dist/tools/TaskListTool/index.js +40 -0
- package/dist/tools/TaskListTool/index.js.map +1 -0
- package/dist/tools/TaskUpdateTool/index.d.ts +18 -0
- package/dist/tools/TaskUpdateTool/index.d.ts.map +1 -0
- package/dist/tools/TaskUpdateTool/index.js +50 -0
- package/dist/tools/TaskUpdateTool/index.js.map +1 -0
- package/dist/tools/WebSearchTool/index.d.ts +15 -0
- package/dist/tools/WebSearchTool/index.d.ts.map +1 -0
- package/dist/tools/WebSearchTool/index.js +76 -0
- package/dist/tools/WebSearchTool/index.js.map +1 -0
- package/dist/tools/web-fetch.test.d.ts +2 -0
- package/dist/tools/web-fetch.test.d.ts.map +1 -0
- package/dist/tools/web-fetch.test.js +27 -0
- package/dist/tools/web-fetch.test.js.map +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +27 -0
- package/dist/tools.js.map +1 -1
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +23 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/theme.d.ts +27 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +45 -0
- package/dist/utils/theme.js.map +1 -0
- package/dist/utils/tokens.d.ts +18 -0
- package/dist/utils/tokens.d.ts.map +1 -0
- package/dist/utils/tokens.js +57 -0
- package/dist/utils/tokens.js.map +1 -0
- package/package.json +61 -57
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
const inputSchema = z.object({});
|
|
5
|
+
export const TaskListTool = {
|
|
6
|
+
name: "TaskList",
|
|
7
|
+
description: "List all tasks from .oh/tasks.json.",
|
|
8
|
+
inputSchema,
|
|
9
|
+
riskLevel: "low",
|
|
10
|
+
isReadOnly() {
|
|
11
|
+
return true;
|
|
12
|
+
},
|
|
13
|
+
isConcurrencySafe() {
|
|
14
|
+
return true;
|
|
15
|
+
},
|
|
16
|
+
async call(_input, context) {
|
|
17
|
+
const filePath = path.join(context.workingDir, ".oh", "tasks.json");
|
|
18
|
+
try {
|
|
19
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
20
|
+
const tasks = JSON.parse(content);
|
|
21
|
+
if (tasks.length === 0) {
|
|
22
|
+
return { output: "No tasks found.", isError: false };
|
|
23
|
+
}
|
|
24
|
+
const output = tasks
|
|
25
|
+
.map((t) => `#${t.id} [${t.status}] ${t.subject}\n ${t.description}`)
|
|
26
|
+
.join("\n\n");
|
|
27
|
+
return { output, isError: false };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err.code === "ENOENT") {
|
|
31
|
+
return { output: "No tasks found. Create a task first.", isError: false };
|
|
32
|
+
}
|
|
33
|
+
return { output: `Error listing tasks: ${err.message}`, isError: true };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
prompt() {
|
|
37
|
+
return `List all tasks from .oh/tasks.json. No parameters required.`;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/TaskListTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AASjC,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,qCAAqC;IAClD,WAAW;IACX,SAAS,EAAE,KAAK;IAEhB,UAAU;QACR,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;QAEpE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,KAAK,GAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAE1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACvD,CAAC;YAED,MAAM,MAAM,GAAG,KAAK;iBACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;iBACtE,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,EAAE,MAAM,EAAE,sCAAsC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5E,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,wBAAwB,GAAG,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,6DAA6D,CAAC;IACvE,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Tool } from "../../Tool.js";
|
|
3
|
+
declare const inputSchema: z.ZodObject<{
|
|
4
|
+
taskId: z.ZodNumber;
|
|
5
|
+
status: z.ZodOptional<z.ZodString>;
|
|
6
|
+
description: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
taskId: number;
|
|
9
|
+
status?: string | undefined;
|
|
10
|
+
description?: string | undefined;
|
|
11
|
+
}, {
|
|
12
|
+
taskId: number;
|
|
13
|
+
status?: string | undefined;
|
|
14
|
+
description?: string | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const TaskUpdateTool: Tool<typeof inputSchema>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/TaskUpdateTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,eAAe,CAAC;AAEnE,QAAA,MAAM,WAAW;;;;;;;;;;;;EAIf,CAAC;AASH,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,OAAO,WAAW,CA8CnD,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
const inputSchema = z.object({
|
|
5
|
+
taskId: z.number(),
|
|
6
|
+
status: z.string().optional(),
|
|
7
|
+
description: z.string().optional(),
|
|
8
|
+
});
|
|
9
|
+
export const TaskUpdateTool = {
|
|
10
|
+
name: "TaskUpdate",
|
|
11
|
+
description: "Update an existing task in .oh/tasks.json.",
|
|
12
|
+
inputSchema,
|
|
13
|
+
riskLevel: "low",
|
|
14
|
+
isReadOnly() {
|
|
15
|
+
return false;
|
|
16
|
+
},
|
|
17
|
+
isConcurrencySafe() {
|
|
18
|
+
return false; // Mutates shared tasks.json
|
|
19
|
+
},
|
|
20
|
+
async call(input, context) {
|
|
21
|
+
const filePath = path.join(context.workingDir, ".oh", "tasks.json");
|
|
22
|
+
try {
|
|
23
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
24
|
+
const tasks = JSON.parse(content);
|
|
25
|
+
const task = tasks.find((t) => t.id === input.taskId);
|
|
26
|
+
if (!task) {
|
|
27
|
+
return { output: `Error: Task #${input.taskId} not found.`, isError: true };
|
|
28
|
+
}
|
|
29
|
+
if (input.status !== undefined)
|
|
30
|
+
task.status = input.status;
|
|
31
|
+
if (input.description !== undefined)
|
|
32
|
+
task.description = input.description;
|
|
33
|
+
await fs.writeFile(filePath, JSON.stringify(tasks, null, 2), "utf-8");
|
|
34
|
+
return { output: `Task #${task.id} updated. Status: ${task.status}`, isError: false };
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.code === "ENOENT") {
|
|
38
|
+
return { output: "Error: No tasks file found. Create a task first.", isError: true };
|
|
39
|
+
}
|
|
40
|
+
return { output: `Error updating task: ${err.message}`, isError: true };
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
prompt() {
|
|
44
|
+
return `Update an existing task in .oh/tasks.json. Parameters:
|
|
45
|
+
- taskId (number, required): The ID of the task to update.
|
|
46
|
+
- status (string, optional): New status for the task.
|
|
47
|
+
- description (string, optional): New description for the task.`;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/TaskUpdateTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AASH,MAAM,CAAC,MAAM,cAAc,GAA6B;IACtD,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,4CAA4C;IACzD,WAAW;IACX,SAAS,EAAE,KAAK;IAEhB,UAAU;QACR,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iBAAiB;QACf,OAAO,KAAK,CAAC,CAAC,4BAA4B;IAC5C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;QAEpE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,KAAK,GAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAE1C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;YACtD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,EAAE,MAAM,EAAE,gBAAgB,KAAK,CAAC,MAAM,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC9E,CAAC;YAED,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC3D,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;gBAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;YAE1E,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAEtE,OAAO,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,EAAE,qBAAqB,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACxF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,EAAE,MAAM,EAAE,kDAAkD,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACvF,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,wBAAwB,GAAG,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO;;;gEAGqD,CAAC;IAC/D,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Tool } from "../../Tool.js";
|
|
3
|
+
declare const inputSchema: z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
query: string;
|
|
8
|
+
limit?: number | undefined;
|
|
9
|
+
}, {
|
|
10
|
+
query: string;
|
|
11
|
+
limit?: number | undefined;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const WebSearchTool: Tool<typeof inputSchema>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/WebSearchTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,eAAe,CAAC;AAEnE,QAAA,MAAM,WAAW;;;;;;;;;EAGf,CAAC;AAIH,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,OAAO,WAAW,CAkFlD,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const inputSchema = z.object({
|
|
3
|
+
query: z.string(),
|
|
4
|
+
limit: z.number().optional(),
|
|
5
|
+
});
|
|
6
|
+
const DEFAULT_LIMIT = 5;
|
|
7
|
+
export const WebSearchTool = {
|
|
8
|
+
name: "WebSearch",
|
|
9
|
+
description: "Search the web via DuckDuckGo and return top results.",
|
|
10
|
+
inputSchema,
|
|
11
|
+
riskLevel: "medium",
|
|
12
|
+
isReadOnly() {
|
|
13
|
+
return true;
|
|
14
|
+
},
|
|
15
|
+
isConcurrencySafe() {
|
|
16
|
+
return true;
|
|
17
|
+
},
|
|
18
|
+
async call(input, _context) {
|
|
19
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
20
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(input.query)}`;
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(url, {
|
|
23
|
+
headers: {
|
|
24
|
+
"User-Agent": "Mozilla/5.0 (compatible; OpenHarness/1.0)",
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
return { output: `Error: HTTP ${response.status}`, isError: true };
|
|
29
|
+
}
|
|
30
|
+
const html = await response.text();
|
|
31
|
+
// Parse results from DuckDuckGo HTML response
|
|
32
|
+
const results = [];
|
|
33
|
+
const resultRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
|
|
34
|
+
const snippetRegex = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
35
|
+
let match;
|
|
36
|
+
const titles = [];
|
|
37
|
+
while ((match = resultRegex.exec(html)) !== null) {
|
|
38
|
+
const rawUrl = match[1];
|
|
39
|
+
const title = match[2].replace(/<[^>]*>/g, "").trim();
|
|
40
|
+
// DuckDuckGo wraps URLs in a redirect; extract the actual URL
|
|
41
|
+
const actualUrlMatch = rawUrl.match(/uddg=([^&]+)/);
|
|
42
|
+
const actualUrl = actualUrlMatch
|
|
43
|
+
? decodeURIComponent(actualUrlMatch[1])
|
|
44
|
+
: rawUrl;
|
|
45
|
+
titles.push({ url: actualUrl, title });
|
|
46
|
+
}
|
|
47
|
+
const snippets = [];
|
|
48
|
+
while ((match = snippetRegex.exec(html)) !== null) {
|
|
49
|
+
snippets.push(match[1].replace(/<[^>]*>/g, "").trim());
|
|
50
|
+
}
|
|
51
|
+
for (let i = 0; i < Math.min(titles.length, limit); i++) {
|
|
52
|
+
results.push({
|
|
53
|
+
title: titles[i].title,
|
|
54
|
+
url: titles[i].url,
|
|
55
|
+
snippet: snippets[i] ?? "",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (results.length === 0) {
|
|
59
|
+
return { output: "No results found.", isError: false };
|
|
60
|
+
}
|
|
61
|
+
const output = results
|
|
62
|
+
.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}\n ${r.snippet}`)
|
|
63
|
+
.join("\n\n");
|
|
64
|
+
return { output, isError: false };
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return { output: `Error performing search: ${err.message}`, isError: true };
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
prompt() {
|
|
71
|
+
return `Search the web using DuckDuckGo and return top results. Parameters:
|
|
72
|
+
- query (string, required): The search query.
|
|
73
|
+
- limit (number, optional): Maximum number of results to return (default 5).`;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/WebSearchTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,uDAAuD;IACpE,WAAW;IACX,SAAS,EAAE,QAAQ;IAEnB,UAAU;QACR,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,aAAa,CAAC;QAC3C,MAAM,GAAG,GAAG,uCAAuC,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAErF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,OAAO,EAAE;oBACP,YAAY,EAAE,2CAA2C;iBAC1D;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO,EAAE,MAAM,EAAE,eAAe,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACrE,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAEnC,8CAA8C;YAC9C,MAAM,OAAO,GAAsD,EAAE,CAAC;YACtE,MAAM,WAAW,GAAG,mEAAmE,CAAC;YACxF,MAAM,YAAY,GAAG,sDAAsD,CAAC;YAE5E,IAAI,KAA6B,CAAC;YAClC,MAAM,MAAM,GAAqC,EAAE,CAAC;YAEpD,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACjD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACxB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBACtD,8DAA8D;gBAC9D,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,cAAc;oBAC9B,CAAC,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;oBACvC,CAAC,CAAC,MAAM,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACzC,CAAC;YAED,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAClD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC;oBACX,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;oBACtB,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG;oBAClB,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE;iBAC3B,CAAC,CAAC;YACL,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACzD,CAAC;YAED,MAAM,MAAM,GAAG,OAAO;iBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;iBACnE,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,EAAE,MAAM,EAAE,4BAA4B,GAAG,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC9E,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO;;6EAEkE,CAAC;IAC5E,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-fetch.test.d.ts","sourceRoot":"","sources":["../../src/tools/web-fetch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { WebFetchTool } from "./WebFetchTool/index.js";
|
|
4
|
+
const ctx = { workingDir: process.cwd() };
|
|
5
|
+
test("blocks localhost", async () => {
|
|
6
|
+
const r = await WebFetchTool.call({ url: "http://localhost:8080/secret" }, ctx);
|
|
7
|
+
assert.equal(r.isError, true);
|
|
8
|
+
assert.ok(r.output.includes("blocked"));
|
|
9
|
+
});
|
|
10
|
+
test("blocks 192.168.x.x", async () => {
|
|
11
|
+
const r = await WebFetchTool.call({ url: "http://192.168.1.1/" }, ctx);
|
|
12
|
+
assert.equal(r.isError, true);
|
|
13
|
+
assert.ok(r.output.includes("blocked"));
|
|
14
|
+
});
|
|
15
|
+
test("blocks .internal hostnames", async () => {
|
|
16
|
+
const r = await WebFetchTool.call({ url: "http://app.internal/api" }, ctx);
|
|
17
|
+
assert.equal(r.isError, true);
|
|
18
|
+
assert.ok(r.output.includes("blocked"));
|
|
19
|
+
});
|
|
20
|
+
test("allows normal https URLs (will fail to connect but not blocked)", async () => {
|
|
21
|
+
// Use a URL that won't actually resolve to avoid network calls,
|
|
22
|
+
// but the SSRF check itself should pass (error will be a fetch error, not "blocked")
|
|
23
|
+
const r = await WebFetchTool.call({ url: "https://example.invalid/page" }, ctx);
|
|
24
|
+
// Should NOT be the SSRF block message
|
|
25
|
+
assert.ok(!r.output.includes("private/internal hosts is blocked"));
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=web-fetch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-fetch.test.js","sourceRoot":"","sources":["../../src/tools/web-fetch.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,GAAG,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAE1C,IAAI,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;IAClC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAC;IAChF,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;IACpC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,qBAAqB,EAAE,EAAE,GAAG,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;IAC5C,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,yBAAyB,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;IACjF,gEAAgE;IAChE,qFAAqF;IACrF,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,8BAA8B,EAAE,EAAE,GAAG,CAAC,CAAC;IAChF,uCAAuC;IACvC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC"}
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAuBvC;;GAEG;AACH,wBAAgB,WAAW,IAAI,KAAK,CAyBnC"}
|
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool registry — aggregates all available tools.
|
|
3
3
|
*/
|
|
4
|
+
// Core tools
|
|
4
5
|
import { BashTool } from "./tools/BashTool/index.js";
|
|
5
6
|
import { FileReadTool } from "./tools/FileReadTool/index.js";
|
|
6
7
|
import { FileWriteTool } from "./tools/FileWriteTool/index.js";
|
|
@@ -8,11 +9,23 @@ import { FileEditTool } from "./tools/FileEditTool/index.js";
|
|
|
8
9
|
import { GlobTool } from "./tools/GlobTool/index.js";
|
|
9
10
|
import { GrepTool } from "./tools/GrepTool/index.js";
|
|
10
11
|
import { WebFetchTool } from "./tools/WebFetchTool/index.js";
|
|
12
|
+
// Advanced tools
|
|
13
|
+
import { WebSearchTool } from "./tools/WebSearchTool/index.js";
|
|
14
|
+
import { TaskCreateTool } from "./tools/TaskCreateTool/index.js";
|
|
15
|
+
import { TaskUpdateTool } from "./tools/TaskUpdateTool/index.js";
|
|
16
|
+
import { TaskListTool } from "./tools/TaskListTool/index.js";
|
|
17
|
+
import { AskUserTool } from "./tools/AskUserTool/index.js";
|
|
18
|
+
import { SkillTool } from "./tools/SkillTool/index.js";
|
|
19
|
+
import { AgentTool } from "./tools/AgentTool/index.js";
|
|
20
|
+
import { EnterPlanModeTool } from "./tools/EnterPlanModeTool/index.js";
|
|
21
|
+
import { ExitPlanModeTool } from "./tools/ExitPlanModeTool/index.js";
|
|
22
|
+
import { NotebookEditTool } from "./tools/NotebookEditTool/index.js";
|
|
11
23
|
/**
|
|
12
24
|
* Returns all registered tools.
|
|
13
25
|
*/
|
|
14
26
|
export function getAllTools() {
|
|
15
27
|
return [
|
|
28
|
+
// Core (always available)
|
|
16
29
|
BashTool,
|
|
17
30
|
FileReadTool,
|
|
18
31
|
FileWriteTool,
|
|
@@ -20,6 +33,20 @@ export function getAllTools() {
|
|
|
20
33
|
GlobTool,
|
|
21
34
|
GrepTool,
|
|
22
35
|
WebFetchTool,
|
|
36
|
+
WebSearchTool,
|
|
37
|
+
// Task management
|
|
38
|
+
TaskCreateTool,
|
|
39
|
+
TaskUpdateTool,
|
|
40
|
+
TaskListTool,
|
|
41
|
+
// Agent interaction
|
|
42
|
+
AskUserTool,
|
|
43
|
+
SkillTool,
|
|
44
|
+
AgentTool,
|
|
45
|
+
// Planning
|
|
46
|
+
EnterPlanModeTool,
|
|
47
|
+
ExitPlanModeTool,
|
|
48
|
+
// Notebooks
|
|
49
|
+
NotebookEditTool,
|
|
23
50
|
];
|
|
24
51
|
}
|
|
25
52
|
//# sourceMappingURL=tools.js.map
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,aAAa;AACb,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO;QACL,0BAA0B;QAC1B,QAAQ;QACR,YAAY;QACZ,aAAa;QACb,YAAY;QACZ,QAAQ;QACR,QAAQ;QACR,YAAY;QACZ,aAAa;QACb,kBAAkB;QAClB,cAAc;QACd,cAAc;QACd,YAAY;QACZ,oBAAoB;QACpB,WAAW;QACX,SAAS;QACT,SAAS;QACT,WAAW;QACX,iBAAiB;QACjB,gBAAgB;QAChB,YAAY;QACZ,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry with exponential backoff.
|
|
3
|
+
*/
|
|
4
|
+
export type RetryOptions = {
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
backoffMs?: number;
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
};
|
|
9
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
10
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,CAAC,CAkBZ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry with exponential backoff.
|
|
3
|
+
*/
|
|
4
|
+
export async function withRetry(fn, options) {
|
|
5
|
+
const { maxRetries = 3, backoffMs = 1000, signal } = options ?? {};
|
|
6
|
+
let lastError;
|
|
7
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
8
|
+
if (signal?.aborted)
|
|
9
|
+
throw new Error("Aborted");
|
|
10
|
+
try {
|
|
11
|
+
return await fn();
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
15
|
+
if (attempt < maxRetries) {
|
|
16
|
+
const delay = backoffMs * Math.pow(2, attempt);
|
|
17
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw lastError;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,OAAsB;IAEtB,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IACnE,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC/C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic theme system for OpenHarness terminal UI.
|
|
3
|
+
* Inspired by Claude Code's 89-color theme with shimmer variants.
|
|
4
|
+
*/
|
|
5
|
+
import React from "react";
|
|
6
|
+
export type Theme = {
|
|
7
|
+
primary: string;
|
|
8
|
+
primaryShimmer: string;
|
|
9
|
+
user: string;
|
|
10
|
+
assistant: string;
|
|
11
|
+
tool: string;
|
|
12
|
+
error: string;
|
|
13
|
+
success: string;
|
|
14
|
+
warning: string;
|
|
15
|
+
border: string;
|
|
16
|
+
dim: string;
|
|
17
|
+
text: string;
|
|
18
|
+
diffAdded: string;
|
|
19
|
+
diffRemoved: string;
|
|
20
|
+
stall: string;
|
|
21
|
+
stallShimmer: string;
|
|
22
|
+
};
|
|
23
|
+
export declare const darkTheme: Theme;
|
|
24
|
+
export declare const lightTheme: Theme;
|
|
25
|
+
export declare const ThemeProvider: React.Provider<Theme>;
|
|
26
|
+
export declare function useTheme(): Theme;
|
|
27
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,KAAK,GAAG;IAElB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IAGvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAGhB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IAGb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IAGpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAoBvB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAoBxB,CAAC;AAIF,eAAO,MAAM,aAAa,uBAAwB,CAAC;AAEnD,wBAAgB,QAAQ,IAAI,KAAK,CAEhC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic theme system for OpenHarness terminal UI.
|
|
3
|
+
* Inspired by Claude Code's 89-color theme with shimmer variants.
|
|
4
|
+
*/
|
|
5
|
+
import React from "react";
|
|
6
|
+
export const darkTheme = {
|
|
7
|
+
primary: "magenta",
|
|
8
|
+
primaryShimmer: "magentaBright",
|
|
9
|
+
user: "cyan",
|
|
10
|
+
assistant: "magenta",
|
|
11
|
+
tool: "yellow",
|
|
12
|
+
error: "red",
|
|
13
|
+
success: "green",
|
|
14
|
+
warning: "yellow",
|
|
15
|
+
border: "gray",
|
|
16
|
+
dim: "gray",
|
|
17
|
+
text: "white",
|
|
18
|
+
diffAdded: "green",
|
|
19
|
+
diffRemoved: "red",
|
|
20
|
+
stall: "yellow",
|
|
21
|
+
stallShimmer: "redBright",
|
|
22
|
+
};
|
|
23
|
+
export const lightTheme = {
|
|
24
|
+
primary: "magentaBright",
|
|
25
|
+
primaryShimmer: "magenta",
|
|
26
|
+
user: "cyanBright",
|
|
27
|
+
assistant: "magentaBright",
|
|
28
|
+
tool: "yellowBright",
|
|
29
|
+
error: "redBright",
|
|
30
|
+
success: "greenBright",
|
|
31
|
+
warning: "yellowBright",
|
|
32
|
+
border: "blackBright",
|
|
33
|
+
dim: "blackBright",
|
|
34
|
+
text: "black",
|
|
35
|
+
diffAdded: "greenBright",
|
|
36
|
+
diffRemoved: "redBright",
|
|
37
|
+
stall: "yellowBright",
|
|
38
|
+
stallShimmer: "red",
|
|
39
|
+
};
|
|
40
|
+
const ThemeContext = React.createContext(darkTheme);
|
|
41
|
+
export const ThemeProvider = ThemeContext.Provider;
|
|
42
|
+
export function useTheme() {
|
|
43
|
+
return React.useContext(ThemeContext);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AA6B1B,MAAM,CAAC,MAAM,SAAS,GAAU;IAC9B,OAAO,EAAE,SAAS;IAClB,cAAc,EAAE,eAAe;IAE/B,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,QAAQ;IAEjB,MAAM,EAAE,MAAM;IACd,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,OAAO;IAEb,SAAS,EAAE,OAAO;IAClB,WAAW,EAAE,KAAK;IAElB,KAAK,EAAE,QAAQ;IACf,YAAY,EAAE,WAAW;CAC1B,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAU;IAC/B,OAAO,EAAE,eAAe;IACxB,cAAc,EAAE,SAAS;IAEzB,IAAI,EAAE,YAAY;IAClB,SAAS,EAAE,eAAe;IAC1B,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,aAAa;IACtB,OAAO,EAAE,cAAc;IAEvB,MAAM,EAAE,aAAa;IACrB,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,OAAO;IAEb,SAAS,EAAE,aAAa;IACxB,WAAW,EAAE,WAAW;IAExB,KAAK,EAAE,cAAc;IACrB,YAAY,EAAE,KAAK;CACpB,CAAC;AAEF,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAAQ,SAAS,CAAC,CAAC;AAE3D,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC;AAEnD,MAAM,UAAU,QAAQ;IACtB,OAAO,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token estimation utilities and context window sizes.
|
|
3
|
+
*/
|
|
4
|
+
import type { Message } from "../types/message.js";
|
|
5
|
+
export declare function estimateTokens(text: string): number;
|
|
6
|
+
export declare function estimateMessagesTokens(messages: Message[]): number;
|
|
7
|
+
export declare const CONTEXT_WINDOWS: Record<string, number>;
|
|
8
|
+
export declare function getContextWindow(model: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Compress messages to fit within a target token budget.
|
|
11
|
+
*
|
|
12
|
+
* Strategy:
|
|
13
|
+
* 1. Always keep first (system) and last 10 messages
|
|
14
|
+
* 2. For middle messages: if role=tool, replace content with "[truncated]"
|
|
15
|
+
* 3. If still over target, drop oldest non-system messages
|
|
16
|
+
*/
|
|
17
|
+
export declare function compressMessages(messages: Message[], targetTokens: number): Message[];
|
|
18
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAElE;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAUlD,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,EAAE,CAiCrF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token estimation utilities and context window sizes.
|
|
3
|
+
*/
|
|
4
|
+
export function estimateTokens(text) {
|
|
5
|
+
return Math.ceil(text.length / 4);
|
|
6
|
+
}
|
|
7
|
+
export function estimateMessagesTokens(messages) {
|
|
8
|
+
return messages.reduce((sum, m) => sum + estimateTokens(m.content) + 10, 0); // +10 per message overhead
|
|
9
|
+
}
|
|
10
|
+
export const CONTEXT_WINDOWS = {
|
|
11
|
+
"llama3": 8192,
|
|
12
|
+
"qwen2.5:7b-instruct": 32768,
|
|
13
|
+
"gpt-4o": 128000,
|
|
14
|
+
"gpt-4o-mini": 128000,
|
|
15
|
+
"o3-mini": 200000,
|
|
16
|
+
"claude-sonnet-4-6": 200000,
|
|
17
|
+
"claude-haiku-4-5": 200000,
|
|
18
|
+
"claude-opus-4-6": 200000,
|
|
19
|
+
"deepseek-chat": 64000,
|
|
20
|
+
};
|
|
21
|
+
export function getContextWindow(model) {
|
|
22
|
+
return CONTEXT_WINDOWS[model] ?? 8192;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compress messages to fit within a target token budget.
|
|
26
|
+
*
|
|
27
|
+
* Strategy:
|
|
28
|
+
* 1. Always keep first (system) and last 10 messages
|
|
29
|
+
* 2. For middle messages: if role=tool, replace content with "[truncated]"
|
|
30
|
+
* 3. If still over target, drop oldest non-system messages
|
|
31
|
+
*/
|
|
32
|
+
export function compressMessages(messages, targetTokens) {
|
|
33
|
+
if (estimateMessagesTokens(messages) <= targetTokens) {
|
|
34
|
+
return messages;
|
|
35
|
+
}
|
|
36
|
+
const first = messages[0];
|
|
37
|
+
const tail = messages.slice(-10);
|
|
38
|
+
const middle = messages.slice(1, -10);
|
|
39
|
+
if (middle.length === 0) {
|
|
40
|
+
return messages;
|
|
41
|
+
}
|
|
42
|
+
// Step 1: truncate tool results in the middle
|
|
43
|
+
const compressed = middle.map((m) => m.role === "tool"
|
|
44
|
+
? { ...m, content: "[truncated]" }
|
|
45
|
+
: m);
|
|
46
|
+
let result = first ? [first, ...compressed, ...tail] : [...compressed, ...tail];
|
|
47
|
+
if (estimateMessagesTokens(result) <= targetTokens) {
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
// Step 2: progressively drop oldest non-system middle messages
|
|
51
|
+
const kept = [...compressed];
|
|
52
|
+
while (kept.length > 0 && estimateMessagesTokens(first ? [first, ...kept, ...tail] : [...kept, ...tail]) > targetTokens) {
|
|
53
|
+
kept.shift();
|
|
54
|
+
}
|
|
55
|
+
return first ? [first, ...kept, ...tail] : [...kept, ...tail];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAmB;IACxD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,2BAA2B;AAC1G,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,QAAQ,EAAE,IAAI;IACd,qBAAqB,EAAE,KAAK;IAC5B,QAAQ,EAAE,MAAM;IAChB,aAAa,EAAE,MAAM;IACrB,SAAS,EAAE,MAAM;IACjB,mBAAmB,EAAE,MAAM;IAC3B,kBAAkB,EAAE,MAAM;IAC1B,iBAAiB,EAAE,MAAM;IACzB,eAAe,EAAE,KAAK;CACvB,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAmB,EAAE,YAAoB;IACxE,IAAI,sBAAsB,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC;QACrD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAEtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,8CAA8C;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,CAAC,CAAC,IAAI,KAAK,MAAM;QACf,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE;QAClC,CAAC,CAAC,CAAC,CACN,CAAC;IAEF,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IAEhF,IAAI,sBAAsB,CAAC,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QACnD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+DAA+D;IAC/D,MAAM,IAAI,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC;QACxH,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;AAChE,CAAC"}
|