@zhijiewang/openharness 2.1.0 → 2.3.1
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/README.md +4 -4
- package/dist/DeferredTool.js +3 -1
- package/dist/Tool.d.ts +1 -1
- package/dist/agents/roles.js +58 -62
- package/dist/commands/cybergotchi.d.ts +1 -1
- package/dist/commands/cybergotchi.js +30 -30
- package/dist/commands/index.js +288 -132
- package/dist/components/App.d.ts +1 -1
- package/dist/components/App.js +6 -6
- package/dist/components/CompanionFooter.d.ts +1 -1
- package/dist/components/CompanionFooter.js +6 -8
- package/dist/components/CybergotchiBubble.js +5 -5
- package/dist/components/CybergotchiPanel.d.ts +1 -1
- package/dist/components/CybergotchiPanel.js +7 -7
- package/dist/components/CybergotchiPanelConnected.js +2 -2
- package/dist/components/CybergotchiSetup.js +26 -24
- package/dist/components/CybergotchiSprite.d.ts +1 -1
- package/dist/components/CybergotchiSprite.js +8 -12
- package/dist/components/DiffView.d.ts +1 -1
- package/dist/components/DiffView.js +10 -10
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/InitWizard.js +65 -33
- package/dist/components/Markdown.js +2 -4
- package/dist/components/Messages.js +4 -4
- package/dist/components/PermissionPrompt.d.ts +1 -1
- package/dist/components/PermissionPrompt.js +15 -17
- package/dist/components/REPL.d.ts +1 -1
- package/dist/components/REPL.js +74 -49
- package/dist/components/Spinner.js +2 -2
- package/dist/components/TextInput.js +35 -29
- package/dist/components/ToolCallDisplay.js +3 -5
- package/dist/cybergotchi/bones.d.ts +1 -1
- package/dist/cybergotchi/bones.js +8 -8
- package/dist/cybergotchi/config.d.ts +2 -2
- package/dist/cybergotchi/config.js +13 -13
- package/dist/cybergotchi/events.d.ts +5 -5
- package/dist/cybergotchi/events.js +7 -7
- package/dist/cybergotchi/needs.d.ts +2 -2
- package/dist/cybergotchi/needs.js +7 -9
- package/dist/cybergotchi/personality.d.ts +2 -2
- package/dist/cybergotchi/personality.js +2 -2
- package/dist/cybergotchi/species.d.ts +1 -1
- package/dist/cybergotchi/species.js +145 -217
- package/dist/cybergotchi/speech.d.ts +2 -2
- package/dist/cybergotchi/speech.js +43 -43
- package/dist/cybergotchi/types.d.ts +4 -4
- package/dist/cybergotchi/types.js +26 -26
- package/dist/cybergotchi/useCybergotchi.d.ts +1 -1
- package/dist/cybergotchi/useCybergotchi.js +29 -25
- package/dist/git/index.js +11 -9
- package/dist/harness/checkpoints.js +29 -21
- package/dist/harness/config.d.ts +3 -3
- package/dist/harness/config.js +15 -9
- package/dist/harness/context-warning.d.ts +1 -1
- package/dist/harness/context-warning.js +1 -1
- package/dist/harness/cost.js +1 -1
- package/dist/harness/credentials.js +13 -13
- package/dist/harness/hooks.js +7 -5
- package/dist/harness/keybindings.js +20 -18
- package/dist/harness/marketplace.d.ts +3 -3
- package/dist/harness/marketplace.js +55 -42
- package/dist/harness/memory.d.ts +23 -5
- package/dist/harness/memory.js +142 -41
- package/dist/harness/onboarding.js +30 -10
- package/dist/harness/plugins.d.ts +9 -1
- package/dist/harness/plugins.js +54 -30
- package/dist/harness/rules.js +12 -7
- package/dist/harness/sandbox.js +15 -15
- package/dist/harness/session-db.d.ts +55 -0
- package/dist/harness/session-db.js +165 -0
- package/dist/harness/session.d.ts +1 -1
- package/dist/harness/session.js +34 -15
- package/dist/harness/store.d.ts +3 -3
- package/dist/harness/store.js +6 -4
- package/dist/harness/submit-handler.d.ts +4 -4
- package/dist/harness/submit-handler.js +25 -23
- package/dist/harness/telemetry.d.ts +1 -1
- package/dist/harness/telemetry.js +23 -19
- package/dist/harness/traces.d.ts +2 -2
- package/dist/harness/traces.js +39 -33
- package/dist/harness/verification.d.ts +1 -1
- package/dist/harness/verification.js +50 -44
- package/dist/lsp/client.js +44 -40
- package/dist/main.js +114 -59
- package/dist/mcp/DeferredMcpTool.d.ts +4 -4
- package/dist/mcp/DeferredMcpTool.js +9 -5
- package/dist/mcp/McpTool.d.ts +4 -4
- package/dist/mcp/McpTool.js +8 -4
- package/dist/mcp/client.d.ts +2 -2
- package/dist/mcp/client.js +21 -21
- package/dist/mcp/loader.d.ts +1 -1
- package/dist/mcp/loader.js +17 -12
- package/dist/mcp/registry.d.ts +3 -3
- package/dist/mcp/registry.js +97 -97
- package/dist/mcp/schema.d.ts +1 -1
- package/dist/mcp/schema.js +16 -16
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +21 -21
- package/dist/mcp/types.d.ts +3 -3
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +10 -9
- package/dist/providers/base.d.ts +1 -1
- package/dist/providers/index.js +10 -3
- package/dist/providers/llamacpp.d.ts +2 -2
- package/dist/providers/llamacpp.js +1 -3
- package/dist/providers/ollama.d.ts +2 -2
- package/dist/providers/ollama.js +3 -4
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +3 -5
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/providers/router.d.ts +1 -1
- package/dist/providers/router.js +7 -7
- package/dist/query/compress.d.ts +2 -2
- package/dist/query/compress.js +22 -21
- package/dist/query/context-manager.d.ts +1 -1
- package/dist/query/context-manager.js +5 -5
- package/dist/query/errors.js +1 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +42 -24
- package/dist/query/tools.js +15 -12
- package/dist/query/types.d.ts +3 -1
- package/dist/query.d.ts +1 -1
- package/dist/query.js +1 -1
- package/dist/remote/auth.d.ts +2 -2
- package/dist/remote/auth.js +8 -8
- package/dist/remote/server.d.ts +3 -3
- package/dist/remote/server.js +60 -60
- package/dist/renderer/cells.js +9 -9
- package/dist/renderer/colors.js +24 -6
- package/dist/renderer/diff.d.ts +2 -2
- package/dist/renderer/diff.js +27 -19
- package/dist/renderer/differ.d.ts +1 -1
- package/dist/renderer/differ.js +9 -9
- package/dist/renderer/image.js +19 -19
- package/dist/renderer/index.d.ts +6 -6
- package/dist/renderer/index.js +163 -93
- package/dist/renderer/input.js +66 -48
- package/dist/renderer/layout.d.ts +6 -6
- package/dist/renderer/layout.js +163 -124
- package/dist/renderer/markdown.d.ts +2 -2
- package/dist/renderer/markdown.js +173 -54
- package/dist/renderer/session-browser.d.ts +2 -2
- package/dist/renderer/session-browser.js +19 -21
- package/dist/repl.d.ts +5 -5
- package/dist/repl.js +311 -198
- package/dist/sdk/index.d.ts +5 -5
- package/dist/sdk/index.js +32 -26
- package/dist/services/AgentDispatcher.d.ts +3 -3
- package/dist/services/AgentDispatcher.js +33 -29
- package/dist/services/CronExecutor.d.ts +4 -4
- package/dist/services/CronExecutor.js +12 -8
- package/dist/services/EvaluatorLoop.d.ts +3 -3
- package/dist/services/EvaluatorLoop.js +29 -21
- package/dist/services/MetaHarness.d.ts +1 -1
- package/dist/services/MetaHarness.js +34 -32
- package/dist/services/PipelineExecutor.d.ts +1 -1
- package/dist/services/PipelineExecutor.js +23 -25
- package/dist/services/SkillExtractor.d.ts +43 -0
- package/dist/services/SkillExtractor.js +163 -0
- package/dist/services/StreamingToolExecutor.d.ts +2 -2
- package/dist/services/StreamingToolExecutor.js +11 -7
- package/dist/services/a2a.d.ts +8 -8
- package/dist/services/a2a.js +44 -34
- package/dist/services/agent-messaging.d.ts +33 -15
- package/dist/services/agent-messaging.js +65 -13
- package/dist/services/cron.js +16 -16
- package/dist/tools/AgentTool/index.d.ts +5 -2
- package/dist/tools/AgentTool/index.js +25 -39
- package/dist/tools/AskUserTool/index.js +1 -1
- package/dist/tools/BashTool/index.d.ts +2 -2
- package/dist/tools/BashTool/index.js +18 -10
- package/dist/tools/CronTool/index.js +30 -12
- package/dist/tools/DiagnosticsTool/index.js +28 -22
- package/dist/tools/EnterPlanModeTool/index.js +93 -14
- package/dist/tools/EnterWorktreeTool/index.js +7 -3
- package/dist/tools/ExitPlanModeTool/index.d.ts +22 -1
- package/dist/tools/ExitPlanModeTool/index.js +20 -5
- package/dist/tools/ExitWorktreeTool/index.js +11 -4
- package/dist/tools/FileEditTool/index.js +3 -5
- package/dist/tools/FileReadTool/index.js +16 -10
- package/dist/tools/FileWriteTool/index.js +2 -2
- package/dist/tools/GlobTool/index.js +5 -9
- package/dist/tools/GrepTool/index.d.ts +2 -2
- package/dist/tools/GrepTool/index.js +14 -9
- package/dist/tools/ImageReadTool/index.js +2 -2
- package/dist/tools/KillProcessTool/index.js +11 -7
- package/dist/tools/LSTool/index.js +3 -3
- package/dist/tools/MemoryTool/index.d.ts +5 -5
- package/dist/tools/MemoryTool/index.js +28 -14
- package/dist/tools/MonitorTool/index.js +24 -19
- package/dist/tools/MultiEditTool/index.js +9 -5
- package/dist/tools/NotebookEditTool/index.js +3 -3
- package/dist/tools/ParallelAgentTool/index.d.ts +4 -4
- package/dist/tools/ParallelAgentTool/index.js +12 -6
- package/dist/tools/PipelineTool/index.js +3 -3
- package/dist/tools/PowerShellTool/index.js +10 -6
- package/dist/tools/RemoteTriggerTool/index.js +8 -4
- package/dist/tools/ScheduleWakeupTool/index.d.ts +42 -0
- package/dist/tools/ScheduleWakeupTool/index.js +115 -0
- package/dist/tools/SendMessageTool/index.js +25 -7
- package/dist/tools/SessionSearchTool/index.d.ts +15 -0
- package/dist/tools/SessionSearchTool/index.js +36 -0
- package/dist/tools/SkillTool/index.d.ts +3 -0
- package/dist/tools/SkillTool/index.js +39 -9
- package/dist/tools/TaskCreateTool/index.d.ts +2 -2
- package/dist/tools/TaskCreateTool/index.js +2 -2
- package/dist/tools/TaskGetTool/index.js +2 -2
- package/dist/tools/TaskListTool/index.js +3 -5
- package/dist/tools/TaskOutputTool/index.js +2 -2
- package/dist/tools/TaskStopTool/index.js +3 -3
- package/dist/tools/TaskUpdateTool/index.d.ts +4 -4
- package/dist/tools/TaskUpdateTool/index.js +2 -2
- package/dist/tools/ToolSearchTool/index.js +9 -6
- package/dist/tools/WebFetchTool/index.js +1 -1
- package/dist/tools/WebSearchTool/index.js +2 -6
- package/dist/tools.js +31 -30
- package/dist/types/permissions.js +15 -9
- package/dist/utils/bash-safety.d.ts +1 -1
- package/dist/utils/bash-safety.js +64 -54
- package/dist/utils/diff-algorithm.d.ts +3 -3
- package/dist/utils/diff-algorithm.js +7 -7
- package/dist/utils/fs.js +3 -3
- package/dist/utils/safe-env.js +1 -1
- package/dist/utils/theme-data.d.ts +1 -1
- package/dist/utils/theme-data.js +1 -1
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/tool-summary.d.ts +1 -1
- package/dist/utils/tool-summary.js +27 -9
- package/package.json +10 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
import { spawn } from "child_process";
|
|
3
3
|
import { safeEnv } from "../../utils/safe-env.js";
|
|
4
4
|
const inputSchema = z.object({
|
|
5
5
|
command: z.string(),
|
|
@@ -8,7 +8,7 @@ const inputSchema = z.object({
|
|
|
8
8
|
run_in_background: z.boolean().optional(),
|
|
9
9
|
});
|
|
10
10
|
const MAX_OUTPUT = 100_000;
|
|
11
|
-
const
|
|
11
|
+
const _DEFAULT_TIMEOUT = 120_000;
|
|
12
12
|
const MAX_TIMEOUT = 600_000;
|
|
13
13
|
export const BashTool = {
|
|
14
14
|
name: "Bash",
|
|
@@ -38,17 +38,25 @@ export const BashTool = {
|
|
|
38
38
|
});
|
|
39
39
|
let stdout = "";
|
|
40
40
|
let stderr = "";
|
|
41
|
-
proc.stdout.on("data", (chunk) => {
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
proc.stdout.on("data", (chunk) => {
|
|
42
|
+
stdout += chunk.toString();
|
|
43
|
+
});
|
|
44
|
+
proc.stderr.on("data", (chunk) => {
|
|
45
|
+
stderr += chunk.toString();
|
|
46
|
+
});
|
|
47
|
+
const timer = setTimeout(() => {
|
|
48
|
+
proc.kill("SIGTERM");
|
|
49
|
+
}, timeoutMs);
|
|
44
50
|
if (context.abortSignal) {
|
|
45
|
-
context.abortSignal.addEventListener("abort", () => {
|
|
51
|
+
context.abortSignal.addEventListener("abort", () => {
|
|
52
|
+
proc.kill("SIGTERM");
|
|
53
|
+
});
|
|
46
54
|
}
|
|
47
55
|
proc.on("close", (code) => {
|
|
48
56
|
clearTimeout(timer);
|
|
49
|
-
let output = stdout + (stderr ?
|
|
57
|
+
let output = stdout + (stderr ? `\n[stderr]\n${stderr}` : "");
|
|
50
58
|
if (output.length > MAX_OUTPUT) {
|
|
51
|
-
output = output.slice(0, MAX_OUTPUT)
|
|
59
|
+
output = `${output.slice(0, MAX_OUTPUT)}\n... [truncated]`;
|
|
52
60
|
}
|
|
53
61
|
// Notify via output chunk when background process completes
|
|
54
62
|
if (context.onOutputChunk && context.callId) {
|
|
@@ -94,9 +102,9 @@ export const BashTool = {
|
|
|
94
102
|
}
|
|
95
103
|
proc.on("close", (code) => {
|
|
96
104
|
clearTimeout(timer);
|
|
97
|
-
let output = stdout + (stderr ?
|
|
105
|
+
let output = stdout + (stderr ? `\n[stderr]\n${stderr}` : "");
|
|
98
106
|
if (output.length > MAX_OUTPUT) {
|
|
99
|
-
output = output.slice(0, MAX_OUTPUT)
|
|
107
|
+
output = `${output.slice(0, MAX_OUTPUT)}\n... [truncated]`;
|
|
100
108
|
}
|
|
101
109
|
if (killed) {
|
|
102
110
|
output += "\n[timed out]";
|
|
@@ -13,47 +13,65 @@ const deleteSchema = z.object({
|
|
|
13
13
|
const listSchema = z.object({
|
|
14
14
|
action: z.literal("list"),
|
|
15
15
|
});
|
|
16
|
-
const
|
|
16
|
+
const _inputSchema = z.discriminatedUnion("action", [createSchema, deleteSchema, listSchema]);
|
|
17
17
|
export const CronCreateTool = {
|
|
18
18
|
name: "CronCreate",
|
|
19
19
|
description: "Create a scheduled recurring task that runs a prompt on an interval.",
|
|
20
20
|
inputSchema: createSchema,
|
|
21
21
|
riskLevel: "medium",
|
|
22
|
-
isReadOnly() {
|
|
23
|
-
|
|
22
|
+
isReadOnly() {
|
|
23
|
+
return false;
|
|
24
|
+
},
|
|
25
|
+
isConcurrencySafe() {
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
24
28
|
async call(input) {
|
|
25
29
|
const cron = createCron(input.name, input.schedule, input.prompt);
|
|
26
30
|
return { output: `Created cron '${cron.name}' (${cron.id}) — schedule: ${cron.schedule}`, isError: false };
|
|
27
31
|
},
|
|
28
|
-
prompt() {
|
|
32
|
+
prompt() {
|
|
33
|
+
return "CronCreate: Schedule a recurring task. Schedules: 'every 5m', 'every 2h', 'every 1d'.";
|
|
34
|
+
},
|
|
29
35
|
};
|
|
30
36
|
export const CronDeleteTool = {
|
|
31
37
|
name: "CronDelete",
|
|
32
38
|
description: "Delete a scheduled recurring task.",
|
|
33
39
|
inputSchema: deleteSchema,
|
|
34
40
|
riskLevel: "medium",
|
|
35
|
-
isReadOnly() {
|
|
36
|
-
|
|
41
|
+
isReadOnly() {
|
|
42
|
+
return false;
|
|
43
|
+
},
|
|
44
|
+
isConcurrencySafe() {
|
|
45
|
+
return true;
|
|
46
|
+
},
|
|
37
47
|
async call(input) {
|
|
38
48
|
const ok = deleteCron(input.id);
|
|
39
49
|
return { output: ok ? `Deleted cron ${input.id}` : `Cron ${input.id} not found`, isError: !ok };
|
|
40
50
|
},
|
|
41
|
-
prompt() {
|
|
51
|
+
prompt() {
|
|
52
|
+
return "CronDelete: Remove a scheduled task by ID.";
|
|
53
|
+
},
|
|
42
54
|
};
|
|
43
55
|
export const CronListTool = {
|
|
44
56
|
name: "CronList",
|
|
45
57
|
description: "List all scheduled recurring tasks.",
|
|
46
58
|
inputSchema: listSchema,
|
|
47
59
|
riskLevel: "low",
|
|
48
|
-
isReadOnly() {
|
|
49
|
-
|
|
60
|
+
isReadOnly() {
|
|
61
|
+
return true;
|
|
62
|
+
},
|
|
63
|
+
isConcurrencySafe() {
|
|
64
|
+
return true;
|
|
65
|
+
},
|
|
50
66
|
async call() {
|
|
51
67
|
const crons = listCrons();
|
|
52
68
|
if (crons.length === 0)
|
|
53
69
|
return { output: "No scheduled tasks.", isError: false };
|
|
54
|
-
const lines = crons.map(c => `${c.id} ${c.name.padEnd(20)} ${c.schedule.padEnd(12)} ${c.enabled ?
|
|
55
|
-
return { output: `Scheduled tasks:\n${lines.join(
|
|
70
|
+
const lines = crons.map((c) => `${c.id} ${c.name.padEnd(20)} ${c.schedule.padEnd(12)} ${c.enabled ? "✓" : "✗"} runs: ${c.runCount}`);
|
|
71
|
+
return { output: `Scheduled tasks:\n${lines.join("\n")}`, isError: false };
|
|
72
|
+
},
|
|
73
|
+
prompt() {
|
|
74
|
+
return "CronList: Show all scheduled recurring tasks.";
|
|
56
75
|
},
|
|
57
|
-
prompt() { return "CronList: Show all scheduled recurring tasks."; },
|
|
58
76
|
};
|
|
59
77
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,7 +2,9 @@ import { z } from "zod";
|
|
|
2
2
|
import { LspClient } from "../../lsp/client.js";
|
|
3
3
|
const inputSchema = z.object({
|
|
4
4
|
file_path: z.string().describe("Absolute path to the file to check"),
|
|
5
|
-
action: z
|
|
5
|
+
action: z
|
|
6
|
+
.enum(["diagnostics", "definition", "references", "hover"])
|
|
7
|
+
.default("diagnostics")
|
|
6
8
|
.describe("Action: diagnostics (errors/warnings), definition (go-to-def), references (find-refs), hover (type info)"),
|
|
7
9
|
line: z.number().optional().describe("Line number (0-indexed) for definition/references"),
|
|
8
10
|
character: z.number().optional().describe("Column number (0-indexed) for definition/references"),
|
|
@@ -10,17 +12,17 @@ const inputSchema = z.object({
|
|
|
10
12
|
// Singleton LSP client per language server
|
|
11
13
|
const lspClients = new Map();
|
|
12
14
|
function getLspCommand(filePath) {
|
|
13
|
-
if (filePath.endsWith(
|
|
14
|
-
return { command:
|
|
15
|
+
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx") || filePath.endsWith(".js") || filePath.endsWith(".jsx")) {
|
|
16
|
+
return { command: "npx", args: ["typescript-language-server", "--stdio"] };
|
|
15
17
|
}
|
|
16
|
-
if (filePath.endsWith(
|
|
17
|
-
return { command:
|
|
18
|
+
if (filePath.endsWith(".py")) {
|
|
19
|
+
return { command: "pylsp", args: [] };
|
|
18
20
|
}
|
|
19
|
-
if (filePath.endsWith(
|
|
20
|
-
return { command:
|
|
21
|
+
if (filePath.endsWith(".go")) {
|
|
22
|
+
return { command: "gopls", args: ["serve"] };
|
|
21
23
|
}
|
|
22
|
-
if (filePath.endsWith(
|
|
23
|
-
return { command:
|
|
24
|
+
if (filePath.endsWith(".rs")) {
|
|
25
|
+
return { command: "rust-analyzer", args: [] };
|
|
24
26
|
}
|
|
25
27
|
return null;
|
|
26
28
|
}
|
|
@@ -45,8 +47,12 @@ export const DiagnosticsTool = {
|
|
|
45
47
|
description: "Get code diagnostics (errors, warnings), go-to-definition, or find-references using the language server.",
|
|
46
48
|
inputSchema,
|
|
47
49
|
riskLevel: "low",
|
|
48
|
-
isReadOnly() {
|
|
49
|
-
|
|
50
|
+
isReadOnly() {
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
isConcurrencySafe() {
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
50
56
|
async call(input, context) {
|
|
51
57
|
const client = await getClient(input.file_path, context.workingDir);
|
|
52
58
|
if (!client) {
|
|
@@ -62,11 +68,11 @@ export const DiagnosticsTool = {
|
|
|
62
68
|
if (diags.length === 0)
|
|
63
69
|
return { output: "No diagnostics found.", isError: false };
|
|
64
70
|
const severityMap = { 1: "Error", 2: "Warning", 3: "Info", 4: "Hint" };
|
|
65
|
-
const lines = diags.map(d => {
|
|
71
|
+
const lines = diags.map((d) => {
|
|
66
72
|
const sev = severityMap[d.severity ?? 1] ?? "Unknown";
|
|
67
73
|
return `${sev} [${d.source ?? ""}] L${d.range.start.line + 1}:${d.range.start.character}: ${d.message}`;
|
|
68
74
|
});
|
|
69
|
-
return { output: lines.join(
|
|
75
|
+
return { output: lines.join("\n"), isError: false };
|
|
70
76
|
}
|
|
71
77
|
if (input.action === "definition") {
|
|
72
78
|
if (input.line === undefined || input.character === undefined) {
|
|
@@ -76,8 +82,8 @@ export const DiagnosticsTool = {
|
|
|
76
82
|
const locs = await client.getDefinition(input.file_path, input.line, input.character);
|
|
77
83
|
if (locs.length === 0)
|
|
78
84
|
return { output: "No definition found.", isError: false };
|
|
79
|
-
const lines = locs.map(l => `${l.uri.replace(
|
|
80
|
-
return { output: lines.join(
|
|
85
|
+
const lines = locs.map((l) => `${l.uri.replace("file://", "")}:${l.range.start.line + 1}:${l.range.start.character}`);
|
|
86
|
+
return { output: lines.join("\n"), isError: false };
|
|
81
87
|
}
|
|
82
88
|
if (input.action === "references") {
|
|
83
89
|
if (input.line === undefined || input.character === undefined) {
|
|
@@ -87,8 +93,8 @@ export const DiagnosticsTool = {
|
|
|
87
93
|
const refs = await client.getReferences(input.file_path, input.line, input.character);
|
|
88
94
|
if (refs.length === 0)
|
|
89
95
|
return { output: "No references found.", isError: false };
|
|
90
|
-
const lines = refs.map(r => `${r.uri.replace(
|
|
91
|
-
return { output: `${refs.length} reference(s):\n${lines.join(
|
|
96
|
+
const lines = refs.map((r) => `${r.uri.replace("file://", "")}:${r.range.start.line + 1}:${r.range.start.character}`);
|
|
97
|
+
return { output: `${refs.length} reference(s):\n${lines.join("\n")}`, isError: false };
|
|
92
98
|
}
|
|
93
99
|
if (input.action === "hover") {
|
|
94
100
|
if (input.line === undefined || input.character === undefined) {
|
|
@@ -97,15 +103,15 @@ export const DiagnosticsTool = {
|
|
|
97
103
|
await client.openFile(input.file_path);
|
|
98
104
|
// Hover uses textDocument/hover which returns MarkupContent
|
|
99
105
|
try {
|
|
100
|
-
const result = await client.send(
|
|
101
|
-
textDocument: { uri: `file://${input.file_path.replace(/\\/g,
|
|
106
|
+
const result = await client.send("textDocument/hover", {
|
|
107
|
+
textDocument: { uri: `file://${input.file_path.replace(/\\/g, "/")}` },
|
|
102
108
|
position: { line: input.line, character: input.character },
|
|
103
109
|
});
|
|
104
|
-
if (!result
|
|
110
|
+
if (!result?.contents)
|
|
105
111
|
return { output: "No hover information.", isError: false };
|
|
106
|
-
const content = typeof result.contents ===
|
|
112
|
+
const content = typeof result.contents === "string"
|
|
107
113
|
? result.contents
|
|
108
|
-
: result.contents.value ?? JSON.stringify(result.contents);
|
|
114
|
+
: (result.contents.value ?? JSON.stringify(result.contents));
|
|
109
115
|
return { output: content, isError: false };
|
|
110
116
|
}
|
|
111
117
|
catch {
|
|
@@ -1,10 +1,90 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
1
3
|
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Generate a memorable plan filename from three random words.
|
|
6
|
+
* Pattern: adjective-verb-noun (e.g., "twinkling-riding-crown")
|
|
7
|
+
*/
|
|
8
|
+
function generatePlanName() {
|
|
9
|
+
const adjectives = [
|
|
10
|
+
"bright",
|
|
11
|
+
"calm",
|
|
12
|
+
"dark",
|
|
13
|
+
"eager",
|
|
14
|
+
"fast",
|
|
15
|
+
"gentle",
|
|
16
|
+
"happy",
|
|
17
|
+
"keen",
|
|
18
|
+
"light",
|
|
19
|
+
"merry",
|
|
20
|
+
"noble",
|
|
21
|
+
"plain",
|
|
22
|
+
"quiet",
|
|
23
|
+
"rare",
|
|
24
|
+
"sharp",
|
|
25
|
+
"tall",
|
|
26
|
+
"vivid",
|
|
27
|
+
"warm",
|
|
28
|
+
"young",
|
|
29
|
+
"bold",
|
|
30
|
+
"clean",
|
|
31
|
+
"deep",
|
|
32
|
+
"fair",
|
|
33
|
+
"grand",
|
|
34
|
+
];
|
|
35
|
+
const verbs = [
|
|
36
|
+
"flying",
|
|
37
|
+
"riding",
|
|
38
|
+
"singing",
|
|
39
|
+
"dancing",
|
|
40
|
+
"running",
|
|
41
|
+
"walking",
|
|
42
|
+
"building",
|
|
43
|
+
"crafting",
|
|
44
|
+
"drawing",
|
|
45
|
+
"growing",
|
|
46
|
+
"hiding",
|
|
47
|
+
"jumping",
|
|
48
|
+
"leading",
|
|
49
|
+
"making",
|
|
50
|
+
"passing",
|
|
51
|
+
"rising",
|
|
52
|
+
"saving",
|
|
53
|
+
"taking",
|
|
54
|
+
"turning",
|
|
55
|
+
"watching",
|
|
56
|
+
];
|
|
57
|
+
const nouns = [
|
|
58
|
+
"arrow",
|
|
59
|
+
"badge",
|
|
60
|
+
"crown",
|
|
61
|
+
"dream",
|
|
62
|
+
"flame",
|
|
63
|
+
"grove",
|
|
64
|
+
"heart",
|
|
65
|
+
"ivory",
|
|
66
|
+
"jewel",
|
|
67
|
+
"knot",
|
|
68
|
+
"latch",
|
|
69
|
+
"maple",
|
|
70
|
+
"night",
|
|
71
|
+
"ocean",
|
|
72
|
+
"pearl",
|
|
73
|
+
"quest",
|
|
74
|
+
"ridge",
|
|
75
|
+
"stone",
|
|
76
|
+
"tower",
|
|
77
|
+
"vault",
|
|
78
|
+
"whale",
|
|
79
|
+
"zenith",
|
|
80
|
+
];
|
|
81
|
+
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
82
|
+
return `${pick(adjectives)}-${pick(verbs)}-${pick(nouns)}`;
|
|
83
|
+
}
|
|
4
84
|
const inputSchema = z.object({});
|
|
5
85
|
export const EnterPlanModeTool = {
|
|
6
86
|
name: "EnterPlanMode",
|
|
7
|
-
description: "Enter plan mode, creating
|
|
87
|
+
description: "Enter plan mode, creating a unique plan file in .oh/plans/.",
|
|
8
88
|
inputSchema,
|
|
9
89
|
riskLevel: "low",
|
|
10
90
|
isReadOnly() {
|
|
@@ -14,24 +94,23 @@ export const EnterPlanModeTool = {
|
|
|
14
94
|
return false;
|
|
15
95
|
},
|
|
16
96
|
async call(_input, context) {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
97
|
+
const plansDir = path.join(context.workingDir, ".oh", "plans");
|
|
98
|
+
const planName = generatePlanName();
|
|
99
|
+
const filePath = path.join(plansDir, `${planName}.md`);
|
|
19
100
|
try {
|
|
20
|
-
await fs.mkdir(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
return { output: "Plan mode entered.", isError: false };
|
|
101
|
+
await fs.mkdir(plansDir, { recursive: true });
|
|
102
|
+
await fs.writeFile(filePath, `# Plan\n\n<!-- Write your plan here -->\n`, "utf-8");
|
|
103
|
+
return {
|
|
104
|
+
output: `Plan mode entered. Plan file: ${filePath}\nWrite your plan to this file using the Write or Edit tool.`,
|
|
105
|
+
isError: false,
|
|
106
|
+
};
|
|
28
107
|
}
|
|
29
108
|
catch (err) {
|
|
30
109
|
return { output: `Error entering plan mode: ${err.message}`, isError: true };
|
|
31
110
|
}
|
|
32
111
|
},
|
|
33
112
|
prompt() {
|
|
34
|
-
return `Enter plan mode. Creates .oh/
|
|
113
|
+
return `Enter plan mode. Creates a unique plan file at .oh/plans/<name>.md. Write your plan to this file, then call ExitPlanMode when done. No parameters required.`;
|
|
35
114
|
},
|
|
36
115
|
};
|
|
37
116
|
//# sourceMappingURL=index.js.map
|
|
@@ -8,9 +8,13 @@ export const EnterWorktreeTool = {
|
|
|
8
8
|
description: "Create an isolated git worktree for safe experimentation. Changes won't affect the main working directory.",
|
|
9
9
|
inputSchema,
|
|
10
10
|
riskLevel: "medium",
|
|
11
|
-
isReadOnly() {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
isReadOnly() {
|
|
12
|
+
return false;
|
|
13
|
+
},
|
|
14
|
+
isConcurrencySafe() {
|
|
15
|
+
return false;
|
|
16
|
+
},
|
|
17
|
+
async call(_input, context) {
|
|
14
18
|
if (!isGitRepo(context.workingDir)) {
|
|
15
19
|
return { output: "Not a git repository — worktrees require git.", isError: true };
|
|
16
20
|
}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { Tool } from "../../Tool.js";
|
|
3
|
-
declare const inputSchema: z.ZodObject<{
|
|
3
|
+
declare const inputSchema: z.ZodObject<{
|
|
4
|
+
allowedPrompts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
5
|
+
tool: z.ZodEnum<["Bash"]>;
|
|
6
|
+
prompt: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
tool: "Bash";
|
|
9
|
+
prompt: string;
|
|
10
|
+
}, {
|
|
11
|
+
tool: "Bash";
|
|
12
|
+
prompt: string;
|
|
13
|
+
}>, "many">>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
allowedPrompts?: {
|
|
16
|
+
tool: "Bash";
|
|
17
|
+
prompt: string;
|
|
18
|
+
}[] | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
allowedPrompts?: {
|
|
21
|
+
tool: "Bash";
|
|
22
|
+
prompt: string;
|
|
23
|
+
}[] | undefined;
|
|
24
|
+
}>;
|
|
4
25
|
export declare const ExitPlanModeTool: Tool<typeof inputSchema>;
|
|
5
26
|
export {};
|
|
6
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
const inputSchema = z.object({
|
|
2
|
+
const inputSchema = z.object({
|
|
3
|
+
allowedPrompts: z
|
|
4
|
+
.array(z.object({
|
|
5
|
+
tool: z.enum(["Bash"]).describe("The tool this prompt applies to"),
|
|
6
|
+
prompt: z.string().describe("Semantic description of the action, e.g. 'run tests', 'install dependencies'"),
|
|
7
|
+
}))
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Prompt-based permissions needed to implement the plan"),
|
|
10
|
+
});
|
|
3
11
|
export const ExitPlanModeTool = {
|
|
4
12
|
name: "ExitPlanMode",
|
|
5
|
-
description: "Exit plan mode.",
|
|
13
|
+
description: "Exit plan mode and signal that the plan is ready for user approval.",
|
|
6
14
|
inputSchema,
|
|
7
15
|
riskLevel: "low",
|
|
8
16
|
isReadOnly() {
|
|
@@ -11,11 +19,18 @@ export const ExitPlanModeTool = {
|
|
|
11
19
|
isConcurrencySafe() {
|
|
12
20
|
return false;
|
|
13
21
|
},
|
|
14
|
-
async call(
|
|
15
|
-
|
|
22
|
+
async call(input, _context) {
|
|
23
|
+
const parts = ["Plan mode exited. Plan is ready for review."];
|
|
24
|
+
if (input.allowedPrompts?.length) {
|
|
25
|
+
parts.push("Requested permissions:");
|
|
26
|
+
for (const p of input.allowedPrompts) {
|
|
27
|
+
parts.push(` - ${p.tool}: ${p.prompt}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { output: parts.join("\n"), isError: false };
|
|
16
31
|
},
|
|
17
32
|
prompt() {
|
|
18
|
-
return `Exit plan mode.
|
|
33
|
+
return `Exit plan mode and signal that the plan is ready for user approval. Optionally specify allowedPrompts to pre-authorize specific actions (e.g., running tests) during plan execution.`;
|
|
19
34
|
},
|
|
20
35
|
};
|
|
21
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { hasWorktreeChanges, removeWorktree } from "../../git/index.js";
|
|
3
3
|
const inputSchema = z.object({
|
|
4
4
|
path: z.string().describe("Path to the worktree to remove"),
|
|
5
5
|
force: z.boolean().optional().describe("Force removal even with uncommitted changes"),
|
|
@@ -9,8 +9,12 @@ export const ExitWorktreeTool = {
|
|
|
9
9
|
description: "Remove a git worktree. Warns if there are uncommitted changes unless force is true.",
|
|
10
10
|
inputSchema,
|
|
11
11
|
riskLevel: "medium",
|
|
12
|
-
isReadOnly() {
|
|
13
|
-
|
|
12
|
+
isReadOnly() {
|
|
13
|
+
return false;
|
|
14
|
+
},
|
|
15
|
+
isConcurrencySafe() {
|
|
16
|
+
return false;
|
|
17
|
+
},
|
|
14
18
|
async call(input) {
|
|
15
19
|
if (!input.force && hasWorktreeChanges(input.path)) {
|
|
16
20
|
return {
|
|
@@ -23,7 +27,10 @@ export const ExitWorktreeTool = {
|
|
|
23
27
|
return { output: `Worktree removed: ${input.path}`, isError: false };
|
|
24
28
|
}
|
|
25
29
|
catch (err) {
|
|
26
|
-
return {
|
|
30
|
+
return {
|
|
31
|
+
output: `Failed to remove worktree: ${err instanceof Error ? err.message : String(err)}`,
|
|
32
|
+
isError: true,
|
|
33
|
+
};
|
|
27
34
|
}
|
|
28
35
|
},
|
|
29
36
|
prompt() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
1
3
|
import { z } from "zod";
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
import * as path from "path";
|
|
4
4
|
const inputSchema = z.object({
|
|
5
5
|
file_path: z.string(),
|
|
6
6
|
old_string: z.string(),
|
|
@@ -44,9 +44,7 @@ export const FileEditTool = {
|
|
|
44
44
|
? content.split(input.old_string).join(input.new_string)
|
|
45
45
|
: content.replace(input.old_string, input.new_string);
|
|
46
46
|
await fs.writeFile(filePath, newContent, "utf-8");
|
|
47
|
-
const occurrences = input.replace_all
|
|
48
|
-
? content.split(input.old_string).length - 1
|
|
49
|
-
: 1;
|
|
47
|
+
const occurrences = input.replace_all ? content.split(input.old_string).length - 1 : 1;
|
|
50
48
|
return {
|
|
51
49
|
output: `Edited ${filePath}: replaced ${occurrences} occurrence(s).\n--- old\n${input.old_string}\n+++ new\n${input.new_string}`,
|
|
52
50
|
isError: false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
1
3
|
import { z } from "zod";
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
import * as path from "path";
|
|
4
4
|
const inputSchema = z.object({
|
|
5
5
|
file_path: z.string(),
|
|
6
6
|
offset: z.number().optional(),
|
|
@@ -16,14 +16,14 @@ function parsePageRange(pages) {
|
|
|
16
16
|
const trimmed = part.trim();
|
|
17
17
|
if (trimmed.includes("-")) {
|
|
18
18
|
const [start, end] = trimmed.split("-").map(Number);
|
|
19
|
-
if (!isNaN(start) && !isNaN(end)) {
|
|
19
|
+
if (!Number.isNaN(start) && !Number.isNaN(end)) {
|
|
20
20
|
for (let i = start; i <= Math.min(end, start + 19); i++)
|
|
21
21
|
result.push(i);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
25
|
const n = Number(trimmed);
|
|
26
|
-
if (!isNaN(n))
|
|
26
|
+
if (!Number.isNaN(n))
|
|
27
27
|
result.push(n);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -55,8 +55,13 @@ export const FileReadTool = {
|
|
|
55
55
|
const buffer = await fs.readFile(filePath);
|
|
56
56
|
const base64 = buffer.toString("base64");
|
|
57
57
|
const mimeTypes = {
|
|
58
|
-
".png": "image/png",
|
|
59
|
-
".
|
|
58
|
+
".png": "image/png",
|
|
59
|
+
".jpg": "image/jpeg",
|
|
60
|
+
".jpeg": "image/jpeg",
|
|
61
|
+
".gif": "image/gif",
|
|
62
|
+
".webp": "image/webp",
|
|
63
|
+
".bmp": "image/bmp",
|
|
64
|
+
".svg": "image/svg+xml",
|
|
60
65
|
};
|
|
61
66
|
return { output: `__IMAGE__:${mimeTypes[ext] ?? "image/png"}:${base64}`, isError: false };
|
|
62
67
|
}
|
|
@@ -64,7 +69,10 @@ export const FileReadTool = {
|
|
|
64
69
|
if (ext === ".pdf") {
|
|
65
70
|
// Guard against very large PDFs without page filter
|
|
66
71
|
if (stat.size > 20 * 1024 * 1024 && !input.pages) {
|
|
67
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
output: `PDF is ${(stat.size / 1024 / 1024).toFixed(1)} MB. Provide a 'pages' parameter (e.g., "1-5") to read specific pages.`,
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
68
76
|
}
|
|
69
77
|
const buffer = await fs.readFile(filePath);
|
|
70
78
|
// Basic PDF text extraction — look for text between BT/ET markers or stream content
|
|
@@ -128,9 +136,7 @@ export const FileReadTool = {
|
|
|
128
136
|
const offset = Math.max(0, (input.offset ?? 1) - 1);
|
|
129
137
|
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
130
138
|
const lines = allLines.slice(offset, offset + limit);
|
|
131
|
-
const numbered = lines
|
|
132
|
-
.map((line, i) => `${offset + i + 1}\t${line}`)
|
|
133
|
-
.join("\n");
|
|
139
|
+
const numbered = lines.map((line, i) => `${offset + i + 1}\t${line}`).join("\n");
|
|
134
140
|
const total = allLines.length;
|
|
135
141
|
const shown = lines.length;
|
|
136
142
|
let result = numbered;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
1
3
|
import { z } from "zod";
|
|
2
|
-
import
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import { walkDir, matchGlob } from "../../utils/fs.js";
|
|
4
|
+
import { matchGlob, walkDir } from "../../utils/fs.js";
|
|
5
5
|
const inputSchema = z.object({
|
|
6
6
|
pattern: z.string(),
|
|
7
7
|
path: z.string().optional(),
|
|
@@ -35,9 +35,7 @@ export const GlobTool = {
|
|
|
35
35
|
}
|
|
36
36
|
matches.sort();
|
|
37
37
|
return {
|
|
38
|
-
output: matches.length
|
|
39
|
-
? matches.join("\n")
|
|
40
|
-
: "No files matched the pattern.",
|
|
38
|
+
output: matches.length ? matches.join("\n") : "No files matched the pattern.",
|
|
41
39
|
isError: false,
|
|
42
40
|
};
|
|
43
41
|
}
|
|
@@ -49,9 +47,7 @@ export const GlobTool = {
|
|
|
49
47
|
.slice(0, MAX_RESULTS)
|
|
50
48
|
.sort();
|
|
51
49
|
return {
|
|
52
|
-
output: matched.length
|
|
53
|
-
? matched.join("\n")
|
|
54
|
-
: "No files matched the pattern.",
|
|
50
|
+
output: matched.length ? matched.join("\n") : "No files matched the pattern.",
|
|
55
51
|
isError: false,
|
|
56
52
|
};
|
|
57
53
|
}
|
|
@@ -20,8 +20,8 @@ declare const inputSchema: z.ZodObject<{
|
|
|
20
20
|
path?: string | undefined;
|
|
21
21
|
type?: string | undefined;
|
|
22
22
|
glob?: string | undefined;
|
|
23
|
-
context?: number | undefined;
|
|
24
23
|
offset?: number | undefined;
|
|
24
|
+
context?: number | undefined;
|
|
25
25
|
output_mode?: "content" | "files_with_matches" | "count" | undefined;
|
|
26
26
|
head_limit?: number | undefined;
|
|
27
27
|
multiline?: boolean | undefined;
|
|
@@ -35,8 +35,8 @@ declare const inputSchema: z.ZodObject<{
|
|
|
35
35
|
path?: string | undefined;
|
|
36
36
|
type?: string | undefined;
|
|
37
37
|
glob?: string | undefined;
|
|
38
|
-
context?: number | undefined;
|
|
39
38
|
offset?: number | undefined;
|
|
39
|
+
context?: number | undefined;
|
|
40
40
|
output_mode?: "content" | "files_with_matches" | "count" | undefined;
|
|
41
41
|
head_limit?: number | undefined;
|
|
42
42
|
multiline?: boolean | undefined;
|