@clubnet/seedclub 0.2.41 → 0.2.43
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/assets/extensions/seedclub/commands/seedclub.ts +18 -33
- package/assets/extensions/seedclub/gate-state.ts +1 -1
- package/assets/extensions/seedclub/index.ts +5 -5
- package/assets/extensions/seedclub/memory.ts +41 -2
- package/package.json +1 -1
- package/packages/seedclub-tui/src/app/interactive-mode.mjs +118 -41
- package/packages/seedclub-tui/src/vendor/coding-agent/modes/interactive/components/oauth-selector.js +5 -2
|
@@ -104,6 +104,21 @@ export function registerSeedclubCommand(pi: ExtensionAPI, deps: SeedclubDeps) {
|
|
|
104
104
|
},
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
+
pi.registerCommand("disconnect", {
|
|
108
|
+
description: "Disconnect your Seed Club account",
|
|
109
|
+
handler: async (_args, ctx) => {
|
|
110
|
+
const confirmed = await ctx.ui.confirm(
|
|
111
|
+
"Disconnect Seed Club",
|
|
112
|
+
"This will remove local Seed Club credentials from this agent.",
|
|
113
|
+
);
|
|
114
|
+
if (!confirmed) {
|
|
115
|
+
ctx.ui.notify("Disconnect cancelled.", "info");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await deps.disconnect(ctx);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
107
122
|
pi.registerCommand("connect-calendar", {
|
|
108
123
|
description: "Connect a personal Google Calendar to your Seed Club account",
|
|
109
124
|
handler: async (_args, ctx) => {
|
|
@@ -171,16 +186,6 @@ export function registerSeedclubCommand(pi: ExtensionAPI, deps: SeedclubDeps) {
|
|
|
171
186
|
},
|
|
172
187
|
});
|
|
173
188
|
|
|
174
|
-
pi.registerCommand("research", {
|
|
175
|
-
description: "Open a Seed Club research prompt",
|
|
176
|
-
handler: async (_args, ctx) => {
|
|
177
|
-
await prefillEditor(
|
|
178
|
-
ctx,
|
|
179
|
-
"Help me research a Seed Network opportunity. Ask me for the company, deck, memo, source URL, or local file if needed. Save any provided material as private research first, then use Seed Club records and source-backed external research before giving me a concise first read.",
|
|
180
|
-
);
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
|
|
184
189
|
pi.registerCommand("source", {
|
|
185
190
|
description: "Open a source-backed research prompt",
|
|
186
191
|
handler: async (_args, ctx) => {
|
|
@@ -191,32 +196,12 @@ export function registerSeedclubCommand(pi: ExtensionAPI, deps: SeedclubDeps) {
|
|
|
191
196
|
},
|
|
192
197
|
});
|
|
193
198
|
|
|
194
|
-
pi.registerCommand("
|
|
195
|
-
description: "Open
|
|
196
|
-
handler: async (_args, ctx) => {
|
|
197
|
-
await prefillEditor(
|
|
198
|
-
ctx,
|
|
199
|
-
"Summarize my current Seed Club investing worldview from recent memory and Seed Club context. Focus on beliefs, decision heuristics, and places where my view has changed. Flag what evidence supports each point.",
|
|
200
|
-
);
|
|
201
|
-
},
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
pi.registerCommand("theses", {
|
|
205
|
-
description: "Open an investment theses prompt",
|
|
206
|
-
handler: async (_args, ctx) => {
|
|
207
|
-
await prefillEditor(
|
|
208
|
-
ctx,
|
|
209
|
-
"Draft my current investment theses from Seed Club memory and recent deal context. Group by thesis, include supporting signals, counterexamples, and what would change my mind.",
|
|
210
|
-
);
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
pi.registerCommand("concerns", {
|
|
215
|
-
description: "Open an investment concerns prompt",
|
|
199
|
+
pi.registerCommand("diligence", {
|
|
200
|
+
description: "Open a Seed Club diligence prompt",
|
|
216
201
|
handler: async (_args, ctx) => {
|
|
217
202
|
await prefillEditor(
|
|
218
203
|
ctx,
|
|
219
|
-
"
|
|
204
|
+
"Help me diligence this opportunity. Start by asking for the company, deck, memo, source URL, or local file if needed. Use Seed Club records and source-backed external research, separate known facts from assumptions, identify risks and open questions, and end with a concise recommendation.",
|
|
220
205
|
);
|
|
221
206
|
},
|
|
222
207
|
});
|
|
@@ -63,7 +63,7 @@ export function markAuthRequired(options?: { authUrl?: string | null; message?:
|
|
|
63
63
|
setState({
|
|
64
64
|
status: "auth_required",
|
|
65
65
|
authUrl: options?.authUrl ?? getSharedStore().state.authUrl,
|
|
66
|
-
message: options?.message ?? "Seed Club sign-in is required before
|
|
66
|
+
message: options?.message ?? "Seed Club sign-in is required before model setup.",
|
|
67
67
|
error: options?.error ?? null,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
@@ -352,7 +352,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
352
352
|
function getPostAuthInstruction(ctx: any): string | null {
|
|
353
353
|
const hasProviderAuth = ctx.modelRegistry.getAvailable().length > 0;
|
|
354
354
|
const hasSelectedModel = !!ctx.model;
|
|
355
|
-
if (!hasProviderAuth) return "Next: /
|
|
355
|
+
if (!hasProviderAuth) return "Next: /model to set up inference.";
|
|
356
356
|
if (!hasSelectedModel) return "Next: /model.";
|
|
357
357
|
return null;
|
|
358
358
|
}
|
|
@@ -427,7 +427,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
427
427
|
usedSeedclubToolThisTurn = false;
|
|
428
428
|
markAuthRequired({
|
|
429
429
|
authUrl: null,
|
|
430
|
-
message: "Seed Club sign-in is required before
|
|
430
|
+
message: "Seed Club sign-in is required before model setup.",
|
|
431
431
|
error: "Use a @seedclub.com account to connect this agent.",
|
|
432
432
|
});
|
|
433
433
|
return null;
|
|
@@ -496,7 +496,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
496
496
|
memory.clear(ctx);
|
|
497
497
|
markAuthRequired({
|
|
498
498
|
authUrl: null,
|
|
499
|
-
message: "Seed Club sign-in is required before
|
|
499
|
+
message: "Seed Club sign-in is required before model setup.",
|
|
500
500
|
error: null,
|
|
501
501
|
});
|
|
502
502
|
}
|
|
@@ -506,7 +506,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
506
506
|
message: isReset
|
|
507
507
|
? "Resetting your Seed Club sign-in and opening the browser to switch accounts."
|
|
508
508
|
: options?.autoStart
|
|
509
|
-
? "Seed Club sign-in is required before
|
|
509
|
+
? "Seed Club sign-in is required before model setup. Opening your browser now."
|
|
510
510
|
: "Opening your browser for Seed Club sign-in.",
|
|
511
511
|
error: null,
|
|
512
512
|
});
|
|
@@ -558,7 +558,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
558
558
|
usedSeedclubToolThisTurn = false;
|
|
559
559
|
markAuthRequired({
|
|
560
560
|
authUrl: null,
|
|
561
|
-
message: "Seed Club sign-in is required before
|
|
561
|
+
message: "Seed Club sign-in is required before model setup.",
|
|
562
562
|
error: null,
|
|
563
563
|
});
|
|
564
564
|
ctx.ui.notify("Logged out", "info");
|
|
@@ -32,8 +32,20 @@ const MEMORY_COMMAND_COMPLETIONS = [
|
|
|
32
32
|
{ value: "recent", label: "recent", description: "Show recent memory" },
|
|
33
33
|
{ value: "on", label: "on", description: "Turn memory on" },
|
|
34
34
|
{ value: "off", label: "off", description: "Turn memory off" },
|
|
35
|
+
{ value: "worldview", label: "worldview", description: "Open an investing worldview prompt" },
|
|
36
|
+
{ value: "theses", label: "theses", description: "Open an investment theses prompt" },
|
|
37
|
+
{ value: "concerns", label: "concerns", description: "Open an investment concerns prompt" },
|
|
35
38
|
];
|
|
36
39
|
|
|
40
|
+
const MEMORY_PROMPTS = {
|
|
41
|
+
worldview:
|
|
42
|
+
"Summarize my current Seed Club investing worldview from recent memory and Seed Club context. Focus on beliefs, decision heuristics, and places where my view has changed. Flag what evidence supports each point.",
|
|
43
|
+
theses:
|
|
44
|
+
"Draft my current investment theses from Seed Club memory and recent deal context. Group by thesis, include supporting signals, counterexamples, and what would change my mind.",
|
|
45
|
+
concerns:
|
|
46
|
+
"List my current recurring investment concerns from Seed Club memory and recent deal context. Group concerns by theme, name the pattern, cite representative context when available, and separate known concerns from guesses.",
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
37
49
|
type MemoryStatus = {
|
|
38
50
|
available: boolean;
|
|
39
51
|
enabled: boolean;
|
|
@@ -55,6 +67,11 @@ function errorMessage(error: unknown) {
|
|
|
55
67
|
return "Seed Club memory request failed.";
|
|
56
68
|
}
|
|
57
69
|
|
|
70
|
+
async function prefillEditor(ctx: any, text: string) {
|
|
71
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
72
|
+
ctx.ui.setEditorText(text);
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
function getSessionId(ctx: any) {
|
|
59
76
|
const cwd = String(ctx?.cwd ?? process.cwd());
|
|
60
77
|
if (MEMORY_SESSION_STRATEGY === "session") {
|
|
@@ -263,11 +280,17 @@ export function registerMemory(pi: ExtensionAPI): MemoryController {
|
|
|
263
280
|
"Show recent memory",
|
|
264
281
|
"Turn memory on",
|
|
265
282
|
"Turn memory off",
|
|
283
|
+
"Investing worldview",
|
|
284
|
+
"Investment theses",
|
|
285
|
+
"Investment concerns",
|
|
266
286
|
]);
|
|
267
287
|
if (choice === "Show status") await showStatus(ctx);
|
|
268
288
|
if (choice === "Show recent memory") await showRecentMemory(ctx);
|
|
269
289
|
if (choice === "Turn memory on") await setEnabled(ctx, true);
|
|
270
290
|
if (choice === "Turn memory off") await setEnabled(ctx, false);
|
|
291
|
+
if (choice === "Investing worldview") await prefillEditor(ctx, MEMORY_PROMPTS.worldview);
|
|
292
|
+
if (choice === "Investment theses") await prefillEditor(ctx, MEMORY_PROMPTS.theses);
|
|
293
|
+
if (choice === "Investment concerns") await prefillEditor(ctx, MEMORY_PROMPTS.concerns);
|
|
271
294
|
}
|
|
272
295
|
|
|
273
296
|
async function showRecentMemory(ctx: any, args = "") {
|
|
@@ -323,7 +346,8 @@ export function registerMemory(pi: ExtensionAPI): MemoryController {
|
|
|
323
346
|
}
|
|
324
347
|
|
|
325
348
|
pi.registerCommand("memory", {
|
|
326
|
-
description:
|
|
349
|
+
description:
|
|
350
|
+
"Open memory status, recent memory, memory on/off, worldview, theses, or concerns (`status`, `recent`, `on`, `off`, `worldview`, `theses`, `concerns`)",
|
|
327
351
|
getArgumentCompletions: (argumentPrefix) => {
|
|
328
352
|
const prefix = argumentPrefix.trim().toLowerCase();
|
|
329
353
|
const completions = MEMORY_COMMAND_COMPLETIONS.filter((item) => item.value.startsWith(prefix));
|
|
@@ -350,11 +374,26 @@ export function registerMemory(pi: ExtensionAPI): MemoryController {
|
|
|
350
374
|
await setEnabled(ctx, false);
|
|
351
375
|
return;
|
|
352
376
|
}
|
|
377
|
+
if (action === "worldview") {
|
|
378
|
+
await prefillEditor(ctx, MEMORY_PROMPTS.worldview);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (action === "theses") {
|
|
382
|
+
await prefillEditor(ctx, MEMORY_PROMPTS.theses);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (action === "concerns") {
|
|
386
|
+
await prefillEditor(ctx, MEMORY_PROMPTS.concerns);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
353
389
|
if (action === "menu") {
|
|
354
390
|
await showMenu(ctx);
|
|
355
391
|
return;
|
|
356
392
|
}
|
|
357
|
-
ctx.ui.notify(
|
|
393
|
+
ctx.ui.notify(
|
|
394
|
+
"Usage: /memory status | /memory recent | /memory on | /memory off | /memory worldview | /memory theses | /memory concerns",
|
|
395
|
+
"error",
|
|
396
|
+
);
|
|
358
397
|
},
|
|
359
398
|
});
|
|
360
399
|
|
package/package.json
CHANGED
|
@@ -395,6 +395,7 @@ const SEEDCLUB_AUTH_GATE_STATE_KEY = "__seedclubAuthGateState";
|
|
|
395
395
|
const SEEDCLUB_SHELL_WELCOME_STATE_KEY = "__seedclubShellWelcomeState";
|
|
396
396
|
const UPDATE_PREFS_FILE = join(homedir(), ".seedclub", "agent", ".seedclub-update-prefs.json");
|
|
397
397
|
const UPDATE_COMMAND = "npm install -g @clubnet/seedclub@latest";
|
|
398
|
+
const STARTUP_UPDATE_CHECK_TIMEOUT_MS = 2500;
|
|
398
399
|
const SEEDCLUB_CONFIG_DIR = join(homedir(), ".config", "seedclub");
|
|
399
400
|
const SEEDCLUB_TOKEN_FILE = join(SEEDCLUB_CONFIG_DIR, "token");
|
|
400
401
|
const SEEDCLUB_BASES_FILE = join(SEEDCLUB_CONFIG_DIR, "bases.json");
|
|
@@ -915,7 +916,7 @@ function renderAuthGateLines(gate) {
|
|
|
915
916
|
renderShellTitle(),
|
|
916
917
|
"",
|
|
917
918
|
` ${theme.fg("accent", "Secure access required")}`,
|
|
918
|
-
` ${theme.fg("dim", gate.message || "Seed Club sign-in is required before
|
|
919
|
+
` ${theme.fg("dim", gate.message || "Seed Club sign-in is required before model setup.")}`,
|
|
919
920
|
];
|
|
920
921
|
if (gate.error) {
|
|
921
922
|
lines.push("");
|
|
@@ -964,33 +965,27 @@ const MEMORY_COMMAND_COMPLETIONS = [
|
|
|
964
965
|
{ value: "recent", label: "recent", description: "Show recent memory" },
|
|
965
966
|
{ value: "on", label: "on", description: "Turn memory on" },
|
|
966
967
|
{ value: "off", label: "off", description: "Turn memory off" },
|
|
968
|
+
{ value: "worldview", label: "worldview", description: "Open an investing worldview prompt" },
|
|
969
|
+
{ value: "theses", label: "theses", description: "Open an investment theses prompt" },
|
|
970
|
+
{ value: "concerns", label: "concerns", description: "Open an investment concerns prompt" },
|
|
967
971
|
];
|
|
968
972
|
|
|
969
973
|
function getBuiltInSlashCommands() {
|
|
970
974
|
return [
|
|
971
|
-
{ name: "new", description: "Start a new session" },
|
|
972
|
-
{ name: "compact", description: "Compact the current session context" },
|
|
973
|
-
{ name: "clear", description: "Clear the visible chat transcript" },
|
|
974
|
-
{ name: "calendar", description: "Open calendar connect and availability actions" },
|
|
975
|
-
{ name: "research", description: "Open a Seed Club research prompt" },
|
|
976
975
|
{ name: "source", description: "Open a source-backed research prompt" },
|
|
976
|
+
{ name: "diligence", description: "Open a Seed Club diligence prompt" },
|
|
977
977
|
{
|
|
978
978
|
name: "memory",
|
|
979
|
-
description: "
|
|
979
|
+
description: "Open memory, recall, and investing perspective actions",
|
|
980
980
|
getArgumentCompletions: (argumentPrefix) => {
|
|
981
981
|
const prefix = argumentPrefix.trim().toLowerCase();
|
|
982
982
|
const completions = MEMORY_COMMAND_COMPLETIONS.filter((item) => item.value.startsWith(prefix));
|
|
983
983
|
return completions.length ? completions : null;
|
|
984
984
|
},
|
|
985
985
|
},
|
|
986
|
-
{ name: "
|
|
987
|
-
{ name: "theses", description: "Open an investment theses prompt" },
|
|
988
|
-
{ name: "concerns", description: "Open an investment concerns prompt" },
|
|
989
|
-
{ name: "model", description: "Select the current model" },
|
|
990
|
-
{ name: "login", description: "Log into a model provider" },
|
|
991
|
-
{ name: "logout", description: "Log out of a model provider" },
|
|
992
|
-
{ name: "update", description: "Show the seedclub package update menu" },
|
|
986
|
+
{ name: "model", description: "Open active model and inference provider settings" },
|
|
993
987
|
{ name: "more", description: "Show everything else" },
|
|
988
|
+
{ name: "disconnect", description: "Disconnect your Seed Club account" },
|
|
994
989
|
{ name: "quit", description: "Exit seedclub" },
|
|
995
990
|
];
|
|
996
991
|
}
|
|
@@ -1004,19 +999,43 @@ function getAuxiliaryBuiltInSlashCommands() {
|
|
|
1004
999
|
}
|
|
1005
1000
|
|
|
1006
1001
|
function getPrimaryExtensionCommandNames() {
|
|
1002
|
+
return new Set([
|
|
1003
|
+
"diligence",
|
|
1004
|
+
"memory",
|
|
1005
|
+
"source",
|
|
1006
|
+
]);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function getSeedclubCommandNames() {
|
|
1007
1010
|
return new Set([
|
|
1008
1011
|
"calendar",
|
|
1009
|
-
"
|
|
1012
|
+
"clearcontext",
|
|
1013
|
+
"clip-status",
|
|
1014
|
+
"connect",
|
|
1015
|
+
"connect-calendar",
|
|
1016
|
+
"diligence",
|
|
1017
|
+
"disconnect",
|
|
1010
1018
|
"memory",
|
|
1011
|
-
"research",
|
|
1012
1019
|
"seedclub",
|
|
1013
1020
|
"seedenv",
|
|
1014
1021
|
"source",
|
|
1015
|
-
"
|
|
1016
|
-
"worldview",
|
|
1022
|
+
"transcripts",
|
|
1017
1023
|
]);
|
|
1018
1024
|
}
|
|
1019
1025
|
|
|
1026
|
+
function isSeedclubCommand(command) {
|
|
1027
|
+
if (getSeedclubCommandNames().has(command.name)) return true;
|
|
1028
|
+
const sourcePath = command.sourceInfo?.path;
|
|
1029
|
+
return typeof sourcePath === "string" && sourcePath.includes("/extensions/seedclub/");
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
function formatCommandList(commands) {
|
|
1033
|
+
return commands
|
|
1034
|
+
.filter((command) => shouldShowCommandInList(command.name))
|
|
1035
|
+
.map((command) => `- \`/${command.name}\`${command.description ? ` ${command.description}` : ""}`)
|
|
1036
|
+
.join("\n");
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1020
1039
|
class SeedclubSurfaceEditor extends CustomEditor {
|
|
1021
1040
|
constructor(tui, editorTheme, keybindings, options) {
|
|
1022
1041
|
super(tui, editorTheme, keybindings, {
|
|
@@ -1273,31 +1292,54 @@ export class SeedclubInteractiveModeApp {
|
|
|
1273
1292
|
this.updateAnnouncementShown = true;
|
|
1274
1293
|
}
|
|
1275
1294
|
|
|
1295
|
+
async getAvailableUpdateInfo(options = {}) {
|
|
1296
|
+
const installed = getInstalledVersionInfo();
|
|
1297
|
+
if (!installed?.seedclubVersion) return null;
|
|
1298
|
+
const latest = await getLatestVersionInfo();
|
|
1299
|
+
if (!latest) return null;
|
|
1300
|
+
if (compareSemver(latest, installed.seedclubVersion) <= 0) return null;
|
|
1301
|
+
const prefs = getUpdatePrefs();
|
|
1302
|
+
if (options.respectSkip !== false && prefs.skipVersion === latest) return null;
|
|
1303
|
+
return {
|
|
1304
|
+
installedVersion: installed.seedclubVersion,
|
|
1305
|
+
latestVersion: latest,
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1276
1309
|
startBackgroundUpdateCheck() {
|
|
1277
1310
|
if (this.updateCheckStarted) return;
|
|
1278
1311
|
this.updateCheckStarted = true;
|
|
1279
1312
|
this.updateAnnouncementShown = false;
|
|
1280
1313
|
this.setAvailableUpdate(null, null);
|
|
1281
1314
|
void (async () => {
|
|
1282
|
-
const
|
|
1283
|
-
if (!
|
|
1284
|
-
|
|
1285
|
-
if (!latest) return;
|
|
1286
|
-
if (compareSemver(latest, installed.seedclubVersion) <= 0) return;
|
|
1287
|
-
const prefs = getUpdatePrefs();
|
|
1288
|
-
if (prefs.skipVersion === latest) return;
|
|
1289
|
-
this.setAvailableUpdate(installed.seedclubVersion, latest);
|
|
1315
|
+
const update = await this.getAvailableUpdateInfo();
|
|
1316
|
+
if (!update) return;
|
|
1317
|
+
this.setAvailableUpdate(update.installedVersion, update.latestVersion);
|
|
1290
1318
|
this.maybeAnnounceAvailableUpdate();
|
|
1291
1319
|
})().catch(() => {});
|
|
1292
1320
|
}
|
|
1293
1321
|
|
|
1294
|
-
async
|
|
1322
|
+
async maybeShowStartupUpdateMenu() {
|
|
1323
|
+
const update = await withTimeout(
|
|
1324
|
+
this.getAvailableUpdateInfo(),
|
|
1325
|
+
STARTUP_UPDATE_CHECK_TIMEOUT_MS,
|
|
1326
|
+
null,
|
|
1327
|
+
);
|
|
1328
|
+
if (!update) return false;
|
|
1329
|
+
this.updateCheckStarted = true;
|
|
1330
|
+
this.setAvailableUpdate(update.installedVersion, update.latestVersion);
|
|
1331
|
+
await this.showUpdateMenu({ availableUpdate: update });
|
|
1332
|
+
this.updateAnnouncementShown = true;
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
async showUpdateMenu(options = {}) {
|
|
1295
1337
|
const installed = getInstalledVersionInfo();
|
|
1296
1338
|
if (!installed?.seedclubVersion) {
|
|
1297
1339
|
this.showExtensionNotify("Unable to determine the installed seedclub version.", "error");
|
|
1298
1340
|
return;
|
|
1299
1341
|
}
|
|
1300
|
-
const latest = await getLatestVersionInfo();
|
|
1342
|
+
const latest = options.availableUpdate?.latestVersion ?? await getLatestVersionInfo();
|
|
1301
1343
|
if (!latest) {
|
|
1302
1344
|
this.showExtensionNotify("Unable to check npm for the latest seedclub version.", "error");
|
|
1303
1345
|
return;
|
|
@@ -1392,6 +1434,7 @@ export class SeedclubInteractiveModeApp {
|
|
|
1392
1434
|
.map((command) => ({
|
|
1393
1435
|
name: command.invocationName,
|
|
1394
1436
|
description: command.description || "",
|
|
1437
|
+
sourceInfo: command.sourceInfo,
|
|
1395
1438
|
})) ?? [];
|
|
1396
1439
|
const promptCommands = (this.session.promptTemplates ?? [])
|
|
1397
1440
|
.map((template) => ({
|
|
@@ -1402,12 +1445,20 @@ export class SeedclubInteractiveModeApp {
|
|
|
1402
1445
|
for (const command of [...builtInCommands, ...extensionCommands, ...promptCommands]) {
|
|
1403
1446
|
if (!deduped.has(command.name)) deduped.set(command.name, command);
|
|
1404
1447
|
}
|
|
1405
|
-
const
|
|
1406
|
-
|
|
1407
|
-
.
|
|
1408
|
-
.
|
|
1409
|
-
|
|
1410
|
-
|
|
1448
|
+
const commands = [...deduped.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
1449
|
+
const seedclubCommands = commands
|
|
1450
|
+
.filter((command) => isSeedclubCommand(command))
|
|
1451
|
+
.filter((command) => shouldShowCommandInList(command.name));
|
|
1452
|
+
const piCommands = commands
|
|
1453
|
+
.filter((command) => !isSeedclubCommand(command))
|
|
1454
|
+
.filter((command) => shouldShowCommandInList(command.name));
|
|
1455
|
+
const seedclubLines = formatCommandList(seedclubCommands);
|
|
1456
|
+
const piLines = formatCommandList(piCommands);
|
|
1457
|
+
const sections = [];
|
|
1458
|
+
if (seedclubLines) sections.push(seedclubLines);
|
|
1459
|
+
if (seedclubLines && piLines) sections.push("---");
|
|
1460
|
+
if (piLines) sections.push(piLines);
|
|
1461
|
+
this.appendAssistantMarkdown(`## More Commands\n\n${sections.join("\n\n")}`);
|
|
1411
1462
|
this.setStatus("Listed all commands.", "accent");
|
|
1412
1463
|
}
|
|
1413
1464
|
|
|
@@ -2001,11 +2052,15 @@ export class SeedclubInteractiveModeApp {
|
|
|
2001
2052
|
}
|
|
2002
2053
|
if (text === "/model" || text.startsWith("/model ")) {
|
|
2003
2054
|
const filter = text.startsWith("/model ") ? text.slice(7).trim() : "";
|
|
2004
|
-
|
|
2055
|
+
if (filter) {
|
|
2056
|
+
await this.showModelSelector(filter);
|
|
2057
|
+
} else {
|
|
2058
|
+
await this.showModelMenu();
|
|
2059
|
+
}
|
|
2005
2060
|
return true;
|
|
2006
2061
|
}
|
|
2007
2062
|
if (text === "/login") {
|
|
2008
|
-
await this.
|
|
2063
|
+
await this.showModelMenu();
|
|
2009
2064
|
return true;
|
|
2010
2065
|
}
|
|
2011
2066
|
if (text.startsWith("/login ")) {
|
|
@@ -2013,7 +2068,7 @@ export class SeedclubInteractiveModeApp {
|
|
|
2013
2068
|
return true;
|
|
2014
2069
|
}
|
|
2015
2070
|
if (text === "/logout") {
|
|
2016
|
-
await this.
|
|
2071
|
+
await this.showModelMenu();
|
|
2017
2072
|
return true;
|
|
2018
2073
|
}
|
|
2019
2074
|
if (text === "/new") {
|
|
@@ -2052,7 +2107,7 @@ export class SeedclubInteractiveModeApp {
|
|
|
2052
2107
|
}
|
|
2053
2108
|
if (available.length === 0) {
|
|
2054
2109
|
this.showExtensionNotify(
|
|
2055
|
-
"No models are currently available. Use /
|
|
2110
|
+
"No models are currently available. Use /model to log into an inference provider, or set an API key environment variable first.",
|
|
2056
2111
|
"warning",
|
|
2057
2112
|
);
|
|
2058
2113
|
return;
|
|
@@ -2076,6 +2131,27 @@ export class SeedclubInteractiveModeApp {
|
|
|
2076
2131
|
}
|
|
2077
2132
|
}
|
|
2078
2133
|
|
|
2134
|
+
async showModelMenu() {
|
|
2135
|
+
const currentModel = this.session.model ?? this.session.state?.model;
|
|
2136
|
+
const activeModel = currentModel ? `${currentModel.provider}/${currentModel.id}` : "none";
|
|
2137
|
+
const choice = await this.showExtensionSelector(`Model\nActive model: ${activeModel}`, [
|
|
2138
|
+
"Change active model",
|
|
2139
|
+
"Login to inference provider",
|
|
2140
|
+
"Logout from inference provider",
|
|
2141
|
+
]);
|
|
2142
|
+
if (choice === "Change active model") {
|
|
2143
|
+
await this.showModelSelector();
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
if (choice === "Login to inference provider") {
|
|
2147
|
+
await this.showOAuthSelector("login");
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
if (choice === "Logout from inference provider") {
|
|
2151
|
+
await this.showOAuthSelector("logout");
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2079
2155
|
async showOAuthSelector(mode) {
|
|
2080
2156
|
const oauthProviders = this.session.modelRegistry.authStorage.getOAuthProviders();
|
|
2081
2157
|
if (mode === "logout") {
|
|
@@ -2083,7 +2159,7 @@ export class SeedclubInteractiveModeApp {
|
|
|
2083
2159
|
.list()
|
|
2084
2160
|
.filter((provider) => this.session.modelRegistry.authStorage.get(provider)?.type === "oauth");
|
|
2085
2161
|
if (loggedInProviders.length === 0) {
|
|
2086
|
-
this.showExtensionNotify("No
|
|
2162
|
+
this.showExtensionNotify("No inference providers are logged in. Use /model to log in first.", "warning");
|
|
2087
2163
|
return;
|
|
2088
2164
|
}
|
|
2089
2165
|
}
|
|
@@ -2124,7 +2200,7 @@ export class SeedclubInteractiveModeApp {
|
|
|
2124
2200
|
|
|
2125
2201
|
async showLoginDialog(providerId) {
|
|
2126
2202
|
if (!providerId) {
|
|
2127
|
-
this.showExtensionNotify("
|
|
2203
|
+
this.showExtensionNotify("Use /model to choose an inference provider login.", "warning");
|
|
2128
2204
|
return;
|
|
2129
2205
|
}
|
|
2130
2206
|
const providerInfo = this.session.modelRegistry.authStorage
|
|
@@ -2502,9 +2578,10 @@ export class SeedclubInteractiveModeApp {
|
|
|
2502
2578
|
this.ui.setFocus(this.editor);
|
|
2503
2579
|
await this.bindExtensions();
|
|
2504
2580
|
this.configureAutocomplete();
|
|
2505
|
-
this.bindShellUiLifecycle();
|
|
2506
2581
|
this.unsubscribe = this.session.subscribe((event) => this.handleSessionEvent(event));
|
|
2507
2582
|
this.ui.start();
|
|
2583
|
+
await this.maybeShowStartupUpdateMenu();
|
|
2584
|
+
this.bindShellUiLifecycle();
|
|
2508
2585
|
this.ui.requestRender(true);
|
|
2509
2586
|
}
|
|
2510
2587
|
|
package/packages/seedclub-tui/src/vendor/coding-agent/modes/interactive/components/oauth-selector.js
CHANGED
|
@@ -24,7 +24,8 @@ export class OAuthSelectorComponent extends Container {
|
|
|
24
24
|
this.onCancelCallback = onCancel;
|
|
25
25
|
this.addChild(new DynamicBorder());
|
|
26
26
|
this.addChild(new Spacer(1));
|
|
27
|
-
const title =
|
|
27
|
+
const title =
|
|
28
|
+
mode === "login" ? "Select inference provider to log in:" : "Select inference provider to log out:";
|
|
28
29
|
this.addChild(new TruncatedText(theme.bold(title)));
|
|
29
30
|
this.addChild(new Spacer(1));
|
|
30
31
|
this.listContainer = new Container();
|
|
@@ -55,7 +56,9 @@ export class OAuthSelectorComponent extends Container {
|
|
|
55
56
|
}
|
|
56
57
|
if (this.allProviders.length === 0) {
|
|
57
58
|
const message =
|
|
58
|
-
this.mode === "login"
|
|
59
|
+
this.mode === "login"
|
|
60
|
+
? "No inference providers available"
|
|
61
|
+
: "No inference providers logged in. Use /model to log in first.";
|
|
59
62
|
this.listContainer.addChild(new TruncatedText(theme.fg("muted", ` ${message}`), 0, 0));
|
|
60
63
|
}
|
|
61
64
|
}
|