ethagent 1.0.8 → 1.1.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 (30) hide show
  1. package/package.json +1 -2
  2. package/src/chat/ChatScreen.tsx +5 -4
  3. package/src/chat/ContinuityEditReviewView.tsx +3 -3
  4. package/src/chat/commands.ts +5 -5
  5. package/src/cli/ResetConfirmView.tsx +12 -13
  6. package/src/cli/main.tsx +27 -30
  7. package/src/cli/reset.ts +7 -8
  8. package/src/cli/updateNotice.ts +52 -0
  9. package/src/identity/continuity/envelope.ts +11 -5
  10. package/src/identity/continuity/storage.ts +1 -1
  11. package/src/identity/hub/IdentityHub.tsx +6 -7
  12. package/src/identity/hub/identityHubModel.ts +12 -12
  13. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +39 -34
  14. package/src/identity/hub/screens/CreateFlow.tsx +4 -4
  15. package/src/identity/hub/screens/DetailsScreen.tsx +2 -2
  16. package/src/identity/hub/screens/EditProfileFlow.tsx +5 -5
  17. package/src/identity/hub/screens/ErrorScreen.tsx +2 -2
  18. package/src/identity/hub/screens/IdentitySummary.tsx +32 -12
  19. package/src/identity/hub/screens/MenuScreen.tsx +17 -17
  20. package/src/identity/hub/screens/NetworkScreen.tsx +7 -3
  21. package/src/identity/hub/screens/RecoveryConfirmScreen.tsx +9 -7
  22. package/src/identity/hub/screens/RestoreFlow.tsx +2 -2
  23. package/src/identity/hub/screens/StorageCredentialScreen.tsx +5 -5
  24. package/src/identity/wallet/wallet-page/wallet.html +1095 -966
  25. package/src/models/ModelPicker.tsx +71 -71
  26. package/src/models/llamacppPreflight.ts +1 -1
  27. package/src/models/modelPickerOptions.ts +22 -22
  28. package/src/storage/factoryReset.ts +17 -20
  29. package/src/tools/privateContinuityEditTool.ts +1 -1
  30. package/src/ui/BrandSplash.tsx +7 -4
@@ -167,8 +167,8 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
167
167
 
168
168
  if (state.kind === 'loading') {
169
169
  return (
170
- <Surface title={contextFit ? 'Switch to Larger-Context Model' : 'Switch Provider / Model'} subtitle="Loading providers and models.">
171
- <Spinner label="loading providers..." />
170
+ <Surface title={contextFit ? 'Switch to Larger-Context Model' : 'Switch Provider · Model'} subtitle="Loading providers and models.">
171
+ <Spinner label="Loading providers..." />
172
172
  </Surface>
173
173
  )
174
174
  }
@@ -178,10 +178,10 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
178
178
  <Surface
179
179
  title="Add Local Model"
180
180
  subtitle={LOCAL_MODEL_LINK_EXAMPLE}
181
- footer="enter checks link · esc returns to picker"
181
+ footer="enter check link · esc back"
182
182
  >
183
183
  <TextInput
184
- label="model link"
184
+ label="Model Link"
185
185
  placeholder={LOCAL_MODEL_LINK_HINT}
186
186
  onSubmit={value => void inspectHfInput(state, value, setState)}
187
187
  onCancel={() => setState({ kind: 'list', data: state.data })}
@@ -194,19 +194,19 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
194
194
  if (state.kind === 'hfLoading') {
195
195
  return (
196
196
  <Surface title="Checking Model Link" subtitle={state.input}>
197
- <Spinner label="reading model page..." />
197
+ <Spinner label="Reading model page..." />
198
198
  </Surface>
199
199
  )
200
200
  }
201
201
 
202
202
  if (state.kind === 'hfFilePick') {
203
203
  const options = buildHfFileOptions(state.repo, state.files, state.data.machineSpec, state.data.hfModels.map(model => model.id))
204
- const recommendedIndex = Math.max(0, options.findIndex(option => option.subtext?.includes('recommended')))
204
+ const recommendedIndex = Math.max(0, options.findIndex(option => option.subtext?.includes('Recommended')))
205
205
  return (
206
206
  <Surface
207
207
  title="Choose a Compatible File"
208
208
  subtitle={`${state.repo.repoId} has ${state.files.length} compatible local model file${state.files.length === 1 ? '' : 's'}.`}
209
- footer="enter selects · esc returns to link input"
209
+ footer="enter select · esc back"
210
210
  >
211
211
  <Select
212
212
  options={options}
@@ -228,7 +228,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
228
228
  <Surface
229
229
  title="Review Model Link"
230
230
  subtitle="Only download models from creators you trust. Check the license and source before continuing."
231
- footer="enter selects · esc returns to picker"
231
+ footer="enter select · esc back"
232
232
  tone={plan.review.risk === 'high' ? 'error' : plan.review.risk === 'medium' ? 'muted' : 'primary'}
233
233
  >
234
234
  <Box flexDirection="column" marginBottom={1}>
@@ -243,9 +243,9 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
243
243
  </Box>
244
244
  <Select<'download' | 'pick' | 'cancel'>
245
245
  options={[
246
- { value: 'download', label: 'download this model', disabled: !canDownload },
247
- { value: 'pick', label: 'pick another file' },
248
- { value: 'cancel', label: 'cancel' },
246
+ { value: 'download', label: 'Download This Model', disabled: !canDownload },
247
+ { value: 'pick', label: 'Pick Another File' },
248
+ { value: 'cancel', label: 'Cancel' },
249
249
  ]}
250
250
  onSubmit={choice => {
251
251
  if (choice === 'download') void startHfDownload(state, setState, hfAbortRef, onPick)
@@ -276,12 +276,12 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
276
276
  <Surface
277
277
  title={state.alreadyInstalled ? 'Model Already Downloaded' : 'Model Ready'}
278
278
  subtitle={state.model.displayName}
279
- footer="enter selects · esc returns to picker"
279
+ footer="enter select · esc back"
280
280
  >
281
281
  <Select<'use' | 'back'>
282
282
  options={[
283
- { value: 'use', label: 'use this model now' },
284
- { value: 'back', label: 'back to picker' },
283
+ { value: 'use', label: 'Use This Model Now' },
284
+ { value: 'back', label: 'Back To Picker' },
285
285
  ]}
286
286
  onSubmit={choice => {
287
287
  if (choice === 'use') void startAndPickHfModel(state.model, state, setState, onPick)
@@ -295,11 +295,11 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
295
295
 
296
296
  if (state.kind === 'hfError') {
297
297
  return (
298
- <Surface title="Model Link Failed" subtitle={state.message} tone="error" footer="enter selects · esc returns to picker">
298
+ <Surface title="Model Link Failed" subtitle={state.message} tone="error" footer="enter select · esc back">
299
299
  <Select<'retry' | 'back'>
300
300
  options={[
301
- { value: 'retry', label: state.input ? 'retry link' : 'download another model' },
302
- { value: 'back', label: 'back to picker' },
301
+ { value: 'retry', label: state.input ? 'Retry Link' : 'Download Another Model' },
302
+ { value: 'back', label: 'Back To Picker' },
303
303
  ]}
304
304
  onSubmit={choice => {
305
305
  if (choice === 'retry') setState({ kind: 'hfInput', data: state.data, error: state.input ? undefined : state.message })
@@ -324,7 +324,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
324
324
  role: 'option' as const,
325
325
  }))
326
326
  return (
327
- <Surface title="Uninstall Downloaded GGUF" subtitle="Choose a downloaded model file to remove." footer="enter selects · esc returns to picker">
327
+ <Surface title="Uninstall Downloaded GGUF" subtitle="Choose a downloaded model file to remove." footer="enter select · esc back">
328
328
  {options.length === 0 ? (
329
329
  <Text color={theme.dim}>No local models found.</Text>
330
330
  ) : (
@@ -345,15 +345,15 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
345
345
  if (state.kind === 'localUninstallConfirm') {
346
346
  const modelName = state.target.displayName
347
347
  return (
348
- <Surface title="Confirm Uninstall" subtitle={modelName} footer="enter selects · esc returns to model list">
348
+ <Surface title="Confirm Uninstall" subtitle={modelName} footer="enter select · esc back">
349
349
  <Box flexDirection="column" marginBottom={1}>
350
350
  <Text color={theme.dim}>{localUninstallBoundaryCopy(state.target)}</Text>
351
351
  <Text color={theme.dim}>Runner binaries are left unchanged.</Text>
352
352
  </Box>
353
353
  <Select<'confirm' | 'back'>
354
354
  options={[
355
- { value: 'confirm', label: 'uninstall local model' },
356
- { value: 'back', label: 'back' },
355
+ { value: 'confirm', label: 'Uninstall Local Model' },
356
+ { value: 'back', label: 'Back' },
357
357
  ]}
358
358
  onSubmit={choice => {
359
359
  if (choice === 'confirm') void uninstallLocalModel(state, setState)
@@ -378,9 +378,9 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
378
378
 
379
379
  if (state.kind === 'localUninstallDone') {
380
380
  return (
381
- <Surface title="Local Model Uninstalled" subtitle={state.modelName} footer="enter returns to picker · esc closes">
381
+ <Surface title="Local Model Uninstalled" subtitle={state.modelName} footer="enter back to picker · esc close">
382
382
  <Select<'back'>
383
- options={[{ value: 'back', label: 'back to picker' }]}
383
+ options={[{ value: 'back', label: 'Back To Picker' }]}
384
384
  onSubmit={() => setState({ kind: 'list', data: state.data })}
385
385
  onCancel={() => setState({ kind: 'list', data: state.data })}
386
386
  />
@@ -390,11 +390,11 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
390
390
 
391
391
  if (state.kind === 'localUninstallError') {
392
392
  return (
393
- <Surface title="Could Not Uninstall Local Model" subtitle={state.message} tone="error" footer="enter selects · esc returns to picker">
393
+ <Surface title="Could Not Uninstall Local Model" subtitle={state.message} tone="error" footer="enter select · esc back">
394
394
  <Select<'retry' | 'back'>
395
395
  options={[
396
- { value: 'retry', label: 'try again' },
397
- { value: 'back', label: 'back to picker' },
396
+ { value: 'retry', label: 'Try Again' },
397
+ { value: 'back', label: 'Back To Picker' },
398
398
  ]}
399
399
  onSubmit={choice => {
400
400
  if (choice === 'retry') void uninstallLocalModel({ kind: 'localUninstallConfirm', data: state.data, target: state.target }, setState)
@@ -411,7 +411,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
411
411
  <Surface
412
412
  title="Install Local Runner"
413
413
  subtitle="This model is downloaded. Install the local runner once to start it here."
414
- footer="enter selects · esc returns to picker"
414
+ footer="enter select · esc back"
415
415
  >
416
416
  <Box flexDirection="column" marginBottom={1}>
417
417
  <Text color={theme.dim}>Ethagent tried to start {friendlyFileName(state.model.filename)} automatically.</Text>
@@ -420,10 +420,10 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
420
420
  </Box>
421
421
  <Select<'install' | 'path' | 'back' | 'download'>
422
422
  options={[
423
- { value: 'install', label: 'install local runner' },
424
- { value: 'path', label: 'use existing runner path' },
425
- { value: 'back', label: 'back to picker' },
426
- { value: 'download', label: 'add another local model' },
423
+ { value: 'install', label: 'Install Local Runner' },
424
+ { value: 'path', label: 'Use Existing Runner Path' },
425
+ { value: 'back', label: 'Back To Picker' },
426
+ { value: 'download', label: 'Add Another Local Model' },
427
427
  ]}
428
428
  onSubmit={choice => {
429
429
  if (choice === 'download') setState({ kind: 'hfInput', data: state.data })
@@ -449,7 +449,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
449
449
  if (state.kind === 'localRunnerInstallFail') {
450
450
  const options = buildRunnerRecoveryOptions(state.result)
451
451
  return (
452
- <Surface title="Runner Setup Needs Attention" subtitle={state.result.message} tone="error" footer="enter selects · esc returns to picker">
452
+ <Surface title="Runner Setup Needs Attention" subtitle={state.result.message} tone="error" footer="enter select · esc back">
453
453
  <Select<'retry' | 'build' | 'path' | 'back'>
454
454
  options={options}
455
455
  onSubmit={choice => {
@@ -469,7 +469,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
469
469
  <Surface
470
470
  title="Runner Path"
471
471
  subtitle="Paste the full path to llama-server."
472
- footer="enter saves · esc returns to install"
472
+ footer="enter save · esc back"
473
473
  >
474
474
  {state.submitting ? (
475
475
  <Spinner label="checking runner path..." />
@@ -489,20 +489,20 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
489
489
  if (state.kind === 'localRunnerStarting') {
490
490
  return (
491
491
  <Surface title="Starting Local Model" subtitle={state.model.displayName}>
492
- <ElapsedSpinner startedAt={state.startedAt} label="starting local runner" />
492
+ <ElapsedSpinner startedAt={state.startedAt} label="Starting local runner" />
493
493
  </Surface>
494
494
  )
495
495
  }
496
496
 
497
497
  if (state.kind === 'localRunnerStartFail') {
498
498
  return (
499
- <Surface title="Local Model Failed to Start" subtitle={localRunnerStartFailureSubtitle(state.result)} tone="error" footer="enter selects · esc returns to picker">
499
+ <Surface title="Local Model Failed to Start" subtitle={localRunnerStartFailureSubtitle(state.result)} tone="error" footer="enter select · esc back">
500
500
  <Select<'retry' | 'path' | 'install' | 'back'>
501
501
  options={[
502
- { value: 'retry', label: 'try again' },
503
- { value: 'path', label: 'use existing runner path' },
504
- { value: 'install', label: 'install local runner' },
505
- { value: 'back', label: 'back to picker' },
502
+ { value: 'retry', label: 'Try Again' },
503
+ { value: 'path', label: 'Use Existing Runner Path' },
504
+ { value: 'install', label: 'Install Local Runner' },
505
+ { value: 'back', label: 'Back To Picker' },
506
506
  ]}
507
507
  onSubmit={choice => {
508
508
  if (choice === 'retry') void startAndPickHfModel(state.model, { kind: 'hfDone', data: state.data, model: state.model }, setState, onPick)
@@ -522,7 +522,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
522
522
  <Surface
523
523
  title={`${capitalize(action)} ${provider} API Key`}
524
524
  subtitle="Stored in your OS keyring when available; never written to config in plaintext."
525
- footer="enter saves · esc returns to picker"
525
+ footer="enter save · esc back"
526
526
  >
527
527
  {submitting ? (
528
528
  <Spinner label={`saving ${provider} key...`} />
@@ -546,16 +546,16 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
546
546
  <Surface
547
547
  title={`${capitalize(provider)} API Key`}
548
548
  subtitle="Manage the stored key for this provider."
549
- footer="enter selects · esc returns to picker"
549
+ footer="enter select · esc back"
550
550
  >
551
551
  {submitting ? (
552
552
  <Spinner label={`removing ${provider} key...`} />
553
553
  ) : (
554
554
  <Select
555
555
  options={[
556
- { value: 'edit', label: 'replace stored api key' },
557
- { value: 'delete', label: 'remove stored api key' },
558
- { value: 'cancel', label: 'back' },
556
+ { value: 'edit', label: 'Replace Stored API Key' },
557
+ { value: 'delete', label: 'Remove Stored API Key' },
558
+ { value: 'cancel', label: 'Back' },
559
559
  ]}
560
560
  onSubmit={(value) => {
561
561
  if (value === 'edit') {
@@ -590,7 +590,7 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
590
590
  <Surface
591
591
  title={`${capitalize(state.provider)} Full Catalog`}
592
592
  subtitle={contextFit ? contextFitSubtitle(contextFit) : 'All discovered models for this provider'}
593
- footer="enter selects · esc returns to picker"
593
+ footer="enter select · esc back"
594
594
  >
595
595
  <Select
596
596
  options={options}
@@ -608,20 +608,20 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
608
608
 
609
609
  if (state.kind === 'localCatalogLoading') {
610
610
  return (
611
- <Surface title="view full catalog" subtitle="loading files from configured hugging face repo.">
612
- <Spinner label="reading hugging face files..." />
611
+ <Surface title="View Full Catalog" subtitle="Loading curated local GGUF files.">
612
+ <Spinner label="Reading Hugging Face files..." />
613
613
  </Surface>
614
614
  )
615
615
  }
616
616
 
617
617
  if (state.kind === 'localCatalogError') {
618
618
  return (
619
- <Surface title="view full catalog failed" subtitle={state.message} tone="error" footer="enter selects · esc returns to picker">
619
+ <Surface title="Catalog Failed" subtitle={state.message} tone="error" footer="enter select · esc back">
620
620
  <Select<'retry' | 'paste' | 'back'>
621
621
  options={[
622
- { value: 'retry', label: 'retry catalog' },
623
- { value: 'paste', label: 'paste a GGUF link' },
624
- { value: 'back', label: 'back to picker' },
622
+ { value: 'retry', label: 'Retry Catalog' },
623
+ { value: 'paste', label: 'Paste GGUF Link' },
624
+ { value: 'back', label: 'Back To Picker' },
625
625
  ]}
626
626
  onSubmit={choice => {
627
627
  if (choice === 'retry') void openLocalCatalog(state.data, setState)
@@ -639,9 +639,9 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
639
639
  const initialIndex = localModelOptionIndex(options, currentProvider, currentModel)
640
640
  return (
641
641
  <Surface
642
- title="view full catalog"
643
- subtitle="one recommendation for this machine + install status"
644
- footer="enter selects · esc returns to picker"
642
+ title="View Full Catalog"
643
+ subtitle="Curated local GGUF files with recommendation and install status."
644
+ footer="enter select · esc back"
645
645
  >
646
646
  <Select
647
647
  options={options}
@@ -660,9 +660,9 @@ export const ModelPicker: React.FC<ModelPickerProps> = ({
660
660
 
661
661
  return (
662
662
  <Surface
663
- title={contextFit ? 'Switch to Larger-Context Model' : 'Switch Provider / Model'}
664
- subtitle={contextFit ? contextFitSubtitle(contextFit) : 'Downloaded GGUF files + cloud providers'}
665
- footer="enter selects · esc closes · /models lists installed models"
663
+ title={contextFit ? 'Switch to Larger-Context Model' : 'Switch Provider · Model'}
664
+ subtitle={contextFit ? contextFitSubtitle(contextFit) : 'Downloaded GGUF files · cloud providers'}
665
+ footer="enter select · esc close · /models lists installed models"
666
666
  >
667
667
  <Select
668
668
  options={options}
@@ -798,7 +798,7 @@ function buildCatalogOptions(
798
798
  if (!catalog || catalog.entries.length === 0) {
799
799
  return [{
800
800
  value: `hdr:catalog-empty:${provider}`,
801
- label: 'no models found',
801
+ label: 'No Models Found',
802
802
  disabled: true,
803
803
  role: 'notice',
804
804
  prefix: 'note',
@@ -953,8 +953,8 @@ export function buildHfFileOptions(
953
953
  return ordered.map(item => {
954
954
  const size = item.file.sizeBytes ? formatBytes(item.file.sizeBytes) : ''
955
955
  const indicators = [
956
- item.file.filename === recommended ? 'recommended' : '',
957
- installed.has(localModelId(repo.repoId, item.file.filename)) ? 'installed' : '',
956
+ item.file.filename === recommended ? 'Recommended' : '',
957
+ installed.has(localModelId(repo.repoId, item.file.filename)) ? 'Installed' : '',
958
958
  ]
959
959
  return {
960
960
  value: item.file.filename,
@@ -972,17 +972,17 @@ function buildRunnerRecoveryOptions(
972
972
  if (result.recovery.includes('source-build')) {
973
973
  options.push({
974
974
  value: 'build',
975
- label: 'build local runner',
976
- hint: 'uses git and cmake if installed',
975
+ label: 'Build Local Runner',
976
+ hint: 'Uses git and CMake if installed',
977
977
  })
978
978
  }
979
979
  if (result.recovery.includes('runner-path')) {
980
- options.push({ value: 'path', label: 'use existing runner path' })
980
+ options.push({ value: 'path', label: 'Use Existing Runner Path' })
981
981
  }
982
982
  if (result.recovery.includes('retry-install')) {
983
- options.push({ value: 'retry', label: 'retry automatic install' })
983
+ options.push({ value: 'retry', label: 'Retry Automatic Install' })
984
984
  }
985
- options.push({ value: 'back', label: 'back to picker' })
985
+ options.push({ value: 'back', label: 'Back To Picker' })
986
986
  return options
987
987
  }
988
988
 
@@ -1256,7 +1256,7 @@ async function runRunnerSetup(
1256
1256
  const startedAt = Date.now()
1257
1257
  const initialProgress: LlamaCppInstallProgress = {
1258
1258
  phase: 'checking',
1259
- label: 'preparing local runner',
1259
+ label: 'Preparing local runner',
1260
1260
  progress: 0.04,
1261
1261
  }
1262
1262
  const updateProgress = (progress: LlamaCppInstallProgress): void => {
@@ -1373,16 +1373,16 @@ function fitColor(fit: GgufMachineFit): string {
1373
1373
  }
1374
1374
 
1375
1375
  function fitLabel(fit: GgufMachineFit, recommended: boolean): string {
1376
- if (recommended && fit !== 'too-large') return 'recommended for this machine'
1377
- if (recommended) return 'best match found; may be too large'
1376
+ if (recommended && fit !== 'too-large') return 'Recommended for this machine'
1377
+ if (recommended) return 'Best match found; may be too large'
1378
1378
  return fileFitHint(fit)
1379
1379
  }
1380
1380
 
1381
1381
  function fileFitHint(fit: GgufMachineFit): string {
1382
1382
  switch (fit) {
1383
- case 'fits': return 'fits this machine'
1384
- case 'tight': return 'may be slow or tight on memory'
1385
- case 'too-large': return 'likely too large for this machine'
1383
+ case 'fits': return 'Fits this machine'
1384
+ case 'tight': return 'May be slow or tight on memory'
1385
+ case 'too-large': return 'Likely too large for this machine'
1386
1386
  case 'unknown': return 'machine fit unknown'
1387
1387
  }
1388
1388
  }
@@ -43,7 +43,7 @@ export async function ensureLlamaCppRunnerReady(
43
43
  message: formatPreflightFailure(
44
44
  'local model is not imported',
45
45
  config.model,
46
- 'choose an imported Hugging Face GGUF model from view full catalog or add a local model file',
46
+ 'choose an imported GGUF model from View Full Catalog or Add Local Model File',
47
47
  ),
48
48
  }
49
49
  }
@@ -11,7 +11,7 @@ import type { UncensoredCatalogEntry } from './uncensoredCatalog.js'
11
11
  export type CloudProviderId = Exclude<ProviderId, 'llamacpp'>
12
12
 
13
13
  export const MODEL_PICKER_CLOUD_PROVIDERS: CloudProviderId[] = ['openai', 'anthropic', 'gemini']
14
- export const LOCAL_MODEL_LINK_HINT = 'paste a GGUF link'
14
+ export const LOCAL_MODEL_LINK_HINT = 'Paste a GGUF link'
15
15
  export const LOCAL_MODEL_LINK_EXAMPLE = 'e.g. https://huggingface.co/Qwen/Qwen3-8B-GGUF'
16
16
 
17
17
  export type LocalHfPickerModel = {
@@ -57,20 +57,20 @@ export function buildModelPickerOptions(
57
57
  ): SelectOption<string>[] {
58
58
  const options: SelectOption<string>[] = []
59
59
 
60
- options.push(sectionOption('hdr:local', 'local models'))
61
- appendHfModelOptions(options, data, context, 'added from links', 46)
62
- options.push(utilityOption('hf:download', 'add local model file', LOCAL_MODEL_LINK_HINT))
63
- options.push(utilityOption('local:catalog', 'view full catalog', 'from configured hugging face repo'))
60
+ options.push(sectionOption('hdr:local', 'Local Models'))
61
+ appendHfModelOptions(options, data, context, 'Added From Links', 46)
62
+ options.push(utilityOption('hf:download', 'Add Local Model File', LOCAL_MODEL_LINK_HINT))
63
+ options.push(utilityOption('local:catalog', 'View Full Catalog', 'Curated local GGUF files'))
64
64
  if (data.hfModels.length > 0) {
65
- options.push(utilityOption('local:uninstall', 'uninstall downloaded GGUF'))
65
+ options.push(utilityOption('local:uninstall', 'Uninstall Downloaded GGUF'))
66
66
  }
67
67
 
68
- options.push(sectionOption('hdr:cloud', 'cloud'))
68
+ options.push(sectionOption('hdr:cloud', 'Cloud'))
69
69
  for (const provider of MODEL_PICKER_CLOUD_PROVIDERS) {
70
70
  options.push(groupOption(`hdr:cloud:${provider}`, provider))
71
71
  const keySet = data.cloudKeys[provider] === true
72
72
  if (!keySet) {
73
- options.push(utilityOption(`key:set:${provider}`, 'api key · add'))
73
+ options.push(utilityOption(`key:set:${provider}`, 'API Key · Add'))
74
74
  continue
75
75
  }
76
76
 
@@ -79,14 +79,14 @@ export function buildModelPickerOptions(
79
79
  const reason = catalog.error ? ` · ${catalog.error}` : ''
80
80
  options.push(noticeOption(
81
81
  `hdr:cloud-fallback:${provider}`,
82
- `catalog unavailable${reason} · showing configured model`,
82
+ `Catalog unavailable${reason} · showing configured model`,
83
83
  CHILD_INDENT,
84
84
  ))
85
85
  }
86
86
 
87
87
  const models = orderModelsForContextFit(provider, cloudPickerModels(provider, catalog, context), context.contextFit)
88
88
  if (models.length === 0) {
89
- options.push(noticeOption(`hdr:cloud-empty:${provider}`, 'no selectable models', CHILD_INDENT))
89
+ options.push(noticeOption(`hdr:cloud-empty:${provider}`, 'No selectable models', CHILD_INDENT))
90
90
  }
91
91
  for (const model of models) {
92
92
  const active = context.currentProvider === provider && context.currentModel === model
@@ -96,8 +96,8 @@ export function buildModelPickerOptions(
96
96
  contextFitLabel(provider, model, `${displayName}${active ? ' *' : ''}`, context.contextFit),
97
97
  ))
98
98
  }
99
- options.push(utilityOption(`catalog:${provider}`, 'full catalog'))
100
- options.push(utilityOption(`key:manage:${provider}`, 'api key · manage'))
99
+ options.push(utilityOption(`catalog:${provider}`, 'Full Catalog'))
100
+ options.push(utilityOption(`key:manage:${provider}`, 'API Key · Manage'))
101
101
  }
102
102
 
103
103
  return options
@@ -109,10 +109,10 @@ export function buildLocalModelCatalogOptions(
109
109
  catalog: UncensoredCatalogEntry[] = [],
110
110
  ): SelectOption<string>[] {
111
111
  const options: SelectOption<string>[] = []
112
- options.push(sectionOption('hdr:local-catalog', 'view full catalog'))
113
- options.push(groupOption('hdr:uncensored:catalog', 'hugging face gguf files'))
112
+ options.push(sectionOption('hdr:local-catalog', 'View Full Catalog'))
113
+ options.push(groupOption('hdr:uncensored:catalog', 'Curated Local GGUF Files'))
114
114
  if (catalog.length === 0) {
115
- options.push(noticeOption('hdr:uncensored-empty', 'setup files unavailable; paste a GGUF link instead', CHILD_INDENT))
115
+ options.push(noticeOption('hdr:uncensored-empty', 'Setup files unavailable; paste a GGUF link instead', CHILD_INDENT))
116
116
  } else {
117
117
  for (const entry of catalog) {
118
118
  const id = localModelId(entry.repo.repoId, entry.file.filename)
@@ -126,18 +126,18 @@ export function buildLocalModelCatalogOptions(
126
126
  displayName,
127
127
  undefined,
128
128
  modelMetadataSubtext(`${quant} · ${formatSize(entry.file.sizeBytes ?? 0)}`, [
129
- entry.recommended ? 'recommended for this machine' : '',
130
- entry.installed ? 'installed' : '',
129
+ entry.recommended ? 'Recommended for this machine' : '',
130
+ entry.installed ? 'Installed' : '',
131
131
  ]),
132
132
  ))
133
133
  }
134
134
  }
135
135
 
136
- appendHfModelOptions(options, data, context, 'downloaded GGUF', 50)
137
- options.push(utilityOption('hf:download', 'add local model file', LOCAL_MODEL_LINK_HINT))
136
+ appendHfModelOptions(options, data, context, 'Downloaded GGUF', 50)
137
+ options.push(utilityOption('hf:download', 'Add Local Model File', LOCAL_MODEL_LINK_HINT))
138
138
 
139
139
  if (data.hfModels.length > 0) {
140
- options.push(utilityOption('local:uninstall', 'uninstall downloaded GGUF'))
140
+ options.push(utilityOption('local:uninstall', 'Uninstall Downloaded GGUF'))
141
141
  }
142
142
  return options
143
143
  }
@@ -151,7 +151,7 @@ function appendHfModelOptions(
151
151
  ): void {
152
152
  options.push(groupOption('hdr:local:hf', groupLabel))
153
153
  if (data.hfModels.length === 0) {
154
- options.push(noticeOption('hdr:hf-empty', 'no downloaded files', CHILD_INDENT))
154
+ options.push(noticeOption('hdr:hf-empty', 'No downloaded files', CHILD_INDENT))
155
155
  return
156
156
  }
157
157
 
@@ -174,7 +174,7 @@ function appendHfModelOptions(
174
174
  `hf:${id}`,
175
175
  contextFitLabel('llamacpp', id, `${active ? '* ' : ' '}${displayName}`, context.contextFit),
176
176
  undefined,
177
- modelMetadataSubtext(size, ['installed']),
177
+ modelMetadataSubtext(size, ['Installed']),
178
178
  ))
179
179
  }
180
180
  }
@@ -48,15 +48,13 @@ export async function createFactoryResetPlan(): Promise<FactoryResetPlan> {
48
48
  deletePaths,
49
49
  preservedPaths,
50
50
  preservedDescriptions: [
51
- 'Hugging Face GGUF model files under models/',
52
- 'local model registry local-models.json',
53
- 'llama.cpp runner assets under runners/',
54
- 'local runner path config local-runner.json',
55
- 'external package-installed runtimes outside ~/.ethagent',
51
+ 'Local GGUF models and metadata',
52
+ 'llama.cpp runner assets',
53
+ 'External package-installed runtimes',
56
54
  ],
57
55
  remoteDescriptions: [
58
56
  'ERC-8004 tokens and onchain records',
59
- 'IPFS-pinned encrypted snapshots and public skills metadata',
57
+ 'IPFS snapshots and public metadata',
60
58
  ],
61
59
  }
62
60
  }
@@ -91,18 +89,16 @@ export async function runFactoryReset(options: { clearSecrets?: boolean } = {}):
91
89
 
92
90
  export function formatFactoryResetPlan(plan: FactoryResetPlan): string {
93
91
  return [
94
- 'ethagent reset',
92
+ 'Ethagent Reset',
95
93
  '',
96
- 'will delete:',
97
- ...formatPaths(plan.deletePaths, plan.configDir),
94
+ 'Deletes:',
95
+ ...formatDeleteSummary(plan.deletePaths.length),
98
96
  '',
99
- 'will keep:',
100
- ...plan.preservedDescriptions.map(item => ` · ${item}`),
97
+ 'Keeps:',
98
+ ...plan.preservedDescriptions.map(item => ` - ${item}`),
101
99
  '',
102
- 'not touched:',
103
- ...plan.remoteDescriptions.map(item => ` · ${item}`),
104
- '',
105
- 'type confirm to reset this machine.',
100
+ 'Not Touched:',
101
+ ...plan.remoteDescriptions.map(item => ` - ${item}`),
106
102
  ].join('\n')
107
103
  }
108
104
 
@@ -115,11 +111,12 @@ async function readConfigEntries(configDir: string): Promise<string[]> {
115
111
  }
116
112
  }
117
113
 
118
- function formatPaths(paths: string[], configDir: string): string[] {
119
- if (paths.length === 0) return [' · no local ethagent data found']
120
- return paths
121
- .map(target => ` · ${path.relative(configDir, target) || path.basename(target)}`)
122
- .sort()
114
+ function formatDeleteSummary(count: number): string[] {
115
+ if (count === 0) return [' - No local ethagent data found']
116
+ return [
117
+ ' - Identity files, sessions, history, credentials',
118
+ ` - ${count} local path${count === 1 ? '' : 's'} under ~/.ethagent`,
119
+ ]
123
120
  }
124
121
 
125
122
  function assertInsideConfigDir(configDir: string, target: string): void {
@@ -154,7 +154,7 @@ function formatPrivateContinuityEditResult(file: 'SOUL.md' | 'MEMORY.md', fullPa
154
154
  `- File: \`identity-vault/${file}\``,
155
155
  `- Review file: \`${fullPath}\``,
156
156
  '- Open: Identity Hub > Memory and Persona',
157
- '- Publish: Identity Hub > Recovery > Publish Snapshot Now',
157
+ '- Save: Identity Hub > Recovery > Save Snapshot Now',
158
158
  '- History: previous version saved to private identity history; `/rewind` does not restore identity continuity',
159
159
  ].join('\n')
160
160
  }
@@ -113,10 +113,11 @@ const Eyes = () => {
113
113
  type SplashProps = {
114
114
  contextLine?: string
115
115
  tipLine?: string
116
+ updateNotice?: string | null
116
117
  compact?: boolean
117
118
  }
118
119
 
119
- export const BrandSplash: React.FC<SplashProps> = ({ contextLine, tipLine, compact }) => {
120
+ export const BrandSplash: React.FC<SplashProps> = ({ contextLine, tipLine, updateNotice, compact }) => {
120
121
  const [width, setWidth] = useState<number>(() => process.stdout.columns ?? 80)
121
122
 
122
123
  useEffect(() => {
@@ -138,6 +139,7 @@ export const BrandSplash: React.FC<SplashProps> = ({ contextLine, tipLine, compa
138
139
  <Text color={theme.dim}>{glyphs.tagline.trim()}</Text>
139
140
  {contextLine ? <Text color={theme.dim}>{contextLine}</Text> : null}
140
141
  {tipLine ? <Text color={theme.dim}>{tipLine}</Text> : null}
142
+ {updateNotice ? <Text color={theme.accentPeach}>{updateNotice}</Text> : null}
141
143
  </Box>
142
144
  )
143
145
  }
@@ -177,9 +179,10 @@ export const BrandSplash: React.FC<SplashProps> = ({ contextLine, tipLine, compa
177
179
  ) : (
178
180
  <Text color={theme.border}>{glyphs.frame.bottomLeft.slice(0, 1) + glyphs.frame.horizontal.repeat(w) + glyphs.frame.bottomRight}</Text>
179
181
  )}
180
- {tipLine ? (
181
- <Box marginTop={1}>
182
- <Text color={theme.dim}>{tipLine}</Text>
182
+ {tipLine || updateNotice ? (
183
+ <Box marginTop={1} flexDirection="column">
184
+ {tipLine ? <Text color={theme.dim}>{tipLine}</Text> : null}
185
+ {updateNotice ? <Text color={theme.accentPeach}>{updateNotice}</Text> : null}
183
186
  </Box>
184
187
  ) : null}
185
188
  </Box>