insta 0.0.6 → 0.0.8
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/deploy.js +25 -3
- package/dist/commands/setup.js +34 -0
- package/dist/config.js +6 -3
- package/dist/index.js +6 -0
- package/dist/observe/install.js +5 -2
- package/package.json +28 -8
package/dist/commands/deploy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve, join } from 'node:path';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { ApiClient, requireProject } from '../api.js';
|
|
4
4
|
import { info, die, handleApproval } from '../util.js';
|
|
5
5
|
import { flyctlBuildAndPush, ensureFlyctl } from '../flyctl-build.js';
|
|
@@ -14,6 +14,18 @@ export function deployRequestBody(image, branch, opts) {
|
|
|
14
14
|
websocket: opts.websocket ? true : undefined,
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
// A port mismatch is the #1 deploy mistake: the app boots "successfully" but the proxy routes to
|
|
18
|
+
// the wrong internal port and every request is refused. For source deploys the Dockerfile states
|
|
19
|
+
// the truth — use its (last) EXPOSE as the default instead of a blind 8080.
|
|
20
|
+
export function dockerfileExposedPort(dockerfile) {
|
|
21
|
+
let port;
|
|
22
|
+
for (const line of dockerfile.split('\n')) {
|
|
23
|
+
const m = /^\s*EXPOSE\s+(\d+)/i.exec(line);
|
|
24
|
+
if (m)
|
|
25
|
+
port = Number(m[1]);
|
|
26
|
+
}
|
|
27
|
+
return port;
|
|
28
|
+
}
|
|
17
29
|
// Deploy either a prebuilt image (`--image`) or a source directory (positional `<dir>`, built
|
|
18
30
|
// remotely on Fly and pushed with a short-lived platform-minted token). Exactly one mode.
|
|
19
31
|
export async function deploy(dir, opts) {
|
|
@@ -24,8 +36,18 @@ export async function deploy(dir, opts) {
|
|
|
24
36
|
const api = await ApiClient.load();
|
|
25
37
|
const p = await requireProject();
|
|
26
38
|
const branch = opts.branch ?? p.branch;
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
let port = opts.port ? Number(opts.port) : undefined;
|
|
40
|
+
if (dir && port === undefined) {
|
|
41
|
+
const dockerfile = join(resolve(process.cwd(), dir), 'Dockerfile');
|
|
42
|
+
const exposed = existsSync(dockerfile) ? dockerfileExposedPort(readFileSync(dockerfile, 'utf8')) : undefined;
|
|
43
|
+
if (exposed) {
|
|
44
|
+
port = exposed;
|
|
45
|
+
info(`using port ${exposed} (Dockerfile EXPOSE) — override with --port`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const effOpts = { ...opts, port: port?.toString() };
|
|
49
|
+
const image = dir ? await buildFromSource(api, p.projectId, dir, branch, effOpts) : opts.image;
|
|
50
|
+
const res = await api.rawRequest('POST', `/projects/${p.projectId}/deploy`, deployRequestBody(image, branch, effOpts));
|
|
29
51
|
if (handleApproval(res))
|
|
30
52
|
return;
|
|
31
53
|
info(`deployed ${image} -> ${res.body.url} (branch ${res.body.branch}, group ${res.body.group})`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// `insta setup agent` — make this machine's coding agents InstaCloud-native in one step
|
|
2
|
+
// (the Railway `railway setup agent` pattern). Installs the `insta` skill USER-GLOBALLY for
|
|
3
|
+
// every agent the skills tool knows: the skill is pure product knowledge with brand-gated
|
|
4
|
+
// triggers — no project state in it (the project binding is carried by ./.insta/project.json
|
|
5
|
+
// at command time), so one machine-level copy is strictly better than per-project copies.
|
|
6
|
+
// Stack skills (neon/tigris/better-auth) intentionally stay per-project: their presence in a
|
|
7
|
+
// project doubles as its stack manifest — that install happens on `project create|link`.
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
9
|
+
import { info } from '../util.js';
|
|
10
|
+
const defaultRunner = (cmd, args) => new Promise((resolve) => {
|
|
11
|
+
const env = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'insta' };
|
|
12
|
+
const p = spawn(cmd, args, { stdio: 'inherit', env });
|
|
13
|
+
p.on('error', () => resolve({ ok: false }));
|
|
14
|
+
p.on('close', (code) => resolve({ ok: code === 0 }));
|
|
15
|
+
});
|
|
16
|
+
// -g = user-level (machine-global); -a '*' = every agent dir the skills tool supports
|
|
17
|
+
// (Claude Code, Codex, Cursor, OpenCode, Copilot, …); --copy = real files, not cache symlinks.
|
|
18
|
+
export const SETUP_ARGS = ['skills', 'add', 'InsForge/insta-skills', '-s', 'insta', '-a', '*', '-g', '-y', '--copy'];
|
|
19
|
+
export async function setupAgent(opts, run = defaultRunner) {
|
|
20
|
+
if (!opts.yes && !process.stdout.isTTY) {
|
|
21
|
+
info('non-interactive shell — assuming -y');
|
|
22
|
+
}
|
|
23
|
+
info('installing the insta skill (user-global, all agents) …');
|
|
24
|
+
const res = await run('npx', SETUP_ARGS);
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
info(' skill install failed — install manually with:');
|
|
27
|
+
info(' npx skills add InsForge/insta-skills -s insta -a "*" -g -y --copy');
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
info('done — agents on this machine now know InstaCloud.');
|
|
32
|
+
info('next: `insta login --oauth github` (cloud) or run instad locally (insta-oss), then `insta project create <name>`.');
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=setup.js.map
|
package/dist/config.js
CHANGED
|
@@ -6,14 +6,17 @@ const GLOBAL_DIR = join(homedir(), '.insta');
|
|
|
6
6
|
const GLOBAL_FILE = join(GLOBAL_DIR, 'config.json');
|
|
7
7
|
const PROJECT_DIR = '.insta';
|
|
8
8
|
const PROJECT_FILE = 'project.json';
|
|
9
|
-
const DEFAULT_API =
|
|
9
|
+
const DEFAULT_API = 'https://beta-api.insta.insforge.dev';
|
|
10
10
|
export async function readGlobal() {
|
|
11
|
+
// INSTA_API_URL overrides the persisted apiUrl, not just the default — otherwise the
|
|
12
|
+
// env var is silently ignored as soon as any login has written a config file.
|
|
13
|
+
const envApi = process.env.INSTA_API_URL;
|
|
11
14
|
try {
|
|
12
15
|
const parsed = JSON.parse(await readFile(GLOBAL_FILE, 'utf8'));
|
|
13
|
-
return { ...parsed, apiUrl: parsed.apiUrl ?? DEFAULT_API };
|
|
16
|
+
return { ...parsed, apiUrl: envApi ?? parsed.apiUrl ?? DEFAULT_API };
|
|
14
17
|
}
|
|
15
18
|
catch {
|
|
16
|
-
return { apiUrl: DEFAULT_API };
|
|
19
|
+
return { apiUrl: envApi ?? DEFAULT_API };
|
|
17
20
|
}
|
|
18
21
|
}
|
|
19
22
|
export async function writeGlobal(c) {
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Command } from 'commander';
|
|
|
4
4
|
import { ApiError } from './api.js';
|
|
5
5
|
import { die } from './util.js';
|
|
6
6
|
import * as auth from './commands/auth.js';
|
|
7
|
+
import * as setup from './commands/setup.js';
|
|
7
8
|
import * as org from './commands/org.js';
|
|
8
9
|
import * as project from './commands/project.js';
|
|
9
10
|
import * as branch from './commands/branch.js';
|
|
@@ -55,6 +56,11 @@ program.command('login').description('Log in with email + password, or --oauth <
|
|
|
55
56
|
.action(guard((o) => auth.login(o)));
|
|
56
57
|
program.command('logout').description('Log out and clear local tokens').action(guard(() => auth.logout()));
|
|
57
58
|
program.command('status').description('Show login + linked project').option('--json').action(guard((o) => auth.status(o)));
|
|
59
|
+
// ---- agent setup (the `curl … | sh --agents` target) ----
|
|
60
|
+
const setupCmd = program.command('setup').description('Set up this machine for InstaCloud agent workflows');
|
|
61
|
+
setupCmd.command('agent').description('Install the insta skill user-globally for all coding agents')
|
|
62
|
+
.option('-y, --yes', 'non-interactive')
|
|
63
|
+
.action(guard((o) => setup.setupAgent(o)));
|
|
58
64
|
// ---- org ----
|
|
59
65
|
const orgCmd = program.command('org').description('Manage organizations');
|
|
60
66
|
orgCmd.command('list').option('--json').action(guard((o) => org.orgList(o)));
|
package/dist/observe/install.js
CHANGED
|
@@ -55,8 +55,11 @@ function materialize(cwd, assetDir) {
|
|
|
55
55
|
writeFileSync(join(dest, 'VERSION'), cliVersion() + '\n');
|
|
56
56
|
}
|
|
57
57
|
function claudeEntry() {
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// Claude Code executes `command` as ONE shell string with $CLAUDE_PROJECT_DIR in the env —
|
|
59
|
+
// there is no `args` field in its hooks schema, so a ${…} template in args reaches node
|
|
60
|
+
// verbatim and throws MODULE_NOT_FOUND after every tool call.
|
|
61
|
+
return { matcher: '*', hooks: [{ type: 'command',
|
|
62
|
+
command: 'node "$CLAUDE_PROJECT_DIR/.insta/observe/hook.js"', timeout: 15, _insta: MARKER }] };
|
|
60
63
|
}
|
|
61
64
|
function codexEntry(cwd) {
|
|
62
65
|
const abs = join(cwd, '.insta', 'observe', 'hook.js'); // Codex doesn't expand ${CLAUDE_PROJECT_DIR}; use an absolute path
|
package/package.json
CHANGED
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "insta",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "InstaCloud CLI — a thin client of the platform control-plane API.",
|
|
6
|
-
"keywords": [
|
|
6
|
+
"keywords": [
|
|
7
|
+
"insta",
|
|
8
|
+
"insforge",
|
|
9
|
+
"cli",
|
|
10
|
+
"backend",
|
|
11
|
+
"baas",
|
|
12
|
+
"platform"
|
|
13
|
+
],
|
|
7
14
|
"license": "Apache-2.0",
|
|
8
15
|
"homepage": "https://github.com/InsForge/insta-cli#readme",
|
|
9
|
-
"repository": {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/InsForge/insta-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/InsForge/insta-cli/issues"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"insta": "dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**/*.js"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
15
35
|
"scripts": {
|
|
16
36
|
"build": "tsc -p tsconfig.json",
|
|
17
37
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|