insta 0.0.38 → 0.0.39

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.
@@ -9,10 +9,12 @@ import { spawn } from 'node:child_process';
9
9
  import { existsSync, readFileSync, statSync } from 'node:fs';
10
10
  import { dirname, join } from 'node:path';
11
11
  import os from 'node:os';
12
+ import { createInterface } from 'node:readline';
12
13
  import { ApiClient } from '../api.js';
13
14
  import { readPersistedGlobal, resolveEnv } from '../config.js';
14
15
  import { DEFAULT_ENV, ENVS, ENV_NAMES, envForApiUrl, envFromEnvVar, isEnvName, mcpServerName } from '../env.js';
15
16
  import { info } from '../util.js';
17
+ import { loginOauth } from './auth.js';
16
18
  import { envUse } from './env.js';
17
19
  import { installAgentConfigs } from './mcp.js';
18
20
  import { detectChannel } from './upgrade.js';
@@ -349,7 +351,33 @@ export function planSetupEnv(flagEnv, persistedApiUrl, apiUrlOverride = process.
349
351
  const target = envVar ?? DEFAULT_ENV;
350
352
  return { target, switch: persisted !== target };
351
353
  }
352
- export async function setupAgent(opts, run = defaultRunner, mint, installConfigs = installAgentConfigs, ensure = (r) => ensureCliInstalled(r), readStored = readPersistedGlobal, switchEnv = (n) => envUse(n)) {
354
+ /** Whether setup should flow straight into login: an interactive human terminal with no session.
355
+ * Pure. Non-TTY (agents, CI, pipes) and -y runs never prompt — a browser OAuth flow cannot work
356
+ * there anyway; they get the printed `next:` hint instead, and prompt.md walks agents through
357
+ * login as its own step (relaying the sign-in link to the human). */
358
+ export function shouldOfferLogin(yes, loggedIn, stdinTty, stdoutTty) {
359
+ return !yes && !loggedIn && stdinTty && stdoutTty;
360
+ }
361
+ // One Enter continues into the browser login; only an explicit n/no declines. Matches the
362
+ // curl-installer feel: the single command carries you as far as automation can go, and the one
363
+ // genuinely human step (authorizing in the browser) starts itself instead of being homework.
364
+ const defaultAsk = async (question) => {
365
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
366
+ // EOF (Ctrl-D) closes the interface without ever answering the question — resolve that as a
367
+ // decline instead of hanging forever after the checkmarks.
368
+ const answer = await new Promise((resolve) => {
369
+ rl.on('close', () => resolve('n'));
370
+ rl.question(question, resolve);
371
+ });
372
+ rl.close();
373
+ return !/^n/i.test(answer.trim());
374
+ };
375
+ export async function setupAgent(opts, run = defaultRunner, mint, installConfigs = installAgentConfigs, ensure = (r) => ensureCliInstalled(r), readStored = readPersistedGlobal, switchEnv = (n) => envUse(n), loginFlow = {
376
+ ask: defaultAsk,
377
+ login: () => loginOauth('github', {}),
378
+ stdinTty: !!process.stdin.isTTY,
379
+ stdoutTty: !!process.stdout.isTTY,
380
+ }) {
353
381
  if (!opts.yes && !process.stdout.isTTY) {
354
382
  info('non-interactive shell — assuming -y');
355
383
  }
@@ -397,8 +425,27 @@ export async function setupAgent(opts, run = defaultRunner, mint, installConfigs
397
425
  // login/create commands in it are env-aware at runtime), and staging serves no equivalent.
398
426
  const stored = await readStored();
399
427
  const loggedIn = !!(stored.accessToken || stored.user);
400
- info(loggedIn
401
- ? 'next: `insta project create <name>` in your app repo — or tell your agent: "Fetch https://instacloud.com/prompt.md and follow it"'
402
- : 'next: `insta login --oauth github` (headless: `insta login --device`), then `insta project create <name>` — or tell your agent: "Fetch https://instacloud.com/prompt.md and follow it"');
428
+ const nextCreate = 'next: `insta project create <name>` in your app repo — or tell your agent: "Fetch https://instacloud.com/prompt.md and follow it"';
429
+ if (loggedIn)
430
+ return info(nextCreate);
431
+ // Default into login on an interactive terminal — see shouldOfferLogin. Best-effort: a declined
432
+ // prompt or a failed browser flow leaves a completed setup plus the manual hint, never an error.
433
+ if (shouldOfferLogin(!!opts.yes, loggedIn, loginFlow.stdinTty, loginFlow.stdoutTty)) {
434
+ if (await loginFlow.ask('log in now with GitHub? (Y/n) ')) {
435
+ try {
436
+ await loginFlow.login();
437
+ // --mcp-token needs a session to mint: the registration above ran logged-out and skipped
438
+ // itself with the login hint — now that the session exists, do the token registration.
439
+ if (opts.mcpToken)
440
+ await registerMcp(run, mint, true);
441
+ return info(nextCreate);
442
+ }
443
+ catch (e) {
444
+ info(` login did not complete (${e instanceof Error ? e.message : String(e)}) — no problem, setup itself is done.`);
445
+ info(' on a remote/SSH machine the browser flow cannot call back here — use `insta login --device` instead.');
446
+ }
447
+ }
448
+ }
449
+ info('next: `insta login --oauth github` (headless: `insta login --device`), then `insta project create <name>` — or tell your agent: "Fetch https://instacloud.com/prompt.md and follow it"');
403
450
  }
404
451
  //# sourceMappingURL=setup.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [