ethagent 1.1.2 → 2.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.
- package/LICENSE +21 -21
- package/README.md +126 -30
- package/package.json +7 -2
- 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
package/src/chat/ChatScreen.tsx
CHANGED
|
@@ -18,7 +18,7 @@ import { SessionStatus, formatTokens } from './SessionStatus.js'
|
|
|
18
18
|
import { formatModelDisplayName } from '../models/modelDisplay.js'
|
|
19
19
|
import { toggleReasoningRow, type MessageRow } from './MessageList.js'
|
|
20
20
|
import { ConversationStack } from './ConversationStack.js'
|
|
21
|
-
import {
|
|
21
|
+
import type { ModelPickerSelection } from '../models/ModelPicker.js'
|
|
22
22
|
import type { ModelPickerContextFit } from '../models/modelPickerOptions.js'
|
|
23
23
|
import type { CopyResult } from '../utils/clipboard.js'
|
|
24
24
|
import { useKeybinding, useRegisterKeybindingContext } from '../app/keybindings/KeybindingProvider.js'
|
|
@@ -55,13 +55,15 @@ import type {
|
|
|
55
55
|
} from '../tools/contracts.js'
|
|
56
56
|
import {
|
|
57
57
|
buildBaseMessages,
|
|
58
|
-
formatBytes,
|
|
59
58
|
sessionMessagesToRows,
|
|
60
59
|
type TurnCheckpoint,
|
|
61
60
|
} from './chatScreenUtils.js'
|
|
62
61
|
import { ChatBottomPane, type ContextLimitState, type CopyPickerState, type IdentityOverlayState, type Overlay } from './ChatBottomPane.js'
|
|
63
62
|
import { setTokenIdentity, getIdentityStatus } from '../storage/identity.js'
|
|
64
63
|
import type { IdentityHubResult } from '../identity/hub/IdentityHub.js'
|
|
64
|
+
import { continuityWorkingTreeStatus } from '../identity/continuity/storage.js'
|
|
65
|
+
import { listPublishedContinuitySnapshots } from '../identity/continuity/snapshots.js'
|
|
66
|
+
import { localChangeStatusView } from '../identity/hub/model/continuity.js'
|
|
65
67
|
import {
|
|
66
68
|
buildResumedSessionState,
|
|
67
69
|
promptHistoryFromSessionMessages,
|
|
@@ -181,6 +183,7 @@ export const ChatScreen: React.FC<ChatScreenProps> = ({ config: initialConfig, o
|
|
|
181
183
|
const pendingContinuityEditReviewRef = useRef<ContinuityEditReviewState | null>(null)
|
|
182
184
|
const contextModelSwitchPromptRef = useRef<string | null>(null)
|
|
183
185
|
const mcpManagerRef = useRef<McpManager | null>(null)
|
|
186
|
+
const savePromptShownRef = useRef<boolean>(false)
|
|
184
187
|
|
|
185
188
|
useEffect(() => { rowsRef.current = rows }, [rows])
|
|
186
189
|
useEffect(() => { overlayRef.current = overlay }, [overlay])
|
|
@@ -206,6 +209,29 @@ export const ChatScreen: React.FC<ChatScreenProps> = ({ config: initialConfig, o
|
|
|
206
209
|
})()
|
|
207
210
|
}, [])
|
|
208
211
|
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
if (savePromptShownRef.current) return
|
|
214
|
+
savePromptShownRef.current = true
|
|
215
|
+
void (async () => {
|
|
216
|
+
try {
|
|
217
|
+
const identity = configRef.current.identity
|
|
218
|
+
if (!identity) return
|
|
219
|
+
const [latest] = await listPublishedContinuitySnapshots(identity, 1)
|
|
220
|
+
const status = await continuityWorkingTreeStatus(identity, latest)
|
|
221
|
+
if (!localChangeStatusView(status).hasLocalChanges) return
|
|
222
|
+
if (overlayRef.current !== 'none') return
|
|
223
|
+
setIdentityOverlay({
|
|
224
|
+
initialAction: 'save-prompt',
|
|
225
|
+
existing: { address: identity.address },
|
|
226
|
+
})
|
|
227
|
+
overlayRef.current = 'identity'
|
|
228
|
+
setOverlay('identity')
|
|
229
|
+
} catch {
|
|
230
|
+
// best-effort; skip prompt on any error
|
|
231
|
+
}
|
|
232
|
+
})()
|
|
233
|
+
}, [])
|
|
234
|
+
|
|
209
235
|
useEffect(() => {
|
|
210
236
|
void (async () => {
|
|
211
237
|
try {
|
|
@@ -1107,7 +1133,7 @@ export const ChatScreen: React.FC<ChatScreenProps> = ({ config: initialConfig, o
|
|
|
1107
1133
|
})
|
|
1108
1134
|
overlayRef.current = 'identity'
|
|
1109
1135
|
setOverlay('identity')
|
|
1110
|
-
pushNote('opening snapshot
|
|
1136
|
+
pushNote('opening snapshot signature.', 'dim')
|
|
1111
1137
|
return
|
|
1112
1138
|
}
|
|
1113
1139
|
overlayRef.current = 'none'
|
|
@@ -1363,8 +1389,8 @@ export const ChatScreen: React.FC<ChatScreenProps> = ({ config: initialConfig, o
|
|
|
1363
1389
|
|
|
1364
1390
|
const contextLine = `${config.provider} · ${formatModelDisplayName(config.provider, config.model, { maxLength: 24 })} · ${compressHome(cwd)}`
|
|
1365
1391
|
const tipLine = streaming
|
|
1366
|
-
? '
|
|
1367
|
-
: '
|
|
1392
|
+
? 'Tip: You can keep typing and press enter to queue the next message · shift+enter for newline'
|
|
1393
|
+
: 'Tip: type /help to get started · shift+enter for newline'
|
|
1368
1394
|
|
|
1369
1395
|
const placeholderHints = useMemo(() => {
|
|
1370
1396
|
if (compactionUi) return ['compaction in progress · esc to cancel']
|
|
@@ -1373,30 +1399,24 @@ export const ChatScreen: React.FC<ChatScreenProps> = ({ config: initialConfig, o
|
|
|
1373
1399
|
|
|
1374
1400
|
const exitHint = exitState.pending ? 'ctrl+c again to quit' : null
|
|
1375
1401
|
const runtimeModeLabel = sessionModeLabel(mode)
|
|
1376
|
-
const modeColor =
|
|
1377
|
-
mode === 'plan'
|
|
1378
|
-
? theme.accentLavender
|
|
1379
|
-
: mode === 'accept-edits'
|
|
1380
|
-
? theme.accentPeach
|
|
1381
|
-
: theme.accentMint
|
|
1382
1402
|
const footerRight = (
|
|
1383
1403
|
<Box flexDirection="row">
|
|
1384
1404
|
{exitHint ? (
|
|
1385
1405
|
<>
|
|
1386
|
-
<Text color={theme.
|
|
1406
|
+
<Text color={theme.text}>{exitHint}</Text>
|
|
1387
1407
|
<Text color={theme.dim}> · </Text>
|
|
1388
1408
|
</>
|
|
1389
1409
|
) : null}
|
|
1390
1410
|
{runtimeModeLabel ? (
|
|
1391
1411
|
<>
|
|
1392
|
-
<Text
|
|
1412
|
+
<Text bold>{runtimeModeLabel}</Text>
|
|
1393
1413
|
<Text color={theme.dim}> (</Text>
|
|
1394
|
-
<Text color={theme.
|
|
1414
|
+
<Text color={theme.accentPeriwinkle}>shift+tab to cycle</Text>
|
|
1395
1415
|
<Text color={theme.dim}>) · </Text>
|
|
1396
1416
|
</>
|
|
1397
1417
|
) : (
|
|
1398
1418
|
<>
|
|
1399
|
-
<Text color={theme.
|
|
1419
|
+
<Text color={theme.accentPeriwinkle}>shift+tab to cycle</Text>
|
|
1400
1420
|
<Text color={theme.dim}> · </Text>
|
|
1401
1421
|
</>
|
|
1402
1422
|
)}
|
|
@@ -64,20 +64,20 @@ export const ContextLimitView: React.FC<ContextLimitViewProps> = ({
|
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
|
-
<Box flexDirection="column" borderStyle="round" borderColor={theme.
|
|
68
|
-
<Text color={theme.
|
|
67
|
+
<Box flexDirection="column" borderStyle="round" borderColor={theme.accentPeriwinkle} paddingX={1}>
|
|
68
|
+
<Text color={theme.accentPeriwinkle} bold>context limit</Text>
|
|
69
69
|
<Text color={theme.dim}>
|
|
70
70
|
{`Context ${usage.percent}% · ~${formatTokens(usage.usedTokens)} / ${formatTokens(usage.windowTokens)} tokens (${usage.source}).`}
|
|
71
71
|
</Text>
|
|
72
72
|
{usage.percent >= 100 ? (
|
|
73
|
-
<Text color={theme.
|
|
73
|
+
<Text color={theme.accentPeriwinkle}>
|
|
74
74
|
This transcript is over the selected model's estimated window. You can still send, but summarizing first is safer.
|
|
75
75
|
</Text>
|
|
76
76
|
) : null}
|
|
77
77
|
<Text color={theme.textSubtle}>{`Pending: ${promptPreview || '(empty)'}`}</Text>
|
|
78
78
|
<Box flexDirection="column" marginTop={1}>
|
|
79
79
|
{CONTEXT_LIMIT_OPTIONS.map((option, index) => (
|
|
80
|
-
<Text key={option.action} color={index === selected ? theme.
|
|
80
|
+
<Text key={option.action} color={index === selected ? theme.accentPeriwinkle : theme.text}>
|
|
81
81
|
{index === selected ? '> ' : ' '}
|
|
82
82
|
{option.label}
|
|
83
83
|
<Text color={theme.dim}>{` · ${option.detail}`}</Text>
|
|
@@ -19,32 +19,16 @@ export const ContinuityEditReviewView: React.FC<{
|
|
|
19
19
|
onCancel: () => void
|
|
20
20
|
}> = ({ review, onSelect, onCancel }) => (
|
|
21
21
|
<Surface
|
|
22
|
-
title=
|
|
23
|
-
|
|
24
|
-
footer="enter select · esc later"
|
|
22
|
+
title={`${review.file} Updated`}
|
|
23
|
+
footer="enter select · esc dismiss"
|
|
25
24
|
>
|
|
26
|
-
<
|
|
27
|
-
<Text color={theme.accentMint}>{review.summary}</Text>
|
|
28
|
-
<Box marginTop={1} flexDirection="column">
|
|
29
|
-
<Text color={theme.textSubtle}>review file</Text>
|
|
30
|
-
<Text color={theme.text}>{review.filePath}</Text>
|
|
31
|
-
</Box>
|
|
32
|
-
{review.editorOpened && (
|
|
33
|
-
<Box marginTop={1}>
|
|
34
|
-
<Text color={theme.accentPeach}>Save with ctrl+s in your editor</Text>
|
|
35
|
-
</Box>
|
|
36
|
-
)}
|
|
37
|
-
<Box marginTop={1} flexDirection="column">
|
|
38
|
-
<Text color={theme.textSubtle}>saved locally</Text>
|
|
39
|
-
<Text color={theme.dim}>Previous version saved in identity history. /rewind does not restore identity continuity.</Text>
|
|
40
|
-
</Box>
|
|
41
|
-
</Box>
|
|
25
|
+
<Text color={theme.accentPeriwinkle}>{displayContinuityReviewText(review.summary)}</Text>
|
|
42
26
|
<Box marginTop={1}>
|
|
43
27
|
<Select<ContinuityEditReviewAction>
|
|
44
28
|
options={[
|
|
45
|
-
{ value: 'open', label: `
|
|
46
|
-
{ value: 'save-publish', label: '
|
|
47
|
-
{ value: 'later', label: '
|
|
29
|
+
{ value: 'open', label: `Open ${review.file}`, hint: 'Review in editor' },
|
|
30
|
+
{ value: 'save-publish', label: 'Save Snapshot', hint: 'Wallet signature' },
|
|
31
|
+
{ value: 'later', label: 'Dismiss', hint: 'Save later from Identity Hub' },
|
|
48
32
|
]}
|
|
49
33
|
onSubmit={onSelect}
|
|
50
34
|
onCancel={onCancel}
|
|
@@ -52,3 +36,7 @@ export const ContinuityEditReviewView: React.FC<{
|
|
|
52
36
|
</Box>
|
|
53
37
|
</Surface>
|
|
54
38
|
)
|
|
39
|
+
|
|
40
|
+
function displayContinuityReviewText(value: string): string {
|
|
41
|
+
return value ? value[0]!.toUpperCase() + value.slice(1) : value
|
|
42
|
+
}
|
package/src/chat/CopyPicker.tsx
CHANGED
package/src/chat/MessageList.tsx
CHANGED
|
@@ -3,14 +3,25 @@ import { Box, Text } from 'ink'
|
|
|
3
3
|
import { theme } from '../ui/theme.js'
|
|
4
4
|
import { ProgressBar } from '../ui/ProgressBar.js'
|
|
5
5
|
import { Spinner } from '../ui/Spinner.js'
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
export type ToolCallResult = {
|
|
8
|
+
content: string
|
|
9
|
+
summary: string
|
|
10
|
+
isError: boolean
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
export type MessageRow =
|
|
9
14
|
| { role: 'user'; id: string; content: string }
|
|
10
15
|
| { role: 'assistant'; id: string; content: string; liveTail?: string; streaming?: boolean }
|
|
11
16
|
| { role: 'thinking'; id: string; content: string; liveTail?: string; streaming?: boolean; expanded?: boolean; showCursor?: boolean }
|
|
12
|
-
| {
|
|
13
|
-
|
|
17
|
+
| {
|
|
18
|
+
role: 'tool_call'
|
|
19
|
+
id: string
|
|
20
|
+
name: string
|
|
21
|
+
summary: string
|
|
22
|
+
input?: string
|
|
23
|
+
result?: ToolCallResult
|
|
24
|
+
}
|
|
14
25
|
| { role: 'note'; id: string; kind: 'info' | 'error' | 'dim'; content: string }
|
|
15
26
|
| {
|
|
16
27
|
role: 'progress'
|
|
@@ -43,7 +54,7 @@ type InlineToken =
|
|
|
43
54
|
|
|
44
55
|
const MAX_RENDERED_MESSAGE_CHARS = 12_000
|
|
45
56
|
const MAX_RENDERED_REASONING_CHARS = 10_000
|
|
46
|
-
const ASSISTANT_ACCENT = theme.
|
|
57
|
+
const ASSISTANT_ACCENT = theme.accentPeriwinkle
|
|
47
58
|
const UNREADABLE_REASONING_TEXT = 'reasoning output was not readable text'
|
|
48
59
|
|
|
49
60
|
const MessageListInner: React.FC<MessageListProps> = ({ rows }) => (
|
|
@@ -54,18 +65,27 @@ const MessageListInner: React.FC<MessageListProps> = ({ rows }) => (
|
|
|
54
65
|
|
|
55
66
|
export const MessageList = React.memo(MessageListInner)
|
|
56
67
|
|
|
68
|
+
function isInspectableRole(role: MessageRow['role']): boolean {
|
|
69
|
+
return role === 'thinking'
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
export function toggleLatestReasoningRow(rows: MessageRow[]): MessageRow[] {
|
|
58
|
-
return
|
|
73
|
+
return toggleInspectableRow(rows)
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
export function toggleReasoningRow(rows: MessageRow[], rowId?: string): MessageRow[] {
|
|
77
|
+
return toggleInspectableRow(rows, rowId)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function toggleInspectableRow(rows: MessageRow[], rowId?: string): MessageRow[] {
|
|
62
81
|
let index = -1
|
|
63
82
|
if (rowId) {
|
|
64
|
-
index = rows.findIndex(row => row.id === rowId && row.role
|
|
83
|
+
index = rows.findIndex(row => row.id === rowId && isInspectableRole(row.role))
|
|
65
84
|
}
|
|
66
85
|
if (index === -1) {
|
|
67
86
|
for (let cursor = rows.length - 1; cursor >= 0; cursor -= 1) {
|
|
68
|
-
|
|
87
|
+
const role = rows[cursor]?.role
|
|
88
|
+
if (role && isInspectableRole(role)) {
|
|
69
89
|
index = cursor
|
|
70
90
|
break
|
|
71
91
|
}
|
|
@@ -73,10 +93,13 @@ export function toggleReasoningRow(rows: MessageRow[], rowId?: string): MessageR
|
|
|
73
93
|
}
|
|
74
94
|
if (index === -1) return rows
|
|
75
95
|
const row = rows[index]
|
|
76
|
-
if (!row
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
if (!row) return rows
|
|
97
|
+
if (row.role === 'thinking') {
|
|
98
|
+
const next = rows.slice()
|
|
99
|
+
next[index] = { ...row, expanded: !row.expanded }
|
|
100
|
+
return next
|
|
101
|
+
}
|
|
102
|
+
return rows
|
|
80
103
|
}
|
|
81
104
|
|
|
82
105
|
const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
@@ -90,7 +113,7 @@ const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
|
90
113
|
) : null}
|
|
91
114
|
{lines.map((line, i) => (
|
|
92
115
|
<Text key={i}>
|
|
93
|
-
<Text color={i === 0 ? theme.
|
|
116
|
+
<Text color={i === 0 ? theme.accentPeriwinkle : theme.dim}>{i === 0 ? '> ' : ' '}</Text>
|
|
94
117
|
<Text color={theme.textSubtle}>{line}</Text>
|
|
95
118
|
</Text>
|
|
96
119
|
))}
|
|
@@ -115,7 +138,7 @@ const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
|
115
138
|
return (
|
|
116
139
|
<Box flexDirection="column" marginTop={1} borderStyle="round" borderColor={borderColor} paddingX={1}>
|
|
117
140
|
<Text>
|
|
118
|
-
<Text color={theme.
|
|
141
|
+
<Text color={theme.accentPeriwinkle} bold>reasoning</Text>
|
|
119
142
|
<Text color={theme.dim}> · expanded · alt+t collapse</Text>
|
|
120
143
|
</Text>
|
|
121
144
|
<ReasoningBody content={text} showCursor={showCursor} />
|
|
@@ -125,7 +148,7 @@ const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
|
125
148
|
return (
|
|
126
149
|
<Box flexDirection="column" marginTop={1} borderStyle="round" borderColor={borderColor} paddingX={1}>
|
|
127
150
|
<Text>
|
|
128
|
-
<Text color={theme.
|
|
151
|
+
<Text color={theme.accentPeriwinkle} bold>reasoning</Text>
|
|
129
152
|
<Text color={theme.dim}> · collapsed · alt+t inspect</Text>
|
|
130
153
|
</Text>
|
|
131
154
|
<Text color={theme.textSubtle}>
|
|
@@ -136,39 +159,27 @@ const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
|
136
159
|
)
|
|
137
160
|
}
|
|
138
161
|
|
|
139
|
-
if (row.role === '
|
|
162
|
+
if (row.role === 'tool_call') {
|
|
163
|
+
const result = row.result
|
|
164
|
+
const inputPreview = row.input ? truncateToolInputForLine(row.input, 60) : ''
|
|
140
165
|
return (
|
|
141
|
-
<Box
|
|
142
|
-
<Text
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
<Box
|
|
153
|
-
flexDirection="column"
|
|
154
|
-
marginTop={1}
|
|
155
|
-
borderStyle="round"
|
|
156
|
-
borderColor={row.isError ? '#a84c4c' : theme.border}
|
|
157
|
-
paddingX={1}
|
|
158
|
-
>
|
|
159
|
-
<Text color={row.isError ? '#e87070' : theme.accentSecondary} bold>{`result · ${row.name}`}</Text>
|
|
160
|
-
<Text color={theme.dim}>{row.summary}</Text>
|
|
161
|
-
{row.isError ? (
|
|
162
|
-
<Text color="#f1b0b0">{row.content}</Text>
|
|
163
|
-
) : hideContent || !row.content ? null : (
|
|
164
|
-
<AssistantBody content={row.content} />
|
|
165
|
-
)}
|
|
166
|
+
<Box marginTop={1}>
|
|
167
|
+
<Text>
|
|
168
|
+
<Text color={theme.dim}>{'· '}</Text>
|
|
169
|
+
<Text color={theme.accentPeriwinkle} bold>{row.name}</Text>
|
|
170
|
+
{inputPreview ? <Text color={theme.textSubtle}>{` ${inputPreview}`}</Text> : null}
|
|
171
|
+
{result ? (
|
|
172
|
+
<Text color={result.isError ? theme.accentError : theme.dim}>{` ${result.summary}`}</Text>
|
|
173
|
+
) : (
|
|
174
|
+
<Text color={theme.dim}>{' running…'}</Text>
|
|
175
|
+
)}
|
|
176
|
+
</Text>
|
|
166
177
|
</Box>
|
|
167
178
|
)
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
if (row.role === 'note') {
|
|
171
|
-
const color = row.kind === 'error' ?
|
|
182
|
+
const color = row.kind === 'error' ? theme.accentError : row.kind === 'dim' ? theme.dim : theme.accentPeriwinkle
|
|
172
183
|
return (
|
|
173
184
|
<Box marginTop={1}>
|
|
174
185
|
<Text color={color}>{row.content}</Text>
|
|
@@ -178,7 +189,7 @@ const RowViewInner: React.FC<{ row: MessageRow }> = ({ row }) => {
|
|
|
178
189
|
|
|
179
190
|
return (
|
|
180
191
|
<Box flexDirection="column" marginTop={1}>
|
|
181
|
-
<Text color={theme.
|
|
192
|
+
<Text color={theme.accentPeriwinkle} bold>{row.title}</Text>
|
|
182
193
|
{row.indeterminate ? (
|
|
183
194
|
<ProgressSpinner row={row} />
|
|
184
195
|
) : (
|
|
@@ -198,7 +209,13 @@ const ProgressSpinner: React.FC<{ row: Extract<MessageRow, { role: 'progress' }>
|
|
|
198
209
|
}
|
|
199
210
|
|
|
200
211
|
export function reasoningBorderColor(row: Extract<MessageRow, { role: 'thinking' }>): string {
|
|
201
|
-
return row.streaming ? theme.
|
|
212
|
+
return row.streaming ? theme.accentPeriwinkle : theme.border
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function truncateToolInputForLine(input: string, max: number): string {
|
|
216
|
+
const flat = input.replace(/\s+/g, ' ').trim()
|
|
217
|
+
if (flat.length <= max) return flat
|
|
218
|
+
return `${flat.slice(0, Math.max(1, max - 1))}…`
|
|
202
219
|
}
|
|
203
220
|
|
|
204
221
|
export function reasoningCursorVisible(row: Extract<MessageRow, { role: 'thinking' }>): boolean {
|
|
@@ -370,7 +387,7 @@ const InlineText: React.FC<{ text: string; color: string; bold?: boolean }> = ({
|
|
|
370
387
|
const ThinkingCursor: React.FC<{ active: boolean; hasPreview: boolean }> = ({ active, hasPreview }) => {
|
|
371
388
|
if (!active) return null
|
|
372
389
|
return (
|
|
373
|
-
<Text color={theme.
|
|
390
|
+
<Text color={theme.accentPeriwinkle}>
|
|
374
391
|
{hasPreview ? ' ' : ''}
|
|
375
392
|
<StreamCursor active />
|
|
376
393
|
</Text>
|
|
@@ -488,7 +505,7 @@ function parseMarkdownBlocks(markdown: string): MarkdownBlock[] {
|
|
|
488
505
|
return blocks
|
|
489
506
|
}
|
|
490
507
|
|
|
491
|
-
function codeAccent(
|
|
508
|
+
function codeAccent(_lang: string | null): string {
|
|
492
509
|
return ASSISTANT_ACCENT
|
|
493
510
|
}
|
|
494
511
|
|
|
@@ -23,23 +23,23 @@ export const PermissionPrompt: React.FC<PermissionPromptProps> = ({ request, onD
|
|
|
23
23
|
>
|
|
24
24
|
{request.kind === 'private-continuity-edit' ? (
|
|
25
25
|
<Box flexDirection="column" marginBottom={1}>
|
|
26
|
-
<Text color={theme.
|
|
26
|
+
<Text color={theme.accentPeriwinkle}>{displayPermissionText(request.changeSummary)}</Text>
|
|
27
27
|
<Text color={theme.textSubtle}>
|
|
28
|
-
Not reversible by /rewind. A private identity-history snapshot is saved before
|
|
28
|
+
Not reversible by /rewind. A private identity-history snapshot is saved before writing.
|
|
29
29
|
</Text>
|
|
30
30
|
<Box marginTop={1}>
|
|
31
31
|
<Text color={theme.textSubtle}>target</Text>
|
|
32
32
|
</Box>
|
|
33
33
|
<Text color={theme.text}>{request.file}</Text>
|
|
34
34
|
<Box marginTop={1}>
|
|
35
|
-
<Text color={theme.
|
|
35
|
+
<Text color={theme.accentPeriwinkle}>diff</Text>
|
|
36
36
|
</Box>
|
|
37
37
|
<Text color={theme.text}>{request.diff}</Text>
|
|
38
38
|
</Box>
|
|
39
39
|
) : null}
|
|
40
40
|
{request.kind === 'private-continuity-read' ? (
|
|
41
41
|
<Box flexDirection="column" marginBottom={1}>
|
|
42
|
-
<Text color={theme.
|
|
42
|
+
<Text color={theme.accentPeriwinkle}>read private {request.file}</Text>
|
|
43
43
|
<Text color={theme.textSubtle}>This reveals private identity continuity to the model for this turn.</Text>
|
|
44
44
|
<Box marginTop={1}>
|
|
45
45
|
<Text color={theme.textSubtle}>range</Text>
|
|
@@ -49,20 +49,20 @@ export const PermissionPrompt: React.FC<PermissionPromptProps> = ({ request, onD
|
|
|
49
49
|
) : null}
|
|
50
50
|
{request.kind === 'edit' || request.kind === 'write' || request.kind === 'delete' ? (
|
|
51
51
|
<Box flexDirection="column" marginBottom={1}>
|
|
52
|
-
<Text color={theme.
|
|
52
|
+
<Text color={theme.accentPeriwinkle}>{displayPermissionText(request.changeSummary)}</Text>
|
|
53
53
|
<Box marginTop={1}>
|
|
54
54
|
<Text color={theme.textSubtle}>before</Text>
|
|
55
55
|
</Box>
|
|
56
56
|
<Text color={theme.textSubtle}>{request.before || '(empty)'}</Text>
|
|
57
57
|
<Box marginTop={1}>
|
|
58
|
-
<Text color={theme.
|
|
58
|
+
<Text color={theme.accentPeriwinkle}>after</Text>
|
|
59
59
|
</Box>
|
|
60
60
|
<Text color={theme.text}>{request.after || '(empty)'}</Text>
|
|
61
61
|
</Box>
|
|
62
62
|
) : null}
|
|
63
63
|
{request.kind === 'bash' && request.warning ? (
|
|
64
64
|
<Box marginBottom={1}>
|
|
65
|
-
<Text color=
|
|
65
|
+
<Text color={theme.accentError}>{request.warning}</Text>
|
|
66
66
|
</Box>
|
|
67
67
|
) : null}
|
|
68
68
|
<Select options={options} onSubmit={onDecision} onCancel={onCancel} />
|
|
@@ -127,8 +127,8 @@ export function permissionOptionsForRequest(request: PermissionRequest): Array<{
|
|
|
127
127
|
|
|
128
128
|
if (request.kind === 'private-continuity-edit') {
|
|
129
129
|
return [
|
|
130
|
-
{ value: 'allow-once', label: '
|
|
131
|
-
{ value: 'deny', label: '
|
|
130
|
+
{ value: 'allow-once', label: 'Approve Once', hint: `Apply this edit to ${request.file}` },
|
|
131
|
+
{ value: 'deny', label: 'Deny', hint: 'Keep private continuity unchanged' },
|
|
132
132
|
]
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -151,3 +151,7 @@ export function permissionOptionsForRequest(request: PermissionRequest): Array<{
|
|
|
151
151
|
{ value: 'deny', label: 'deny', hint: 'return a denial back to the model' },
|
|
152
152
|
]
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
function displayPermissionText(value: string): string {
|
|
156
|
+
return value ? value[0]!.toUpperCase() + value.slice(1) : value
|
|
157
|
+
}
|
|
@@ -70,11 +70,11 @@ export const PlanApprovalView: React.FC<PlanApprovalViewProps> = ({
|
|
|
70
70
|
const active = optionIndex === index
|
|
71
71
|
return (
|
|
72
72
|
<Box key={option.value} flexDirection="row">
|
|
73
|
-
<Text color={active ? theme.
|
|
73
|
+
<Text color={active ? theme.accentPeriwinkle : theme.dim}>
|
|
74
74
|
{active ? '> ' : ' '}
|
|
75
75
|
{optionIndex + 1}.{' '}
|
|
76
76
|
</Text>
|
|
77
|
-
<Text color={active ? theme.
|
|
77
|
+
<Text color={active ? theme.accentPeriwinkle : theme.text} bold={active}>
|
|
78
78
|
{option.label}
|
|
79
79
|
</Text>
|
|
80
80
|
</Box>
|
|
@@ -82,7 +82,7 @@ export const PlanApprovalView: React.FC<PlanApprovalViewProps> = ({
|
|
|
82
82
|
})}
|
|
83
83
|
</Box>
|
|
84
84
|
<Box flexDirection="column" marginLeft={4} flexShrink={1}>
|
|
85
|
-
<Text color={theme.
|
|
85
|
+
<Text color={theme.accentPeriwinkle} bold>{selected.title}</Text>
|
|
86
86
|
<Text color={theme.dim}>{selected.detail(contextLabel)}</Text>
|
|
87
87
|
</Box>
|
|
88
88
|
</Box>
|
package/src/chat/ResumeView.tsx
CHANGED
|
@@ -26,8 +26,6 @@ export const CLEAR_ALL_SESSIONS_VALUE = '__clear_all_sessions__'
|
|
|
26
26
|
export const ResumeView: React.FC<ResumeViewProps> = ({ currentSessionId, onResume, onClearAll, onCancel }) => {
|
|
27
27
|
const [state, setState] = useState<State>({ kind: 'loading' })
|
|
28
28
|
|
|
29
|
-
// Allow ESC to close the view during loading / error states
|
|
30
|
-
// (Select handles ESC only when it's rendered in the 'ready' state)
|
|
31
29
|
const escActive = state.kind === 'loading' || state.kind === 'error' || (state.kind === 'ready' && state.sessions.length === 0)
|
|
32
30
|
useAppInput((_input, key) => {
|
|
33
31
|
if (key.escape) onCancel()
|
|
@@ -75,7 +73,7 @@ export const ResumeView: React.FC<ResumeViewProps> = ({ currentSessionId, onResu
|
|
|
75
73
|
<Box flexDirection="column" marginBottom={1}>
|
|
76
74
|
<Text color={theme.dim}>Removes saved chats and resume context from this machine.</Text>
|
|
77
75
|
<Text color={theme.dim}>Config, identities, keys, and local models stay.</Text>
|
|
78
|
-
{state.error ? <Text color=
|
|
76
|
+
{state.error ? <Text color={theme.accentError}>{state.error}</Text> : null}
|
|
79
77
|
</Box>
|
|
80
78
|
<Select<'back' | 'clear'>
|
|
81
79
|
options={[
|
|
@@ -212,7 +210,6 @@ export function buildResumeOptions(
|
|
|
212
210
|
}
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
// Utility section sits below all session groups with a visual gap
|
|
216
213
|
options.push(manageSpacer)
|
|
217
214
|
options.push(clearOption)
|
|
218
215
|
|
package/src/chat/RewindView.tsx
CHANGED
|
@@ -312,7 +312,7 @@ function buildActionOptions(canRestoreConversation: boolean): Array<SelectOption
|
|
|
312
312
|
|
|
313
313
|
const CompactPreview: React.FC<{ entry: RewindEntry }> = ({ entry }) => (
|
|
314
314
|
<Box flexDirection="column" marginTop={1}>
|
|
315
|
-
<Text color={theme.
|
|
315
|
+
<Text color={theme.accentPeriwinkle}>{entry.relativePath}</Text>
|
|
316
316
|
<Text color={theme.dim}>{entry.promptSnippet || '(prompt snippet unavailable for older checkpoints)'}</Text>
|
|
317
317
|
</Box>
|
|
318
318
|
)
|
|
@@ -323,7 +323,7 @@ const ActionPreview: React.FC<{
|
|
|
323
323
|
canRestoreConversation: boolean
|
|
324
324
|
}> = ({ entry, selectedAction, canRestoreConversation }) => (
|
|
325
325
|
<Box flexDirection="column" marginTop={1}>
|
|
326
|
-
<Text color={theme.
|
|
326
|
+
<Text color={theme.accentPeriwinkle}>{entry.relativePath}</Text>
|
|
327
327
|
<Text color={theme.dim}>{formatTimestamp(entry.createdAt)} · {entry.changeSummary}</Text>
|
|
328
328
|
<Text color={theme.textSubtle}>
|
|
329
329
|
{selectedAction === 'both'
|
|
@@ -73,7 +73,7 @@ export function moveThroughHistory(
|
|
|
73
73
|
historyIndex: number,
|
|
74
74
|
direction: 1 | -1,
|
|
75
75
|
draftBuffer: ChatBuffer,
|
|
76
|
-
|
|
76
|
+
_preferredColumn: number | null,
|
|
77
77
|
): { preview: HistoryPreviewState; buffer: ChatBuffer } {
|
|
78
78
|
const next = historyIndex + direction
|
|
79
79
|
if (next < 0) {
|
|
@@ -52,26 +52,37 @@ export function buildBaseMessages(
|
|
|
52
52
|
|
|
53
53
|
export function sessionMessagesToRows(messages: SessionMessage[], nextRowId: () => string): MessageRow[] {
|
|
54
54
|
const restored: MessageRow[] = []
|
|
55
|
+
const toolCallByUseId = new Map<string, Extract<MessageRow, { role: 'tool_call' }>>()
|
|
55
56
|
for (const msg of messages) {
|
|
56
57
|
if (msg.role === 'user') restored.push({ role: 'user', id: nextRowId(), content: msg.content })
|
|
57
58
|
else if (msg.role === 'assistant') restored.push({ role: 'assistant', id: nextRowId(), content: msg.content })
|
|
58
59
|
else if (msg.role === 'tool_use') {
|
|
59
|
-
|
|
60
|
-
role: '
|
|
60
|
+
const row: Extract<MessageRow, { role: 'tool_call' }> = {
|
|
61
|
+
role: 'tool_call',
|
|
61
62
|
id: nextRowId(),
|
|
62
63
|
name: msg.name,
|
|
63
64
|
summary: msg.name,
|
|
64
65
|
input: summarizeToolInput(msg.input),
|
|
65
|
-
}
|
|
66
|
+
}
|
|
67
|
+
restored.push(row)
|
|
68
|
+
toolCallByUseId.set(msg.toolUseId, row)
|
|
66
69
|
} else if (msg.role === 'tool_result') {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
70
|
+
const isError = Boolean(msg.isError)
|
|
71
|
+
const summary = isError ? `${msg.name} failed` : `${msg.name} completed`
|
|
72
|
+
const content = toolResultContentForRow(msg.name, msg.content, msg.isError)
|
|
73
|
+
const existing = toolCallByUseId.get(msg.toolUseId)
|
|
74
|
+
if (existing) {
|
|
75
|
+
existing.result = { content, summary, isError }
|
|
76
|
+
existing.name = msg.name
|
|
77
|
+
} else {
|
|
78
|
+
restored.push({
|
|
79
|
+
role: 'tool_call',
|
|
80
|
+
id: nextRowId(),
|
|
81
|
+
name: msg.name,
|
|
82
|
+
summary: msg.name,
|
|
83
|
+
result: { content, summary, isError },
|
|
84
|
+
})
|
|
85
|
+
}
|
|
75
86
|
}
|
|
76
87
|
}
|
|
77
88
|
return restored
|
|
@@ -49,7 +49,7 @@ export function resolveModelSelection(
|
|
|
49
49
|
model: selection.model,
|
|
50
50
|
baseUrl,
|
|
51
51
|
},
|
|
52
|
-
notice: `
|
|
52
|
+
notice: `Local Hugging Face model ready. Now using ${formatModelDisplayName('llamacpp', selection.model, { maxLength: 64 })}.`,
|
|
53
53
|
tone: 'info',
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -69,7 +69,7 @@ export function resolveModelSelection(
|
|
|
69
69
|
return {
|
|
70
70
|
kind: 'switch',
|
|
71
71
|
config: nextConfig,
|
|
72
|
-
notice: `${selection.keyJustSet ? `${selection.provider} key saved.` : `${selection.provider} ready.`}
|
|
72
|
+
notice: `${selection.keyJustSet ? `${selection.provider} key saved.` : `${selection.provider} ready.`} Now using ${nextConfig.provider} · ${formatModelDisplayName(nextConfig.provider, nextConfig.model, { maxLength: 64 })}.`,
|
|
73
73
|
tone: 'dim',
|
|
74
74
|
}
|
|
75
75
|
}
|