insta 0.0.18 → 0.0.20
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/branch.js +18 -0
- package/dist/commands/compute.js +5 -3
- package/dist/commands/services.js +43 -11
- package/dist/ensure-skills.js +6 -2
- package/dist/index.js +18 -10
- package/package.json +1 -1
package/dist/commands/branch.js
CHANGED
|
@@ -38,4 +38,22 @@ export async function branchDelete(name) {
|
|
|
38
38
|
return;
|
|
39
39
|
info(`deleted branch ${name}`);
|
|
40
40
|
}
|
|
41
|
+
// insta branch merge <source> [--into <target>] — structurally merge source's services into target
|
|
42
|
+
// (default target: current branch). No data is copied; existing services are left untouched.
|
|
43
|
+
export async function branchMerge(source, opts = {}) {
|
|
44
|
+
const api = await ApiClient.load();
|
|
45
|
+
const p = await requireProject();
|
|
46
|
+
const target = opts.into ?? p.branch;
|
|
47
|
+
if (!target)
|
|
48
|
+
throw new Error('no target branch — pass --into <branch> (or link a branch first)');
|
|
49
|
+
const res = await api.rawRequest('POST', `/projects/${p.projectId}/branches/${encodeURIComponent(target)}/merge`, { from: source });
|
|
50
|
+
if (handleApproval(res))
|
|
51
|
+
return;
|
|
52
|
+
const { created = [], skipped = [] } = (res.body ?? {});
|
|
53
|
+
info(`merged ${source} → ${target}: ${created.length} created, ${skipped.length} skipped`);
|
|
54
|
+
for (const c of created)
|
|
55
|
+
info(` + ${c.type}/${c.name}`);
|
|
56
|
+
for (const s of skipped)
|
|
57
|
+
info(` = ${s.type}/${s.name} (${s.reason})`);
|
|
58
|
+
}
|
|
41
59
|
//# sourceMappingURL=branch.js.map
|
package/dist/commands/compute.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApiClient, requireProject } from '../api.js';
|
|
2
2
|
import { info, printJson, handleApproval } from '../util.js';
|
|
3
|
-
import { resolveComputeServiceId } from './services.js';
|
|
3
|
+
import { resolveComputeServiceId, q } from './services.js';
|
|
4
4
|
// Attach a developer-owned custom domain to a branch's compute service. Fly issues the cert + routes
|
|
5
5
|
// it; the platform returns the DNS records to set in your OWN zone.
|
|
6
6
|
export async function setDomain(host, opts) {
|
|
@@ -46,7 +46,8 @@ function printDomain(r, json) {
|
|
|
46
46
|
async function lifecycle(verb, serviceName, opts) {
|
|
47
47
|
const api = await ApiClient.load();
|
|
48
48
|
const p = await requireProject();
|
|
49
|
-
const
|
|
49
|
+
const branch = opts.branch ?? p.branch;
|
|
50
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
|
|
50
51
|
const id = resolveComputeServiceId(services, serviceName);
|
|
51
52
|
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/${verb}`);
|
|
52
53
|
if (handleApproval(res))
|
|
@@ -61,7 +62,8 @@ export const computeSuspend = (service, opts) => lifecycle('suspend', service, o
|
|
|
61
62
|
export async function computeStatus(serviceName, opts) {
|
|
62
63
|
const api = await ApiClient.load();
|
|
63
64
|
const p = await requireProject();
|
|
64
|
-
const
|
|
65
|
+
const branch = opts.branch ?? p.branch;
|
|
66
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
|
|
65
67
|
const id = resolveComputeServiceId(services, serviceName);
|
|
66
68
|
const r = await api.request('GET', `/projects/${p.projectId}/services/${id}/state`);
|
|
67
69
|
if (opts.json)
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { ApiClient, requireProject } from '../api.js';
|
|
3
3
|
import { info, printJson, handleApproval, renderNextActions } from '../util.js';
|
|
4
4
|
export const SERVICE_TYPES = ['postgres', 'storage', 'compute'];
|
|
5
|
+
export function q(branch) {
|
|
6
|
+
return branch ? `?branch=${encodeURIComponent(branch)}` : '';
|
|
7
|
+
}
|
|
5
8
|
// ---- pure, unit-tested helpers (throw plain Errors; the CLI guard turns them into clean output) ----
|
|
6
9
|
// Validate a service-type argument against the allowed set for a command.
|
|
7
10
|
export function assertType(type, allowed = SERVICE_TYPES) {
|
|
@@ -38,40 +41,69 @@ export function resolveComputeServiceId(services, name) {
|
|
|
38
41
|
return compute[0].id;
|
|
39
42
|
}
|
|
40
43
|
// ---- commands ----
|
|
41
|
-
export async function servicesAdd(type, name) {
|
|
44
|
+
export async function servicesAdd(type, name, opts = {}) {
|
|
42
45
|
assertType(type);
|
|
46
|
+
if (opts.public && type !== 'storage')
|
|
47
|
+
throw new Error('--public is only valid for storage services');
|
|
43
48
|
const api = await ApiClient.load();
|
|
44
49
|
const p = await requireProject();
|
|
45
|
-
const
|
|
50
|
+
const branch = opts.branch ?? p.branch;
|
|
51
|
+
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services`, { type, name, ...(branch ? { branch } : {}), public: !!opts.public });
|
|
46
52
|
if (handleApproval(res))
|
|
47
53
|
return;
|
|
48
54
|
const svc = res.body.service;
|
|
49
|
-
|
|
55
|
+
const access = svc.type === 'storage' ? ` [${svc.public ? 'public' : 'private'}]` : '';
|
|
56
|
+
info(`added ${type} service ${name} on ${branch ?? 'default'} (${svc.id})${access}${svc.domain ? ` — ${svc.domain}` : ''}`);
|
|
50
57
|
renderNextActions(res.body.nextActions);
|
|
51
58
|
}
|
|
52
59
|
export async function servicesList(opts) {
|
|
53
60
|
const api = await ApiClient.load();
|
|
54
61
|
const p = await requireProject();
|
|
55
|
-
const
|
|
62
|
+
const branch = opts.branch ?? p.branch;
|
|
63
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
|
|
56
64
|
if (opts.json)
|
|
57
65
|
return printJson(services);
|
|
58
66
|
if (!services.length)
|
|
59
|
-
return info(
|
|
67
|
+
return info(`(no services on ${branch ?? 'default'} — add one with \`insta services add <postgres|storage|compute> <name>\`)`);
|
|
60
68
|
for (const s of services) {
|
|
61
|
-
const extra = s.type === 'compute' ? ` x${s.machine_count}` : '';
|
|
69
|
+
const extra = s.type === 'compute' ? ` x${s.machine_count}` : s.type === 'storage' ? ` ${s.public ? 'public' : 'private'}` : '';
|
|
62
70
|
info(`${s.type}/${s.name} [${s.status}]${extra}${s.domain ? ` ${s.domain}` : ''} ${s.id}`);
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
|
-
export async function servicesRemove(type, name) {
|
|
73
|
+
export async function servicesRemove(type, name, opts = {}) {
|
|
66
74
|
assertType(type);
|
|
67
75
|
const api = await ApiClient.load();
|
|
68
76
|
const p = await requireProject();
|
|
69
|
-
const
|
|
77
|
+
const branch = opts.branch ?? p.branch;
|
|
78
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(branch)}`);
|
|
70
79
|
const id = resolveServiceId(services, type, name);
|
|
71
80
|
const res = await api.rawRequest('DELETE', `/projects/${p.projectId}/services/${id}`);
|
|
72
81
|
if (handleApproval(res))
|
|
73
82
|
return;
|
|
74
|
-
info(`removed ${type} service ${name}`);
|
|
83
|
+
info(`removed ${type} service ${name} from ${branch ?? 'default'}`);
|
|
84
|
+
}
|
|
85
|
+
// Validate a bucket access-mode argument.
|
|
86
|
+
export function parseAccess(raw) {
|
|
87
|
+
if (raw === 'public')
|
|
88
|
+
return true;
|
|
89
|
+
if (raw === 'private')
|
|
90
|
+
return false;
|
|
91
|
+
throw new Error(`access must be public|private, got: ${raw}`);
|
|
92
|
+
}
|
|
93
|
+
// insta services set-access storage <name> <public|private>
|
|
94
|
+
export async function servicesSetAccess(type, name, access, _opts) {
|
|
95
|
+
assertType(type, ['storage']);
|
|
96
|
+
const isPublic = parseAccess(access);
|
|
97
|
+
const api = await ApiClient.load();
|
|
98
|
+
const p = await requireProject();
|
|
99
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(p.branch)}`);
|
|
100
|
+
const id = resolveServiceId(services, type, name);
|
|
101
|
+
const res = await api.rawRequest('PUT', `/projects/${p.projectId}/services/${id}/access`, { public: isPublic });
|
|
102
|
+
if (handleApproval(res))
|
|
103
|
+
return;
|
|
104
|
+
if (_opts.json)
|
|
105
|
+
return printJson(res.body.service);
|
|
106
|
+
info(`set storage ${name} access to ${access}`);
|
|
75
107
|
}
|
|
76
108
|
// insta services scale compute <name> <number> [region]
|
|
77
109
|
export async function servicesScale(type, name, number, region, _opts) {
|
|
@@ -79,7 +111,7 @@ export async function servicesScale(type, name, number, region, _opts) {
|
|
|
79
111
|
const machineCount = parseCount(number);
|
|
80
112
|
const api = await ApiClient.load();
|
|
81
113
|
const p = await requireProject();
|
|
82
|
-
const { services } = await api.request('GET', `/projects/${p.projectId}/services`);
|
|
114
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(_opts.branch ?? p.branch)}`);
|
|
83
115
|
const id = resolveServiceId(services, type, name);
|
|
84
116
|
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/scale`, { machineCount, region });
|
|
85
117
|
if (handleApproval(res))
|
|
@@ -93,7 +125,7 @@ export async function servicesUpgrade(type, name, spec, _opts) {
|
|
|
93
125
|
assertType(type, ['compute', 'postgres']);
|
|
94
126
|
const api = await ApiClient.load();
|
|
95
127
|
const p = await requireProject();
|
|
96
|
-
const { services } = await api.request('GET', `/projects/${p.projectId}/services`);
|
|
128
|
+
const { services } = await api.request('GET', `/projects/${p.projectId}/services${q(_opts.branch ?? p.branch)}`);
|
|
97
129
|
const id = resolveServiceId(services, type, name);
|
|
98
130
|
const res = await api.rawRequest('POST', `/projects/${p.projectId}/services/${id}/upgrade`, { spec });
|
|
99
131
|
if (handleApproval(res))
|
package/dist/ensure-skills.js
CHANGED
|
@@ -47,9 +47,13 @@ export async function installSkills(deps) {
|
|
|
47
47
|
const run = deps.run ?? defaultRunner;
|
|
48
48
|
const print = deps.print ?? ((s) => process.stdout.write(s + '\n'));
|
|
49
49
|
try {
|
|
50
|
-
print(' installing related agent skills (insta, neon-postgres, tigris, better-auth)
|
|
50
|
+
print(' installing related agent skills (insta, neon-postgres, tigris, better-auth) …');
|
|
51
51
|
for (const s of SKILLS) {
|
|
52
|
-
|
|
52
|
+
// Don't stream: the `skills` tool's clack UI (clone spinner, banners) is noise. Run it
|
|
53
|
+
// silent (stdio 'ignore') and let the per-skill ✓/failed line below be the clean output —
|
|
54
|
+
// it appears as each skill finishes, so there's still live progress. (Also avoids the
|
|
55
|
+
// child inheriting a piped stdin.)
|
|
56
|
+
const r = await run('npx', s.args);
|
|
53
57
|
print(r.ok ? ` ${s.label} ✓` : ` ${s.label} failed — add manually: npx ${s.args.join(' ')}`);
|
|
54
58
|
}
|
|
55
59
|
const added = ensureGitignore(deps.cwd, SKILL_DIRS);
|
package/dist/index.js
CHANGED
|
@@ -83,17 +83,25 @@ br.command('create <name>').option('--from <branch>', 'parent branch (default: c
|
|
|
83
83
|
br.command('list').option('--json').action(guard((o) => branch.branchList(o)));
|
|
84
84
|
br.command('switch <name>').action(guard((name) => branch.branchSwitch(name)));
|
|
85
85
|
br.command('delete <name>').action(guard((name) => branch.branchDelete(name)));
|
|
86
|
+
br.command('merge <source>').description('Merge a branch service set into another (structural, no data)')
|
|
87
|
+
.option('--into <branch>', 'target branch (default: current)').action(guard((source, o) => branch.branchMerge(source, o)));
|
|
86
88
|
// ---- services (opt-in postgres/storage/compute) ----
|
|
87
89
|
const svc = program.command('services').alias('svc').description('Manage project services (postgres|storage|compute)');
|
|
88
90
|
svc.command('add <type> <name>').description('Provision a service on demand (assigns a default domain for postgres/compute)')
|
|
89
|
-
.
|
|
90
|
-
|
|
91
|
+
.option('--branch <branch>', 'target branch (default: current)')
|
|
92
|
+
.option('--public', 'storage only: serve the bucket with anonymous public-read (default private)')
|
|
93
|
+
.action(guard((type, name, o) => services.servicesAdd(type, name, o)));
|
|
94
|
+
svc.command('list').option('--json').option('--branch <branch>', 'branch (default: current)')
|
|
95
|
+
.action(guard((o) => services.servicesList(o)));
|
|
91
96
|
svc.command('remove <type> <name>').description('Remove a service and destroy its resources')
|
|
92
|
-
.
|
|
97
|
+
.option('--branch <branch>', 'branch (default: current)')
|
|
98
|
+
.action(guard((type, name, o) => services.servicesRemove(type, name, o)));
|
|
99
|
+
svc.command('set-access <type> <name> <access>').description('Set a storage service bucket access mode (access: public|private)')
|
|
100
|
+
.option('--json').action(guard((type, name, access, o) => services.servicesSetAccess(type, name, access, o)));
|
|
93
101
|
svc.command('scale <type> <name> <number> [region]').description('Set a compute service machine count (paid plans only)')
|
|
94
|
-
.option('--json').action(guard((type, name, number, region, o) => services.servicesScale(type, name, number, region, o)));
|
|
102
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((type, name, number, region, o) => services.servicesScale(type, name, number, region, o)));
|
|
95
103
|
svc.command('upgrade <type> <name> <spec>').description('Change a compute/postgres service spec (paid plans only)')
|
|
96
|
-
.option('--json').action(guard((type, name, spec, o) => services.servicesUpgrade(type, name, spec, o)));
|
|
104
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((type, name, spec, o) => services.servicesUpgrade(type, name, spec, o)));
|
|
97
105
|
// ---- secrets (seam) ----
|
|
98
106
|
const sec = program.command('secrets').description('Fetch the credential bundle (secret seam) into .env')
|
|
99
107
|
.option('--branch <branch>').option('-o, --output <file>', 'output file (default .env)').option('--print', 'print instead of writing').option('--json')
|
|
@@ -117,13 +125,13 @@ compute.command('check-domain <host>').description("Show a custom domain's cert
|
|
|
117
125
|
compute.command('remove-domain <host>').description('Detach a custom domain (gated: deploy)')
|
|
118
126
|
.option('--branch <b>').option('--group <g>').action(guard((host, o) => computeCmd.removeDomain(host, o)));
|
|
119
127
|
compute.command('start [service]').description('Bring a compute service online (persistent — re-enables auto-wake)')
|
|
120
|
-
.option('--json').action(guard((service, o) => computeCmd.computeStart(service, o)));
|
|
128
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStart(service, o)));
|
|
121
129
|
compute.command('stop [service]').description('Take a compute service offline; traffic will NOT wake it until `start`')
|
|
122
|
-
.option('--json').action(guard((service, o) => computeCmd.computeStop(service, o)));
|
|
130
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStop(service, o)));
|
|
123
131
|
compute.command('suspend [service]').description('Suspend a compute service (RAM snapshot); stays down until `start`')
|
|
124
|
-
.option('--json').action(guard((service, o) => computeCmd.computeSuspend(service, o)));
|
|
132
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeSuspend(service, o)));
|
|
125
133
|
compute.command('status [service]').description("Show a compute service's desired vs. live state")
|
|
126
|
-
.option('--json').action(guard((service, o) => computeCmd.computeStatus(service, o)));
|
|
134
|
+
.option('--json').option('--branch <branch>', 'branch (default: current)').action(guard((service, o) => computeCmd.computeStatus(service, o)));
|
|
127
135
|
// ---- manifest ----
|
|
128
136
|
program.command('manifest').description('Print an agent-legible view of the project environments').option('--json').action(guard((o) => manifest(o)));
|
|
129
137
|
// ---- observability ----
|
|
@@ -161,7 +169,7 @@ ob.command('sync').description('Upload findings into the project timeline').acti
|
|
|
161
169
|
// ---- policy ----
|
|
162
170
|
const pol = program.command('policy').description('Governance policy');
|
|
163
171
|
pol.command('get').option('--json').action(guard((o) => govern.policyGet(o)));
|
|
164
|
-
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)));
|
|
172
|
+
pol.command('set <action> <decision>').description('action: secrets.read|secrets.write|deploy|project.delete|branch.delete|service.add|service.remove|service.scale|service.upgrade|service.setAccess; decision: allow|deny|approve').action(guard((a, d) => govern.policySet(a, d)));
|
|
165
173
|
// ---- self-update ----
|
|
166
174
|
program.command('upgrade').description('Update the insta CLI to the latest release (binary or npm install)')
|
|
167
175
|
.action(guard(() => selfUpdate.upgrade()));
|