insta 0.0.14 → 0.0.16

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.
@@ -1,18 +1,24 @@
1
- import { createInterface } from 'node:readline/promises';
1
+ import { homedir } from 'node:os';
2
2
  import { ApiClient, requireProject } from '../api.js';
3
3
  import { writeProject } from '../config.js';
4
4
  import { info, die, printJson, handleApproval, renderNextActions } from '../util.js';
5
5
  import { installObserve } from '../observe/install.js';
6
6
  import { installSkills } from '../ensure-skills.js';
7
- // Interactive name prompt (stderr, so piped stdout stays clean). Enter accepts the default.
8
- async function promptName(question, def) {
9
- const rl = createInterface({ input: process.stdin, output: process.stderr });
10
- try {
11
- return (await rl.question(`${question} [${def}]: `)).trim();
12
- }
13
- finally {
14
- rl.close();
15
- }
7
+ // Generic directory names that make a useless project name ("projects", "~", "tmp", …). When the
8
+ // cwd basename is one of these we auto-generate a friendly name instead of using it.
9
+ const GENERIC_DIRS = new Set([
10
+ 'projects', 'project', 'home', 'tmp', 'temp', 'desktop', 'documents', 'downloads',
11
+ 'src', 'source', 'code', 'dev', 'work', 'workspace', 'repos', 'repo', 'git',
12
+ 'app', 'apps', 'users', 'user', 'bin', 'new', 'test', 'tests',
13
+ ]);
14
+ const ADJ = ['swift', 'brave', 'calm', 'bright', 'bold', 'quiet', 'warm', 'keen', 'wise',
15
+ 'lucky', 'sunny', 'cosmic', 'gentle', 'rapid', 'vivid', 'amber', 'crisp', 'noble'];
16
+ const NOUN = ['otter', 'falcon', 'maple', 'river', 'harbor', 'meadow', 'comet', 'cedar', 'lark',
17
+ 'delta', 'summit', 'ember', 'willow', 'pixel', 'forge', 'harbor', 'atlas', 'quartz'];
18
+ /** A friendly auto-generated name like `swift-meadow-482` (Vercel/Render style). */
19
+ export function generateProjectName(rand = Math.random) {
20
+ const pick = (a) => a[Math.floor(rand() * a.length)];
21
+ return `${pick(ADJ)}-${pick(NOUN)}-${100 + Math.floor(rand() * 900)}`;
16
22
  }
17
23
  // Best-effort: wire the credential-audit hook into the project (no-op if assets aren't built).
18
24
  function tryInstallObserve() {
@@ -35,20 +41,23 @@ async function resolveOrg(api, given) {
35
41
  export function slugifyName(raw) {
36
42
  return raw.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40);
37
43
  }
38
- /** Name resolution so the recommended one-liner (`insta project create`, no arg) is paste-and-run:
39
- * explicit arg wins; else prompt with the cwd basename as default (TTY); else use the basename. */
40
- export async function resolveProjectName(nameArg, cwd = process.cwd(), prompt) {
41
- const fromDir = slugifyName(cwd.split('/').filter(Boolean).pop() ?? 'app') || 'app';
44
+ /** Name resolution so `insta project create` (no arg) NEVER blocks on a prompt — the whole point
45
+ * of a paste-and-run one-liner. Explicit arg wins; else use the cwd basename when it's a real
46
+ * project-dir name; else auto-generate a friendly name (e.g. in ~/projects, where the basename
47
+ * "projects" is useless). You can always pass a name or rename later. */
48
+ export async function resolveProjectName(nameArg, cwd = process.cwd(), generate = generateProjectName) {
42
49
  if (nameArg)
43
50
  return slugifyName(nameArg);
44
- if (prompt && process.stdin.isTTY)
45
- return slugifyName((await prompt('project name', fromDir)) || fromDir) || fromDir;
46
- return fromDir;
51
+ const base = slugifyName(cwd.split('/').filter(Boolean).pop() ?? '');
52
+ const home = slugifyName(homedir().split('/').filter(Boolean).pop() ?? '');
53
+ if (base && base !== home && !GENERIC_DIRS.has(base))
54
+ return base;
55
+ return generate();
47
56
  }
48
57
  export async function projectCreate(name, opts) {
49
58
  const api = await ApiClient.load();
50
59
  const orgId = await resolveOrg(api, opts.org);
51
- const resolved = await resolveProjectName(name, process.cwd(), promptName);
60
+ const resolved = await resolveProjectName(name, process.cwd());
52
61
  const out = await api.request('POST', `/orgs/${orgId}/projects`, { name: resolved });
53
62
  await writeProject({ projectId: out.project.id, orgId, branch: out.defaultBranch.name });
54
63
  info(`created project ${out.project.id} (${resolved})`);
@@ -71,11 +71,14 @@ export function summarizeInstall(output) {
71
71
  : `${count} agent${count === 1 ? '' : 's'}`;
72
72
  return `✓ Agent skills — ${list}`;
73
73
  }
74
- // Capture stdout+stderr silently (don't stream) so we can print our own clean summary. We keep
75
- // the child's stdin inherited in case the tool ever needs a TTY, but with -y it shouldn't.
74
+ // Capture stdout+stderr silently (don't stream) so we can print our own clean summary.
75
+ // stdin is 'ignore', NOT 'inherit': under the canonical `curl … | sh` install, stdin is the
76
+ // piped install script itself — a child that inherits it (npx/skills reads for keypresses even
77
+ // with -y) consumes the rest of the script, so the shell never runs the trailing "Get started"
78
+ // guidance. Ignoring stdin keeps the installer's own output intact. (-y means no prompt anyway.)
76
79
  const defaultRunner = (cmd, args) => new Promise((resolve) => {
77
80
  const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta', FORCE_COLOR: '0' };
78
- const p = spawn(cmd, args, { stdio: ['inherit', 'pipe', 'pipe'], env });
81
+ const p = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], env });
79
82
  let output = '';
80
83
  const grab = (chunk) => { output += chunk.toString(); };
81
84
  p.stdout?.on('data', grab);
@@ -90,7 +93,7 @@ export async function setupAgent(opts, run = defaultRunner) {
90
93
  if (!opts.yes && !process.stdout.isTTY) {
91
94
  info('non-interactive shell — assuming -y');
92
95
  }
93
- info('setting up coding-agent skills … (~20s)');
96
+ info('setting up coding-agent skills …');
94
97
  const res = await run('npx', SETUP_ARGS);
95
98
  if (!res.ok) {
96
99
  info(' skill install failed — install manually with:');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [