insta 0.0.12 → 0.0.14
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 +77 -29
- package/package.json +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -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
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
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,67 @@ 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. We keep
|
|
75
|
+
// the child's stdin inherited in case the tool ever needs a TTY, but with -y it shouldn't.
|
|
21
76
|
const defaultRunner = (cmd, args) => new Promise((resolve) => {
|
|
22
|
-
const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta', FORCE_COLOR: '
|
|
77
|
+
const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta', FORCE_COLOR: '0' };
|
|
23
78
|
const p = spawn(cmd, args, { stdio: ['inherit', 'pipe', 'pipe'], env });
|
|
24
|
-
let
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
});
|
|
79
|
+
let output = '';
|
|
80
|
+
const grab = (chunk) => { output += chunk.toString(); };
|
|
81
|
+
p.stdout?.on('data', grab);
|
|
82
|
+
p.stderr?.on('data', grab);
|
|
83
|
+
p.on('error', () => resolve({ ok: false, output }));
|
|
84
|
+
p.on('close', (code) => resolve({ ok: code === 0, output }));
|
|
45
85
|
});
|
|
46
86
|
// -g = user-level (machine-global); -a '*' = every agent dir the skills tool supports
|
|
47
87
|
// (Claude Code, Codex, Cursor, OpenCode, Copilot, …); --copy = real files, not cache symlinks.
|
|
@@ -50,15 +90,23 @@ export async function setupAgent(opts, run = defaultRunner) {
|
|
|
50
90
|
if (!opts.yes && !process.stdout.isTTY) {
|
|
51
91
|
info('non-interactive shell — assuming -y');
|
|
52
92
|
}
|
|
53
|
-
info('
|
|
93
|
+
info('setting up coding-agent skills … (~20s)');
|
|
54
94
|
const res = await run('npx', SETUP_ARGS);
|
|
55
95
|
if (!res.ok) {
|
|
56
96
|
info(' skill install failed — install manually with:');
|
|
57
97
|
info(' npx skills add InsForge/insta-skills -s insta -a "*" -g -y --copy');
|
|
98
|
+
// Surface the REAL error: the captured tail, minus the expected no-global-support noise.
|
|
99
|
+
const tail = (res.output ?? '')
|
|
100
|
+
.split('\n')
|
|
101
|
+
.map((l) => l.replace(/\x1b\[[0-9;]*m/g, '').trimEnd())
|
|
102
|
+
.filter((l) => l.trim() && classifyInstallLine(l) === 'keep')
|
|
103
|
+
.slice(-6);
|
|
104
|
+
for (const l of tail)
|
|
105
|
+
info(' ' + l);
|
|
58
106
|
process.exitCode = 1;
|
|
59
107
|
return;
|
|
60
108
|
}
|
|
61
|
-
info(
|
|
62
|
-
info('
|
|
109
|
+
info(summarizeInstall(res.output ?? ''));
|
|
110
|
+
info(' every coding agent on this machine now knows InstaCloud (review skills before use — they run with full permissions).');
|
|
63
111
|
}
|
|
64
112
|
//# sourceMappingURL=setup.js.map
|