@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.
@@ -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("worldview", {
195
- description: "Open an investing worldview prompt",
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
- "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.",
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 /login or /model.",
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: /login, then /model.";
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 /login or /model.",
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 /login or /model.",
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 /login or /model. Opening your browser now."
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 /login or /model.",
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: "Show Seed Club memory status, recent memory, or turn memory on/off (`status`, `recent`, `on`, `off`)",
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("Usage: /memory status | /memory recent | /memory on | /memory off", "error");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clubnet/seedclub",
3
- "version": "0.2.41",
3
+ "version": "0.2.43",
4
4
  "description": "A branded command-line agent wrapper around pi, with integrated Seed Club commands, tools, and app actions",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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 /login or /model.")}`,
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: "Show Seed Club memory status, recent memory, or turn memory on/off",
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: "worldview", description: "Open an investing worldview prompt" },
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
- "concerns",
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
- "theses",
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 installed = getInstalledVersionInfo();
1283
- if (!installed?.seedclubVersion) return;
1284
- const latest = await getLatestVersionInfo();
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 showUpdateMenu() {
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 lines = [...deduped.values()]
1406
- .filter((command) => shouldShowCommandInList(command.name))
1407
- .sort((left, right) => left.name.localeCompare(right.name))
1408
- .map((command) => `- \`/${command.name}\`${command.description ? ` ${command.description}` : ""}`)
1409
- .join("\n");
1410
- this.appendAssistantMarkdown(`## More Commands\n\n${lines}`);
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
- await this.showModelSelector(filter);
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.showOAuthSelector("login");
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.showOAuthSelector("logout");
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 /login or set an API key environment variable first.",
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 OAuth providers are logged in. Use /login first.", "warning");
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("Usage: /login <provider> or /login", "warning");
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
 
@@ -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 = mode === "login" ? "Select provider to login:" : "Select provider to logout:";
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" ? "No OAuth providers available" : "No OAuth providers logged in. Use /login first.";
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
  }