insta 0.0.3 → 0.0.5

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,6 +1,6 @@
1
1
  import { writeFile } from 'node:fs/promises';
2
2
  import { ApiClient, requireProject } from '../api.js';
3
- import { info, printJson, serializeEnv, handleApproval } from '../util.js';
3
+ import { info, printJson, serializeEnv, handleApproval, die } from '../util.js';
4
4
  function q(branch) {
5
5
  return branch ? `?branch=${encodeURIComponent(branch)}` : '';
6
6
  }
@@ -33,4 +33,33 @@ export async function secretsList(opts) {
33
33
  for (const name of Object.keys(res.body.secrets))
34
34
  info(name);
35
35
  }
36
+ async function readStdin() {
37
+ let data = '';
38
+ for await (const chunk of process.stdin)
39
+ data += chunk;
40
+ return data.trim();
41
+ }
42
+ // Set a user secret. Project-wide by default; --branch scopes it to one branch. Value comes from
43
+ // the argument, or stdin when omitted (keeps secret values out of shell history).
44
+ export async function secretsSet(name, value, opts) {
45
+ const api = await ApiClient.load();
46
+ const p = await requireProject();
47
+ const v = value ?? (await readStdin());
48
+ if (!v)
49
+ die('value is required (pass as an argument or on stdin)');
50
+ const payload = opts.branch ? { value: v, branch: opts.branch } : { value: v };
51
+ const res = await api.rawRequest('PUT', `/projects/${p.projectId}/secrets/${encodeURIComponent(name)}`, payload);
52
+ if (handleApproval(res))
53
+ return;
54
+ info(`set ${name} (${opts.branch ? `branch ${opts.branch}` : 'project-wide'})`);
55
+ }
56
+ export async function secretsUnset(name, opts) {
57
+ const api = await ApiClient.load();
58
+ const p = await requireProject();
59
+ const qs = opts.branch ? `?branch=${encodeURIComponent(opts.branch)}` : '';
60
+ const res = await api.rawRequest('DELETE', `/projects/${p.projectId}/secrets/${encodeURIComponent(name)}${qs}`);
61
+ if (handleApproval(res))
62
+ return;
63
+ info(`unset ${name} (${opts.branch ? `branch ${opts.branch}` : 'project-wide'})`);
64
+ }
36
65
  //# sourceMappingURL=secrets.js.map
@@ -11,8 +11,15 @@ import { join } from 'node:path';
11
11
  // Codex → .agents/skills/ (.github/skills/ is the third well-known dir). These are regenerable
12
12
  // agent context, not the developer's source — keep them out of git.
13
13
  const SKILL_DIRS = ['.claude/skills/', '.agents/skills/', '.github/skills/'];
14
+ // `skills` prints a full-screen ASCII banner at the top of every `add`, so our 4 invocations
15
+ // would stack 4 banners. It skips the banner when it detects an agent driving it rather than a
16
+ // human — AI_AGENT is its first-checked signal (any non-empty value ⇒ agent mode). Setting it is
17
+ // honest here (this IS programmatic, not an interactive prompt) and, because we already pin the
18
+ // agents/skills/-y, has no effect on the install beyond quieting the banner. Preserve a caller's
19
+ // existing AI_AGENT (e.g. running inside another agent) rather than clobbering it.
14
20
  const defaultRunner = (cmd, args, inherit = false) => new Promise((resolve) => {
15
- const p = spawn(cmd, args, { stdio: inherit ? 'inherit' : 'ignore' });
21
+ const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta' };
22
+ const p = spawn(cmd, args, { stdio: inherit ? 'inherit' : 'ignore', env });
16
23
  p.on('error', () => resolve({ ok: false })); // e.g. npx not on PATH
17
24
  p.on('close', (code) => resolve({ ok: code === 0 }));
18
25
  });
package/dist/index.js CHANGED
@@ -24,6 +24,14 @@ function onError(e) {
24
24
  // Wrap an async action so rejections surface as clean CLI errors.
25
25
  const guard = (fn) => (...a) => fn(...a).then(() => undefined).catch(onError);
26
26
  const program = new Command();
27
+ // Positional options: some command groups (e.g. `secrets`, `billing`) declare a flag (like
28
+ // --branch or --org) both on the group itself (for its own default action) and on a subcommand
29
+ // of that group. Without this, commander lets the group's own option greedily match the flag
30
+ // no matter where it appears, so e.g. `secrets set NAME val --branch b` silently drops --branch
31
+ // into the (unused) group-level options instead of the subcommand's. Positional parsing makes a
32
+ // group's own options only match before the subcommand name, so occurrences after it are matched
33
+ // against the subcommand's own (identically-named) option instead.
34
+ program.enablePositionalOptions();
27
35
  // Version resolution: INSTA_CLI_VERSION (baked into the standalone binary via bun build --define) →
28
36
  // the installed package.json (npm/node — ../package.json sits beside dist/) → 0.0.0.
29
37
  function resolveVersion() {
@@ -78,6 +86,10 @@ const sec = program.command('secrets').description('Fetch the credential bundle
78
86
  .option('--branch <branch>').option('-o, --output <file>', 'output file (default .env)').option('--print', 'print instead of writing').option('--json')
79
87
  .action(guard((o) => secretsCmd.secrets(o)));
80
88
  sec.command('list').description('List secret names only').option('--branch <branch>').action(guard((o) => secretsCmd.secretsList(o)));
89
+ sec.command('set <name> [value]').description('Set a user secret (project-wide; value from stdin if omitted)')
90
+ .option('--branch <branch>', 'scope to one branch').action(guard((n, v, o) => secretsCmd.secretsSet(n, v, o)));
91
+ sec.command('unset <name>').description('Remove a user secret')
92
+ .option('--branch <branch>', 'scope to one branch').action(guard((n, o) => secretsCmd.secretsUnset(n, o)));
81
93
  // ---- deploy ----
82
94
  program.command('deploy [dir]').description('Deploy a source directory (built remotely on Fly) or a prebuilt --image to a branch compute group')
83
95
  .option('--image <url>', 'prebuilt container image to deploy (instead of a source dir)').option('--branch <b>').option('--group <g>').option('--port <p>')
@@ -127,6 +139,6 @@ ob.command('sync').description('Upload findings into the project timeline').acti
127
139
  // ---- policy ----
128
140
  const pol = program.command('policy').description('Governance policy');
129
141
  pol.command('get').option('--json').action(guard((o) => govern.policyGet(o)));
130
- pol.command('set <action> <decision>').description('action: secrets.read|deploy|project.delete|branch.delete|service.add|service.remove|service.scale|service.upgrade; decision: allow|deny|approve').action(guard((a, d) => govern.policySet(a, d)));
142
+ pol.command('set <action> <decision>').description('action: secrets.read|secrets.write|deploy|project.delete|branch.delete|service.add|service.remove|service.scale|service.upgrade; decision: allow|deny|approve').action(guard((a, d) => govern.policySet(a, d)));
131
143
  program.parseAsync(process.argv);
132
144
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insta",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "description": "InstaCloud CLI — a thin client of the platform control-plane API.",
6
6
  "keywords": ["insta", "insforge", "cli", "backend", "baas", "platform"],