ethagent 0.2.0 → 1.0.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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -32
  3. package/bin/ethagent.js +11 -2
  4. package/package.json +30 -8
  5. package/src/app/FirstRun.tsx +412 -0
  6. package/src/app/hooks/useCancelRequest.ts +22 -0
  7. package/src/app/hooks/useDoublePress.ts +46 -0
  8. package/src/app/hooks/useExitOnCtrlC.ts +36 -0
  9. package/src/app/input/AppInputProvider.tsx +116 -0
  10. package/src/app/input/appInputParser.ts +279 -0
  11. package/src/app/keybindings/KeybindingProvider.tsx +134 -0
  12. package/src/app/keybindings/resolver.ts +42 -0
  13. package/src/app/keybindings/types.ts +26 -0
  14. package/src/chat/ChatBottomPane.tsx +280 -0
  15. package/src/chat/ChatInput.tsx +722 -0
  16. package/src/chat/ChatScreen.tsx +1575 -0
  17. package/src/chat/ContextLimitView.tsx +95 -0
  18. package/src/chat/ContinuityEditReviewView.tsx +48 -0
  19. package/src/chat/ConversationStack.tsx +47 -0
  20. package/src/chat/CopyPicker.tsx +52 -0
  21. package/src/chat/MessageList.tsx +609 -0
  22. package/src/chat/PermissionPrompt.tsx +153 -0
  23. package/src/chat/PermissionsView.tsx +159 -0
  24. package/src/chat/PlanApprovalView.tsx +91 -0
  25. package/src/chat/ResumeView.tsx +267 -0
  26. package/src/chat/RewindView.tsx +386 -0
  27. package/src/chat/SessionStatus.tsx +51 -0
  28. package/src/chat/TranscriptView.tsx +202 -0
  29. package/src/chat/chatInputState.ts +247 -0
  30. package/src/chat/chatPaste.ts +49 -0
  31. package/src/chat/chatScreenUtils.ts +187 -0
  32. package/src/chat/chatSessionState.ts +142 -0
  33. package/src/chat/chatTurnOrchestrator.ts +701 -0
  34. package/src/chat/commands.ts +673 -0
  35. package/src/chat/textCursor.ts +202 -0
  36. package/src/chat/toolResultDisplay.ts +8 -0
  37. package/src/chat/transcriptViewport.ts +247 -0
  38. package/src/cli/ResetConfirmView.tsx +61 -0
  39. package/src/cli/main.tsx +177 -0
  40. package/src/cli/preview.tsx +19 -0
  41. package/src/cli/reset.ts +106 -0
  42. package/src/identity/continuity/editor.ts +149 -0
  43. package/src/identity/continuity/envelope.ts +345 -0
  44. package/src/identity/continuity/history.ts +153 -0
  45. package/src/identity/continuity/privateEdit.ts +334 -0
  46. package/src/identity/continuity/publicSkills.ts +173 -0
  47. package/src/identity/continuity/snapshots.ts +183 -0
  48. package/src/identity/continuity/storage.ts +507 -0
  49. package/src/identity/crypto/backupEnvelope.ts +486 -0
  50. package/src/identity/crypto/eth.ts +137 -0
  51. package/src/identity/hub/IdentityHub.tsx +868 -0
  52. package/src/identity/hub/identityHubEffects.ts +1146 -0
  53. package/src/identity/hub/identityHubModel.ts +291 -0
  54. package/src/identity/hub/identityHubReducer.ts +212 -0
  55. package/src/identity/hub/screens/BusyScreen.tsx +26 -0
  56. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +144 -0
  57. package/src/identity/hub/screens/CreateFlow.tsx +206 -0
  58. package/src/identity/hub/screens/DetailsScreen.tsx +64 -0
  59. package/src/identity/hub/screens/EditProfileFlow.tsx +145 -0
  60. package/src/identity/hub/screens/ErrorScreen.tsx +35 -0
  61. package/src/identity/hub/screens/IdentitySummary.tsx +70 -0
  62. package/src/identity/hub/screens/MenuScreen.tsx +117 -0
  63. package/src/identity/hub/screens/NetworkScreen.tsx +41 -0
  64. package/src/identity/hub/screens/RebackupStorageScreen.tsx +50 -0
  65. package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +85 -0
  66. package/src/identity/hub/screens/RestoreFlow.tsx +206 -0
  67. package/src/identity/hub/screens/StorageCredentialScreen.tsx +128 -0
  68. package/src/identity/hub/screens/WalletApprovalScreen.tsx +43 -0
  69. package/src/identity/profile/imagePicker.ts +180 -0
  70. package/src/identity/registry/erc8004.ts +1106 -0
  71. package/src/identity/registry/registryConfig.ts +69 -0
  72. package/src/identity/storage/ipfs.ts +212 -0
  73. package/src/identity/storage/pinataJwt.ts +53 -0
  74. package/src/identity/wallet/browserWallet.ts +393 -0
  75. package/src/identity/wallet/wallet-page/wallet.html +1082 -0
  76. package/src/mcp/approvals.ts +113 -0
  77. package/src/mcp/config.ts +235 -0
  78. package/src/mcp/manager.ts +541 -0
  79. package/src/mcp/names.ts +19 -0
  80. package/src/mcp/output.ts +96 -0
  81. package/src/models/ModelPicker.tsx +1446 -0
  82. package/src/models/catalog.ts +296 -0
  83. package/src/models/huggingface.ts +651 -0
  84. package/src/models/llamacpp.ts +810 -0
  85. package/src/models/llamacppPreflight.ts +150 -0
  86. package/src/models/modelDisplay.ts +105 -0
  87. package/src/models/modelPickerOptions.ts +421 -0
  88. package/src/models/modelRecommendation.ts +140 -0
  89. package/src/models/runtimeDetection.ts +81 -0
  90. package/src/models/uncensoredCatalog.ts +86 -0
  91. package/src/providers/anthropic.ts +259 -0
  92. package/src/providers/contracts.ts +62 -0
  93. package/src/providers/errors.ts +62 -0
  94. package/src/providers/gemini.ts +152 -0
  95. package/src/providers/openai-chat.ts +472 -0
  96. package/src/providers/registry.ts +42 -0
  97. package/src/providers/retry.ts +58 -0
  98. package/src/providers/sse.ts +93 -0
  99. package/src/runtime/compaction.ts +389 -0
  100. package/src/runtime/cwd.ts +43 -0
  101. package/src/runtime/sessionMode.ts +55 -0
  102. package/src/runtime/systemPrompt.ts +209 -0
  103. package/src/runtime/toolClaimGuards.ts +143 -0
  104. package/src/runtime/toolExecution.ts +304 -0
  105. package/src/runtime/toolIntent.ts +163 -0
  106. package/src/runtime/turn.ts +858 -0
  107. package/src/storage/atomicWrite.ts +68 -0
  108. package/src/storage/config.ts +189 -0
  109. package/src/storage/factoryReset.ts +130 -0
  110. package/src/storage/history.ts +58 -0
  111. package/src/storage/identity.ts +99 -0
  112. package/src/storage/permissions.ts +76 -0
  113. package/src/storage/rewind.ts +246 -0
  114. package/src/storage/secrets.ts +181 -0
  115. package/src/storage/sessionExport.ts +49 -0
  116. package/src/storage/sessions.ts +482 -0
  117. package/src/tools/bashSafety.ts +174 -0
  118. package/src/tools/bashTool.ts +140 -0
  119. package/src/tools/changeDirectoryTool.ts +213 -0
  120. package/src/tools/contracts.ts +179 -0
  121. package/src/tools/deleteFileTool.ts +111 -0
  122. package/src/tools/editTool.ts +160 -0
  123. package/src/tools/editUtils.ts +170 -0
  124. package/src/tools/listDirectoryTool.ts +55 -0
  125. package/src/tools/mcpResourceTools.ts +95 -0
  126. package/src/tools/permissionRules.ts +85 -0
  127. package/src/tools/privateContinuityEditTool.ts +178 -0
  128. package/src/tools/privateContinuityReadTool.ts +107 -0
  129. package/src/tools/readTool.ts +85 -0
  130. package/src/tools/registry.ts +67 -0
  131. package/src/tools/writeFileTool.ts +142 -0
  132. package/src/ui/BrandSplash.tsx +193 -0
  133. package/src/ui/ProgressBar.tsx +34 -0
  134. package/src/ui/Select.tsx +143 -0
  135. package/src/ui/Spinner.tsx +269 -0
  136. package/src/ui/Surface.tsx +47 -0
  137. package/src/ui/TextInput.tsx +97 -0
  138. package/src/ui/theme.ts +59 -0
  139. package/src/utils/clipboard.ts +216 -0
  140. package/src/utils/markdownSegments.ts +51 -0
  141. package/src/utils/messages.ts +35 -0
  142. package/src/utils/withRetry.ts +280 -0
  143. 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
+ }