ethagent 0.2.1 → 1.0.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/LICENSE +21 -0
- package/README.md +114 -32
- package/bin/ethagent.js +11 -2
- package/package.json +25 -7
- package/src/app/FirstRun.tsx +412 -0
- package/src/app/hooks/useCancelRequest.ts +22 -0
- package/src/app/hooks/useDoublePress.ts +46 -0
- package/src/app/hooks/useExitOnCtrlC.ts +36 -0
- package/src/app/input/AppInputProvider.tsx +116 -0
- package/src/app/input/appInputParser.ts +279 -0
- package/src/app/keybindings/KeybindingProvider.tsx +134 -0
- package/src/app/keybindings/resolver.ts +42 -0
- package/src/app/keybindings/types.ts +26 -0
- package/src/chat/ChatBottomPane.tsx +280 -0
- package/src/chat/ChatInput.tsx +722 -0
- package/src/chat/ChatScreen.tsx +1575 -0
- package/src/chat/ContextLimitView.tsx +95 -0
- package/src/chat/ContinuityEditReviewView.tsx +48 -0
- package/src/chat/ConversationStack.tsx +47 -0
- package/src/chat/CopyPicker.tsx +52 -0
- package/src/chat/MessageList.tsx +609 -0
- package/src/chat/PermissionPrompt.tsx +153 -0
- package/src/chat/PermissionsView.tsx +159 -0
- package/src/chat/PlanApprovalView.tsx +91 -0
- package/src/chat/ResumeView.tsx +267 -0
- package/src/chat/RewindView.tsx +386 -0
- package/src/chat/SessionStatus.tsx +51 -0
- package/src/chat/TranscriptView.tsx +202 -0
- package/src/chat/chatInputState.ts +247 -0
- package/src/chat/chatPaste.ts +49 -0
- package/src/chat/chatScreenUtils.ts +187 -0
- package/src/chat/chatSessionState.ts +142 -0
- package/src/chat/chatTurnOrchestrator.ts +701 -0
- package/src/chat/commands.ts +673 -0
- package/src/chat/textCursor.ts +202 -0
- package/src/chat/toolResultDisplay.ts +8 -0
- package/src/chat/transcriptViewport.ts +247 -0
- package/src/cli/ResetConfirmView.tsx +61 -0
- package/src/cli/main.tsx +177 -0
- package/src/cli/preview.tsx +19 -0
- package/src/cli/reset.ts +106 -0
- package/src/identity/continuity/editor.ts +149 -0
- package/src/identity/continuity/envelope.ts +345 -0
- package/src/identity/continuity/history.ts +153 -0
- package/src/identity/continuity/privateEdit.ts +334 -0
- package/src/identity/continuity/publicSkills.ts +173 -0
- package/src/identity/continuity/snapshots.ts +183 -0
- package/src/identity/continuity/storage.ts +507 -0
- package/src/identity/crypto/backupEnvelope.ts +486 -0
- package/src/identity/crypto/eth.ts +137 -0
- package/src/identity/hub/IdentityHub.tsx +845 -0
- package/src/identity/hub/identityHubEffects.ts +1100 -0
- package/src/identity/hub/identityHubModel.ts +291 -0
- package/src/identity/hub/identityHubReducer.ts +209 -0
- package/src/identity/hub/screens/BusyScreen.tsx +26 -0
- package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +139 -0
- package/src/identity/hub/screens/CreateFlow.tsx +206 -0
- package/src/identity/hub/screens/DetailsScreen.tsx +64 -0
- package/src/identity/hub/screens/EditProfileFlow.tsx +145 -0
- package/src/identity/hub/screens/ErrorScreen.tsx +35 -0
- package/src/identity/hub/screens/IdentitySummary.tsx +70 -0
- package/src/identity/hub/screens/MenuScreen.tsx +117 -0
- package/src/identity/hub/screens/NetworkScreen.tsx +41 -0
- package/src/identity/hub/screens/RebackupStorageScreen.tsx +50 -0
- package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +85 -0
- package/src/identity/hub/screens/RestoreFlow.tsx +206 -0
- package/src/identity/hub/screens/StorageCredentialScreen.tsx +128 -0
- package/src/identity/hub/screens/WalletApprovalScreen.tsx +43 -0
- package/src/identity/profile/imagePicker.ts +180 -0
- package/src/identity/registry/erc8004.ts +1106 -0
- package/src/identity/registry/registryConfig.ts +69 -0
- package/src/identity/storage/ipfs.ts +212 -0
- package/src/identity/storage/pinataJwt.ts +53 -0
- package/src/identity/wallet/browserWallet.ts +393 -0
- package/src/identity/wallet/wallet-page/wallet.html +1082 -0
- package/src/mcp/approvals.ts +113 -0
- package/src/mcp/config.ts +235 -0
- package/src/mcp/manager.ts +541 -0
- package/src/mcp/names.ts +19 -0
- package/src/mcp/output.ts +96 -0
- package/src/models/ModelPicker.tsx +1446 -0
- package/src/models/catalog.ts +296 -0
- package/src/models/huggingface.ts +651 -0
- package/src/models/llamacpp.ts +810 -0
- package/src/models/llamacppPreflight.ts +150 -0
- package/src/models/modelDisplay.ts +105 -0
- package/src/models/modelPickerOptions.ts +421 -0
- package/src/models/modelRecommendation.ts +140 -0
- package/src/models/runtimeDetection.ts +81 -0
- package/src/models/uncensoredCatalog.ts +86 -0
- package/src/providers/anthropic.ts +259 -0
- package/src/providers/contracts.ts +62 -0
- package/src/providers/errors.ts +62 -0
- package/src/providers/gemini.ts +152 -0
- package/src/providers/openai-chat.ts +472 -0
- package/src/providers/registry.ts +42 -0
- package/src/providers/retry.ts +58 -0
- package/src/providers/sse.ts +93 -0
- package/src/runtime/compaction.ts +389 -0
- package/src/runtime/cwd.ts +43 -0
- package/src/runtime/sessionMode.ts +55 -0
- package/src/runtime/systemPrompt.ts +209 -0
- package/src/runtime/toolClaimGuards.ts +143 -0
- package/src/runtime/toolExecution.ts +304 -0
- package/src/runtime/toolIntent.ts +163 -0
- package/src/runtime/turn.ts +858 -0
- package/src/storage/atomicWrite.ts +68 -0
- package/src/storage/config.ts +189 -0
- package/src/storage/factoryReset.ts +130 -0
- package/src/storage/history.ts +58 -0
- package/src/storage/identity.ts +99 -0
- package/src/storage/permissions.ts +76 -0
- package/src/storage/rewind.ts +246 -0
- package/src/storage/secrets.ts +181 -0
- package/src/storage/sessionExport.ts +49 -0
- package/src/storage/sessions.ts +482 -0
- package/src/tools/bashSafety.ts +174 -0
- package/src/tools/bashTool.ts +140 -0
- package/src/tools/changeDirectoryTool.ts +213 -0
- package/src/tools/contracts.ts +179 -0
- package/src/tools/deleteFileTool.ts +111 -0
- package/src/tools/editTool.ts +160 -0
- package/src/tools/editUtils.ts +170 -0
- package/src/tools/listDirectoryTool.ts +55 -0
- package/src/tools/mcpResourceTools.ts +95 -0
- package/src/tools/permissionRules.ts +85 -0
- package/src/tools/privateContinuityEditTool.ts +178 -0
- package/src/tools/privateContinuityReadTool.ts +107 -0
- package/src/tools/readTool.ts +85 -0
- package/src/tools/registry.ts +67 -0
- package/src/tools/writeFileTool.ts +142 -0
- package/src/ui/BrandSplash.tsx +193 -0
- package/src/ui/ProgressBar.tsx +34 -0
- package/src/ui/Select.tsx +143 -0
- package/src/ui/Spinner.tsx +269 -0
- package/src/ui/Surface.tsx +47 -0
- package/src/ui/TextInput.tsx +97 -0
- package/src/ui/theme.ts +59 -0
- package/src/utils/clipboard.ts +216 -0
- package/src/utils/markdownSegments.ts +51 -0
- package/src/utils/messages.ts +35 -0
- package/src/utils/withRetry.ts +280 -0
- package/src/cli.tsx +0 -147
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { PendingToolUse } from './turn.js'
|
|
2
|
+
import { unsupportedToolStateClaims, type ToolEvidence } from './toolClaimGuards.js'
|
|
3
|
+
export { parseLocalModelTextToolUses as extractLocalTextToolUses } from './turn.js'
|
|
4
|
+
|
|
5
|
+
export type ToolIntent = {
|
|
6
|
+
name: string
|
|
7
|
+
input: Record<string, unknown>
|
|
8
|
+
reason: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* detectDirectToolIntent — typed detection for high-confidence direct
|
|
13
|
+
* filesystem requests. Returns the first matching intent, or null for
|
|
14
|
+
* ambiguous or multi-step engineering requests so the model handles those.
|
|
15
|
+
*
|
|
16
|
+
* Covers:
|
|
17
|
+
* - change_directory: "cd into identity", "go to src/identity"
|
|
18
|
+
* - list_directory: "list files", "show what's here", "ls"
|
|
19
|
+
* - read_file: "read package.json", "open/show/cat <file>"
|
|
20
|
+
*
|
|
21
|
+
* Returns null for anything else.
|
|
22
|
+
*/
|
|
23
|
+
export function detectDirectToolIntent(userText: string): ToolIntent | null {
|
|
24
|
+
const uses = directToolUsesForUserText(userText)
|
|
25
|
+
if (uses.length === 0) return null
|
|
26
|
+
const first = uses[0]!
|
|
27
|
+
const reason = intentReason(first.name, first.input)
|
|
28
|
+
return { name: first.name, input: first.input, reason }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* validateAssistantTextAgainstTurnEvidence — checks whether assistant prose
|
|
33
|
+
* claims workspace state that isn't backed by a tool result from the active
|
|
34
|
+
* turn.
|
|
35
|
+
*
|
|
36
|
+
* Returns 'ok' if the text is safe (no unsupported claims), or 'needs-tool'
|
|
37
|
+
* if the text claims state that has no matching tool evidence.
|
|
38
|
+
*/
|
|
39
|
+
export function validateAssistantTextAgainstTurnEvidence(
|
|
40
|
+
text: string,
|
|
41
|
+
evidence: ToolEvidence[],
|
|
42
|
+
): 'ok' | 'needs-tool' {
|
|
43
|
+
const unsupported = unsupportedToolStateClaims(text, evidence)
|
|
44
|
+
return unsupported.length > 0 ? 'needs-tool' : 'ok'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function intentReason(name: string, input: Record<string, unknown>): string {
|
|
48
|
+
switch (name) {
|
|
49
|
+
case 'change_directory':
|
|
50
|
+
return `user requested directory change to ${input.path ?? '.'}`
|
|
51
|
+
case 'list_directory':
|
|
52
|
+
return input.path ? `user requested listing of ${input.path}` : 'user requested directory listing'
|
|
53
|
+
case 'read_file':
|
|
54
|
+
return `user requested read of ${input.path ?? '<unknown>'}`
|
|
55
|
+
default:
|
|
56
|
+
return `user requested ${name}`
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function directToolUsesForUserText(userText: string, iterationIndex = 0): PendingToolUse[] {
|
|
61
|
+
const text = userText.trim()
|
|
62
|
+
if (!text || text.startsWith('/')) return []
|
|
63
|
+
|
|
64
|
+
const cdPath = parseChangeDirectoryIntent(text)
|
|
65
|
+
if (cdPath) {
|
|
66
|
+
return [{
|
|
67
|
+
id: `direct-tool-${iterationIndex}-0`,
|
|
68
|
+
name: 'change_directory',
|
|
69
|
+
input: { path: cdPath },
|
|
70
|
+
}]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const listPath = parseListDirectoryIntent(text)
|
|
74
|
+
if (listPath !== null) {
|
|
75
|
+
return [{
|
|
76
|
+
id: `direct-tool-${iterationIndex}-0`,
|
|
77
|
+
name: 'list_directory',
|
|
78
|
+
input: listPath ? { path: listPath } : {},
|
|
79
|
+
}]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const readPath = parseReadFileIntent(text)
|
|
83
|
+
if (readPath) {
|
|
84
|
+
return [{
|
|
85
|
+
id: `direct-tool-${iterationIndex}-0`,
|
|
86
|
+
name: 'read_file',
|
|
87
|
+
input: { path: readPath },
|
|
88
|
+
}]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return []
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseChangeDirectoryIntent(text: string): string | null {
|
|
95
|
+
const normalized = trimCommandText(text)
|
|
96
|
+
const patterns = [
|
|
97
|
+
/^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?(?:cd|chdir)\s+(?:to\s+|into\s+|in\s+)?(.+)$/i,
|
|
98
|
+
/^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?go\s+(?:to|into|in)\s+(.+)$/i,
|
|
99
|
+
/^(?:no[, ]+)?(?:please\s+)?(?:now\s+)?change\s+(?:the\s+)?(?:current\s+)?(?:directory|folder)\s+(?:to|into)\s+(.+)$/i,
|
|
100
|
+
]
|
|
101
|
+
return firstPathMatch(normalized, patterns)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function parseListDirectoryIntent(text: string): string | null {
|
|
105
|
+
const normalized = trimCommandText(text)
|
|
106
|
+
const patterns = [
|
|
107
|
+
/^(?:please\s+)?(?:ls|dir)$/i,
|
|
108
|
+
/^(?:please\s+)?(?:ls|dir)\s+(.+)$/i,
|
|
109
|
+
/^(?:please\s+)?(?:list|show)\s+(?:the\s+)?(?:files|directories|folders|entries)(?:\s+(?:in|inside|of)\s+(.+))?$/i,
|
|
110
|
+
]
|
|
111
|
+
const match = firstPathMatch(normalized, patterns)
|
|
112
|
+
if (match) return match
|
|
113
|
+
return patterns.some(pattern => pattern.test(normalized)) ? '' : null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseReadFileIntent(text: string): string | null {
|
|
117
|
+
const normalized = trimCommandText(text)
|
|
118
|
+
const path = firstPathMatch(normalized, [
|
|
119
|
+
/^(?:please\s+)?(?:read|open|cat)\s+(.+)$/i,
|
|
120
|
+
/^(?:please\s+)?show\s+(?:me\s+)?(?:the\s+)?(?:contents\s+of\s+)?(.+)$/i,
|
|
121
|
+
])
|
|
122
|
+
if (!path) return null
|
|
123
|
+
return looksLikeConcreteReadTarget(path) ? path : null
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function firstPathMatch(text: string, patterns: RegExp[]): string | null {
|
|
127
|
+
for (const pattern of patterns) {
|
|
128
|
+
const match = text.match(pattern)
|
|
129
|
+
if (!match) continue
|
|
130
|
+
const raw = match[1]
|
|
131
|
+
if (raw === undefined) return ''
|
|
132
|
+
const cleaned = cleanPath(raw)
|
|
133
|
+
if (cleaned) return cleaned
|
|
134
|
+
}
|
|
135
|
+
return null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function trimCommandText(text: string): string {
|
|
139
|
+
return text
|
|
140
|
+
.trim()
|
|
141
|
+
.replace(/[.!?]+$/g, '')
|
|
142
|
+
.replace(/\s+/g, ' ')
|
|
143
|
+
.trim()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function cleanPath(value: string): string {
|
|
147
|
+
return value
|
|
148
|
+
.trim()
|
|
149
|
+
.replace(/^["'`]+|["'`]+$/g, '')
|
|
150
|
+
.replace(/\s+(?:please|now)$/i, '')
|
|
151
|
+
.trim()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function looksLikeConcreteReadTarget(path: string): boolean {
|
|
155
|
+
return path === '.'
|
|
156
|
+
|| path.startsWith('~')
|
|
157
|
+
|| path.startsWith('./')
|
|
158
|
+
|| path.startsWith('../')
|
|
159
|
+
|| /^[A-Za-z]:[\\/]/.test(path)
|
|
160
|
+
|| path.includes('/')
|
|
161
|
+
|| path.includes('\\')
|
|
162
|
+
|| /\.[A-Za-z0-9]{1,12}$/.test(path)
|
|
163
|
+
}
|