ethagent 1.1.2 → 2.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 -21
- package/README.md +124 -32
- package/package.json +8 -3
- package/src/app/FirstRun.tsx +190 -146
- package/src/app/FirstRunTimeline.tsx +47 -0
- package/src/app/input/AppInputProvider.tsx +1 -1
- package/src/app/keybindings/KeybindingProvider.tsx +1 -1
- package/src/chat/ChatBottomPane.tsx +0 -1
- package/src/chat/ChatInput.tsx +6 -6
- package/src/chat/ChatScreen.tsx +35 -15
- package/src/chat/ContextLimitView.tsx +4 -4
- package/src/chat/ContinuityEditReviewView.tsx +10 -22
- package/src/chat/CopyPicker.tsx +0 -1
- package/src/chat/MessageList.tsx +62 -45
- package/src/chat/PermissionPrompt.tsx +13 -9
- package/src/chat/PlanApprovalView.tsx +3 -3
- package/src/chat/ResumeView.tsx +1 -4
- package/src/chat/RewindView.tsx +2 -2
- package/src/chat/chatInputState.ts +1 -1
- package/src/chat/chatScreenUtils.ts +22 -11
- package/src/chat/chatSessionState.ts +2 -2
- package/src/chat/chatTurnOrchestrator.ts +16 -81
- package/src/chat/commands.ts +1 -1
- package/src/chat/textCursor.ts +1 -1
- package/src/chat/transcriptViewport.ts +2 -7
- package/src/cli/ResetConfirmView.tsx +1 -1
- package/src/cli/main.tsx +9 -3
- package/src/cli/preview.tsx +0 -5
- package/src/cli/updateNotice.ts +4 -2
- package/src/identity/continuity/editor.ts +7 -107
- package/src/identity/continuity/envelope.ts +1048 -40
- package/src/identity/continuity/history.ts +4 -4
- package/src/identity/continuity/localBackup.ts +249 -0
- package/src/identity/continuity/privateEdit/apply.ts +170 -0
- package/src/identity/continuity/privateEdit/diff.ts +82 -0
- package/src/identity/continuity/privateEdit/files.ts +23 -0
- package/src/identity/continuity/privateEdit/types.ts +28 -0
- package/src/identity/continuity/privateEdit.ts +10 -298
- package/src/identity/continuity/publicSkills.ts +8 -9
- package/src/identity/continuity/snapshots.ts +17 -6
- package/src/identity/continuity/storage/defaults.ts +111 -0
- package/src/identity/continuity/storage/files.ts +72 -0
- package/src/identity/continuity/storage/markdown.ts +81 -0
- package/src/identity/continuity/storage/paths.ts +24 -0
- package/src/identity/continuity/storage/scaffold.ts +124 -0
- package/src/identity/continuity/storage/status.ts +86 -0
- package/src/identity/continuity/storage/types.ts +27 -0
- package/src/identity/continuity/storage.ts +32 -507
- package/src/identity/continuity/zipWriter.ts +95 -0
- package/src/identity/crypto/backupEnvelope.ts +14 -247
- package/src/identity/crypto/eth.ts +7 -7
- package/src/identity/ens/agentRecords.ts +96 -0
- package/src/identity/ens/ensAutomation/contracts.ts +38 -0
- package/src/identity/ens/ensAutomation/delete.ts +80 -0
- package/src/identity/ens/ensAutomation/names.ts +14 -0
- package/src/identity/ens/ensAutomation/operators.ts +29 -0
- package/src/identity/ens/ensAutomation/read.ts +114 -0
- package/src/identity/ens/ensAutomation/root.ts +63 -0
- package/src/identity/ens/ensAutomation/setup.ts +284 -0
- package/src/identity/ens/ensAutomation/transactions.ts +107 -0
- package/src/identity/ens/ensAutomation/types.ts +126 -0
- package/src/identity/ens/ensAutomation.ts +29 -0
- package/src/identity/ens/ensLookup/client.ts +43 -0
- package/src/identity/ens/ensLookup/constants.ts +26 -0
- package/src/identity/ens/ensLookup/discovery.ts +70 -0
- package/src/identity/ens/ensLookup/names.ts +34 -0
- package/src/identity/ens/ensLookup/records.ts +45 -0
- package/src/identity/ens/ensLookup/resolve.ts +75 -0
- package/src/identity/ens/ensLookup/tokenReference.ts +17 -0
- package/src/identity/ens/ensLookup/types.ts +38 -0
- package/src/identity/ens/ensLookup/validation.ts +72 -0
- package/src/identity/ens/ensLookup.ts +19 -0
- package/src/identity/ens/ensRegistration.ts +199 -0
- package/src/identity/ens/resolverDelegation.ts +48 -0
- package/src/identity/hub/IdentityHub.tsx +13 -817
- package/src/identity/hub/OperationalRoutes.tsx +370 -0
- package/src/identity/hub/Routes.tsx +361 -0
- package/src/identity/hub/advancedEnsValidation.ts +45 -0
- package/src/identity/hub/{screens → components}/DetailsScreen.tsx +14 -8
- package/src/identity/hub/{screens → components}/ErrorScreen.tsx +15 -5
- package/src/identity/hub/components/FlowTimeline.tsx +27 -0
- package/src/identity/hub/components/IdentitySummary.tsx +190 -0
- package/src/identity/hub/components/MenuScreen.tsx +237 -0
- package/src/identity/hub/{screens → components}/NetworkScreen.tsx +3 -3
- package/src/identity/hub/{screens/RebackupStorageScreen.tsx → components/PinataJwtInput.tsx} +21 -18
- package/src/identity/hub/components/UnlinkedIdentityScreen.tsx +76 -0
- package/src/identity/hub/{screens → components}/WalletApprovalScreen.tsx +9 -8
- package/src/identity/hub/components/menuFlagsFromReconciliation.ts +68 -0
- package/src/identity/hub/effects/create.ts +310 -0
- package/src/identity/hub/effects/ens/flows.ts +218 -0
- package/src/identity/hub/effects/ens/index.ts +11 -0
- package/src/identity/hub/effects/ens/transactions.ts +239 -0
- package/src/identity/hub/effects/index.ts +74 -0
- package/src/identity/hub/effects/profile/profileState.ts +173 -0
- package/src/identity/hub/effects/publicProfile/index.ts +5 -0
- package/src/identity/hub/effects/publicProfile/runPublicProfileSave.ts +646 -0
- package/src/identity/hub/effects/rebackup/index.ts +7 -0
- package/src/identity/hub/effects/rebackup/operatorVault.ts +378 -0
- package/src/identity/hub/effects/rebackup/runRebackup.ts +451 -0
- package/src/identity/hub/effects/receipts.ts +46 -0
- package/src/identity/hub/effects/restore/apply.ts +112 -0
- package/src/identity/hub/effects/restore/auth.ts +159 -0
- package/src/identity/hub/effects/restore/discover.ts +86 -0
- package/src/identity/hub/effects/restore/envelopes.ts +21 -0
- package/src/identity/hub/effects/restore/fetch.ts +25 -0
- package/src/identity/hub/effects/restore/index.ts +22 -0
- package/src/identity/hub/effects/restore/recovery.ts +135 -0
- package/src/identity/hub/effects/restore/resolve.ts +102 -0
- package/src/identity/hub/effects/restore/restoreEffects.ts +22 -0
- package/src/identity/hub/effects/restore/shared.ts +91 -0
- package/src/identity/hub/effects/restoreAdmin.ts +93 -0
- package/src/identity/hub/effects/shared/profilePrep.ts +139 -0
- package/src/identity/hub/effects/shared/snapshot.ts +336 -0
- package/src/identity/hub/effects/shared/sync.ts +190 -0
- package/src/identity/hub/effects/token-transfer/index.ts +6 -0
- package/src/identity/hub/effects/token-transfer/progress.ts +59 -0
- package/src/identity/hub/effects/token-transfer/runTokenTransfer.ts +299 -0
- package/src/identity/hub/effects/types.ts +53 -0
- package/src/identity/hub/effects/vault/preflight.ts +50 -0
- package/src/identity/hub/flows/continuity/ContinuityDashboardScreen.tsx +170 -0
- package/src/identity/hub/flows/continuity/RebackupStorageScreen.tsx +28 -0
- package/src/identity/hub/{screens → flows/continuity}/RecoveryConfirmScreen.tsx +28 -19
- package/src/identity/hub/flows/continuity/SavePromptScreen.tsx +49 -0
- package/src/identity/hub/{screens → flows/create}/CreateFlow.tsx +61 -62
- package/src/identity/hub/flows/custody/CustodyEditFlow.tsx +347 -0
- package/src/identity/hub/flows/custody/custodyEffects.ts +321 -0
- package/src/identity/hub/flows/custody/custodyFlowActions.ts +236 -0
- package/src/identity/hub/flows/custody/custodyFlowEffects.ts +163 -0
- package/src/identity/hub/flows/custody/custodyFlowHelpers.ts +25 -0
- package/src/identity/hub/flows/custody/custodyFlowRoutes.tsx +239 -0
- package/src/identity/hub/flows/custody/custodyFlowTypes.ts +45 -0
- package/src/identity/hub/flows/custody/useCustodyFlow.tsx +25 -0
- package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +336 -0
- package/src/identity/hub/flows/ens/EnsEditFlow.tsx +397 -0
- package/src/identity/hub/flows/ens/EnsEditMaintenanceScreens.tsx +332 -0
- package/src/identity/hub/flows/ens/EnsEditReviewScreens.tsx +471 -0
- package/src/identity/hub/flows/ens/EnsEditRunners.tsx +198 -0
- package/src/identity/hub/flows/ens/EnsEditShared.tsx +162 -0
- package/src/identity/hub/flows/ens/EnsEditSimpleScreens.tsx +518 -0
- package/src/identity/hub/flows/ens/IdentityHubEnsFlow.tsx +299 -0
- package/src/identity/hub/flows/ens/OperatorWalletsScreen.tsx +398 -0
- package/src/identity/hub/flows/ens/ensEditCopy.ts +117 -0
- package/src/identity/hub/flows/ens/ensEditTypes.ts +91 -0
- package/src/identity/hub/flows/profile/EditProfileFlow.tsx +271 -0
- package/src/identity/hub/flows/restore/RestoreFlow.tsx +324 -0
- package/src/identity/hub/flows/restore/useRestoreFlowEffects.ts +77 -0
- package/src/identity/hub/{screens → flows/settings}/StorageCredentialScreen.tsx +23 -44
- package/src/identity/hub/flows/token-transfer/IdentityHubTokenTransferFlow.tsx +162 -0
- package/src/identity/hub/flows/token-transfer/TokenTransferScreens.tsx +256 -0
- package/src/identity/hub/identityHubReducer.ts +164 -99
- package/src/identity/hub/model/continuity.ts +94 -0
- package/src/identity/hub/model/copy.ts +35 -0
- package/src/identity/hub/model/custody.ts +54 -0
- package/src/identity/hub/model/ens.ts +49 -0
- package/src/identity/hub/model/errors.ts +140 -0
- package/src/identity/hub/model/format.ts +15 -0
- package/src/identity/hub/model/identity.ts +94 -0
- package/src/identity/hub/model/network.ts +32 -0
- package/src/identity/hub/model/transfer.ts +57 -0
- package/src/identity/hub/operatorWallets.ts +131 -0
- package/src/identity/hub/reconciliation/agentReconciliation/hook.ts +46 -0
- package/src/identity/hub/reconciliation/agentReconciliation/ownership.ts +129 -0
- package/src/identity/hub/reconciliation/agentReconciliation/run.ts +302 -0
- package/src/identity/hub/reconciliation/agentReconciliation/types.ts +17 -0
- package/src/identity/hub/reconciliation/index.ts +21 -0
- package/src/identity/hub/reconciliation/useAgentReconciliation.ts +10 -0
- package/src/identity/hub/reconciliation/walletSetup.ts +220 -0
- package/src/identity/hub/txGuard.ts +51 -0
- package/src/identity/hub/types.ts +17 -0
- package/src/identity/hub/useIdentityHubContinuity.ts +136 -0
- package/src/identity/hub/useIdentityHubController.ts +396 -0
- package/src/identity/hub/useIdentityHubSideEffects.ts +309 -0
- package/src/identity/hub/utils.ts +79 -0
- package/src/identity/identityCompat.ts +34 -0
- package/src/identity/profile/agentIcon.ts +61 -0
- package/src/identity/profile/imagePicker.ts +12 -12
- package/src/identity/registry/erc8004/abi.ts +14 -0
- package/src/identity/registry/erc8004/chains.ts +150 -0
- package/src/identity/registry/erc8004/client.ts +11 -0
- package/src/identity/registry/erc8004/discovery.ts +511 -0
- package/src/identity/registry/erc8004/metadata.ts +335 -0
- package/src/identity/registry/erc8004/ownership.ts +121 -0
- package/src/identity/registry/erc8004/preflight.ts +123 -0
- package/src/identity/registry/erc8004/transactions.ts +77 -0
- package/src/identity/registry/erc8004/types.ts +88 -0
- package/src/identity/registry/erc8004/uri.ts +59 -0
- package/src/identity/registry/erc8004/utils.ts +58 -0
- package/src/identity/registry/erc8004.ts +53 -1106
- package/src/identity/registry/fieldParsers.ts +28 -0
- package/src/identity/registry/operatorVault/bytecode.ts +98 -0
- package/src/identity/registry/operatorVault/constants.ts +38 -0
- package/src/identity/registry/operatorVault/read.ts +246 -0
- package/src/identity/registry/operatorVault/transactions.ts +81 -0
- package/src/identity/registry/operatorVault.ts +44 -0
- package/src/identity/storage/ipfs.ts +26 -24
- package/src/identity/wallet/browserWallet/gas.ts +41 -0
- package/src/identity/wallet/browserWallet/html.ts +106 -0
- package/src/identity/wallet/browserWallet/http.ts +28 -0
- package/src/identity/wallet/browserWallet/requestServer.ts +106 -0
- package/src/identity/wallet/browserWallet/requests.ts +191 -0
- package/src/identity/wallet/browserWallet/session.ts +325 -0
- package/src/identity/wallet/browserWallet/types.ts +192 -0
- package/src/identity/wallet/browserWallet/validation.ts +74 -0
- package/src/identity/wallet/browserWallet.ts +30 -393
- package/src/identity/wallet/page/constants.ts +5 -0
- package/src/identity/wallet/page/controller.ts +251 -0
- package/src/identity/wallet/page/copy.ts +340 -0
- package/src/identity/wallet/page/grainient.ts +278 -0
- package/src/identity/wallet/page/html.ts +28 -0
- package/src/identity/wallet/page/markup.ts +50 -0
- package/src/identity/wallet/page/state.ts +9 -0
- package/src/identity/wallet/page/styles/base.ts +259 -0
- package/src/identity/wallet/page/styles/components.ts +262 -0
- package/src/identity/wallet/page/styles/index.ts +5 -0
- package/src/identity/wallet/page/styles/responsive.ts +247 -0
- package/src/identity/wallet/page/types.ts +47 -0
- package/src/identity/wallet/page/view.ts +535 -0
- package/src/identity/wallet/page/walletProvider.ts +70 -0
- package/src/identity/wallet/page.tsx +38 -0
- package/src/identity/wallet/walletPurposeCompat.ts +27 -0
- package/src/mcp/manager.ts +0 -1
- package/src/models/ModelPicker.tsx +36 -30
- package/src/models/catalog.ts +5 -2
- package/src/models/huggingface.ts +9 -9
- package/src/models/llamacpp.ts +13 -13
- package/src/models/modelDisplay.ts +75 -0
- package/src/models/modelPickerOptions.ts +16 -3
- package/src/models/modelRecommendation.ts +0 -1
- package/src/providers/errors.ts +16 -0
- package/src/providers/gemini.ts +252 -39
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +1 -1
- package/src/runtime/sessionMode.ts +1 -1
- package/src/runtime/systemPrompt.ts +2 -0
- package/src/runtime/toolExecution.ts +18 -22
- package/src/runtime/toolIntent.ts +0 -20
- package/src/runtime/turn.ts +0 -92
- package/src/storage/atomicWrite.ts +4 -1
- package/src/storage/config.ts +181 -5
- package/src/storage/identity.ts +9 -3
- package/src/storage/secrets.ts +2 -2
- package/src/tools/bashSafety.ts +8 -0
- package/src/tools/changeDirectoryTool.ts +1 -1
- package/src/tools/deleteFileTool.ts +4 -4
- package/src/tools/editTool.ts +4 -4
- package/src/tools/editUtils.ts +5 -5
- package/src/tools/privateContinuityEditTool.ts +4 -5
- package/src/tools/privateContinuityReadTool.ts +1 -2
- package/src/tools/registry.ts +30 -0
- package/src/tools/writeFileTool.ts +5 -5
- package/src/ui/BrandSplash.tsx +20 -85
- package/src/ui/ProgressBar.tsx +3 -5
- package/src/ui/Select.tsx +20 -8
- package/src/ui/Spinner.tsx +38 -3
- package/src/ui/Surface.tsx +2 -2
- package/src/ui/TextInput.tsx +63 -20
- package/src/ui/theme.ts +7 -34
- package/src/utils/openExternal.ts +21 -0
- package/src/utils/withRetry.ts +47 -3
- package/src/identity/hub/identityHubEffects.ts +0 -937
- package/src/identity/hub/identityHubModel.ts +0 -371
- package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +0 -156
- package/src/identity/hub/screens/EditProfileFlow.tsx +0 -146
- package/src/identity/hub/screens/IdentitySummary.tsx +0 -106
- package/src/identity/hub/screens/MenuScreen.tsx +0 -117
- package/src/identity/hub/screens/RestoreFlow.tsx +0 -206
- package/src/identity/wallet/wallet-page/wallet.html +0 -1202
- /package/src/identity/hub/{screens → components}/BusyScreen.tsx +0 -0
|
@@ -60,18 +60,6 @@ export type StreamingTurnResult = {
|
|
|
60
60
|
cancelled: boolean
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/**
|
|
64
|
-
* runStreamingTurn - the UI adapter over runRuntimeTurn.
|
|
65
|
-
*
|
|
66
|
-
* Responsibilities (UI-only; logic lives in runtime/turn.ts):
|
|
67
|
-
* - translate runtime events into Ink MessageRow updates,
|
|
68
|
-
* - flush streaming text to rows on a debounce,
|
|
69
|
-
* - persist SessionMessages on commit boundaries,
|
|
70
|
-
* - drive the tool batch (permission prompts, row pushes, persistence),
|
|
71
|
-
* - surface plan-mode output to the caller,
|
|
72
|
-
* - return a summary of what happened (finishedNormally / cancelled)
|
|
73
|
-
* for the caller to act on.
|
|
74
|
-
*/
|
|
75
63
|
export async function runStreamingTurn(
|
|
76
64
|
context: TurnOrchestratorContext,
|
|
77
65
|
): Promise<StreamingTurnResult> {
|
|
@@ -86,7 +74,6 @@ export async function runStreamingTurn(
|
|
|
86
74
|
nowIso,
|
|
87
75
|
getConfig,
|
|
88
76
|
getCwd,
|
|
89
|
-
getSessionMessages,
|
|
90
77
|
setActiveCheckpoint,
|
|
91
78
|
setStreaming,
|
|
92
79
|
updateRows,
|
|
@@ -135,8 +122,6 @@ export async function runStreamingTurn(
|
|
|
135
122
|
]
|
|
136
123
|
}
|
|
137
124
|
|
|
138
|
-
// Per-iteration UI scratch. These are reset each time the runtime loop
|
|
139
|
-
// re-enters streaming (new provider call = new assistant row, new accumulator).
|
|
140
125
|
let accumulated = ''
|
|
141
126
|
let thinkingContent = ''
|
|
142
127
|
let thinkingRowId: string | null = null
|
|
@@ -207,9 +192,6 @@ export async function runStreamingTurn(
|
|
|
207
192
|
flushStreamRows(true)
|
|
208
193
|
updateRows(prev => {
|
|
209
194
|
let next = finalizeStreamingRowsById(prev, assistantId, thinkingRowId, accumulated, thinkingContent)
|
|
210
|
-
// If we emitted tool_uses, strip the empty assistant text row - tool_use
|
|
211
|
-
// rows replace it. If the assistant emitted no text at all (pure tool
|
|
212
|
-
// turn), drop the empty row.
|
|
213
195
|
if (assistantId && (hasPendingToolUse || accumulated.length === 0)) {
|
|
214
196
|
next = next.filter(r => r.id !== assistantId)
|
|
215
197
|
}
|
|
@@ -235,13 +217,6 @@ export async function runStreamingTurn(
|
|
|
235
217
|
name: string
|
|
236
218
|
input: Record<string, unknown>
|
|
237
219
|
}>) => {
|
|
238
|
-
// Persist the assistant tool_use blocks into the session before execution
|
|
239
|
-
// so microcompact / rebuild has them on the next provider call. The actual
|
|
240
|
-
// Message[] sent to the provider is rebuilt from session messages.
|
|
241
|
-
// (This mirrors the pre-Wave-2 behavior, just routed from the event loop.)
|
|
242
|
-
// NOTE: some provider loops keep tool_use blocks inside the assistant
|
|
243
|
-
// message; ethagent stores them as discrete tool_use SessionMessages via
|
|
244
|
-
// runPendingToolUses, which keeps the microcompact model simpler.
|
|
245
220
|
const step = await runPendingToolUses({
|
|
246
221
|
pendingToolUses,
|
|
247
222
|
nextRowId,
|
|
@@ -351,10 +326,6 @@ export async function runStreamingTurn(
|
|
|
351
326
|
}
|
|
352
327
|
}
|
|
353
328
|
|
|
354
|
-
// ---------------------------------------------------------------------------
|
|
355
|
-
// Event handling: per-event UI translation
|
|
356
|
-
// ---------------------------------------------------------------------------
|
|
357
|
-
|
|
358
329
|
type EventHandlerContext = {
|
|
359
330
|
ensureAssistantRow: () => string
|
|
360
331
|
flushStreamRows: (immediate?: boolean) => void
|
|
@@ -391,10 +362,6 @@ function isCancelledEvent(ev: TurnEvent): boolean {
|
|
|
391
362
|
async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<void> {
|
|
392
363
|
switch (ev.type) {
|
|
393
364
|
case 'iteration_start': {
|
|
394
|
-
// Reset per-iteration scratch so each provider call gets a fresh
|
|
395
|
-
// assistant row, accumulator, and hasPendingToolUse flag. Iteration 0
|
|
396
|
-
// is the initial stream - resetting before anything runs is a no-op,
|
|
397
|
-
// which is fine.
|
|
398
365
|
ctx.resetIteration()
|
|
399
366
|
return
|
|
400
367
|
}
|
|
@@ -433,7 +400,6 @@ async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<voi
|
|
|
433
400
|
return
|
|
434
401
|
}
|
|
435
402
|
case 'retry': {
|
|
436
|
-
ctx.pushNote(formatRetryStatus(ev), 'dim')
|
|
437
403
|
return
|
|
438
404
|
}
|
|
439
405
|
case 'tool_use_stop': {
|
|
@@ -442,8 +408,6 @@ async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<voi
|
|
|
442
408
|
return
|
|
443
409
|
}
|
|
444
410
|
case 'assistant_message_committed': {
|
|
445
|
-
// End of a streaming round with no tool_use - finalize rows, persist
|
|
446
|
-
// the assistant text, and hand it to the plan hook if in plan mode.
|
|
447
411
|
ctx.finalizeStreamingRows()
|
|
448
412
|
if (ev.text) {
|
|
449
413
|
await ctx.persistTurnMessage({
|
|
@@ -458,22 +422,14 @@ async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<voi
|
|
|
458
422
|
return
|
|
459
423
|
}
|
|
460
424
|
case 'tool_executed': {
|
|
461
|
-
// Row + session persistence happened inside runPendingToolUses; the
|
|
462
|
-
// event is informational for observers that need it (tests, future
|
|
463
|
-
// instrumentation). No UI side-effect here.
|
|
464
425
|
return
|
|
465
426
|
}
|
|
466
427
|
case 'local_tool_recovery': {
|
|
467
|
-
// The runtime recovered tool calls from local model text output.
|
|
468
|
-
// Discard the streamed assistant rows that contained the JSON blob
|
|
469
|
-
// so they are not persisted or displayed as prose.
|
|
470
428
|
ctx.discardStreamingRows()
|
|
471
429
|
ctx.markPendingToolUse()
|
|
472
430
|
return
|
|
473
431
|
}
|
|
474
432
|
case 'continuation_nudge': {
|
|
475
|
-
// Clean break between provider calls. Corrective nudges suppress the
|
|
476
|
-
// unverified assistant row so it cannot become durable context.
|
|
477
433
|
if (
|
|
478
434
|
ev.reason === 'tool_state_claim' ||
|
|
479
435
|
ev.reason === 'tool_capability' ||
|
|
@@ -501,9 +457,6 @@ async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<voi
|
|
|
501
457
|
return
|
|
502
458
|
}
|
|
503
459
|
case 'done': {
|
|
504
|
-
// If we ended mid-iteration (no assistant_message_committed yet) the
|
|
505
|
-
// finalize call from error/cancelled already ran. If we ended after a
|
|
506
|
-
// tool_executed batch, finalize here so the UI settles.
|
|
507
460
|
ctx.finalizeStreamingRows()
|
|
508
461
|
if (ev.finishedNormally) ctx.onFinishedNormally()
|
|
509
462
|
return
|
|
@@ -514,21 +467,6 @@ async function handleEvent(ev: TurnEvent, ctx: EventHandlerContext): Promise<voi
|
|
|
514
467
|
}
|
|
515
468
|
}
|
|
516
469
|
|
|
517
|
-
function formatRetryStatus(ev: Extract<TurnEvent, { type: 'retry' }>): string {
|
|
518
|
-
const totalAttempts = ev.maxRetries + 1
|
|
519
|
-
const reason = ev.status !== undefined ? `HTTP ${ev.status}` : ev.code ?? ev.reason
|
|
520
|
-
return `provider retry ${ev.nextAttempt}/${totalAttempts} in ${formatRetryDelay(ev.delayMs)} (${reason})`
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
function formatRetryDelay(delayMs: number): string {
|
|
524
|
-
if (delayMs < 1000) return `${Math.max(0, Math.round(delayMs))}ms`
|
|
525
|
-
const seconds = delayMs / 1000
|
|
526
|
-
if (seconds < 10) return `${seconds.toFixed(1).replace(/\.0$/, '')}s`
|
|
527
|
-
if (seconds < 60) return `${Math.round(seconds)}s`
|
|
528
|
-
const minutes = seconds / 60
|
|
529
|
-
return `${minutes.toFixed(minutes < 10 ? 1 : 0).replace(/\.0$/, '')}m`
|
|
530
|
-
}
|
|
531
|
-
|
|
532
470
|
function updateStreamingRows(
|
|
533
471
|
rows: MessageRow[],
|
|
534
472
|
assistantId: string | null,
|
|
@@ -592,10 +530,6 @@ function findRowIndexById(rows: MessageRow[], id: string): number {
|
|
|
592
530
|
return -1
|
|
593
531
|
}
|
|
594
532
|
|
|
595
|
-
// ---------------------------------------------------------------------------
|
|
596
|
-
// File-mention context (unchanged from pre-Wave-2 - pure helper)
|
|
597
|
-
// ---------------------------------------------------------------------------
|
|
598
|
-
|
|
599
533
|
async function buildFileMentionContextMessages(
|
|
600
534
|
userText: string,
|
|
601
535
|
cwd: string,
|
|
@@ -641,23 +575,24 @@ export async function buildIdentityContinuityContextMessages(
|
|
|
641
575
|
|
|
642
576
|
try {
|
|
643
577
|
const privateFiles = await readContinuityFiles(identity)
|
|
578
|
+
const parts: string[] = [
|
|
579
|
+
'<identity_continuity_files>',
|
|
580
|
+
'The active identity continuity files have been loaded automatically for this turn.',
|
|
581
|
+
'SOUL.md is private owner continuity and is the authoritative persona, voice, and standing-behavior layer for this active identity.',
|
|
582
|
+
'MEMORY.md is private owner continuity for durable preferences, facts, and project context.',
|
|
583
|
+
'Apply SOUL.md and MEMORY.md over generic ethagent identity/style unless they conflict with safety, tool correctness, developer instructions, or the user\'s latest explicit request. Do not quote private continuity unless necessary.',
|
|
584
|
+
'<SOUL.md visibility="private">',
|
|
585
|
+
privateFiles['SOUL.md'].trimEnd(),
|
|
586
|
+
'</SOUL.md>',
|
|
587
|
+
'',
|
|
588
|
+
'<MEMORY.md visibility="private">',
|
|
589
|
+
privateFiles['MEMORY.md'].trimEnd(),
|
|
590
|
+
'</MEMORY.md>',
|
|
591
|
+
'</identity_continuity_files>',
|
|
592
|
+
]
|
|
644
593
|
return [{
|
|
645
594
|
role: 'system',
|
|
646
|
-
content:
|
|
647
|
-
'<identity_continuity_files>',
|
|
648
|
-
'The active identity continuity files have been loaded automatically for this turn.',
|
|
649
|
-
'SOUL.md is private owner continuity and is the authoritative persona, voice, and standing-behavior layer for this active identity.',
|
|
650
|
-
'MEMORY.md is private owner continuity for durable preferences, facts, and project context.',
|
|
651
|
-
'Apply SOUL.md and MEMORY.md over generic ethagent identity/style unless they conflict with safety, tool correctness, developer instructions, or the user\'s latest explicit request. Do not quote private continuity unless necessary.',
|
|
652
|
-
'<SOUL.md visibility="private">',
|
|
653
|
-
privateFiles['SOUL.md'].trimEnd(),
|
|
654
|
-
'</SOUL.md>',
|
|
655
|
-
'',
|
|
656
|
-
'<MEMORY.md visibility="private">',
|
|
657
|
-
privateFiles['MEMORY.md'].trimEnd(),
|
|
658
|
-
'</MEMORY.md>',
|
|
659
|
-
'</identity_continuity_files>',
|
|
660
|
-
].join('\n'),
|
|
595
|
+
content: parts.join('\n'),
|
|
661
596
|
}]
|
|
662
597
|
} catch (err: unknown) {
|
|
663
598
|
return [{
|
package/src/chat/commands.ts
CHANGED
|
@@ -210,7 +210,7 @@ const COMMANDS: CommandSpec[] = [
|
|
|
210
210
|
}
|
|
211
211
|
await saveConfig(next)
|
|
212
212
|
ctx.onReplaceConfig(next)
|
|
213
|
-
return { kind: 'note', text: `
|
|
213
|
+
return { kind: 'note', text: `Now using ${next.provider} · ${formatModelDisplayName(next.provider, name, { maxLength: 64 })}.` }
|
|
214
214
|
},
|
|
215
215
|
},
|
|
216
216
|
{
|
package/src/chat/textCursor.ts
CHANGED
|
@@ -119,7 +119,7 @@ export function moveVerticalVisualCursor(
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export function cursorOnLastLine(value: string,
|
|
122
|
+
export function cursorOnLastLine(value: string, _offset: number): TextCursor {
|
|
123
123
|
const lines = getLogicalLines(value)
|
|
124
124
|
const lastLine = Math.max(0, lines.length - 1)
|
|
125
125
|
return normalizeCursor(value, offsetFromPosition(lines, lastLine, 0))
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { MessageRow } from './MessageList.js'
|
|
2
|
-
import { hidesSuccessfulToolResultContent } from './toolResultDisplay.js'
|
|
3
2
|
|
|
4
3
|
export type TranscriptAnchor = {
|
|
5
4
|
rowId: string
|
|
@@ -219,12 +218,8 @@ export function estimateMessageRowHeight(row: MessageRow, columns = 80): number
|
|
|
219
218
|
return row.expanded
|
|
220
219
|
? 3 + wrappedLineCount([row.content, row.liveTail ?? ''].filter(Boolean).join('\n'), contentWidth)
|
|
221
220
|
: 3 + wrappedLineCount(reasoningPreview(row), contentWidth)
|
|
222
|
-
case '
|
|
223
|
-
return
|
|
224
|
-
case 'tool_result':
|
|
225
|
-
return hidesSuccessfulToolResultContent(row.name, row.isError)
|
|
226
|
-
? 3
|
|
227
|
-
: 3 + wrappedLineCount(row.content, contentWidth)
|
|
221
|
+
case 'tool_call':
|
|
222
|
+
return 1
|
|
228
223
|
case 'note':
|
|
229
224
|
return 1 + wrappedLineCount(row.content, contentWidth)
|
|
230
225
|
case 'progress':
|
|
@@ -47,7 +47,7 @@ export const ResetConfirmView: React.FC<{
|
|
|
47
47
|
|
|
48
48
|
const Section: React.FC<{ title: string; lines: string[] }> = ({ title, lines }) => (
|
|
49
49
|
<Box flexDirection="column" marginBottom={1}>
|
|
50
|
-
<Text color={theme.
|
|
50
|
+
<Text color={theme.accentPeriwinkle}>{title}</Text>
|
|
51
51
|
{lines.map(line => (
|
|
52
52
|
<Text key={line} color={theme.textSubtle}>- {line}</Text>
|
|
53
53
|
))}
|
package/src/cli/main.tsx
CHANGED
|
@@ -103,13 +103,19 @@ const AppRoot: React.FC<{ setExitCode: (code: number) => void; currentVersion: s
|
|
|
103
103
|
|
|
104
104
|
useAppInput((input, key) => {
|
|
105
105
|
if (phase.kind === 'ready') return
|
|
106
|
-
if (key.ctrl && (input === 'c' || input === 'd'))
|
|
106
|
+
if (key.ctrl && (input === 'c' || input === 'd')) {
|
|
107
|
+
if (phase.kind === 'setup') {
|
|
108
|
+
setPhase({ kind: 'cancelled' })
|
|
109
|
+
} else {
|
|
110
|
+
exit()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
107
113
|
})
|
|
108
114
|
|
|
109
115
|
if (phase.kind === 'loading') {
|
|
110
116
|
return (
|
|
111
117
|
<Box padding={1}>
|
|
112
|
-
<Spinner label="
|
|
118
|
+
<Spinner label="starting ethagent..." showElapsed={false} />
|
|
113
119
|
</Box>
|
|
114
120
|
)
|
|
115
121
|
}
|
|
@@ -131,7 +137,7 @@ const AppRoot: React.FC<{ setExitCode: (code: number) => void; currentVersion: s
|
|
|
131
137
|
if (phase.kind === 'error') {
|
|
132
138
|
return (
|
|
133
139
|
<Box padding={1}>
|
|
134
|
-
<Text color=
|
|
140
|
+
<Text color={theme.accentError}>Error: {phase.message}</Text>
|
|
135
141
|
</Box>
|
|
136
142
|
)
|
|
137
143
|
}
|
package/src/cli/preview.tsx
CHANGED
|
@@ -2,17 +2,12 @@ import React from 'react'
|
|
|
2
2
|
import { Box, render } from 'ink'
|
|
3
3
|
import { BrandSplash } from '../ui/BrandSplash.js'
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* `ethagent preview` — renders the brand splash with only the tagline
|
|
7
|
-
* in the top border, no technical details at the bottom, and exits.
|
|
8
|
-
*/
|
|
9
5
|
export async function runPreviewCommand(): Promise<number> {
|
|
10
6
|
const instance = render(
|
|
11
7
|
<Box flexDirection="column" marginY={1}>
|
|
12
8
|
<BrandSplash />
|
|
13
9
|
</Box>,
|
|
14
10
|
)
|
|
15
|
-
// Give Ink one tick to paint, then unmount cleanly.
|
|
16
11
|
await new Promise<void>(resolve => setTimeout(resolve, 50))
|
|
17
12
|
instance.unmount()
|
|
18
13
|
return 0
|
package/src/cli/updateNotice.ts
CHANGED
|
@@ -12,8 +12,10 @@ export function compareVersions(left: string, right: string): number {
|
|
|
12
12
|
const b = parseVersion(right)
|
|
13
13
|
if (!a || !b) return 0
|
|
14
14
|
for (let i = 0; i < 3; i++) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const av = a[i as 0 | 1 | 2]
|
|
16
|
+
const bv = b[i as 0 | 1 | 2]
|
|
17
|
+
if (av > bv) return 1
|
|
18
|
+
if (av < bv) return -1
|
|
17
19
|
}
|
|
18
20
|
return 0
|
|
19
21
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
1
|
import { spawn } from 'node:child_process'
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
type EditorOpenResult =
|
|
6
4
|
| { ok: true; method: string; waited: boolean }
|
|
7
5
|
| { ok: false; error: string }
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
type EditorCommand = {
|
|
10
8
|
cmd: string
|
|
11
9
|
args: string[]
|
|
12
10
|
method: string
|
|
@@ -14,59 +12,10 @@ export type EditorCommand = {
|
|
|
14
12
|
shell?: boolean
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const IDE_CANDIDATES = ['code', 'cursor', 'windsurf'] as const
|
|
23
|
-
|
|
24
|
-
export function openFileInEditor(file: string, env: NodeJS.ProcessEnv = process.env): Promise<EditorOpenResult> {
|
|
25
|
-
const command = resolveEditorCommand(file, env)
|
|
26
|
-
if (command) return openEditorCommand(command)
|
|
27
|
-
return openDefaultEditor(file)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function resolveEditorCommand(
|
|
31
|
-
file: string,
|
|
32
|
-
env: NodeJS.ProcessEnv = process.env,
|
|
33
|
-
options: EditorResolutionOptions = {},
|
|
34
|
-
): EditorCommand | null {
|
|
35
|
-
const platform = options.platform ?? process.platform
|
|
36
|
-
const commandExists = options.commandExists ?? (command => findExecutable(command, env, platform))
|
|
37
|
-
|
|
38
|
-
const ethagentEditor = env.ETHAGENT_EDITOR?.trim()
|
|
39
|
-
if (ethagentEditor) return configuredCommand(ethagentEditor, file, true, platform)
|
|
40
|
-
|
|
41
|
-
for (const candidate of IDE_CANDIDATES) {
|
|
42
|
-
const executable = commandExists(candidate)
|
|
43
|
-
if (executable) {
|
|
44
|
-
return {
|
|
45
|
-
cmd: executable,
|
|
46
|
-
args: [file],
|
|
47
|
-
method: candidate,
|
|
48
|
-
waited: false,
|
|
49
|
-
shell: platform === 'win32' && /\.(?:cmd|bat)$/i.test(executable),
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const configured = env.VISUAL?.trim() || env.EDITOR?.trim()
|
|
55
|
-
if (configured) return configuredCommand(configured, file, true, platform)
|
|
56
|
-
|
|
57
|
-
return defaultEditorCommand(file, platform)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function configuredCommand(commandLine: string, file: string, waited: boolean, platform: NodeJS.Platform): EditorCommand | null {
|
|
61
|
-
const [cmd, ...args] = splitCommand(commandLine)
|
|
62
|
-
if (!cmd) return null
|
|
63
|
-
return {
|
|
64
|
-
cmd,
|
|
65
|
-
args: [...args, file],
|
|
66
|
-
method: path.basename(cmd),
|
|
67
|
-
waited,
|
|
68
|
-
shell: platform === 'win32' && /\.(?:cmd|bat)$/i.test(cmd),
|
|
69
|
-
}
|
|
15
|
+
export function openFileInEditor(file: string): Promise<EditorOpenResult> {
|
|
16
|
+
const command = defaultEditorCommand(file)
|
|
17
|
+
if (!command) return Promise.resolve({ ok: false, error: 'no default open command for this platform' })
|
|
18
|
+
return openEditorCommand(command)
|
|
70
19
|
}
|
|
71
20
|
|
|
72
21
|
function openEditorCommand(command: EditorCommand): Promise<EditorOpenResult> {
|
|
@@ -93,57 +42,8 @@ function openEditorCommand(command: EditorCommand): Promise<EditorOpenResult> {
|
|
|
93
42
|
})
|
|
94
43
|
}
|
|
95
44
|
|
|
96
|
-
function
|
|
97
|
-
const command = defaultEditorCommand(file)
|
|
98
|
-
if (!command) return Promise.resolve({ ok: false, error: 'no default editor command for this platform' })
|
|
99
|
-
return openEditorCommand(command)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function defaultEditorCommand(file: string, platform: NodeJS.Platform = process.platform): EditorCommand | null {
|
|
45
|
+
export function defaultEditorCommand(file: string, platform: NodeJS.Platform = process.platform): EditorCommand | null {
|
|
103
46
|
if (platform === 'win32') return { cmd: 'cmd', args: ['/c', 'start', '', file], method: 'cmd', waited: false }
|
|
104
47
|
if (platform === 'darwin') return { cmd: 'open', args: [file], method: 'open', waited: false }
|
|
105
48
|
return { cmd: 'xdg-open', args: [file], method: 'xdg-open', waited: false }
|
|
106
49
|
}
|
|
107
|
-
|
|
108
|
-
function splitCommand(commandLine: string): string[] {
|
|
109
|
-
return commandLine.match(/"[^"]+"|'[^']+'|\S+/g)?.map(part => {
|
|
110
|
-
if ((part.startsWith('"') && part.endsWith('"')) || (part.startsWith("'") && part.endsWith("'"))) {
|
|
111
|
-
return part.slice(1, -1)
|
|
112
|
-
}
|
|
113
|
-
return part
|
|
114
|
-
}) ?? []
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function findExecutable(command: string, env: NodeJS.ProcessEnv, platform: NodeJS.Platform): string | null {
|
|
118
|
-
const hasPathSeparator = command.includes('/') || command.includes('\\')
|
|
119
|
-
if (hasPathSeparator || path.isAbsolute(command)) {
|
|
120
|
-
return canAccessExecutable(command) ? command : null
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const pathValue = env.PATH ?? ''
|
|
124
|
-
const pathParts = pathValue.split(path.delimiter).filter(Boolean)
|
|
125
|
-
const extensions = platform === 'win32'
|
|
126
|
-
? (env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean)
|
|
127
|
-
: ['']
|
|
128
|
-
|
|
129
|
-
for (const dir of pathParts) {
|
|
130
|
-
for (const ext of extensions) {
|
|
131
|
-
const candidate = path.join(dir, platform === 'win32' && path.extname(command) === '' ? `${command}${ext.toLowerCase()}` : command)
|
|
132
|
-
if (canAccessExecutable(candidate)) return candidate
|
|
133
|
-
if (platform === 'win32') {
|
|
134
|
-
const upperCandidate = path.join(dir, path.extname(command) === '' ? `${command}${ext.toUpperCase()}` : command)
|
|
135
|
-
if (canAccessExecutable(upperCandidate)) return upperCandidate
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return null
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function canAccessExecutable(file: string): boolean {
|
|
143
|
-
try {
|
|
144
|
-
fs.accessSync(file, fs.constants.X_OK)
|
|
145
|
-
return true
|
|
146
|
-
} catch {
|
|
147
|
-
return false
|
|
148
|
-
}
|
|
149
|
-
}
|