@mem9/opencode 0.1.2 → 0.1.3
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/package.json +1 -1
- package/src/tui/index.ts +59 -23
package/package.json
CHANGED
package/src/tui/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
TuiCommand,
|
|
4
4
|
TuiPlugin,
|
|
5
5
|
TuiPluginApi,
|
|
6
|
+
TuiToast,
|
|
6
7
|
} from "@opencode-ai/plugin/tui";
|
|
7
8
|
import {
|
|
8
9
|
resolveMem9Home,
|
|
@@ -61,6 +62,22 @@ interface SetupProfileOptionState {
|
|
|
61
62
|
currentProfileId?: string;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
let hasShownVisibleApiKeyWarning = false;
|
|
66
|
+
const DEFAULT_TOAST_DURATION_MS = 5000;
|
|
67
|
+
|
|
68
|
+
function scheduleDialogTransition(next: () => void): void {
|
|
69
|
+
// Delay prompt-to-prompt transitions so the next dialog does not reuse
|
|
70
|
+
// the same Enter keypress that confirmed the current prompt.
|
|
71
|
+
setTimeout(next, 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function showToast(api: TuiPluginApi, toast: TuiToast): void {
|
|
75
|
+
api.ui.toast({
|
|
76
|
+
duration: toast.duration ?? DEFAULT_TOAST_DURATION_MS,
|
|
77
|
+
...toast,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
function getProjectDir(api: TuiPluginApi): string {
|
|
65
82
|
const worktree = api.state.path.worktree.trim();
|
|
66
83
|
if (worktree.length > 0) {
|
|
@@ -113,7 +130,7 @@ function showError(
|
|
|
113
130
|
retryCommand = false,
|
|
114
131
|
): void {
|
|
115
132
|
const suffix = retryCommand ? " Run /mem9-setup again when you are ready to retry." : "";
|
|
116
|
-
api
|
|
133
|
+
showToast(api, {
|
|
117
134
|
variant: "error",
|
|
118
135
|
title: "mem9 setup failed",
|
|
119
136
|
message: `${error instanceof Error ? error.message : String(error)}${suffix}`,
|
|
@@ -121,7 +138,7 @@ function showError(
|
|
|
121
138
|
}
|
|
122
139
|
|
|
123
140
|
function showProfileSavedSuccess(api: TuiPluginApi, profileId: string): void {
|
|
124
|
-
api
|
|
141
|
+
showToast(api, {
|
|
125
142
|
variant: "success",
|
|
126
143
|
title: "mem9 configured",
|
|
127
144
|
message: `Saved profile ${profileId} and set it as the default user profile. Restart OpenCode to reload mem9.`,
|
|
@@ -134,7 +151,7 @@ function showScopeSavedSuccess(
|
|
|
134
151
|
profileId: string,
|
|
135
152
|
): void {
|
|
136
153
|
const scopeLabel = scope === "user" ? "user settings" : "project settings";
|
|
137
|
-
api
|
|
154
|
+
showToast(api, {
|
|
138
155
|
variant: "success",
|
|
139
156
|
title: "mem9 configured",
|
|
140
157
|
message: `Saved ${scopeLabel} with profile ${profileId}. Restart OpenCode to reload mem9.`,
|
|
@@ -335,7 +352,7 @@ function showProfileIdDialog(
|
|
|
335
352
|
onConfirm: (value) => {
|
|
336
353
|
const next = value.trim();
|
|
337
354
|
if (next.length === 0) {
|
|
338
|
-
api
|
|
355
|
+
showToast(api, {
|
|
339
356
|
variant: "warning",
|
|
340
357
|
message: "Profile ID is required.",
|
|
341
358
|
});
|
|
@@ -343,7 +360,7 @@ function showProfileIdDialog(
|
|
|
343
360
|
}
|
|
344
361
|
|
|
345
362
|
if (isReusableProfileID(state, next)) {
|
|
346
|
-
api
|
|
363
|
+
showToast(api, {
|
|
347
364
|
variant: "warning",
|
|
348
365
|
message: "That profile already has credentials. Pick a new profile ID or use the existing profile in scope settings.",
|
|
349
366
|
});
|
|
@@ -354,7 +371,9 @@ function showProfileIdDialog(
|
|
|
354
371
|
if (draft.label.trim().length === 0) {
|
|
355
372
|
draft.label = next === "default" ? "Personal" : next;
|
|
356
373
|
}
|
|
357
|
-
|
|
374
|
+
scheduleDialogTransition(() => {
|
|
375
|
+
showProfileLabelDialog(api, paths, state, action, draft);
|
|
376
|
+
});
|
|
358
377
|
},
|
|
359
378
|
onCancel: () => {
|
|
360
379
|
showActionDialog(api, paths, state);
|
|
@@ -378,7 +397,7 @@ function showProfileLabelDialog(
|
|
|
378
397
|
onConfirm: (value) => {
|
|
379
398
|
const next = value.trim();
|
|
380
399
|
if (next.length === 0) {
|
|
381
|
-
api
|
|
400
|
+
showToast(api, {
|
|
382
401
|
variant: "warning",
|
|
383
402
|
message: "Profile label is required.",
|
|
384
403
|
});
|
|
@@ -386,10 +405,14 @@ function showProfileLabelDialog(
|
|
|
386
405
|
}
|
|
387
406
|
|
|
388
407
|
draft.label = next;
|
|
389
|
-
|
|
408
|
+
scheduleDialogTransition(() => {
|
|
409
|
+
showProfileBaseUrlDialog(api, paths, state, action, draft);
|
|
410
|
+
});
|
|
390
411
|
},
|
|
391
412
|
onCancel: () => {
|
|
392
|
-
|
|
413
|
+
scheduleDialogTransition(() => {
|
|
414
|
+
showProfileIdDialog(api, paths, state, action, draft);
|
|
415
|
+
});
|
|
393
416
|
},
|
|
394
417
|
}),
|
|
395
418
|
);
|
|
@@ -410,7 +433,7 @@ function showProfileBaseUrlDialog(
|
|
|
410
433
|
onConfirm: (value) => {
|
|
411
434
|
const next = value.trim();
|
|
412
435
|
if (next.length === 0) {
|
|
413
|
-
api
|
|
436
|
+
showToast(api, {
|
|
414
437
|
variant: "warning",
|
|
415
438
|
message: "mem9 API URL is required.",
|
|
416
439
|
});
|
|
@@ -423,10 +446,14 @@ function showProfileBaseUrlDialog(
|
|
|
423
446
|
return;
|
|
424
447
|
}
|
|
425
448
|
|
|
426
|
-
|
|
449
|
+
scheduleDialogTransition(() => {
|
|
450
|
+
showProfileApiKeyDialog(api, paths, state, draft);
|
|
451
|
+
});
|
|
427
452
|
},
|
|
428
453
|
onCancel: () => {
|
|
429
|
-
|
|
454
|
+
scheduleDialogTransition(() => {
|
|
455
|
+
showProfileLabelDialog(api, paths, state, action, draft);
|
|
456
|
+
});
|
|
430
457
|
},
|
|
431
458
|
}),
|
|
432
459
|
);
|
|
@@ -438,11 +465,14 @@ function showProfileApiKeyDialog(
|
|
|
438
465
|
state: SetupState,
|
|
439
466
|
draft: ProfileDraft,
|
|
440
467
|
): void {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
468
|
+
if (!hasShownVisibleApiKeyWarning) {
|
|
469
|
+
hasShownVisibleApiKeyWarning = true;
|
|
470
|
+
showToast(api, {
|
|
471
|
+
variant: "warning",
|
|
472
|
+
message: "API key input is visible while typing.",
|
|
473
|
+
duration: 4000,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
446
476
|
|
|
447
477
|
api.ui.dialog.replace(() =>
|
|
448
478
|
api.ui.DialogPrompt({
|
|
@@ -451,7 +481,7 @@ function showProfileApiKeyDialog(
|
|
|
451
481
|
onConfirm: (value) => {
|
|
452
482
|
const next = value.trim();
|
|
453
483
|
if (next.length === 0) {
|
|
454
|
-
api
|
|
484
|
+
showToast(api, {
|
|
455
485
|
variant: "warning",
|
|
456
486
|
message: "mem9 API key is required.",
|
|
457
487
|
});
|
|
@@ -462,7 +492,9 @@ function showProfileApiKeyDialog(
|
|
|
462
492
|
void submitManualProfile(api, paths, draft);
|
|
463
493
|
},
|
|
464
494
|
onCancel: () => {
|
|
465
|
-
|
|
495
|
+
scheduleDialogTransition(() => {
|
|
496
|
+
showProfileBaseUrlDialog(api, paths, state, "manual-api-key", draft);
|
|
497
|
+
});
|
|
466
498
|
},
|
|
467
499
|
}),
|
|
468
500
|
);
|
|
@@ -570,7 +602,7 @@ function showDefaultTimeoutDialog(
|
|
|
570
602
|
onConfirm: (value) => {
|
|
571
603
|
const parsed = parsePositiveInteger(value, "defaultTimeoutMs");
|
|
572
604
|
if (parsed === null) {
|
|
573
|
-
api
|
|
605
|
+
showToast(api, {
|
|
574
606
|
variant: "warning",
|
|
575
607
|
message: "Default timeout must be a positive integer.",
|
|
576
608
|
});
|
|
@@ -578,7 +610,9 @@ function showDefaultTimeoutDialog(
|
|
|
578
610
|
}
|
|
579
611
|
|
|
580
612
|
draft.defaultTimeoutMs = parsed;
|
|
581
|
-
|
|
613
|
+
scheduleDialogTransition(() => {
|
|
614
|
+
showSearchTimeoutDialog(api, paths, state, draft);
|
|
615
|
+
});
|
|
582
616
|
},
|
|
583
617
|
onCancel: () => {
|
|
584
618
|
showScopeDebugDialog(api, paths, state, draft);
|
|
@@ -601,7 +635,7 @@ function showSearchTimeoutDialog(
|
|
|
601
635
|
onConfirm: (value) => {
|
|
602
636
|
const parsed = parsePositiveInteger(value, "searchTimeoutMs");
|
|
603
637
|
if (parsed === null) {
|
|
604
|
-
api
|
|
638
|
+
showToast(api, {
|
|
605
639
|
variant: "warning",
|
|
606
640
|
message: "Search timeout must be a positive integer.",
|
|
607
641
|
});
|
|
@@ -612,7 +646,9 @@ function showSearchTimeoutDialog(
|
|
|
612
646
|
void submitScopeConfigDraft(api, paths, draft);
|
|
613
647
|
},
|
|
614
648
|
onCancel: () => {
|
|
615
|
-
|
|
649
|
+
scheduleDialogTransition(() => {
|
|
650
|
+
showDefaultTimeoutDialog(api, paths, state, draft);
|
|
651
|
+
});
|
|
616
652
|
},
|
|
617
653
|
}),
|
|
618
654
|
);
|