insta 0.0.43 → 0.0.44
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/README.md +1 -1
- package/dist/commands/setup.js +53 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,7 +157,7 @@ That host is a CloudFront cache, so after a change to the installer it can serve
|
|
|
157
157
|
previous copy for up to about a day. This form is equivalent and always current:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging
|
|
160
|
+
curl -fsSL https://raw.githubusercontent.com/InsForge/insta-cli/main/install.sh | sh -s -- --agents --staging
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
If the environment cannot be applied — an installed CLI older than 0.0.23 has no `insta
|
package/dist/commands/setup.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Stack skills (tigris/better-auth) intentionally stay per-project: their presence in a
|
|
7
7
|
// project doubles as its stack manifest — that install happens on `project create|link`.
|
|
8
8
|
import { spawn } from 'node:child_process';
|
|
9
|
-
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
9
|
+
import { closeSync, createReadStream, existsSync, openSync, readFileSync, statSync } from 'node:fs';
|
|
10
10
|
import { dirname, join } from 'node:path';
|
|
11
11
|
import os from 'node:os';
|
|
12
12
|
import { createInterface } from 'node:readline';
|
|
@@ -357,8 +357,55 @@ export function shouldOfferLogin(yes, loggedIn, stdinTty, stdoutTty) {
|
|
|
357
357
|
// One Enter continues into the browser login; only an explicit n/no declines. Matches the
|
|
358
358
|
// curl-installer feel: the single command carries you as far as automation can go, and the one
|
|
359
359
|
// genuinely human step (authorizing in the browser) starts itself instead of being homework.
|
|
360
|
+
// Where to read the answer from. Under `curl … | sh` stdin is the SCRIPT pipe, not the human —
|
|
361
|
+
// but the controlling terminal can still answer, via /dev/tty (the standard installer trick;
|
|
362
|
+
// Homebrew prompts the same way). Never on Windows (no /dev/tty, and the curl path doesn't exist
|
|
363
|
+
// there), and never without one (agents, CI, cron — openSync fails, so they can't be prompted).
|
|
364
|
+
/** Wrap an already-open fd as a prompt input with SINGLE-OWNER cleanup: the stream owns the fd
|
|
365
|
+
* (autoClose), close() only destroys the stream, and post-close stream errors are swallowed.
|
|
366
|
+
* ReadStream.destroy() closes the fd asynchronously on Node 20, so a second closeSync here
|
|
367
|
+
* would race it into an unhandled EBADF right after the user answers. */
|
|
368
|
+
export function makePromptSource(fd) {
|
|
369
|
+
const stream = createReadStream('', { fd, autoClose: true });
|
|
370
|
+
stream.on('error', () => { });
|
|
371
|
+
return { input: stream, close: () => { try {
|
|
372
|
+
stream.destroy();
|
|
373
|
+
}
|
|
374
|
+
catch { /* already destroyed */ } } };
|
|
375
|
+
}
|
|
376
|
+
const openPromptInput = () => {
|
|
377
|
+
if (process.stdin.isTTY)
|
|
378
|
+
return { input: process.stdin, close: () => { } };
|
|
379
|
+
if (process.platform === 'win32')
|
|
380
|
+
return null;
|
|
381
|
+
try {
|
|
382
|
+
return makePromptSource(openSync('/dev/tty', 'r'));
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
/** Whether a human can answer a prompt at all: an interactive stdin, or a reachable /dev/tty
|
|
389
|
+
* (the curl|sh case). The stdout-TTY requirement lives in shouldOfferLogin — an agent piping
|
|
390
|
+
* our output must never be prompted even though its process may have a controlling terminal. */
|
|
391
|
+
export function canPromptViaTty() {
|
|
392
|
+
if (process.stdin.isTTY)
|
|
393
|
+
return true;
|
|
394
|
+
if (process.platform === 'win32')
|
|
395
|
+
return false;
|
|
396
|
+
try {
|
|
397
|
+
closeSync(openSync('/dev/tty', 'r'));
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
360
404
|
const defaultAsk = async (question) => {
|
|
361
|
-
const
|
|
405
|
+
const src = openPromptInput();
|
|
406
|
+
if (!src)
|
|
407
|
+
return false; // gate said yes but the terminal vanished — decline, never hang
|
|
408
|
+
const rl = createInterface({ input: src.input, output: process.stdout });
|
|
362
409
|
// EOF (Ctrl-D) closes the interface without ever answering the question — resolve that as a
|
|
363
410
|
// decline instead of hanging forever after the checkmarks.
|
|
364
411
|
const answer = await new Promise((resolve) => {
|
|
@@ -366,12 +413,13 @@ const defaultAsk = async (question) => {
|
|
|
366
413
|
rl.question(question, resolve);
|
|
367
414
|
});
|
|
368
415
|
rl.close();
|
|
416
|
+
src.close();
|
|
369
417
|
return !/^n/i.test(answer.trim());
|
|
370
418
|
};
|
|
371
419
|
export async function setupAgent(opts, run = defaultRunner, mint, installConfigs = installAgentConfigs, ensure = (r) => ensureCliInstalled(r), readStored = readPersistedGlobal, switchEnv = (n) => envUse(n), loginFlow = {
|
|
372
420
|
ask: defaultAsk,
|
|
373
421
|
login: () => loginOauth('github', {}),
|
|
374
|
-
stdinTty:
|
|
422
|
+
stdinTty: canPromptViaTty(),
|
|
375
423
|
stdoutTty: !!process.stdout.isTTY,
|
|
376
424
|
}) {
|
|
377
425
|
if (!opts.yes && !process.stdout.isTTY) {
|
|
@@ -445,7 +493,7 @@ export async function setupAgent(opts, run = defaultRunner, mint, installConfigs
|
|
|
445
493
|
// (project create/link, deploys, login via the device flow), so the human just asks for the
|
|
446
494
|
// thing they actually want.
|
|
447
495
|
info(loggedIn
|
|
448
|
-
? 'next: open your coding agent inside your app and ask it to "deploy this app on InstaCloud"'
|
|
449
|
-
: 'next: open your coding agent inside your app and ask it to "deploy this app on InstaCloud"
|
|
496
|
+
? 'next: open your coding agent inside your app and start building — ask it to "deploy this app on InstaCloud" when you\'re ready'
|
|
497
|
+
: 'next: open your coding agent inside your app and start building — ask it to "deploy this app on InstaCloud" when you\'re ready (it will walk you through `insta login`)');
|
|
450
498
|
}
|
|
451
499
|
//# sourceMappingURL=setup.js.map
|