insta 0.0.51 → 0.0.52

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.
@@ -16,7 +16,7 @@ import { DEFAULT_ENV, ENVS, ENV_NAMES, envForApiUrl, envFromEnvVar, isEnvName, m
16
16
  import { info, openUrl } from '../util.js';
17
17
  import { isRunnableFile, resolveSpawnable } from '../spawn.js';
18
18
  import { loginDevice } from './auth.js';
19
- import { projectLink } from './project.js';
19
+ import { projectCreate, projectLink, slugifyName } from './project.js';
20
20
  import { envUse } from './env.js';
21
21
  import { installAgentConfigs } from './mcp.js';
22
22
  import { detectChannel } from './upgrade.js';
@@ -276,6 +276,18 @@ export function planSetupEnv(flagEnv, persistedApiUrl, apiUrlOverride = process.
276
276
  const target = envVar ?? DEFAULT_ENV;
277
277
  return { target, switch: persisted !== target };
278
278
  }
279
+ /** The project step. Only a contradictory flag pair throws: rejecting a nameless `--create` here
280
+ * would abort the whole setup, and `projectCreate` already guides that case. */
281
+ export function planProject(opts) {
282
+ if (opts.create !== undefined && opts.project !== undefined) {
283
+ throw new Error('--create and --project are mutually exclusive — create a new project, or link an existing one');
284
+ }
285
+ if (opts.project)
286
+ return { kind: 'link', id: opts.project };
287
+ if (opts.create === undefined)
288
+ return { kind: 'none' };
289
+ return { kind: 'create', name: typeof opts.create === 'string' ? opts.create : undefined };
290
+ }
279
291
  /** Whether setup should flow straight into login: an interactive human terminal with no session.
280
292
  * Pure. Non-TTY (agents, CI, pipes) and -y runs never prompt — a browser OAuth flow cannot work
281
293
  * there anyway; they get the printed `next:` hint instead, and prompt.md walks agents through
@@ -350,10 +362,12 @@ export async function setupAgent(opts, run = defaultRunner, mint, installConfigs
350
362
  login: () => loginDevice({}, openUrl),
351
363
  stdinTty: canPromptViaTty(),
352
364
  stdoutTty: !!process.stdout.isTTY,
353
- }, link = projectLink) {
365
+ }, link = projectLink, create = (n) => projectCreate(n, {})) {
354
366
  if (!opts.yes && !process.stdout.isTTY) {
355
367
  info('non-interactive shell — assuming -y');
356
368
  }
369
+ // Reject an impossible --project/--create request here, while the machine is still untouched.
370
+ const project = planProject(opts);
357
371
  // Pin the environment BEFORE anything is installed (see planSetupEnv). A required switch goes
358
372
  // through `env use` — the one path that persists the choice and drops the now-foreign session —
359
373
  // and announces itself, so the machine can never end up with its CLI on one deployment and its
@@ -411,26 +425,33 @@ export async function setupAgent(opts, run = defaultRunner, mint, installConfigs
411
425
  }
412
426
  }
413
427
  }
414
- // --project: link this directory inside the SAME process. The console's connect panel used to
415
- // print `setup agent && insta project link <id>` as one paste — but no shell joiner survives
416
- // every Windows shell, and in shells without bracketed paste the queued link line is eaten as
417
- // the answer to the login prompt above (console PR #290). Carrying the id as a flag is the one
418
- // form where "one line" is safe. Linking needs the session: without one the manual command is
419
- // the hint, never a hang; a failed link (bad id, no access) is a REAL error — the link is the
420
- // entire point of the flag — so it sets the exit code instead of pretending setup succeeded.
421
- if (opts.project) {
428
+ // --project / --create: bind this directory to a project inside the SAME process. Never split
429
+ // this back into `setup agent && insta project <cmd>` as one paste: no shell joiner survives
430
+ // every Windows shell, and in shells without bracketed paste the queued second line is eaten
431
+ // as the answer to the login prompt above (console PR #290). Both need the session: without
432
+ // one the manual command is the hint, never a hang; a failure (bad id, no access, name taken)
433
+ // is a REAL error — binding a project is the entire point of the flag — so it sets the exit
434
+ // code instead of pretending setup succeeded.
435
+ if (project.kind !== 'none') {
436
+ const linking = project.kind === 'link';
437
+ const retry = linking
438
+ ? `insta project link ${project.id}`
439
+ : `insta project create${project.name ? ` ${slugifyName(project.name)}` : ''}`;
422
440
  if (!loggedIn) {
423
- info(` not logged in — project not linked; run \`insta login\`, then \`insta project link ${opts.project}\``);
441
+ info(` not logged in — project not ${linking ? 'linked' : 'created'}; run \`insta login\`, then \`${retry}\``);
424
442
  }
425
443
  else {
426
444
  try {
427
- await link(opts.project);
445
+ if (project.kind === 'link')
446
+ await link(project.id);
447
+ else
448
+ await create(project.name);
428
449
  }
429
450
  catch (e) {
430
451
  // Stop here — like the skill-install failure above, finishing with the success summary
431
452
  // and a cheerful `next:` after an error is mixed messaging. Setup itself did succeed,
432
453
  // so say exactly that alongside the retry command.
433
- info(` project link failed (${e instanceof Error ? e.message : String(e)}) — agent setup itself is done; run \`insta project link ${opts.project}\` to retry the link`);
454
+ info(` project ${linking ? 'link' : 'create'} failed (${e instanceof Error ? e.message : String(e)}) — agent setup itself is done; run \`${retry}\` to retry the ${linking ? 'link' : 'create'}`);
434
455
  process.exitCode = 1;
435
456
  return;
436
457
  }
package/dist/index.js CHANGED
@@ -91,6 +91,7 @@ setupCmd.command('agent').description('Install the insta CLI (if missing), the i
91
91
  .option('--env <prod|staging>', 'deployment to set this machine up for (default: prod — switches and persists, like `insta env use`)')
92
92
  .option('--mcp-token', 'register the MCP server with a minted insta_ API token instead of OAuth (headless machines / CI)')
93
93
  .option('--project <id>', 'also link this directory to an existing project after setup (flows through login first if needed)')
94
+ .option('--create [name]', 'also create a new project and link this directory after setup (default name: this directory; mutually exclusive with --project)')
94
95
  .action(guard((o) => setup.setupAgent(o)));
95
96
  // ---- MCP server integration ----
96
97
  const mcpCmd = program.command('mcp').description('insta-cloud remote MCP server integration');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.51",
3
+ "version": "0.0.52",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [