@zhijiewang/openharness 2.1.0 → 2.3.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/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 +98 -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 +30 -22
- package/dist/query/tools.js +15 -12
- package/dist/query/types.d.ts +1 -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 +300 -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 +143 -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 +35 -15
- 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.d.ts +2 -2
- 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 +11 -11
- 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.d.ts +4 -4
- 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,14 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
2
|
import { Box, Text } from "ink";
|
|
4
|
-
import
|
|
5
|
-
import Markdown from "./Markdown.js";
|
|
3
|
+
import React from "react";
|
|
6
4
|
import { useTheme } from "../utils/theme.js";
|
|
5
|
+
import Markdown from "./Markdown.js";
|
|
6
|
+
import ToolCallDisplay from "./ToolCallDisplay.js";
|
|
7
7
|
export default function Messages({ messages, toolCalls }) {
|
|
8
8
|
const theme = useTheme();
|
|
9
9
|
return (_jsx(Box, { flexDirection: "column", children: messages.map((msg, i) => {
|
|
10
10
|
const showDivider = msg.role === "user" && i > 0;
|
|
11
|
-
return (_jsxs(React.Fragment, { children: [showDivider &&
|
|
11
|
+
return (_jsxs(React.Fragment, { children: [showDivider && _jsx(Text, { color: theme.dim, children: "─".repeat(60) }), _jsx(MessageRow, { message: msg, toolCalls: toolCalls, theme: theme })] }, msg.uuid));
|
|
12
12
|
}) }));
|
|
13
13
|
}
|
|
14
14
|
function MessageRow({ message, toolCalls, theme, }) {
|
|
@@ -4,6 +4,6 @@ type Props = {
|
|
|
4
4
|
riskLevel: string;
|
|
5
5
|
onResolve: (allowed: boolean) => void;
|
|
6
6
|
};
|
|
7
|
-
export default function PermissionPrompt({ toolName, description, riskLevel, onResolve
|
|
7
|
+
export default function PermissionPrompt({ toolName, description, riskLevel, onResolve }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=PermissionPrompt.d.ts.map
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
import { Box, Text, useInput } from "ink";
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import { extractDiffInfo } from "../renderer/diff.js";
|
|
4
9
|
import { useTheme } from "../utils/theme.js";
|
|
5
10
|
import { summarizeToolArgs } from "../utils/tool-summary.js";
|
|
6
|
-
import { extractDiffInfo } from "../renderer/diff.js";
|
|
7
11
|
import DiffView from "./DiffView.js";
|
|
8
|
-
import { writeFileSync, unlinkSync } from "node:fs";
|
|
9
|
-
import { execSync } from "node:child_process";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
12
|
// extractFileInfo moved to shared renderer/diff.ts as extractDiffInfo
|
|
13
|
-
export default function PermissionPrompt({ toolName, description, riskLevel, onResolve
|
|
13
|
+
export default function PermissionPrompt({ toolName, description, riskLevel, onResolve }) {
|
|
14
14
|
const theme = useTheme();
|
|
15
15
|
const [showDiff, setShowDiff] = useState(false);
|
|
16
16
|
const fileInfo = extractDiffInfo(toolName, description);
|
|
@@ -22,27 +22,25 @@ export default function PermissionPrompt({ toolName, description, riskLevel, onR
|
|
|
22
22
|
if (key === "n")
|
|
23
23
|
onResolve(false);
|
|
24
24
|
if (key === "d" && hasDiff)
|
|
25
|
-
setShowDiff(prev => !prev);
|
|
25
|
+
setShowDiff((prev) => !prev);
|
|
26
26
|
if (key === "e" && hasDiff && fileInfo?.newContent) {
|
|
27
27
|
// Open new content in $EDITOR
|
|
28
|
-
const editor = process.env.EDITOR || process.env.VISUAL ||
|
|
28
|
+
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
29
29
|
const tmpFile = join(tmpdir(), `oh-edit-${Date.now()}.tmp`);
|
|
30
30
|
try {
|
|
31
31
|
writeFileSync(tmpFile, fileInfo.newContent);
|
|
32
|
-
execSync(`${editor} "${tmpFile}"`, { stdio:
|
|
32
|
+
execSync(`${editor} "${tmpFile}"`, { stdio: "inherit" });
|
|
33
33
|
// User may have modified — we can't easily integrate the edit back into the tool call
|
|
34
34
|
// Just show a message
|
|
35
35
|
unlinkSync(tmpFile);
|
|
36
36
|
}
|
|
37
|
-
catch {
|
|
37
|
+
catch {
|
|
38
|
+
/* ignore */
|
|
39
|
+
}
|
|
38
40
|
}
|
|
39
41
|
});
|
|
40
|
-
const borderColor = riskLevel === "high"
|
|
41
|
-
? theme.error
|
|
42
|
-
: riskLevel === "medium"
|
|
43
|
-
? theme.warning
|
|
44
|
-
: theme.success;
|
|
42
|
+
const borderColor = riskLevel === "high" ? theme.error : riskLevel === "medium" ? theme.warning : theme.success;
|
|
45
43
|
const suggestion = summarizeToolArgs(toolName, description);
|
|
46
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 2, paddingY: 0, marginY: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: borderColor, bold: true, children: "⚠ " }), _jsx(Text, { bold: true, children: toolName }), _jsxs(Text, { color: theme.dim, children: [" ", riskLevel, " risk"] })] }), suggestion && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: theme.dim, children: suggestion }) })), !showDiff && (_jsx(Box, { marginLeft: 2, marginY: 0, children: _jsx(Text, { children: description.slice(0, 300) }) })), showDiff && hasDiff && (_jsx(Box, { marginLeft: 2, marginY: 0, children: _jsx(DiffView, { oldContent: fileInfo.oldContent, newContent: fileInfo.newContent, filePath: fileInfo.filePath ??
|
|
44
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 2, paddingY: 0, marginY: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: borderColor, bold: true, children: "⚠ " }), _jsx(Text, { bold: true, children: toolName }), _jsxs(Text, { color: theme.dim, children: [" ", riskLevel, " risk"] })] }), suggestion && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: theme.dim, children: suggestion }) })), !showDiff && (_jsx(Box, { marginLeft: 2, marginY: 0, children: _jsx(Text, { children: description.slice(0, 300) }) })), showDiff && hasDiff && (_jsx(Box, { marginLeft: 2, marginY: 0, children: _jsx(DiffView, { oldContent: fileInfo.oldContent, newContent: fileInfo.newContent, filePath: fileInfo.filePath ?? "" }) })), _jsx(Box, { marginTop: 0, children: _jsxs(Text, { children: ["[", _jsx(Text, { color: theme.success, bold: true, children: "Y" }), "]es [", _jsx(Text, { color: theme.error, bold: true, children: "N" }), "]o", hasDiff && (_jsxs(_Fragment, { children: [" ", "[", _jsx(Text, { color: "cyan", bold: true, children: "D" }), "]iff [", _jsx(Text, { color: "yellow", bold: true, children: "E" }), "]dit"] }))] }) })] }));
|
|
47
45
|
}
|
|
48
46
|
//# sourceMappingURL=PermissionPrompt.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Message } from "../types/message.js";
|
|
2
1
|
import type { Provider } from "../providers/base.js";
|
|
3
2
|
import type { Tools } from "../Tool.js";
|
|
3
|
+
import type { Message } from "../types/message.js";
|
|
4
4
|
import type { PermissionMode } from "../types/permissions.js";
|
|
5
5
|
type REPLProps = {
|
|
6
6
|
provider: Provider;
|
package/dist/components/REPL.js
CHANGED
|
@@ -1,44 +1,46 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useCallback, useRef, useEffect } from "react";
|
|
3
|
-
import { Box, Text, Static, useApp, useInput } from "ink";
|
|
4
|
-
import { createAssistantMessage, createUserMessage, createMessage, createInfoMessage } from "../types/message.js";
|
|
5
|
-
import { query } from "../query/index.js";
|
|
6
2
|
import { homedir } from "node:os";
|
|
7
3
|
import { join } from "node:path";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
4
|
+
import { Box, Static, Text, useApp, useInput } from "ink";
|
|
5
|
+
import TextInputComponent from "ink-text-input";
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
10
7
|
import { processSlashCommand } from "../commands/index.js";
|
|
11
|
-
import {
|
|
8
|
+
import { cybergotchiEvents } from "../cybergotchi/events.js";
|
|
12
9
|
import { autoCommitAIEdits, isGitRepo } from "../git/index.js";
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
10
|
+
import { estimateMessageTokens, getContextWarning } from "../harness/context-warning.js";
|
|
11
|
+
import { CostTracker, estimateCost } from "../harness/cost.js";
|
|
12
|
+
import { createSession, loadSession, saveSession } from "../harness/session.js";
|
|
13
|
+
import { query } from "../query/index.js";
|
|
14
|
+
import { createAssistantMessage, createInfoMessage, createMessage, createUserMessage } from "../types/message.js";
|
|
17
15
|
import CybergotchiPanelConnected from "./CybergotchiPanelConnected.js";
|
|
18
16
|
import CybergotchiSetup from "./CybergotchiSetup.js";
|
|
19
|
-
import
|
|
17
|
+
import PermissionPrompt from "./PermissionPrompt.js";
|
|
18
|
+
import Spinner from "./Spinner.js";
|
|
19
|
+
import TextInput from "./TextInput.js";
|
|
20
20
|
/** Minimum terminal width to show the companion */
|
|
21
21
|
const MIN_WIDTH_FOR_COMPANION = 40;
|
|
22
22
|
function getTerminalWidth() {
|
|
23
23
|
return process.stdout.columns ?? 80;
|
|
24
24
|
}
|
|
25
25
|
import { loadCompanionConfig, saveCompanionConfig } from "../cybergotchi/config.js";
|
|
26
|
+
import { createKeybindingMatcher } from "../harness/keybindings.js";
|
|
26
27
|
import { detectMemories, saveMemory } from "../harness/memory.js";
|
|
27
28
|
import { resolveMcpMention } from "../mcp/loader.js";
|
|
28
|
-
import { createKeybindingMatcher } from "../harness/keybindings.js";
|
|
29
29
|
export default function REPL({ provider, tools, permissionMode, systemPrompt, model, initialMessages, resumeSessionId, }) {
|
|
30
30
|
const { exit } = useApp();
|
|
31
31
|
// Session and cost tracking
|
|
32
32
|
const sessionRef = useRef(resumeSessionId
|
|
33
|
-
? (() => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
? (() => {
|
|
34
|
+
try {
|
|
35
|
+
return loadSession(resumeSessionId);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return createSession(provider.name, model ?? "");
|
|
39
|
+
}
|
|
40
|
+
})()
|
|
39
41
|
: createSession(provider.name, model ?? ""));
|
|
40
42
|
const costRef = useRef(new CostTracker());
|
|
41
|
-
const [
|
|
43
|
+
const [_totalCost, setTotalCost] = useState(0);
|
|
42
44
|
const [sessionId] = useState(sessionRef.current.id);
|
|
43
45
|
const [messages, setMessages] = useState(resumeSessionId ? sessionRef.current.messages : (initialMessages ?? []));
|
|
44
46
|
const [loading, setLoading] = useState(false);
|
|
@@ -73,7 +75,9 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
73
75
|
try {
|
|
74
76
|
saveSession(sessionRef.current);
|
|
75
77
|
}
|
|
76
|
-
catch {
|
|
78
|
+
catch {
|
|
79
|
+
/* ignore */
|
|
80
|
+
}
|
|
77
81
|
};
|
|
78
82
|
}, [messages]);
|
|
79
83
|
// Long-wait detection: emit cybergotchi event after 30s of loading
|
|
@@ -81,7 +85,7 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
81
85
|
useEffect(() => {
|
|
82
86
|
if (loading) {
|
|
83
87
|
loadingTimerRef.current = setTimeout(() => {
|
|
84
|
-
cybergotchiEvents.emit(
|
|
88
|
+
cybergotchiEvents.emit("cybergotchi", { type: "longWait" });
|
|
85
89
|
}, 30_000);
|
|
86
90
|
}
|
|
87
91
|
else {
|
|
@@ -114,7 +118,7 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
114
118
|
});
|
|
115
119
|
// Queue prompt submissions — useEffect picks them up for async processing
|
|
116
120
|
const pendingPromptRef = useRef(null);
|
|
117
|
-
const [
|
|
121
|
+
const [_submitCount, setSubmitCount] = useState(0);
|
|
118
122
|
const messagesRef = useRef(messages);
|
|
119
123
|
messagesRef.current = messages;
|
|
120
124
|
useEffect(() => {
|
|
@@ -146,10 +150,14 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
146
150
|
const askUserQuestion = (question, options) => {
|
|
147
151
|
return new Promise((resolve) => {
|
|
148
152
|
setQuestionAnswer("");
|
|
149
|
-
setPendingQuestion({
|
|
153
|
+
setPendingQuestion({
|
|
154
|
+
question,
|
|
155
|
+
options,
|
|
156
|
+
resolve: (answer) => {
|
|
150
157
|
setPendingQuestion(null);
|
|
151
158
|
resolve(answer);
|
|
152
|
-
}
|
|
159
|
+
},
|
|
160
|
+
});
|
|
153
161
|
});
|
|
154
162
|
};
|
|
155
163
|
const config = {
|
|
@@ -165,7 +173,7 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
165
173
|
// Resolve @mentions to MCP resource content
|
|
166
174
|
let resolvedPrompt = prompt;
|
|
167
175
|
const mentionPattern = /@(\w[\w.-]*)/g;
|
|
168
|
-
const mentions = [...prompt.matchAll(mentionPattern)].map(m => m[1]);
|
|
176
|
+
const mentions = [...prompt.matchAll(mentionPattern)].map((m) => m[1]);
|
|
169
177
|
const companionName = cybergotchiConfigRef.current?.soul?.name?.toLowerCase();
|
|
170
178
|
for (const mention of mentions) {
|
|
171
179
|
if (companionName && mention.toLowerCase() === companionName)
|
|
@@ -176,7 +184,9 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
176
184
|
resolvedPrompt += `\n\n[Resource @${mention}]:\n${content.slice(0, 5000)}`;
|
|
177
185
|
}
|
|
178
186
|
}
|
|
179
|
-
catch {
|
|
187
|
+
catch {
|
|
188
|
+
/* ignore */
|
|
189
|
+
}
|
|
180
190
|
}
|
|
181
191
|
let accumulated = "";
|
|
182
192
|
try {
|
|
@@ -188,23 +198,24 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
188
198
|
case "thinking_delta":
|
|
189
199
|
setThinkingText((prev) => prev + event.content);
|
|
190
200
|
break;
|
|
191
|
-
case "text_delta":
|
|
201
|
+
case "text_delta": {
|
|
192
202
|
accumulated += event.content;
|
|
193
203
|
// Move completed lines to Static (messages array) — keep only the current partial line in live area
|
|
194
|
-
const deltaLines = accumulated.split(
|
|
204
|
+
const deltaLines = accumulated.split("\n");
|
|
195
205
|
if (deltaLines.length > 1) {
|
|
196
|
-
const completedText = deltaLines.slice(0, -1).join(
|
|
206
|
+
const completedText = deltaLines.slice(0, -1).join("\n");
|
|
197
207
|
setMessages((prev) => {
|
|
198
208
|
const last = prev[prev.length - 1];
|
|
199
209
|
if (last?.meta?.isStreaming) {
|
|
200
|
-
return [...prev.slice(0, -1), { ...last, content: last.content + completedText
|
|
210
|
+
return [...prev.slice(0, -1), { ...last, content: `${last.content + completedText}\n` }];
|
|
201
211
|
}
|
|
202
|
-
return [...prev, createMessage(
|
|
212
|
+
return [...prev, createMessage("assistant", `${completedText}\n`, { meta: { isStreaming: true } })];
|
|
203
213
|
});
|
|
204
214
|
accumulated = deltaLines[deltaLines.length - 1];
|
|
205
215
|
}
|
|
206
216
|
setStreamingText(accumulated);
|
|
207
217
|
break;
|
|
218
|
+
}
|
|
208
219
|
case "tool_call_start":
|
|
209
220
|
setToolCalls((prev) => {
|
|
210
221
|
const next = new Map(prev);
|
|
@@ -235,16 +246,16 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
235
246
|
const next = new Map(prev);
|
|
236
247
|
const existing = next.get(event.callId);
|
|
237
248
|
if (existing) {
|
|
238
|
-
const lines =
|
|
249
|
+
const lines = existing.liveOutput ?? [];
|
|
239
250
|
// Split chunk by newlines and append
|
|
240
251
|
const chunks = event.chunk.split("\n");
|
|
241
252
|
const merged = [...lines];
|
|
242
253
|
if (merged.length > 0 && !event.chunk.startsWith("\n")) {
|
|
243
254
|
merged[merged.length - 1] = (merged[merged.length - 1] ?? "") + chunks[0];
|
|
244
|
-
merged.push(...chunks.slice(1).filter(c => c !== ""));
|
|
255
|
+
merged.push(...chunks.slice(1).filter((c) => c !== ""));
|
|
245
256
|
}
|
|
246
257
|
else {
|
|
247
|
-
merged.push(...chunks.filter(c => c !== ""));
|
|
258
|
+
merged.push(...chunks.filter((c) => c !== ""));
|
|
248
259
|
}
|
|
249
260
|
next.set(event.callId, { ...existing, liveOutput: merged });
|
|
250
261
|
}
|
|
@@ -264,8 +275,8 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
264
275
|
return next;
|
|
265
276
|
});
|
|
266
277
|
// Emit cybergotchi event
|
|
267
|
-
cybergotchiEvents.emit(
|
|
268
|
-
type: event.isError ?
|
|
278
|
+
cybergotchiEvents.emit("cybergotchi", {
|
|
279
|
+
type: event.isError ? "toolError" : "toolSuccess",
|
|
269
280
|
toolName,
|
|
270
281
|
});
|
|
271
282
|
// Git auto-commit for write tools
|
|
@@ -278,7 +289,7 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
278
289
|
const hash = autoCommitAIEdits(toolName, files, process.cwd());
|
|
279
290
|
if (hash) {
|
|
280
291
|
setMessages((prev) => [...prev, createInfoMessage(`git: committed ${hash}`)]);
|
|
281
|
-
cybergotchiEvents.emit(
|
|
292
|
+
cybergotchiEvents.emit("cybergotchi", { type: "commit" });
|
|
282
293
|
}
|
|
283
294
|
}
|
|
284
295
|
}
|
|
@@ -322,7 +333,9 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
322
333
|
try {
|
|
323
334
|
saveSession(sessionRef.current);
|
|
324
335
|
}
|
|
325
|
-
catch {
|
|
336
|
+
catch {
|
|
337
|
+
/* ignore */
|
|
338
|
+
}
|
|
326
339
|
break;
|
|
327
340
|
}
|
|
328
341
|
}
|
|
@@ -343,17 +356,19 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
343
356
|
const msgCount = messagesRef.current.length;
|
|
344
357
|
if (msgCount > 0 && msgCount % 10 === 0) {
|
|
345
358
|
detectMemories(provider, messagesRef.current.slice(-10), model)
|
|
346
|
-
.then(memories => {
|
|
359
|
+
.then((memories) => {
|
|
347
360
|
for (const m of memories) {
|
|
348
361
|
saveMemory(m.name, m.type, m.description, m.content);
|
|
349
362
|
}
|
|
350
363
|
})
|
|
351
|
-
.catch(() => {
|
|
364
|
+
.catch(() => {
|
|
365
|
+
/* ignore memory detection errors */
|
|
366
|
+
});
|
|
352
367
|
}
|
|
353
368
|
}
|
|
354
369
|
};
|
|
355
370
|
run();
|
|
356
|
-
}, [
|
|
371
|
+
}, [loading, provider, tools, systemPrompt, permissionMode, currentModel, model]);
|
|
357
372
|
const handleSubmit = useCallback((input) => {
|
|
358
373
|
const trimmed = input.trim();
|
|
359
374
|
if (trimmed === "exit" || trimmed === "quit" || trimmed === "/exit" || trimmed === "/quit") {
|
|
@@ -367,14 +382,14 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
367
382
|
const name = gotchiCfg.soul.name.toLowerCase();
|
|
368
383
|
const lower = trimmed.toLowerCase();
|
|
369
384
|
if (lower.startsWith(`@${name}`) || lower.startsWith(`${name},`) || lower.startsWith(`${name} `)) {
|
|
370
|
-
cybergotchiEvents.emit(
|
|
385
|
+
cybergotchiEvents.emit("cybergotchi", { type: "userAddressed", text: trimmed });
|
|
371
386
|
return;
|
|
372
387
|
}
|
|
373
388
|
}
|
|
374
389
|
}
|
|
375
390
|
// Handle /vim toggle directly
|
|
376
391
|
if (trimmed === "/vim") {
|
|
377
|
-
setVimMode(v => !v);
|
|
392
|
+
setVimMode((v) => !v);
|
|
378
393
|
setMessages((prev) => [...prev, createInfoMessage(vimMode ? "Vim mode OFF" : "Vim mode ON")]);
|
|
379
394
|
return;
|
|
380
395
|
}
|
|
@@ -403,7 +418,9 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
403
418
|
sessionRef.current = sess;
|
|
404
419
|
setMessages(sess.messages);
|
|
405
420
|
}
|
|
406
|
-
catch {
|
|
421
|
+
catch {
|
|
422
|
+
/* already shown error in output */
|
|
423
|
+
}
|
|
407
424
|
}
|
|
408
425
|
if (result.clearMessages) {
|
|
409
426
|
setMessages([]);
|
|
@@ -435,7 +452,7 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
435
452
|
setMessages((prev) => [...prev, userMsg]);
|
|
436
453
|
pendingPromptRef.current = input;
|
|
437
454
|
setSubmitCount((c) => c + 1);
|
|
438
|
-
}, [exit, currentModel, permissionMode, sessionId]);
|
|
455
|
+
}, [exit, currentModel, permissionMode, sessionId, vimMode, provider.name]);
|
|
439
456
|
// Process pending keybinding actions
|
|
440
457
|
useEffect(() => {
|
|
441
458
|
const action = pendingKeybindAction.current;
|
|
@@ -446,7 +463,13 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
446
463
|
});
|
|
447
464
|
// Show cybergotchi setup if needed (first run or /cybergotchi reset)
|
|
448
465
|
if (cybergotchiConfigRef.current === null || showCybergotchiSetup) {
|
|
449
|
-
return (_jsx(CybergotchiSetup, { onComplete: () => {
|
|
466
|
+
return (_jsx(CybergotchiSetup, { onComplete: () => {
|
|
467
|
+
cybergotchiConfigRef.current = loadCompanionConfig();
|
|
468
|
+
setShowCybergotchiSetup(false);
|
|
469
|
+
}, onSkip: () => {
|
|
470
|
+
cybergotchiConfigRef.current = loadCompanionConfig();
|
|
471
|
+
setShowCybergotchiSetup(false);
|
|
472
|
+
} }));
|
|
450
473
|
}
|
|
451
474
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: messages, children: (msg, i) => {
|
|
452
475
|
const showDivider = msg.role === "user" && i > 0;
|
|
@@ -460,8 +483,10 @@ export default function REPL({ provider, tools, permissionMode, systemPrompt, mo
|
|
|
460
483
|
return (_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [" ", msg.content] }) }, msg.uuid));
|
|
461
484
|
}
|
|
462
485
|
return _jsx(Box, {}, msg.uuid);
|
|
463
|
-
} }), _jsxs(Box, { flexDirection: "column", children: [thinkingText && (_jsx(Box, { marginY: 0, children: _jsxs(Text, { dimColor: true, children: ["💭 ", thinkingText.split(
|
|
464
|
-
|
|
486
|
+
} }), _jsxs(Box, { flexDirection: "column", children: [thinkingText && (_jsx(Box, { marginY: 0, children: _jsxs(Text, { dimColor: true, children: ["💭 ", thinkingText.split("\n").slice(-3).join("\n")] }) })), loading && streamingText && (_jsxs(Box, { marginY: 0, children: [_jsx(Text, { color: "magenta", bold: true, children: "◆ " }), _jsx(Text, { children: streamingText })] })), loading && !streamingText && _jsx(Spinner, { model: currentModel, tokens: costRef.current.totalOutputTokens }), error && (_jsx(Box, { marginY: 1, borderStyle: "round", borderColor: "red", paddingX: 1, children: _jsxs(Text, { color: "red", children: ["✗ ", error] }) })), pendingPermission && (_jsx(PermissionPrompt, { toolName: pendingPermission.toolName, description: pendingPermission.description, riskLevel: pendingPermission.riskLevel, onResolve: pendingPermission.resolve })), pendingQuestion && (_jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [_jsxs(Text, { color: "yellow", children: ["\u2753 ", pendingQuestion.question] }), pendingQuestion.options && pendingQuestion.options.length > 0 && (_jsx(Box, { flexDirection: "column", children: pendingQuestion.options.map((o, i) => (_jsxs(Text, { dimColor: true, children: [" ", i + 1, ". ", o] }, i))) })), _jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: "❯ " }), _jsx(TextInputComponent, { value: questionAnswer, onChange: setQuestionAnswer, onSubmit: (val) => {
|
|
487
|
+
if (val.trim())
|
|
488
|
+
pendingQuestion.resolve(val.trim());
|
|
489
|
+
}, focus: true })] })] })), _jsxs(Box, { flexDirection: "row", marginTop: 1, children: [_jsx(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: _jsx(TextInput, { onSubmit: handleSubmit, disabled: loading || !!pendingQuestion, vimMode: vimMode }) }), getTerminalWidth() >= MIN_WIDTH_FOR_COMPANION && (_jsx(Box, { flexShrink: 0, width: 16, children: _jsx(CybergotchiPanelConnected, { paused: loading }) }))] }), _jsxs(Text, { dimColor: true, children: ["exit to quit", loading ? " | Ctrl+C to interrupt" : "", cybergotchiConfigRef.current?.soul?.name ? ` | @${cybergotchiConfigRef.current.soul.name} to chat` : ""] }), (() => {
|
|
465
490
|
const warning = getContextWarning(estimateMessageTokens(messages), currentModel);
|
|
466
491
|
if (!warning)
|
|
467
492
|
return null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from "react";
|
|
3
2
|
import { Box, Text } from "ink";
|
|
4
|
-
import {
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
5
4
|
import { formatTokenCount } from "../utils/format.js";
|
|
5
|
+
import { useTheme } from "../utils/theme.js";
|
|
6
6
|
export default function Spinner({ model, tokens }) {
|
|
7
7
|
const theme = useTheme();
|
|
8
8
|
const [elapsed, setElapsed] = useState(0);
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useCallback } from "react";
|
|
3
2
|
import { Box, Text, useInput } from "ink";
|
|
4
3
|
import InkTextInput from "ink-text-input";
|
|
5
|
-
import {
|
|
4
|
+
import { useCallback, useState } from "react";
|
|
6
5
|
import { getCommandNames } from "../commands/index.js";
|
|
6
|
+
import { useTheme } from "../utils/theme.js";
|
|
7
7
|
export default function TextInput({ onSubmit, disabled, vimMode = false }) {
|
|
8
8
|
const theme = useTheme();
|
|
9
9
|
const [value, setValue] = useState("");
|
|
10
10
|
const [history, setHistory] = useState([]);
|
|
11
11
|
const [historyIndex, setHistoryIndex] = useState(-1);
|
|
12
|
-
const [vim, setVim] = useState(vimMode ?
|
|
12
|
+
const [vim, setVim] = useState(vimMode ? "normal" : "insert");
|
|
13
13
|
const [autocomplete, setAutocomplete] = useState([]);
|
|
14
14
|
const [acIndex, setAcIndex] = useState(-1);
|
|
15
15
|
// Autocomplete for slash commands
|
|
16
16
|
const updateAutocomplete = useCallback((val) => {
|
|
17
|
-
if (val.startsWith(
|
|
17
|
+
if (val.startsWith("/") && val.length > 1 && !val.includes(" ")) {
|
|
18
18
|
const prefix = val.slice(1).toLowerCase();
|
|
19
|
-
const matches = getCommandNames()
|
|
19
|
+
const matches = getCommandNames()
|
|
20
|
+
.filter((n) => n.startsWith(prefix))
|
|
21
|
+
.slice(0, 5);
|
|
20
22
|
setAutocomplete(matches);
|
|
21
23
|
setAcIndex(-1);
|
|
22
24
|
}
|
|
@@ -27,41 +29,41 @@ export default function TextInput({ onSubmit, disabled, vimMode = false }) {
|
|
|
27
29
|
}, []);
|
|
28
30
|
useInput((input, key) => {
|
|
29
31
|
// Vim mode handling
|
|
30
|
-
if (vimMode && vim ===
|
|
31
|
-
if (input ===
|
|
32
|
-
setVim(
|
|
32
|
+
if (vimMode && vim === "normal") {
|
|
33
|
+
if (input === "i") {
|
|
34
|
+
setVim("insert");
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
|
-
if (input ===
|
|
36
|
-
setVim(
|
|
37
|
+
if (input === "a") {
|
|
38
|
+
setVim("insert");
|
|
37
39
|
return;
|
|
38
40
|
}
|
|
39
|
-
if (input ===
|
|
40
|
-
setVim(
|
|
41
|
+
if (input === "A") {
|
|
42
|
+
setVim("insert");
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
if (input ===
|
|
45
|
+
if (input === "0") {
|
|
44
46
|
return;
|
|
45
47
|
} // cursor to start — not easily doable with InkTextInput
|
|
46
|
-
if (input ===
|
|
48
|
+
if (input === "$") {
|
|
47
49
|
return;
|
|
48
50
|
} // cursor to end
|
|
49
|
-
if (input ===
|
|
50
|
-
setValue(v => v.slice(0, -1));
|
|
51
|
+
if (input === "x") {
|
|
52
|
+
setValue((v) => v.slice(0, -1));
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
53
|
-
if (input ===
|
|
54
|
-
setValue(
|
|
55
|
-
if (input ===
|
|
56
|
-
setVim(
|
|
55
|
+
if (input === "D" || input === "C") {
|
|
56
|
+
setValue("");
|
|
57
|
+
if (input === "C")
|
|
58
|
+
setVim("insert");
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
|
-
if (input ===
|
|
60
|
-
setValue(
|
|
61
|
+
if (input === "u") {
|
|
62
|
+
setValue("");
|
|
61
63
|
return;
|
|
62
64
|
} // undo = clear
|
|
63
65
|
// History navigation in normal mode
|
|
64
|
-
if (key.upArrow || input ===
|
|
66
|
+
if (key.upArrow || input === "k") {
|
|
65
67
|
if (history.length > 0) {
|
|
66
68
|
const next = Math.min(historyIndex + 1, history.length - 1);
|
|
67
69
|
setHistoryIndex(next);
|
|
@@ -69,7 +71,7 @@ export default function TextInput({ onSubmit, disabled, vimMode = false }) {
|
|
|
69
71
|
}
|
|
70
72
|
return;
|
|
71
73
|
}
|
|
72
|
-
if (key.downArrow || input ===
|
|
74
|
+
if (key.downArrow || input === "j") {
|
|
73
75
|
if (historyIndex <= 0) {
|
|
74
76
|
setHistoryIndex(-1);
|
|
75
77
|
setValue("");
|
|
@@ -86,7 +88,7 @@ export default function TextInput({ onSubmit, disabled, vimMode = false }) {
|
|
|
86
88
|
// Escape → normal mode (vim) or clear autocomplete
|
|
87
89
|
if (key.escape) {
|
|
88
90
|
if (vimMode) {
|
|
89
|
-
setVim(
|
|
91
|
+
setVim("normal");
|
|
90
92
|
return;
|
|
91
93
|
}
|
|
92
94
|
setAutocomplete([]);
|
|
@@ -134,11 +136,15 @@ export default function TextInput({ onSubmit, disabled, vimMode = false }) {
|
|
|
134
136
|
setAutocomplete([]);
|
|
135
137
|
setAcIndex(-1);
|
|
136
138
|
if (vimMode)
|
|
137
|
-
setVim(
|
|
139
|
+
setVim("normal");
|
|
138
140
|
onSubmit(submitted);
|
|
139
141
|
}, [onSubmit, disabled, vimMode]);
|
|
140
|
-
const placeholder = disabled
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
const placeholder = disabled
|
|
143
|
+
? "Waiting..."
|
|
144
|
+
: vimMode && vim === "normal"
|
|
145
|
+
? "-- NORMAL -- (i to insert)"
|
|
146
|
+
: "Ask anything...";
|
|
147
|
+
const modeIndicator = vimMode ? (vim === "normal" ? "[N]" : "[I]") : null;
|
|
148
|
+
return (_jsxs(Box, { flexDirection: "column", children: [autocomplete.length > 0 && (_jsx(Box, { flexDirection: "row", gap: 1, children: autocomplete.map((cmd, i) => (_jsxs(Text, { color: i === acIndex ? "cyan" : undefined, dimColor: i !== acIndex, children: ["/", cmd] }, cmd))) })), _jsxs(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: theme.border, paddingX: 0, children: [modeIndicator && (_jsxs(Text, { color: vim === "normal" ? "blue" : "green", bold: true, children: [modeIndicator, " "] })), _jsx(Text, { color: theme.user, bold: true, children: "❯ " }), _jsx(InkTextInput, { value: value, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder })] })] }));
|
|
143
149
|
}
|
|
144
150
|
//# sourceMappingURL=TextInput.js.map
|
|
@@ -5,16 +5,14 @@ const MAX_LIVE_LINES = 10;
|
|
|
5
5
|
export default function ToolCallDisplay({ toolCall }) {
|
|
6
6
|
const { toolName, status, output, args, liveOutput } = toolCall;
|
|
7
7
|
const liveLines = liveOutput ?? [];
|
|
8
|
-
const overflow = liveLines.length > MAX_LIVE_LINES
|
|
9
|
-
? liveLines.length - MAX_LIVE_LINES
|
|
10
|
-
: 0;
|
|
8
|
+
const overflow = liveLines.length > MAX_LIVE_LINES ? liveLines.length - MAX_LIVE_LINES : 0;
|
|
11
9
|
const visibleLive = overflow > 0 ? liveLines.slice(-MAX_LIVE_LINES) : liveLines;
|
|
12
|
-
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginY: 0, children: [_jsxs(Box, { children: [status === "running" ? (_jsxs(Text, { color: "yellow", children: [_jsx(InkSpinner, { type: "dots" }), " "] })) : status === "error" ? (_jsx(Text, { color: "red", children: "✗ " })) : (_jsx(Text, { color: "green", children: "✓ " })), _jsx(Text, { color: "yellow", bold: true, children: toolName }), status === "running" && args && (_jsxs(Text, { dimColor: true, children: [" ", args.slice(0, 60), args.length > 60 ? "..." : ""] }))] }), status === "running" && liveLines.length > 0 && (_jsxs(Box, { flexDirection: "column", marginLeft: 4, children: [overflow > 0 &&
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginY: 0, children: [_jsxs(Box, { children: [status === "running" ? (_jsxs(Text, { color: "yellow", children: [_jsx(InkSpinner, { type: "dots" }), " "] })) : status === "error" ? (_jsx(Text, { color: "red", children: "✗ " })) : (_jsx(Text, { color: "green", children: "✓ " })), _jsx(Text, { color: "yellow", bold: true, children: toolName }), status === "running" && args && (_jsxs(Text, { dimColor: true, children: [" ", args.slice(0, 60), args.length > 60 ? "..." : ""] }))] }), status === "running" && liveLines.length > 0 && (_jsxs(Box, { flexDirection: "column", marginLeft: 4, children: [overflow > 0 && _jsx(Text, { dimColor: true, children: `... (${overflow} earlier lines)` }), visibleLive.map((line, i) => (_jsx(Text, { dimColor: true, children: line }, i)))] })), output != null && status !== "running" && (_jsx(Box, { marginLeft: 4, children: _jsx(Text, { color: status === "error" ? "red" : "gray", dimColor: true, children: truncate(output, 3) }) }))] }));
|
|
13
11
|
}
|
|
14
12
|
function truncate(text, maxLines) {
|
|
15
13
|
const lines = text.split("\n");
|
|
16
14
|
if (lines.length <= maxLines)
|
|
17
15
|
return text;
|
|
18
|
-
return lines.slice(0, maxLines).join("\n")
|
|
16
|
+
return `${lines.slice(0, maxLines).join("\n")}\n... (${lines.length} lines)`;
|
|
19
17
|
}
|
|
20
18
|
//# sourceMappingURL=ToolCallDisplay.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { hostname, userInfo } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
const SALT =
|
|
5
|
-
const STAT_KEYS = [
|
|
1
|
+
import { hostname, userInfo } from "node:os";
|
|
2
|
+
import { SPECIES } from "./species.js";
|
|
3
|
+
import { RARITY_TIERS } from "./types.js";
|
|
4
|
+
const SALT = "openharness-2026";
|
|
5
|
+
const STAT_KEYS = ["DEBUGGING", "PATIENCE", "CHAOS", "WISDOM", "SNARK"];
|
|
6
6
|
/** FNV-1a 32-bit hash */
|
|
7
7
|
function fnv1a(str) {
|
|
8
8
|
let hash = 0x811c9dc5;
|
|
@@ -16,7 +16,7 @@ function fnv1a(str) {
|
|
|
16
16
|
function mulberry32(seed) {
|
|
17
17
|
let state = seed | 0;
|
|
18
18
|
return () => {
|
|
19
|
-
state = (state +
|
|
19
|
+
state = (state + 0x6d2b79f5) | 0;
|
|
20
20
|
let t = Math.imul(state ^ (state >>> 15), 1 | state);
|
|
21
21
|
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
22
22
|
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
@@ -31,7 +31,7 @@ function rollRarity(rand) {
|
|
|
31
31
|
if (roll < acc)
|
|
32
32
|
return tier.rarity;
|
|
33
33
|
}
|
|
34
|
-
return
|
|
34
|
+
return "common";
|
|
35
35
|
}
|
|
36
36
|
/** Generate stats with one peak, one dump, rest scattered */
|
|
37
37
|
function rollStats(rand, floor) {
|
|
@@ -70,7 +70,7 @@ export function roll(seed) {
|
|
|
70
70
|
const species = SPECIES[speciesIdx].name;
|
|
71
71
|
// Rarity
|
|
72
72
|
const rarity = rollRarity(rand);
|
|
73
|
-
const floor = RARITY_TIERS.find(t => t.rarity === rarity).statFloor;
|
|
73
|
+
const floor = RARITY_TIERS.find((t) => t.rarity === rarity).statFloor;
|
|
74
74
|
// Shiny (1% independent chance)
|
|
75
75
|
const isShiny = rand() < 0.01;
|
|
76
76
|
// Stats
|