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.
- package/dist/commands/setup.js +51 -4
- package/package.json +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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
|