insta 0.0.13 → 0.0.15

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.
@@ -7,10 +7,13 @@
7
7
  // project doubles as its stack manifest — that install happens on `project create|link`.
8
8
  import { spawn } from 'node:child_process';
9
9
  import { info } from '../util.js';
10
- // The skills tool reports agents that don't support user-global installs (Eve, PromptScript, …)
11
- // as red failures. That's expected reality, not a problem with THIS machine — showing red in the
12
- // first 30s of onboarding erodes trust (Railway's installer reads all-green for a reason).
13
- // Classify each output line: drop that expected noise, keep everything real.
10
+ // The `skills` tool we shell out to prints a clack UI: a frame-by-frame clone spinner, an
11
+ // "Installing to all N agents" banner, a full N-line install-path box, and a third-party
12
+ // "Security Risk Assessment" that flags our OWN first-party skill as "Critical Risk". Streamed
13
+ // verbatim during onboarding that reads as noisy and alarming — the opposite of Railway's two
14
+ // clean ✓ lines. So we CAPTURE its output and print our own one-line summary instead. This
15
+ // classifier decides which captured lines are worth showing if the install FAILS (surface the
16
+ // real error; drop the expected no-global-support noise).
14
17
  export function classifyInstallLine(line) {
15
18
  if (/does not support global skill installation/.test(line))
16
19
  return 'skip';
@@ -18,30 +21,70 @@ export function classifyInstallLine(line) {
18
21
  return 'skip';
19
22
  return 'keep';
20
23
  }
24
+ // Map a skill-install target directory to a human agent name. `-a '*'` installs to every agent
25
+ // dir the tool knows (~70+); we name the well-known ones (Railway-style) and roll the long tail
26
+ // into "+N more" rather than dumping every path. Order = display priority.
27
+ const AGENT_NAMES = [
28
+ [/\.agents\b/, 'Universal (.agents)'],
29
+ [/\.claude\b/, 'Claude Code'],
30
+ [/\.codex\b/, 'OpenAI Codex'],
31
+ [/\.cursor\b/, 'Cursor'],
32
+ [/opencode\b/, 'OpenCode'],
33
+ [/copilot\b/, 'GitHub Copilot'],
34
+ [/\.gemini\b/, 'Gemini CLI'],
35
+ [/windsurf\b/, 'Windsurf'],
36
+ [/\.factory\b/, 'Factory Droid'],
37
+ [/goose\b/, 'Goose'],
38
+ [/aider\b/, 'Aider'],
39
+ [/\.continue\b/, 'Continue'],
40
+ [/\.roo\b/, 'Roo'],
41
+ [/kilocode\b/, 'Kilo Code'],
42
+ [/\.qwen\b/, 'Qwen'],
43
+ ];
44
+ // Pull install-target paths out of the skills tool's summary lines ("→ ~/.claude/skills/insta")
45
+ // and resolve the well-known ones to names. Returns the total install count + named agents.
46
+ export function parseInstalledAgents(output) {
47
+ const paths = new Set();
48
+ for (const line of output.split('\n')) {
49
+ const plain = line.replace(/\x1b\[[0-9;]*m/g, '');
50
+ // The tool boxes each line ("│ → ~/.claude/skills/insta │"), so don't anchor to EOL.
51
+ const m = plain.match(/→\s*(\S+)\/skills\/[A-Za-z0-9_-]+/);
52
+ if (m && m[1])
53
+ paths.add(m[1]);
54
+ }
55
+ const names = [];
56
+ for (const [re, name] of AGENT_NAMES) {
57
+ if ([...paths].some((p) => re.test(p)))
58
+ names.push(name);
59
+ }
60
+ return { count: paths.size, names };
61
+ }
62
+ // The Railway-style one-liner: a few named agents, the rest as "+N more".
63
+ export function summarizeInstall(output) {
64
+ const { count, names } = parseInstalledAgents(output);
65
+ if (count === 0)
66
+ return '✓ insta skill installed for your coding agents';
67
+ const shown = names.slice(0, 6);
68
+ const more = count - shown.length;
69
+ const list = shown.length
70
+ ? shown.join(', ') + (more > 0 ? `, +${more} more` : '')
71
+ : `${count} agent${count === 1 ? '' : 's'}`;
72
+ return `✓ Agent skills — ${list}`;
73
+ }
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.)
21
79
  const defaultRunner = (cmd, args) => new Promise((resolve) => {
22
- const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta', FORCE_COLOR: '1' };
23
- const p = spawn(cmd, args, { stdio: ['inherit', 'pipe', 'pipe'], env });
24
- let skipped = 0;
25
- const sift = (chunk) => {
26
- for (const line of chunk.toString().split('\n')) {
27
- // strip ANSI before classifying; print the original line to preserve the tool's styling
28
- const plain = line.replace(/\x1b\[[0-9;]*m/g, '');
29
- if (classifyInstallLine(plain) === 'skip') {
30
- skipped++;
31
- continue;
32
- }
33
- if (line.trim())
34
- process.stdout.write(line + '\n');
35
- }
36
- };
37
- p.stdout?.on('data', sift);
38
- p.stderr?.on('data', sift);
39
- p.on('error', () => resolve({ ok: false }));
40
- p.on('close', (code) => {
41
- if (skipped)
42
- info(` (skipped ${skipped >= 3 ? 'some' : skipped} agent targets that don't support user-global installs — expected)`);
43
- resolve({ ok: code === 0 });
44
- });
80
+ const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta', FORCE_COLOR: '0' };
81
+ const p = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], env });
82
+ let output = '';
83
+ const grab = (chunk) => { output += chunk.toString(); };
84
+ p.stdout?.on('data', grab);
85
+ p.stderr?.on('data', grab);
86
+ p.on('error', () => resolve({ ok: false, output }));
87
+ p.on('close', (code) => resolve({ ok: code === 0, output }));
45
88
  });
46
89
  // -g = user-level (machine-global); -a '*' = every agent dir the skills tool supports
47
90
  // (Claude Code, Codex, Cursor, OpenCode, Copilot, …); --copy = real files, not cache symlinks.
@@ -50,15 +93,23 @@ export async function setupAgent(opts, run = defaultRunner) {
50
93
  if (!opts.yes && !process.stdout.isTTY) {
51
94
  info('non-interactive shell — assuming -y');
52
95
  }
53
- info('installing the insta skill (user-global, all agents) …');
96
+ info('setting up coding-agent skills …');
54
97
  const res = await run('npx', SETUP_ARGS);
55
98
  if (!res.ok) {
56
99
  info(' skill install failed — install manually with:');
57
100
  info(' npx skills add InsForge/insta-skills -s insta -a "*" -g -y --copy');
101
+ // Surface the REAL error: the captured tail, minus the expected no-global-support noise.
102
+ const tail = (res.output ?? '')
103
+ .split('\n')
104
+ .map((l) => l.replace(/\x1b\[[0-9;]*m/g, '').trimEnd())
105
+ .filter((l) => l.trim() && classifyInstallLine(l) === 'keep')
106
+ .slice(-6);
107
+ for (const l of tail)
108
+ info(' ' + l);
58
109
  process.exitCode = 1;
59
110
  return;
60
111
  }
61
- info('done — agents on this machine now know InstaCloud.');
62
- info('next: `insta login --oauth github` (cloud) or run instad locally (insta-oss), then `insta project create <name>`.');
112
+ info(summarizeInstall(res.output ?? ''));
113
+ info(' every coding agent on this machine now knows InstaCloud (review skills before use — they run with full permissions).');
63
114
  }
64
115
  //# sourceMappingURL=setup.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": [