ei-tui 0.1.24 → 0.2.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 (98) hide show
  1. package/README.md +42 -0
  2. package/package.json +1 -1
  3. package/src/README.md +4 -11
  4. package/src/cli/README.md +4 -5
  5. package/src/cli/retrieval.ts +3 -25
  6. package/src/cli.ts +3 -7
  7. package/src/core/AGENTS.md +1 -1
  8. package/src/core/constants/built-in-facts.ts +49 -0
  9. package/src/core/constants/index.ts +1 -0
  10. package/src/core/context-utils.ts +0 -1
  11. package/src/core/embedding-service.ts +8 -0
  12. package/src/core/handlers/dedup.ts +34 -14
  13. package/src/core/handlers/heartbeat.ts +2 -3
  14. package/src/core/handlers/human-extraction.ts +95 -30
  15. package/src/core/handlers/human-matching.ts +326 -248
  16. package/src/core/handlers/index.ts +8 -6
  17. package/src/core/handlers/persona-generation.ts +8 -8
  18. package/src/core/handlers/rewrite.ts +4 -29
  19. package/src/core/handlers/utils.ts +23 -1
  20. package/src/core/heartbeat-manager.ts +2 -4
  21. package/src/core/human-data-manager.ts +5 -27
  22. package/src/core/message-manager.ts +10 -10
  23. package/src/core/orchestrators/ceremony.ts +60 -46
  24. package/src/core/orchestrators/dedup-phase.ts +11 -5
  25. package/src/core/orchestrators/human-extraction.ts +351 -207
  26. package/src/core/orchestrators/index.ts +6 -4
  27. package/src/core/orchestrators/persona-generation.ts +3 -3
  28. package/src/core/processor.ts +113 -22
  29. package/src/core/prompt-context-builder.ts +4 -6
  30. package/src/core/state/human.ts +1 -26
  31. package/src/core/state/personas.ts +2 -2
  32. package/src/core/state-manager.ts +107 -14
  33. package/src/core/tools/builtin/read-memory.ts +7 -8
  34. package/src/core/types/data-items.ts +2 -4
  35. package/src/core/types/entities.ts +6 -4
  36. package/src/core/types/enums.ts +6 -9
  37. package/src/core/types/llm.ts +2 -2
  38. package/src/core/utils/crossFind.ts +2 -5
  39. package/src/core/utils/event-windows.ts +31 -0
  40. package/src/integrations/claude-code/importer.ts +8 -4
  41. package/src/integrations/claude-code/types.ts +2 -0
  42. package/src/integrations/opencode/importer.ts +7 -3
  43. package/src/prompts/AGENTS.md +73 -1
  44. package/src/prompts/ceremony/dedup.ts +41 -7
  45. package/src/prompts/ceremony/rewrite.ts +3 -22
  46. package/src/prompts/ceremony/types.ts +3 -3
  47. package/src/prompts/generation/descriptions.ts +2 -2
  48. package/src/prompts/generation/types.ts +2 -2
  49. package/src/prompts/heartbeat/types.ts +2 -2
  50. package/src/prompts/human/event-scan.ts +122 -0
  51. package/src/prompts/human/fact-find.ts +106 -0
  52. package/src/prompts/human/fact-scan.ts +0 -2
  53. package/src/prompts/human/index.ts +17 -10
  54. package/src/prompts/human/person-match.ts +65 -0
  55. package/src/prompts/human/person-scan.ts +52 -59
  56. package/src/prompts/human/person-update.ts +241 -0
  57. package/src/prompts/human/topic-match.ts +65 -0
  58. package/src/prompts/human/topic-scan.ts +51 -71
  59. package/src/prompts/human/topic-update.ts +295 -0
  60. package/src/prompts/human/types.ts +63 -40
  61. package/src/prompts/index.ts +4 -8
  62. package/src/prompts/persona/topics-update.ts +2 -2
  63. package/src/prompts/persona/traits.ts +2 -2
  64. package/src/prompts/persona/types.ts +3 -3
  65. package/src/prompts/response/index.ts +1 -1
  66. package/src/prompts/response/sections.ts +9 -12
  67. package/src/prompts/response/types.ts +2 -3
  68. package/src/storage/embeddings.ts +1 -1
  69. package/src/storage/index.ts +1 -0
  70. package/src/storage/indexed.ts +174 -0
  71. package/src/storage/merge.ts +67 -2
  72. package/tui/src/app.tsx +7 -5
  73. package/tui/src/commands/archive.tsx +2 -2
  74. package/tui/src/commands/context.tsx +3 -4
  75. package/tui/src/commands/delete.tsx +4 -4
  76. package/tui/src/commands/dlq.ts +3 -4
  77. package/tui/src/commands/help.tsx +1 -1
  78. package/tui/src/commands/me.tsx +8 -18
  79. package/tui/src/commands/persona.tsx +2 -2
  80. package/tui/src/commands/provider.tsx +3 -5
  81. package/tui/src/commands/queue.ts +3 -4
  82. package/tui/src/commands/quotes.tsx +6 -8
  83. package/tui/src/commands/registry.ts +1 -1
  84. package/tui/src/commands/setsync.tsx +2 -2
  85. package/tui/src/commands/settings.tsx +18 -4
  86. package/tui/src/commands/spotify-auth.ts +0 -1
  87. package/tui/src/commands/tools.tsx +4 -5
  88. package/tui/src/context/ei.tsx +5 -14
  89. package/tui/src/context/overlay.tsx +17 -6
  90. package/tui/src/util/editor.ts +22 -11
  91. package/tui/src/util/persona-editor.tsx +6 -8
  92. package/tui/src/util/provider-editor.tsx +6 -8
  93. package/tui/src/util/toolkit-editor.tsx +3 -4
  94. package/tui/src/util/yaml-serializers.ts +48 -33
  95. package/src/cli/commands/traits.ts +0 -25
  96. package/src/prompts/human/item-match.ts +0 -74
  97. package/src/prompts/human/item-update.ts +0 -364
  98. package/src/prompts/human/trait-scan.ts +0 -115
@@ -77,7 +77,7 @@ export const providerCommand: Command = {
77
77
  ctx.showNotification("No providers configured. Use /provider new to create one.", "info");
78
78
  return;
79
79
  }
80
- ctx.showOverlay((hideOverlay) => (
80
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
81
81
  <ProviderListOverlay
82
82
  providers={providers}
83
83
  activeProviderKey={activeKey}
@@ -86,8 +86,7 @@ export const providerCommand: Command = {
86
86
  await setProviderOnPersona(provider.key, provider.defaultModel, ctx);
87
87
  }}
88
88
  onEdit={async (provider) => {
89
- hideOverlay();
90
- await new Promise(r => setTimeout(r, 50));
89
+ hideForEditor();
91
90
  const human = await ctx.ei.getHuman();
92
91
  const account = human.settings?.accounts?.find(a => a.id === provider.id);
93
92
  if (account) {
@@ -96,12 +95,11 @@ export const providerCommand: Command = {
96
95
  }}
97
96
  onNew={async () => {
98
97
  hideOverlay();
99
- await new Promise(r => setTimeout(r, 50));
100
98
  await createProviderViaEditor(ctx);
101
99
  }}
102
100
  onDismiss={hideOverlay}
103
101
  />
104
- ));
102
+ ), ctx.renderer);
105
103
  return;
106
104
  }
107
105
 
@@ -53,18 +53,17 @@ export const queueCommand: Command = {
53
53
  const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
54
54
 
55
55
  const shouldReEdit = await new Promise<boolean>((resolve) => {
56
- ctx.showOverlay((hideOverlay) =>
56
+ ctx.showOverlay((hideOverlay, hideForEditor) =>
57
57
  ConfirmOverlay({
58
58
  message: `YAML error:\n${errorMsg}\n\nRe-edit?`,
59
- onConfirm: () => { hideOverlay(); resolve(true); },
59
+ onConfirm: () => { hideForEditor(); resolve(true); },
60
60
  onCancel: () => { hideOverlay(); resolve(false); },
61
61
  })
62
- );
62
+ , ctx.renderer);
63
63
  });
64
64
 
65
65
  if (shouldReEdit) {
66
66
  yamlContent = result.content;
67
- await new Promise(r => setTimeout(r, 50));
68
67
  continue;
69
68
  }
70
69
 
@@ -75,12 +75,12 @@ async function openQuotesInEditor(
75
75
  });
76
76
 
77
77
  const shouldReEdit = await new Promise<boolean>((resolve) => {
78
- ctx.showOverlay((hideOverlay) => (
78
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
79
79
  <ConfirmOverlay
80
80
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
81
81
  onConfirm={() => {
82
82
  logger.debug("[quotes] user confirmed re-edit");
83
- hideOverlay();
83
+ hideForEditor();
84
84
  resolve(true);
85
85
  }}
86
86
  onCancel={() => {
@@ -89,7 +89,7 @@ async function openQuotesInEditor(
89
89
  resolve(false);
90
90
  }}
91
91
  />
92
- ));
92
+ ), ctx.renderer);
93
93
  });
94
94
 
95
95
  logger.debug("[quotes] shouldReEdit", { shouldReEdit, iteration: editorIteration });
@@ -97,7 +97,6 @@ async function openQuotesInEditor(
97
97
  if (shouldReEdit) {
98
98
  yamlContent = result.content;
99
99
  logger.debug("[quotes] continuing to next iteration");
100
- await new Promise((r) => setTimeout(r, 50));
101
100
  continue;
102
101
  } else {
103
102
  ctx.showNotification("Changes discarded", "info");
@@ -146,14 +145,13 @@ export const quotesCommand: Command = {
146
145
  const allQuotes = await ctx.ei.getQuotes();
147
146
  const messageQuotes = allQuotes.filter(q => q.message_id === targetMessage.id);
148
147
 
149
- ctx.showOverlay((hide) => (
148
+ ctx.showOverlay((hide, hideForEditor) => (
150
149
  <QuotesOverlay
151
150
  quotes={messageQuotes}
152
151
  messageIndex={index}
153
152
  onClose={hide}
154
153
  onEdit={async () => {
155
- hide();
156
- await new Promise((r) => setTimeout(r, 50));
154
+ hideForEditor();
157
155
  await openQuotesInEditor(ctx, messageQuotes, `quotes from message [${index}]`);
158
156
  }}
159
157
  onDelete={async (quoteId) => {
@@ -161,7 +159,7 @@ export const quotesCommand: Command = {
161
159
  ctx.showNotification("Quote deleted", "info");
162
160
  }}
163
161
  />
164
- ));
162
+ ), ctx.renderer);
165
163
  return;
166
164
  }
167
165
 
@@ -11,7 +11,7 @@ export interface Command {
11
11
  }
12
12
 
13
13
  export interface CommandContext {
14
- showOverlay: (renderer: OverlayRenderer) => void;
14
+ showOverlay: (renderer: OverlayRenderer, cliRenderer?: CliRenderer) => void;
15
15
  hideOverlay: () => void;
16
16
  showNotification: (msg: string, level: "error" | "warn" | "info") => void;
17
17
  exitApp: () => Promise<void>;
@@ -16,7 +16,7 @@ export const setSyncCommand: Command = {
16
16
  const [username, passphrase] = args;
17
17
 
18
18
  const confirmed = await new Promise<boolean>((resolve) => {
19
- ctx.showOverlay((hideOverlay) => (
19
+ ctx.showOverlay((hideOverlay, _hideForEditor) => (
20
20
  <ConfirmOverlay
21
21
  message={`Set sync credentials for "${username}"?\n\nThis requires a restart. Just re-run ei once it closes!`}
22
22
  onConfirm={() => {
@@ -28,7 +28,7 @@ export const setSyncCommand: Command = {
28
28
  resolve(false);
29
29
  }}
30
30
  />
31
- ));
31
+ ), ctx.renderer);
32
32
  });
33
33
 
34
34
  if (!confirmed) {
@@ -45,6 +45,21 @@ export const settingsCommand: Command = {
45
45
  // Validate provider name in default_model (case-insensitive match + auto-correct)
46
46
  const llmAccounts = human.settings?.accounts?.filter(a => a.type === "llm") ?? [];
47
47
  newSettings.default_model = validateModelProvider(newSettings.default_model, llmAccounts);
48
+
49
+ if (newSettings.opencode?.extraction_model) {
50
+ newSettings.opencode.extraction_model = validateModelProvider(
51
+ newSettings.opencode.extraction_model,
52
+ llmAccounts
53
+ );
54
+ }
55
+
56
+ if (newSettings.claudeCode?.extraction_model) {
57
+ newSettings.claudeCode.extraction_model = validateModelProvider(
58
+ newSettings.claudeCode.extraction_model,
59
+ llmAccounts
60
+ );
61
+ }
62
+
48
63
  await ctx.ei.updateSettings(newSettings);
49
64
  ctx.showNotification("Settings updated", "info");
50
65
  return;
@@ -54,11 +69,11 @@ export const settingsCommand: Command = {
54
69
  logger.debug("[settings] YAML parse error, prompting for re-edit", { iteration: editorIteration, error: errorMsg });
55
70
 
56
71
  const shouldReEdit = await new Promise<boolean>((resolve) => {
57
- ctx.showOverlay((hideOverlay) => (
72
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
58
73
  <ConfirmOverlay
59
74
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
60
75
  onConfirm={() => {
61
- hideOverlay();
76
+ hideForEditor();
62
77
  resolve(true);
63
78
  }}
64
79
  onCancel={() => {
@@ -66,12 +81,11 @@ export const settingsCommand: Command = {
66
81
  resolve(false);
67
82
  }}
68
83
  />
69
- ));
84
+ ), ctx.renderer);
70
85
  });
71
86
 
72
87
  if (shouldReEdit) {
73
88
  yamlContent = result.content;
74
- await new Promise(r => setTimeout(r, 50));
75
89
  continue;
76
90
  } else {
77
91
  ctx.showNotification("Changes discarded", "info");
@@ -45,7 +45,6 @@ export async function runSpotifyAuth(ctx: CommandContext): Promise<void> {
45
45
  const codePromise = waitForAuthCode(ctx);
46
46
 
47
47
  // Give the server a tick to bind its port before opening the browser
48
- await new Promise<void>((r) => setTimeout(r, 50));
49
48
  logger.info("[spotify-auth] Server should be up — opening browser now");
50
49
 
51
50
  // Open the authorization URL in the user's default browser
@@ -25,20 +25,19 @@ export const toolsCommand: Command = {
25
25
  toolCount: allTools.filter(t => t.provider_id === p.id).length,
26
26
  }));
27
27
 
28
- ctx.showOverlay((hideOverlay) => (
28
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
29
29
  <ToolkitListOverlay
30
30
  toolkits={toolkits}
31
31
  onEdit={async (toolkit) => {
32
- hideOverlay();
33
- await new Promise(r => setTimeout(r, 50));
32
+ hideForEditor();
34
33
  const provider = providers.find(p => p.id === toolkit.id);
35
34
  if (provider) {
36
- const providerTools = allTools.filter(t => t.provider_id === provider.id);
35
+ const providerTools = allTools.filter(t => t.provider_id === toolkit.id);
37
36
  await openToolkitEditor(provider, providerTools, ctx);
38
37
  }
39
38
  }}
40
39
  onDismiss={hideOverlay}
41
40
  />
42
- ));
41
+ ), ctx.renderer);
43
42
  },
44
43
  };
@@ -23,7 +23,6 @@ import type {
23
23
  HumanEntity,
24
24
  HumanSettings,
25
25
  Fact,
26
- Trait,
27
26
  Topic,
28
27
  Person,
29
28
  Quote,
@@ -78,10 +77,9 @@ export interface EiContextValue {
78
77
  updateHuman: (updates: Partial<HumanEntity>) => Promise<void>;
79
78
  updateSettings: (updates: Partial<HumanSettings>) => Promise<void>;
80
79
  upsertFact: (fact: Fact) => Promise<void>;
81
- upsertTrait: (trait: Trait) => Promise<void>;
82
80
  upsertTopic: (topic: Topic) => Promise<void>;
83
81
  upsertPerson: (person: Person) => Promise<void>;
84
- removeDataItem: (type: "fact" | "trait" | "topic" | "person", id: string) => Promise<void>;
82
+ removeDataItem: (type: "fact" | "topic" | "person", id: string) => Promise<void>;
85
83
  syncStatus: () => { configured: boolean; envBased: boolean };
86
84
  triggerSync: () => Promise<{ success: boolean; error?: string }>;
87
85
  getGroupList: () => Promise<string[]>;
@@ -92,10 +90,9 @@ export interface EiContextValue {
92
90
  quotesVersion: () => number;
93
91
  searchHumanData: (
94
92
  query: string,
95
- options?: { types?: Array<"fact" | "trait" | "topic" | "person" | "quote">; limit?: number }
93
+ options?: { types?: Array<"fact" | "topic" | "person" | "quote">; limit?: number }
96
94
  ) => Promise<{
97
95
  facts: Fact[];
98
- traits: Trait[];
99
96
  topics: Topic[];
100
97
  people: Person[];
101
98
  quotes: Quote[];
@@ -329,11 +326,6 @@ export const EiProvider: ParentComponent = (props) => {
329
326
  await processor.upsertFact(fact);
330
327
  };
331
328
 
332
- const upsertTrait = async (trait: Trait) => {
333
- if (!processor) return;
334
- await processor.upsertTrait(trait);
335
- };
336
-
337
329
  const upsertTopic = async (topic: Topic) => {
338
330
  if (!processor) return;
339
331
  await processor.upsertTopic(topic);
@@ -344,7 +336,7 @@ export const EiProvider: ParentComponent = (props) => {
344
336
  await processor.upsertPerson(person);
345
337
  };
346
338
 
347
- const removeDataItem = async (type: "fact" | "trait" | "topic" | "person", id: string) => {
339
+ const removeDataItem = async (type: "fact" | "topic" | "person", id: string) => {
348
340
  if (!processor) return;
349
341
  await processor.removeDataItem(type, id);
350
342
  };
@@ -450,9 +442,9 @@ export const EiProvider: ParentComponent = (props) => {
450
442
 
451
443
  const searchHumanData = async (
452
444
  query: string,
453
- options?: { types?: Array<"fact" | "trait" | "topic" | "person" | "quote">; limit?: number }
445
+ options?: { types?: Array<"fact" | "topic" | "person" | "quote">; limit?: number }
454
446
  ) => {
455
- if (!processor) return { facts: [], traits: [], topics: [], people: [], quotes: [] };
447
+ if (!processor) return { facts: [], topics: [], people: [], quotes: [] };
456
448
  return processor.searchHumanData(query, options);
457
449
  };
458
450
 
@@ -648,7 +640,6 @@ export const EiProvider: ParentComponent = (props) => {
648
640
  updateHuman,
649
641
  updateSettings,
650
642
  upsertFact,
651
- upsertTrait,
652
643
  upsertTopic,
653
644
  upsertPerson,
654
645
  removeDataItem,
@@ -6,24 +6,35 @@ import {
6
6
  type JSX,
7
7
  type Accessor,
8
8
  } from "solid-js";
9
+ import { type CliRenderer } from "@opentui/core";
9
10
  import { logger } from "../util/logger";
10
11
 
11
- export type OverlayRenderer = (hideOverlay: () => void) => JSX.Element;
12
+ export type OverlayRenderer = (hideOverlay: () => void, hideForEditor: () => void) => JSX.Element;
12
13
 
13
14
  interface OverlayContextValue {
14
- overlayRenderer: Accessor<OverlayRenderer | null>;
15
- showOverlay: (renderer: OverlayRenderer) => void;
15
+ overlayRenderer: Accessor<(() => JSX.Element) | null>;
16
+ showOverlay: (renderer: OverlayRenderer, cliRenderer?: CliRenderer) => void;
16
17
  hideOverlay: () => void;
17
18
  }
18
19
 
19
20
  const OverlayContext = createContext<OverlayContextValue>();
20
21
 
21
22
  export const OverlayProvider: ParentComponent = (props) => {
22
- const [overlayRenderer, setOverlayRenderer] = createSignal<OverlayRenderer | null>(null);
23
+ const [overlayRenderer, setOverlayRenderer] = createSignal<(() => JSX.Element) | null>(null);
23
24
 
24
- const showOverlay = (renderer: OverlayRenderer) => {
25
+ const showOverlay = (renderer: OverlayRenderer, cliRenderer?: CliRenderer) => {
25
26
  logger.debug("[overlay] showOverlay called");
26
- setOverlayRenderer(() => renderer);
27
+ const hideForEditor = () => {
28
+ if (cliRenderer) {
29
+ cliRenderer.currentRenderBuffer.clear();
30
+ }
31
+ setOverlayRenderer(null);
32
+ };
33
+ const hideOverlay = () => {
34
+ logger.debug("[overlay] hideOverlay called");
35
+ setOverlayRenderer(null);
36
+ };
37
+ setOverlayRenderer(() => () => renderer(hideOverlay, hideForEditor));
27
38
  };
28
39
 
29
40
  const hideOverlay = () => {
@@ -3,6 +3,7 @@ import * as fs from "fs";
3
3
  import * as os from "os";
4
4
  import * as path from "path";
5
5
  import type { CliRenderer } from "@opentui/core";
6
+ import { RendererControlState } from "@opentui/core";
6
7
  import { logger } from "./logger";
7
8
 
8
9
  export interface EditorOptions {
@@ -103,23 +104,30 @@ export async function spawnEditor(options: EditorOptions): Promise<EditorResult>
103
104
  const safeName = filename.replace(/\s+/g, "-");
104
105
  const tmpFile = path.join(tmpDir, `ei-${Date.now()}-${safeName}`);
105
106
 
106
- logger.debug("[editor] spawnEditor called", { filename, editor });
107
+ logger.debug("[editor] spawnEditor called - START", { filename, editor });
108
+
109
+ // CRITICAL: 50ms delay to let SolidJS reactive updates settle before suspending
110
+ // This prevents ghost frames when transitioning from overlays to editor
111
+ await new Promise(resolve => setTimeout(resolve, 50));
107
112
 
108
113
  fs.writeFileSync(tmpFile, initialContent, "utf-8");
109
114
  const originalContent = initialContent;
110
115
 
111
116
  return new Promise((resolve) => {
112
- logger.debug("[editor] calling renderer.suspend()");
113
- renderer.suspend();
114
- logger.debug("[editor] calling renderer.currentRenderBuffer.clear()");
115
- renderer.currentRenderBuffer.clear();
117
+ const wasAlreadySuspended = renderer.controlState === RendererControlState.EXPLICIT_SUSPENDED;
118
+ logger.debug("[editor] renderer state", { controlState: renderer.controlState, wasAlreadySuspended });
119
+
120
+ if (!wasAlreadySuspended) {
121
+ renderer.suspend();
122
+ }
116
123
 
117
- logger.debug("[editor] spawning editor process");
124
+ renderer.currentRenderBuffer.clear();
118
125
  const child = spawn(editor, [tmpFile], {
119
126
  stdio: "inherit",
120
127
  shell: true,
121
128
  });
122
129
 
130
+
123
131
  child.on("error", () => {
124
132
  logger.error("[editor] editor process error");
125
133
  renderer.currentRenderBuffer.clear();
@@ -135,13 +143,16 @@ export async function spawnEditor(options: EditorOptions): Promise<EditorResult>
135
143
 
136
144
  child.on("exit", (code) => {
137
145
  logger.debug("[editor] editor process exited", { code });
138
- logger.debug("[editor] calling renderer.currentRenderBuffer.clear()");
139
146
  renderer.currentRenderBuffer.clear();
140
- logger.debug("[editor] calling renderer.resume()");
141
- renderer.resume();
142
- logger.debug("[editor] queueMicrotask for requestRender");
147
+
148
+ if (!wasAlreadySuspended) {
149
+ logger.debug("[editor] calling renderer.resume()");
150
+ renderer.resume();
151
+ } else {
152
+ logger.debug("[editor] already suspended before spawn, skipping resume");
153
+ }
154
+
143
155
  queueMicrotask(() => {
144
- logger.debug("[editor] calling renderer.requestRender()");
145
156
  renderer.requestRender();
146
157
  });
147
158
 
@@ -80,12 +80,12 @@ export async function createPersonaViaEditor(options: NewPersonaEditorOptions):
80
80
  logger.debug("[persona-editor] YAML parse error in new persona", { error: errorMsg });
81
81
 
82
82
  const shouldReEdit = await new Promise<boolean>((resolve) => {
83
- ctx.showOverlay((hideOverlay) => (
83
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
84
84
  <ConfirmOverlay
85
85
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
86
86
  onConfirm={() => {
87
87
  logger.debug("[persona-editor] user confirmed re-edit (new)");
88
- hideOverlay();
88
+ hideForEditor();
89
89
  resolve(true);
90
90
  }}
91
91
  onCancel={() => {
@@ -94,12 +94,11 @@ export async function createPersonaViaEditor(options: NewPersonaEditorOptions):
94
94
  resolve(false);
95
95
  }}
96
96
  />
97
- ));
97
+ ), ctx.renderer);
98
98
  });
99
99
 
100
100
  if (shouldReEdit) {
101
101
  yamlContent = result.content;
102
- await new Promise(r => setTimeout(r, 50));
103
102
  continue;
104
103
  } else {
105
104
  ctx.showNotification("Creation cancelled", "info");
@@ -155,12 +154,12 @@ export async function openPersonaEditor(options: PersonaEditorOptions): Promise<
155
154
  logger.debug("[persona-editor] YAML parse error", { error: errorMsg });
156
155
 
157
156
  const shouldReEdit = await new Promise<boolean>((resolve) => {
158
- ctx.showOverlay((hideOverlay) => (
157
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
159
158
  <ConfirmOverlay
160
159
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
161
160
  onConfirm={() => {
162
161
  logger.debug("[persona-editor] user confirmed re-edit");
163
- hideOverlay();
162
+ hideForEditor();
164
163
  resolve(true);
165
164
  }}
166
165
  onCancel={() => {
@@ -169,12 +168,11 @@ export async function openPersonaEditor(options: PersonaEditorOptions): Promise<
169
168
  resolve(false);
170
169
  }}
171
170
  />
172
- ));
171
+ ), ctx.renderer);
173
172
  });
174
173
 
175
174
  if (shouldReEdit) {
176
175
  yamlContent = result.content;
177
- await new Promise(r => setTimeout(r, 50));
178
176
  continue;
179
177
  } else {
180
178
  ctx.showNotification("Changes discarded", "info");
@@ -66,11 +66,11 @@ export async function createProviderViaEditor(ctx: CommandContext): Promise<NewP
66
66
  logger.debug("[provider-editor] YAML parse error in new provider", { error: errorMsg });
67
67
 
68
68
  const shouldReEdit = await new Promise<boolean>((resolve) => {
69
- ctx.showOverlay((hideOverlay) => (
69
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
70
70
  <ConfirmOverlay
71
71
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
72
72
  onConfirm={() => {
73
- hideOverlay();
73
+ hideForEditor();
74
74
  resolve(true);
75
75
  }}
76
76
  onCancel={() => {
@@ -78,12 +78,11 @@ export async function createProviderViaEditor(ctx: CommandContext): Promise<NewP
78
78
  resolve(false);
79
79
  }}
80
80
  />
81
- ));
81
+ ), ctx.renderer);
82
82
  });
83
83
 
84
84
  if (shouldReEdit) {
85
85
  yamlContent = result.content;
86
- await new Promise(r => setTimeout(r, 50));
87
86
  continue;
88
87
  } else {
89
88
  ctx.showNotification("Creation cancelled", "info");
@@ -140,11 +139,11 @@ export async function openProviderEditor(account: ProviderAccount, ctx: CommandC
140
139
  logger.debug("[provider-editor] YAML parse error", { error: errorMsg });
141
140
 
142
141
  const shouldReEdit = await new Promise<boolean>((resolve) => {
143
- ctx.showOverlay((hideOverlay) => (
142
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
144
143
  <ConfirmOverlay
145
144
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
146
145
  onConfirm={() => {
147
- hideOverlay();
146
+ hideForEditor();
148
147
  resolve(true);
149
148
  }}
150
149
  onCancel={() => {
@@ -152,12 +151,11 @@ export async function openProviderEditor(account: ProviderAccount, ctx: CommandC
152
151
  resolve(false);
153
152
  }}
154
153
  />
155
- ));
154
+ ), ctx.renderer);
156
155
  });
157
156
 
158
157
  if (shouldReEdit) {
159
158
  yamlContent = result.content;
160
- await new Promise(r => setTimeout(r, 50));
161
159
  continue;
162
160
  } else {
163
161
  ctx.showNotification("Changes discarded", "info");
@@ -55,11 +55,11 @@ export async function openToolkitEditor(
55
55
  logger.debug("[toolkit-editor] YAML parse error", { error: errorMsg });
56
56
 
57
57
  const shouldReEdit = await new Promise<boolean>((resolve) => {
58
- ctx.showOverlay((hideOverlay) => (
58
+ ctx.showOverlay((hideOverlay, hideForEditor) => (
59
59
  <ConfirmOverlay
60
60
  message={`YAML parse error:\n${errorMsg}\n\nRe-edit?`}
61
61
  onConfirm={() => {
62
- hideOverlay();
62
+ hideForEditor();
63
63
  resolve(true);
64
64
  }}
65
65
  onCancel={() => {
@@ -67,12 +67,11 @@ export async function openToolkitEditor(
67
67
  resolve(false);
68
68
  }}
69
69
  />
70
- ));
70
+ ), ctx.renderer);
71
71
  });
72
72
 
73
73
  if (shouldReEdit) {
74
74
  yamlContent = result.content;
75
- await new Promise(r => setTimeout(r, 50));
76
75
  continue;
77
76
  } else {
78
77
  ctx.showNotification("Changes discarded", "info");