@lasso-ai/cli 1.2.6 → 1.3.1

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.
@@ -147,6 +147,91 @@ function proposalMatchesCurrentSource(cwd, changes) {
147
147
  return false;
148
148
  }
149
149
  }
150
+ async function validateBuild(cwd) {
151
+ const pkgPath = node_path_1.default.join(cwd, "package.json");
152
+ if (!node_fs_1.default.existsSync(pkgPath)) {
153
+ return { passed: true, errors: [], command: "none" };
154
+ }
155
+ const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgPath, "utf8"));
156
+ const scripts = pkg.scripts || {};
157
+ // Determine which build command to run
158
+ let buildCommand = "";
159
+ if (scripts.build) {
160
+ buildCommand = "build";
161
+ }
162
+ else if (scripts["build:cli"] || scripts["build:overlay"]) {
163
+ // Monorepo with separate build scripts
164
+ buildCommand = scripts["build:cli"] ? "build:cli" : "build:overlay";
165
+ }
166
+ else if (scripts.compile) {
167
+ buildCommand = "compile";
168
+ }
169
+ else if (scripts.check) {
170
+ buildCommand = "check";
171
+ }
172
+ else if (scripts.lint) {
173
+ buildCommand = "lint";
174
+ }
175
+ else if (scripts.typecheck) {
176
+ buildCommand = "typecheck";
177
+ }
178
+ else if (node_fs_1.default.existsSync(node_path_1.default.join(cwd, "tsconfig.json"))) {
179
+ buildCommand = "tsc"; // Run TypeScript compiler directly
180
+ }
181
+ else {
182
+ // No suitable build command found
183
+ return { passed: true, errors: [], command: "none" };
184
+ }
185
+ try {
186
+ const result = await execFileAsync(buildCommand === "tsc" ? "tsc" : "npm", buildCommand === "tsc" ? [] : ["run", buildCommand], { cwd, maxBuffer: 1024 * 1024 * 10, timeout: 60000 });
187
+ const output = result.stdout + result.stderr;
188
+ const errors = [];
189
+ // Parse TypeScript errors
190
+ if (output.includes("error TS")) {
191
+ const tsErrors = output.match(/error TS\d+.*$/gm) || [];
192
+ errors.push(...tsErrors);
193
+ }
194
+ // Parse general build errors
195
+ if (output.includes("Error:") || output.includes("error:")) {
196
+ const lines = output.split("\n");
197
+ for (const line of lines) {
198
+ if (line.includes("Error:") || line.includes("error:")) {
199
+ errors.push(line.trim());
200
+ }
201
+ }
202
+ }
203
+ return {
204
+ passed: errors.length === 0,
205
+ errors,
206
+ command: buildCommand === "tsc" ? "tsc" : `npm run ${buildCommand}`
207
+ };
208
+ }
209
+ catch (error) {
210
+ const stderr = error.stderr || "";
211
+ const errors = [];
212
+ if (stderr.includes("error TS")) {
213
+ const tsErrors = stderr.match(/error TS\d+.*$/gm) || [];
214
+ errors.push(...tsErrors);
215
+ }
216
+ if (stderr.includes("Error:") || stderr.includes("error:")) {
217
+ const lines = stderr.split("\n");
218
+ for (const line of lines) {
219
+ if (line.includes("Error:") || line.includes("error:")) {
220
+ errors.push(line.trim());
221
+ }
222
+ }
223
+ }
224
+ // If no specific errors found, include the full stderr
225
+ if (errors.length === 0 && stderr) {
226
+ errors.push(stderr);
227
+ }
228
+ return {
229
+ passed: false,
230
+ errors,
231
+ command: buildCommand === "tsc" ? "tsc" : `npm run ${buildCommand}`
232
+ };
233
+ }
234
+ }
150
235
  function readEnvFile(cwd, filename) {
151
236
  try {
152
237
  return node_fs_1.default.readFileSync(node_path_1.default.join(cwd, filename), "utf8").split(/\r?\n/).reduce((values, line) => {
@@ -164,7 +249,7 @@ function readEnvFile(cwd, filename) {
164
249
  return {};
165
250
  }
166
251
  }
167
- function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = exports.DEFAULT_BRIDGE_PORT) {
252
+ async function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = exports.DEFAULT_BRIDGE_PORT) {
168
253
  const bridgeServer = node_http_1.default.createServer(); // dedicated, empty HTTP server
169
254
  const wss = new ws_1.WebSocketServer({ server: bridgeServer });
170
255
  let overlaySocket = null;
@@ -179,7 +264,10 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
179
264
  ...readEnvFile(root, ".env.local"),
180
265
  ...readEnvFile(root, ".env.production"),
181
266
  }), {});
182
- const resolvedLassoKey = (0, project_1.resolveLassoApiKey)(fileEnv) ||
267
+ // Prioritize CLI auth credentials over env vars
268
+ const cliCredentials = (0, auth_1.loadCredentials)();
269
+ const resolvedLassoKey = cliCredentials?.apiKey ||
270
+ (0, project_1.resolveLassoApiKey)(fileEnv) ||
183
271
  process.env.LASSO_API_KEY ||
184
272
  fileEnv.LASSO_API_KEY ||
185
273
  process.env.VITE_LASSO_API_KEY ||
@@ -188,6 +276,19 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
188
276
  fileEnv.NEXT_LASSO_API_KEY ||
189
277
  "";
190
278
  const lassoKeyConfigured = Boolean(resolvedLassoKey);
279
+ // Fetch workspace configuration from server (dashboard-configured providers)
280
+ let workspaceConfig = null;
281
+ if (lassoKeyConfigured) {
282
+ workspaceConfig = await (0, project_1.resolveWorkspaceConfig)(fileEnv);
283
+ }
284
+ // Fetch available models from server
285
+ let dynamicModels = { anthropic: [], openai: [], google: [], nvidia: [] };
286
+ try {
287
+ dynamicModels = await (0, project_1.fetchModels)(fileEnv);
288
+ }
289
+ catch (error) {
290
+ console.warn('[Lasso] Failed to fetch dynamic models, using fallback');
291
+ }
191
292
  const localProviderKeys = {
192
293
  google: process.env.GOOGLE_GENERATIVE_AI_API_KEY || fileEnv.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GEMINI_API_KEY || fileEnv.GEMINI_API_KEY,
193
294
  openai: process.env.OPENAI_API_KEY || fileEnv.OPENAI_API_KEY,
@@ -197,8 +298,9 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
197
298
  };
198
299
  let agentConfig = (() => {
199
300
  const provider = (process.env.LASSO_AGENT_PROVIDER || fileEnv.LASSO_AGENT_PROVIDER || process.env.AI_PROVIDER || fileEnv.AI_PROVIDER || "").toLowerCase();
200
- const selectedProvider = provider === "google" || provider === "gemini" ? "google" : provider === "openai" ? "openai" : provider === "ollama" ? "ollama" : provider === "anthropic" ? "anthropic" : provider === "nvidia" ? "nvidia" : localProviderKeys.ollama ? "ollama" : localProviderKeys.nvidia ? "nvidia" : localProviderKeys.google ? "google" : localProviderKeys.openai ? "openai" : localProviderKeys.anthropic ? "anthropic" : "google";
301
+ const selectedProvider = provider === "google" || provider === "gemini" ? "google" : provider === "openai" ? "openai" : provider === "ollama" ? "ollama" : provider === "anthropic" ? "anthropic" : provider === "nvidia" ? "nvidia" : localProviderKeys.ollama ? "ollama" : localProviderKeys.nvidia ? "nvidia" : localProviderKeys.google ? "google" : localProviderKeys.openai ? "openai" : localProviderKeys.anthropic ? "anthropic" : (cliCredentials ? "anthropic" : "google");
201
302
  const apiKey = selectedProvider === "ollama" ? "ollama" : localProviderKeys[selectedProvider];
303
+ // If user has CLI auth, use Lasso gateway by default
202
304
  if (!apiKey && !lassoKeyConfigured)
203
305
  return null;
204
306
  return {
@@ -301,7 +403,7 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
301
403
  return [];
302
404
  }
303
405
  }
304
- const availableModels = async (collabConfig = null) => {
406
+ const availableModels = async (collabConfig = null, workspaceConfig = null) => {
305
407
  localAgents = await (0, agent_1.detectLocalAgents)();
306
408
  const locals = await localModels();
307
409
  const discoveredOpenCodeModels = await openCodeModels();
@@ -310,51 +412,67 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
310
412
  const base = process.env.OLLAMA_BASE_URL || fileEnv.OLLAMA_BASE_URL || "http://localhost:11434/api";
311
413
  agentConfig = { provider: "ollama", apiKey: "ollama", model: process.env.OLLAMA_MODEL || fileEnv.OLLAMA_MODEL, baseUrl: `${base.replace(/\/api\/?$/, "")}/v1` };
312
414
  }
313
- const isPaidPlan = Boolean(collabConfig?.plan && collabConfig.plan.toLowerCase() !== "free");
314
- const configuredProviders = collabConfig?.configuredProviders || [];
415
+ // Check if user has CLI auth credentials (lasso auth login)
416
+ const cliCredentials = (0, auth_1.loadCredentials)();
417
+ const hasCliAuth = Boolean(cliCredentials?.apiKey);
418
+ // Prioritize workspace config (dashboard) over project config
419
+ // Workspace config is fetched independently of project config
420
+ const workspacePlan = (workspaceConfig?.plan || "free").toLowerCase();
421
+ const workspaceProviders = workspaceConfig?.configuredProviders || [];
422
+ const projectPlan = (collabConfig?.plan || "free").toLowerCase();
423
+ const projectProviders = collabConfig?.configuredProviders || [];
424
+ // Use the highest-tier plan available
425
+ const isPaidPlan = workspacePlan !== "free" || projectPlan !== "free";
426
+ // Use workspace providers if available, otherwise fall back to project providers
427
+ const configuredProviders = workspaceProviders.length > 0 ? workspaceProviders : projectProviders;
428
+ // Build model list from dynamic server fetch, falling back to hardcoded models
315
429
  const allModels = [
316
- // NVIDIA NIM models (confirmed working with server API key)
317
- { id: "meta/llama-3.2-11b-vision-instruct", label: "Llama 3.2 11B Vision", provider: "nvidia" },
318
- { id: "openai/gpt-oss-20b", label: "GPT-OSS 20B (NVIDIA)", provider: "nvidia" },
319
- { id: "deepseek-ai/deepseek-coder-6.7b-instruct", label: "DeepSeek Coder 6.7B", provider: "nvidia" },
320
- { id: "deepseek-ai/deepseek-v4.1-flash", label: "DeepSeek V4.1 Flash", provider: "nvidia" },
321
- { id: "ibm/granite-34b-code-instruct", label: "Granite 34B Code", provider: "nvidia" },
322
- { id: "ibm/granite-3.0-8b-instruct", label: "Granite 3.0 8B", provider: "nvidia" },
323
- { id: "mistralai/mistral-large-2-instruct", label: "Mistral Large 2", provider: "nvidia" },
324
- { id: "mistralai/codestral-22b-instruct-v0.1", label: "Codestral 22B", provider: "nvidia" },
325
- { id: "mistralai/mistral-large", label: "Mistral Large", provider: "nvidia" },
326
- { id: "nv-mistralai/mistral-nemo-12b-instruct", label: "Mistral Nemo 12B", provider: "nvidia" },
327
- { id: "nvidia/nemotron-3.5-lightning-30b-a3b", label: "Nemotron Lightning 30B", provider: "nvidia" },
328
- { id: "microsoft/phi-3.5-moe-instruct", label: "Phi-3.5 MoE", provider: "nvidia" },
329
- { id: "google/gemma-4-31b-it", label: "Gemma 4 31B", provider: "nvidia" },
330
- { id: "moonshotai/kimi-k2.6", label: "Kimi K2.6", provider: "nvidia" },
331
- { id: "poolside/laguna-xs-2.1", label: "Laguna XS 2.1", provider: "nvidia" },
332
- // Existing models
333
- { id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", provider: "anthropic" },
334
- { id: "claude-opus-4-1-20250805", label: "Claude Opus 4.1", provider: "anthropic" },
335
- { id: "gpt-4.1", label: "GPT-4.1", provider: "openai" },
336
- { id: "gpt-4.1-mini", label: "GPT-4.1 mini", provider: "openai" },
337
- { id: "gemini-3.8-flash", label: "Gemini 3.8 Flash", provider: "google" },
338
- { id: "gemini-3.7-flash", label: "Gemini 3.7 Flash", provider: "google" },
339
- { id: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro Preview", provider: "google" },
340
- { id: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview", provider: "google" },
341
- { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro", provider: "google" },
342
- { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash", provider: "google" },
343
- { id: "gemini-2.5-flash-lite", label: "Gemini 2.5 Flash-Lite", provider: "google" },
430
+ // Dynamic models from server API
431
+ ...dynamicModels.anthropic.map(m => ({ id: m.id, label: m.name, provider: m.provider })),
432
+ ...dynamicModels.openai.map(m => ({ id: m.id, label: m.name, provider: m.provider })),
433
+ ...dynamicModels.google.map(m => ({ id: m.id, label: m.name, provider: m.provider })),
434
+ ...dynamicModels.nvidia.map(m => ({ id: m.id, label: m.name, provider: m.provider })),
435
+ // Fallback hardcoded models (only if dynamic fetch failed)
436
+ ...(dynamicModels.anthropic.length === 0 ? [
437
+ { id: "claude-opus-4-5-20251101", label: "Claude Opus 4.5", provider: "anthropic" },
438
+ { id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", provider: "anthropic" },
439
+ { id: "claude-haiku-4-5-20251015", label: "Claude Haiku 4.5", provider: "anthropic" },
440
+ ] : []),
441
+ ...(dynamicModels.openai.length === 0 ? [
442
+ { id: "gpt-5.1", label: "GPT-5.1", provider: "openai" },
443
+ { id: "gpt-5.1-codex", label: "GPT-5.1 Codex", provider: "openai" },
444
+ { id: "gpt-5.1-codex-mini", label: "GPT-5.1 Codex Mini", provider: "openai" },
445
+ { id: "o3", label: "OpenAI o3", provider: "openai" },
446
+ { id: "o3-mini", label: "OpenAI o3-mini", provider: "openai" },
447
+ ] : []),
448
+ ...(dynamicModels.google.length === 0 ? [
449
+ { id: "gemini-3-pro-preview", label: "Gemini 3 Pro", provider: "google" },
450
+ { id: "gemini-3-flash-preview", label: "Gemini 3 Flash", provider: "google" },
451
+ { id: "gemini-2.5-flash-preview-09-2025", label: "Gemini 2.5 Flash", provider: "google" },
452
+ { id: "gemini-2.5-flash-lite-preview-09-2025", label: "Gemini 2.5 Flash Lite", provider: "google" },
453
+ ] : []),
454
+ ...(dynamicModels.nvidia.length === 0 ? [
455
+ { id: "nvidia/llama-3.3-nemotron-super-49b-v1", label: "Llama 3.3 Nemotron Super 49B", provider: "nvidia" },
456
+ { id: "deepseek-ai/deepseek-r1-distill-llama-70b", label: "DeepSeek R1 Distill Llama 70B", provider: "nvidia" },
457
+ { id: "deepseek-ai/deepseek-r1-distill-llama-8b", label: "DeepSeek R1 Distill Llama 8B", provider: "nvidia" },
458
+ { id: "google/gemma-3-1b-it", label: "Gemma 3 1B Instruct", provider: "nvidia" },
459
+ { id: "openai/gpt-oss-120b", label: "GPT-OSS 120B", provider: "nvidia" },
460
+ ] : []),
461
+ // Local CLI agents (always included)
344
462
  ...(localAgents.has("claude-code") ? [
345
- { id: "claude-code:sonnet", label: "Claude Code · Sonnet", provider: "cli" },
346
- { id: "claude-code:opus", label: "Claude Code · Opus", provider: "cli" },
347
- { id: "claude-code:haiku", label: "Claude Code · Haiku", provider: "cli" },
463
+ { id: "claude-code:sonnet", label: "Claude Code · Sonnet 4.5", provider: "cli" },
464
+ { id: "claude-code:opus", label: "Claude Code · Opus 4.5", provider: "cli" },
465
+ { id: "claude-code:haiku", label: "Claude Code · Haiku 4.5", provider: "cli" },
348
466
  ] : []),
349
467
  ...(localAgents.has("codex") ? [
350
- { id: "codex:gpt-5", label: "Codex · GPT-5", provider: "cli" },
351
- { id: "codex:gpt-5-codex", label: "Codex · GPT-5-Codex", provider: "cli" },
468
+ { id: "codex:gpt-5.1", label: "Codex · GPT-5.1", provider: "cli" },
469
+ { id: "codex:gpt-5.1-codex", label: "Codex · GPT-5.1-Codex", provider: "cli" },
352
470
  ] : []),
353
471
  ...(localAgents.has("opencode") ? [
354
472
  { id: "opencode:opencode/big-pickle", label: "OpenCode · Big Pickle", provider: "cli" },
355
473
  { id: "opencode:deepseek/deepseek-chat", label: "OpenCode · DeepSeek Chat", provider: "cli" },
356
- { id: "opencode:anthropic/claude-sonnet-4-5", label: "OpenCode · Claude Sonnet", provider: "cli" },
357
- { id: "opencode:openai/gpt-5", label: "OpenCode · GPT-5", provider: "cli" },
474
+ { id: "opencode:anthropic/claude-sonnet-4-5", label: "OpenCode · Claude Sonnet 4.5", provider: "cli" },
475
+ { id: "opencode:openai/gpt-5.1", label: "OpenCode · GPT-5.1", provider: "cli" },
358
476
  ] : []),
359
477
  ...(localAgents.has("cursor") ? [
360
478
  { id: "cursor:claude-sonnet-4.5", label: "Cursor · Claude Sonnet 4.5", provider: "cli" },
@@ -387,16 +505,33 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
387
505
  return model;
388
506
  }
389
507
  // Free plans: check if provider is configured
390
- const envKey = providerKeyMapping[model.provider];
391
- const isConfigured = configuredProviders.includes(model.provider) ||
392
- Boolean(process.env[envKey]) ||
393
- Boolean(fileEnv[envKey]) ||
394
- Boolean(localProviderKeys[model.provider]);
508
+ let isConfigured = false;
509
+ let lockedReason = "Configure your API key in the dashboard to use this model";
510
+ if (hasCliAuth) {
511
+ // User has CLI auth: check dashboard-configured providers first
512
+ isConfigured = configuredProviders.includes(model.provider);
513
+ lockedReason = "Configure this provider in your workspace dashboard to use this model";
514
+ }
515
+ // If not configured via dashboard, fall back to env-based detection
516
+ if (!isConfigured) {
517
+ const envKey = providerKeyMapping[model.provider];
518
+ isConfigured = Boolean(process.env[envKey]) ||
519
+ Boolean(fileEnv[envKey]) ||
520
+ Boolean(localProviderKeys[model.provider]);
521
+ if (!isConfigured) {
522
+ lockedReason = hasCliAuth
523
+ ? "Configure this provider in your workspace dashboard, or set the provider API key in your .env file"
524
+ : "Run `lasso auth login` to configure providers in your dashboard, or set the provider API key in your .env file";
525
+ }
526
+ else {
527
+ lockedReason = "";
528
+ }
529
+ }
395
530
  if (!isConfigured) {
396
531
  return {
397
532
  ...model,
398
533
  locked: true,
399
- lockedReason: "Configure your API key in the dashboard to use this model",
534
+ lockedReason: lockedReason || "Configure your API key to use this model",
400
535
  };
401
536
  }
402
537
  return model;
@@ -410,7 +545,7 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
410
545
  ? { name: creds.userName, email: creds.userEmail }
411
546
  : (process.env.USER ? { name: process.env.USER } : null);
412
547
  socket.send(JSON.stringify({ type: "config", apiKeyConfigured: lassoKeyConfigured, agentConfigured: lassoKeyConfigured || Boolean(agentConfig) || localAgents.size > 0, models: [], collab: collabConfig?.registered ? { ...collabConfig, plan: collabConfig.plan, configuredProviders: collabConfig.configuredProviders } : null, user: userInfo }));
413
- void availableModels(collabConfig).then((models) => {
548
+ void availableModels(collabConfig, workspaceConfig).then((models) => {
414
549
  if (socket.readyState === socket.OPEN)
415
550
  socket.send(JSON.stringify({ type: "config", apiKeyConfigured: lassoKeyConfigured, agentConfigured: lassoKeyConfigured || Boolean(agentConfig) || localAgents.size > 0, models, collab: collabConfig?.registered ? { ...collabConfig, plan: collabConfig.plan, configuredProviders: collabConfig.configuredProviders } : null, user: userInfo }));
416
551
  });
@@ -763,7 +898,14 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
763
898
  return;
764
899
  }
765
900
  const provider = (msg.provider || agentConfig?.provider || "google");
766
- const model = msg.model || agentConfig?.model || (provider === "nvidia" ? "nvidia/llama-3.1-nemotron-70b-instruct" : provider === "google" ? "gemini-2.5-flash" : "claude-3-7-sonnet");
901
+ const model = msg.model || agentConfig?.model;
902
+ if (!model) {
903
+ socket.send(JSON.stringify({
904
+ type: "error",
905
+ message: "No model selected. Please select a model in settings."
906
+ }));
907
+ return;
908
+ }
767
909
  const localKey = localProviderKeys[provider];
768
910
  const serverUrl = collabConfig?.serverUrl || (0, auth_1.serverUrlFrom)(fileEnv);
769
911
  const targetApiUrl = (serverUrl.includes("collab.lasso.byorello.space") ? "https://api.lasso.byorello.space" : serverUrl).replace(/\/api\/v1\/?$/, "");
@@ -852,7 +994,14 @@ function startBridge(cwd = process.cwd(), collabConfig = null, bridgePort = expo
852
994
  node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), { recursive: true });
853
995
  node_fs_1.default.writeFileSync(filePath, nextContent);
854
996
  }
855
- socket.send(JSON.stringify({ type: "applied", taskId: msg.taskId, message: `${msg.changes.length} file${msg.changes.length === 1 ? "" : "s"} updated. Your dev server will reload.` }));
997
+ // Run build validation after applying changes
998
+ const validation = await validateBuild(cwd);
999
+ socket.send(JSON.stringify({
1000
+ type: "applied",
1001
+ taskId: msg.taskId,
1002
+ message: `${msg.changes.length} file${msg.changes.length === 1 ? "" : "s"} updated. Your dev server will reload.`,
1003
+ validation
1004
+ }));
856
1005
  }
857
1006
  catch (error) {
858
1007
  // Validation happens before writes, but restore this task's snapshot
@@ -75,7 +75,7 @@ void (async () => {
75
75
  const nextBin = node_path_1.default.join(cwd, "node_modules", ".bin", "next");
76
76
  if (!node_fs_1.default.existsSync(nextBin))
77
77
  throw new Error("Next.js is not installed in this project.");
78
- const bridge = (0, bridge_1.startBridge)(cwd, null, bridgePort);
78
+ const bridge = await (0, bridge_1.startBridge)(cwd, null, bridgePort);
79
79
  const nextProcess = (0, node_child_process_1.spawn)(nextBin, ["dev", "--port", String(nextPort), "--hostname", "127.0.0.1"], {
80
80
  cwd,
81
81
  env: { ...process.env, PORT: String(nextPort) },
@@ -27,7 +27,7 @@ function lassoOverlayPlugin() {
27
27
  };
28
28
  }
29
29
  void (async () => {
30
- const bridge = (0, bridge_1.startBridge)(cwd, null, bridgePort);
30
+ const bridge = await (0, bridge_1.startBridge)(cwd, null, bridgePort);
31
31
  const require = (0, node_module_1.createRequire)(node_path_1.default.join(cwd, "package.json"));
32
32
  const viteEntry = require.resolve("vite");
33
33
  const { createServer } = await import((0, node_url_1.pathToFileURL)(viteEntry).href);
package/dist/cli/index.js CHANGED
@@ -94,6 +94,23 @@ program.command("create [name]")
94
94
  }
95
95
  });
96
96
  // prettier-ignore
97
+ program.command("whoami")
98
+ .description("Show the currently authenticated Lasso user")
99
+ .action(() => {
100
+ const credentials = (0, auth_1.loadCredentials)();
101
+ if (!credentials) {
102
+ console.log(chalk_1.default.dim("Not authenticated. Run ") + chalk_1.default.cyan("lasso auth login") + chalk_1.default.dim(" to sign in."));
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ const summary = (0, auth_1.credentialSummary)(credentials);
107
+ console.log(chalk_1.default.green("✓") + ` Authenticated as ${chalk_1.default.bold(summary.userEmail || "your account")}` + (summary.userName ? ` (${summary.userName})` : ""));
108
+ if (summary.workspaceName)
109
+ console.log(chalk_1.default.dim(`Workspace: ${summary.workspaceName} (${summary.workspaceId})`));
110
+ if (summary.masked)
111
+ console.log(chalk_1.default.dim("Credential: ") + summary.masked);
112
+ });
113
+ // prettier-ignore
97
114
  const daemon = program.command("daemon [action]")
98
115
  .description("Start/stop Lasso Host — the local .lasso domain server (start|status|stop|restart|install|uninstall)")
99
116
  .usage("[action]")
@@ -439,7 +456,7 @@ program.command("dev", { isDefault: true }).description("Start your dev server w
439
456
  else {
440
457
  console.log(chalk_1.default.yellow("!") + ` No ${chalk_1.default.bold(project_1.LASSO_CONFIG_FILE)} found. Run ${chalk_1.default.cyan("npx @lasso-ai/cli init")} to enable realtime collaboration.`);
441
458
  }
442
- (0, bridge_1.startBridge)(cwd, collabConfig);
459
+ await (0, bridge_1.startBridge)(cwd, collabConfig);
443
460
  switch (framework) {
444
461
  case "vite":
445
462
  console.log(chalk_1.default.green("✓") + " Detected: Vite");
@@ -31,5 +31,4 @@ export interface ConversationMessage {
31
31
  role: "user" | "assistant";
32
32
  content: string;
33
33
  }
34
- export declare function isConversationalPrompt(prompt: string): boolean;
35
34
  export declare function runOneShotAgent(cwd: string, prompt: string, scope: "project" | "component", config: AgentConfig, signal: AbortSignal, onProgress: ProgressCallback, onPrompt: PromptCallback, messages?: ConversationMessage[], serverUrl?: string, apiKey?: string, taskId?: string, pageContext?: any): Promise<OneShotResult>;