@instafy/cli 0.1.10 → 0.2.0
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/LICENSE +661 -0
- package/README.md +77 -10
- package/bin/instafy.js +1 -1
- package/dist/cli.js +10152 -0
- package/package.json +22 -11
- package/dist/api.js +0 -166
- package/dist/auth.js +0 -578
- package/dist/config-command.js +0 -106
- package/dist/config.js +0 -292
- package/dist/controller-fetch.js +0 -33
- package/dist/errors.js +0 -63
- package/dist/git-credential.js +0 -205
- package/dist/git-setup.js +0 -56
- package/dist/git-wrapper.js +0 -502
- package/dist/git.js +0 -104
- package/dist/index.js +0 -636
- package/dist/org.js +0 -46
- package/dist/project-manifest.js +0 -24
- package/dist/project.js +0 -412
- package/dist/rathole.js +0 -216
- package/dist/runtime.js +0 -823
- package/dist/supabase-session.js +0 -89
- package/dist/tunnel.js +0 -484
package/dist/index.js
DELETED
|
@@ -1,636 +0,0 @@
|
|
|
1
|
-
import { Command, Option } from "commander";
|
|
2
|
-
import { pathToFileURL } from "node:url";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import kleur from "kleur";
|
|
5
|
-
import { runtimeStart, runtimeStatus, runtimeStop, runtimeToken, findProjectManifest, } from "./runtime.js";
|
|
6
|
-
import { login, logout } from "./auth.js";
|
|
7
|
-
import { runGitCredentialHelper } from "./git-credential.js";
|
|
8
|
-
import { projectInit, projectProfile } from "./project.js";
|
|
9
|
-
import { listTunnelSessions, startTunnelDetached, stopTunnelSession, tailTunnelLogs, runTunnelCommand } from "./tunnel.js";
|
|
10
|
-
import { requestControllerApi } from "./api.js";
|
|
11
|
-
import { configGet, configList, configPath, configSet, configUnset } from "./config-command.js";
|
|
12
|
-
import { getInstafyProfileConfigPath, listInstafyProfileNames, readInstafyProfileConfig } from "./config.js";
|
|
13
|
-
import { runInstafyGit, runInstafyGitSync } from "./git-wrapper.js";
|
|
14
|
-
export const program = new Command();
|
|
15
|
-
const require = createRequire(import.meta.url);
|
|
16
|
-
const pkg = require("../package.json");
|
|
17
|
-
function addServerUrlOptions(command) {
|
|
18
|
-
return command
|
|
19
|
-
.option("--server-url <url>", "Instafy server URL")
|
|
20
|
-
.addOption(new Option("--controller-url <url>").hideHelp());
|
|
21
|
-
}
|
|
22
|
-
function addAccessTokenOptions(command, description) {
|
|
23
|
-
return command
|
|
24
|
-
.option("--access-token <token>", description)
|
|
25
|
-
.addOption(new Option("--controller-access-token <token>").hideHelp());
|
|
26
|
-
}
|
|
27
|
-
function addServiceTokenOptions(command, description) {
|
|
28
|
-
return command
|
|
29
|
-
.option("--service-token <token>", description)
|
|
30
|
-
.addOption(new Option("--controller-token <token>").hideHelp());
|
|
31
|
-
}
|
|
32
|
-
function collectStringOption(value, previous) {
|
|
33
|
-
return [...previous, value];
|
|
34
|
-
}
|
|
35
|
-
program
|
|
36
|
-
.name("instafy")
|
|
37
|
-
.description("Instafy CLI — run your project locally and connect to Studio")
|
|
38
|
-
.version(pkg.version ?? "0.1.0");
|
|
39
|
-
program
|
|
40
|
-
.command("login")
|
|
41
|
-
.description("Log in and save an access token for future CLI commands")
|
|
42
|
-
.option("--studio-url <url>", "Studio web URL (default: staging or localhost)")
|
|
43
|
-
.option("--server-url <url>", "Instafy server/controller URL")
|
|
44
|
-
.option("--profile <name>", "Save token under a named profile (multi-account support)")
|
|
45
|
-
.option("--token <token>", "Provide token directly (skips prompt)")
|
|
46
|
-
.option("--email <email>", "Email for non-interactive login (requires SUPABASE_URL + SUPABASE_ANON_KEY)")
|
|
47
|
-
.option("--password <password>", "Password for non-interactive login (requires SUPABASE_URL + SUPABASE_ANON_KEY)")
|
|
48
|
-
.option("--no-git-setup", "Do not configure git credential helper")
|
|
49
|
-
.option("--no-store", "Do not save token to ~/.instafy/config.json")
|
|
50
|
-
.option("--json", "Output JSON")
|
|
51
|
-
.action(async (opts) => {
|
|
52
|
-
try {
|
|
53
|
-
await login({
|
|
54
|
-
controllerUrl: opts.serverUrl,
|
|
55
|
-
studioUrl: opts.studioUrl,
|
|
56
|
-
token: opts.token,
|
|
57
|
-
email: opts.email,
|
|
58
|
-
password: opts.password,
|
|
59
|
-
gitSetup: opts.gitSetup,
|
|
60
|
-
noStore: opts.store === false,
|
|
61
|
-
profile: opts.profile,
|
|
62
|
-
json: opts.json,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
console.error(kleur.red(String(error)));
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
program
|
|
71
|
-
.command("logout")
|
|
72
|
-
.description("Clear the saved CLI access token")
|
|
73
|
-
.option("--profile <name>", "Clear the token for a named profile")
|
|
74
|
-
.option("--json", "Output JSON")
|
|
75
|
-
.action(async (opts) => {
|
|
76
|
-
try {
|
|
77
|
-
await logout({ json: opts.json, profile: opts.profile });
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
console.error(kleur.red(String(error)));
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
const projectCommand = program
|
|
85
|
-
.command("project")
|
|
86
|
-
.description("Create/link and manage Instafy projects");
|
|
87
|
-
projectCommand.action(() => projectCommand.outputHelp());
|
|
88
|
-
const projectInitCommand = projectCommand
|
|
89
|
-
.command("init")
|
|
90
|
-
.description("Create an Instafy project and link this folder (.instafy/project.json)")
|
|
91
|
-
.option("--path <dir>", "Directory where the manifest should be written (default: cwd)");
|
|
92
|
-
addServerUrlOptions(projectInitCommand);
|
|
93
|
-
projectInitCommand
|
|
94
|
-
.option("--access-token <token>", "Instafy or Supabase access token")
|
|
95
|
-
.option("--profile <name>", "CLI profile to use when running commands in this folder")
|
|
96
|
-
.option("--project-type <type>", "Project type (customer|sandbox)")
|
|
97
|
-
.option("--org-id <uuid>", "Optional organization id")
|
|
98
|
-
.option("--org-name <name>", "Optional organization name")
|
|
99
|
-
.option("--org-slug <slug>", "Optional organization slug")
|
|
100
|
-
.option("--owner-user-id <uuid>", "Explicit owner user id (defaults to caller)")
|
|
101
|
-
.option("--json", "Output JSON")
|
|
102
|
-
.action(async (opts) => {
|
|
103
|
-
try {
|
|
104
|
-
await projectInit({
|
|
105
|
-
path: opts.path,
|
|
106
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
107
|
-
accessToken: opts.accessToken,
|
|
108
|
-
profile: opts.profile,
|
|
109
|
-
projectType: opts.projectType,
|
|
110
|
-
orgId: opts.orgId,
|
|
111
|
-
orgName: opts.orgName,
|
|
112
|
-
orgSlug: opts.orgSlug,
|
|
113
|
-
ownerUserId: opts.ownerUserId,
|
|
114
|
-
json: opts.json,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
console.error(kleur.red(String(error)));
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
projectCommand
|
|
123
|
-
.command("profile")
|
|
124
|
-
.description("Get/set the CLI profile for this folder (.instafy/project.json)")
|
|
125
|
-
.argument("[profile]", "Profile name to set (omit to print current)")
|
|
126
|
-
.option("--unset", "Clear the configured profile for this folder")
|
|
127
|
-
.option("--path <dir>", "Directory to search for the manifest (default: cwd)")
|
|
128
|
-
.option("--json", "Output JSON")
|
|
129
|
-
.action(async (profile, opts) => {
|
|
130
|
-
try {
|
|
131
|
-
projectProfile({
|
|
132
|
-
profile,
|
|
133
|
-
unset: opts.unset,
|
|
134
|
-
path: opts.path,
|
|
135
|
-
json: opts.json,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
console.error(kleur.red(String(error)));
|
|
140
|
-
process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
const projectListCommand = projectCommand
|
|
144
|
-
.command("list")
|
|
145
|
-
.description("List projects for your account")
|
|
146
|
-
.option("--access-token <token>", "Instafy or Supabase access token");
|
|
147
|
-
addServerUrlOptions(projectListCommand);
|
|
148
|
-
projectListCommand
|
|
149
|
-
.option("--org-id <uuid>", "Filter by organization id")
|
|
150
|
-
.option("--org-slug <slug>", "Filter by organization slug")
|
|
151
|
-
.option("--json", "Output JSON")
|
|
152
|
-
.action(async (opts) => {
|
|
153
|
-
try {
|
|
154
|
-
await (await import("./project.js")).listProjects({
|
|
155
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
156
|
-
accessToken: opts.accessToken,
|
|
157
|
-
orgId: opts.orgId,
|
|
158
|
-
orgSlug: opts.orgSlug,
|
|
159
|
-
json: opts.json,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
console.error(kleur.red(String(error)));
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
const configCommand = program.command("config").description("Get/set saved CLI configuration");
|
|
168
|
-
configCommand.action(() => configCommand.outputHelp());
|
|
169
|
-
configCommand
|
|
170
|
-
.command("path")
|
|
171
|
-
.description("Print the config file path")
|
|
172
|
-
.option("--json", "Output JSON")
|
|
173
|
-
.action(async (opts) => {
|
|
174
|
-
try {
|
|
175
|
-
configPath({ json: opts.json });
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
console.error(kleur.red(String(error)));
|
|
179
|
-
process.exit(1);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
configCommand
|
|
183
|
-
.command("list")
|
|
184
|
-
.description("List saved configuration")
|
|
185
|
-
.option("--json", "Output JSON")
|
|
186
|
-
.action(async (opts) => {
|
|
187
|
-
try {
|
|
188
|
-
configList({ json: opts.json });
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
console.error(kleur.red(String(error)));
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
configCommand
|
|
196
|
-
.command("get")
|
|
197
|
-
.description("Get a config value (controller-url, studio-url)")
|
|
198
|
-
.argument("<key>", "Config key")
|
|
199
|
-
.option("--json", "Output JSON")
|
|
200
|
-
.action(async (key, opts) => {
|
|
201
|
-
try {
|
|
202
|
-
configGet({ key, json: opts.json });
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
console.error(kleur.red(String(error)));
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
configCommand
|
|
210
|
-
.command("set")
|
|
211
|
-
.description("Set a config value (controller-url, studio-url)")
|
|
212
|
-
.argument("<key>", "Config key")
|
|
213
|
-
.argument("<value>", "Config value")
|
|
214
|
-
.option("--json", "Output JSON")
|
|
215
|
-
.action(async (key, value, opts) => {
|
|
216
|
-
try {
|
|
217
|
-
configSet({ key, value, json: opts.json });
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
console.error(kleur.red(String(error)));
|
|
221
|
-
process.exit(1);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
configCommand
|
|
225
|
-
.command("unset")
|
|
226
|
-
.description("Unset a config value (controller-url, studio-url)")
|
|
227
|
-
.argument("<key>", "Config key")
|
|
228
|
-
.option("--json", "Output JSON")
|
|
229
|
-
.action(async (key, opts) => {
|
|
230
|
-
try {
|
|
231
|
-
configUnset({ key, json: opts.json });
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
console.error(kleur.red(String(error)));
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
const runtimeCommand = program
|
|
239
|
-
.command("runtime")
|
|
240
|
-
.description("Start/stop the local Instafy runtime");
|
|
241
|
-
runtimeCommand.action(() => runtimeCommand.outputHelp());
|
|
242
|
-
const runtimeStartCommand = runtimeCommand
|
|
243
|
-
.command("start")
|
|
244
|
-
.description("Start a local runtime for this project")
|
|
245
|
-
.option("--project <id>", "Project UUID");
|
|
246
|
-
addServerUrlOptions(runtimeStartCommand);
|
|
247
|
-
addServiceTokenOptions(runtimeStartCommand, "Instafy service token (advanced)");
|
|
248
|
-
addAccessTokenOptions(runtimeStartCommand, "Instafy access token (from Studio)");
|
|
249
|
-
runtimeStartCommand
|
|
250
|
-
.option("--supabase-access-token <token>", "Supabase session token (alternative to Studio token)")
|
|
251
|
-
.option("--supabase-access-token-file <path>", "File containing the Supabase session token")
|
|
252
|
-
.option("--runtime-token <token>", "Pre-minted runtime access token (bypasses agent key)")
|
|
253
|
-
.option("--codex-bin <path>", "Path to codex binary (fallback to PATH)")
|
|
254
|
-
.option("--proxy-base-url <url>", "Codex proxy base URL")
|
|
255
|
-
.option("--workspace <path>", "Workspace directory (defaults to ./.instafy/workspace)")
|
|
256
|
-
.option("--runtime-mode <mode>", "Runtime runner (auto|docker|process)", "auto")
|
|
257
|
-
.option("--origin-id <uuid>", "Origin ID to use (auto-generated if omitted)")
|
|
258
|
-
.option("--origin-endpoint <url>", "Explicit origin endpoint (skip tunnel setup when provided)")
|
|
259
|
-
.option("--origin-token <token>", "Runtime/origin access token for Studio registration")
|
|
260
|
-
.option("--runtime-id <uuid>", "Runtime ID to use (advanced)")
|
|
261
|
-
.option("--runtime-lease-id <uuid>", "Runtime lease ID to use (advanced)")
|
|
262
|
-
.option("--display-name <name>", "Human-friendly runtime name")
|
|
263
|
-
.option("--provider <provider>", "Runtime provider label (default: self-hosted)")
|
|
264
|
-
.option("--bind-host <host>", "Origin bind host (default 127.0.0.1)")
|
|
265
|
-
.option("--bind-port <port>", "Origin bind port (default 54332)")
|
|
266
|
-
.option("--detach", "Run runtime in background and exit immediately")
|
|
267
|
-
.option("--log-file <path>", "Write runtime stdout/stderr to a file (implied when detached)")
|
|
268
|
-
.action(async (opts) => {
|
|
269
|
-
try {
|
|
270
|
-
await runtimeStart({
|
|
271
|
-
...opts,
|
|
272
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
273
|
-
controllerToken: opts.serviceToken ?? opts.controllerToken,
|
|
274
|
-
controllerAccessToken: opts.accessToken ?? opts.controllerAccessToken,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
catch (error) {
|
|
278
|
-
console.error(kleur.red(String(error)));
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
runtimeCommand
|
|
283
|
-
.command("status")
|
|
284
|
-
.description("Show runtime health")
|
|
285
|
-
.option("--json", "Output status as JSON")
|
|
286
|
-
.action(async (opts) => {
|
|
287
|
-
try {
|
|
288
|
-
await runtimeStatus({ json: opts.json });
|
|
289
|
-
}
|
|
290
|
-
catch (error) {
|
|
291
|
-
console.error(kleur.red(String(error)));
|
|
292
|
-
process.exit(1);
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
runtimeCommand
|
|
296
|
-
.command("stop")
|
|
297
|
-
.description("Stop the local Instafy runtime")
|
|
298
|
-
.option("--json", "Output result as JSON")
|
|
299
|
-
.action(async (opts) => {
|
|
300
|
-
try {
|
|
301
|
-
await runtimeStop({ json: opts.json });
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
console.error(kleur.red(String(error)));
|
|
305
|
-
process.exit(1);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
const runtimeTokenCommand = runtimeCommand
|
|
309
|
-
.command("token")
|
|
310
|
-
.description("Mint a runtime access token")
|
|
311
|
-
.option("--project <id>", "Project UUID (defaults to .instafy/project.json)");
|
|
312
|
-
addServerUrlOptions(runtimeTokenCommand);
|
|
313
|
-
addAccessTokenOptions(runtimeTokenCommand, "Instafy access token (required)");
|
|
314
|
-
runtimeTokenCommand
|
|
315
|
-
.option("--runtime-id <uuid>", "Runtime ID to bind token to")
|
|
316
|
-
.option("--scope <scope...>", "Override scopes (default agent.* + origin.*)")
|
|
317
|
-
.option("--json", "Output token as JSON")
|
|
318
|
-
.action(async (opts) => {
|
|
319
|
-
try {
|
|
320
|
-
const project = typeof opts.project === "string" && opts.project.trim()
|
|
321
|
-
? opts.project.trim()
|
|
322
|
-
: findProjectManifest(process.cwd()).manifest?.projectId ?? null;
|
|
323
|
-
if (!project) {
|
|
324
|
-
throw new Error("No project configured. Run `instafy project init` or pass --project.");
|
|
325
|
-
}
|
|
326
|
-
await runtimeToken({
|
|
327
|
-
project,
|
|
328
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
329
|
-
controllerAccessToken: opts.accessToken ?? opts.controllerAccessToken,
|
|
330
|
-
runtimeId: opts.runtimeId,
|
|
331
|
-
scopes: opts.scope,
|
|
332
|
-
json: opts.json,
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
catch (error) {
|
|
336
|
-
console.error(kleur.red(String(error)));
|
|
337
|
-
process.exit(1);
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
program
|
|
341
|
-
.command("git")
|
|
342
|
-
.description("Run git against the Instafy canonical checkout (.instafy/.git)")
|
|
343
|
-
.allowUnknownOption(true);
|
|
344
|
-
const tunnelCommand = program
|
|
345
|
-
.command("tunnel")
|
|
346
|
-
.description("Create and manage shareable tunnels");
|
|
347
|
-
tunnelCommand.action(() => tunnelCommand.outputHelp());
|
|
348
|
-
const tunnelStartCommand = tunnelCommand
|
|
349
|
-
.command("start")
|
|
350
|
-
.description("Create a shareable tunnel URL for a local port (defaults to detached)")
|
|
351
|
-
.option("--port <port>", "Local port to expose (default 3000)")
|
|
352
|
-
.option("--project <id>", "Project UUID (defaults to .instafy/project.json or PROJECT_ID)");
|
|
353
|
-
addServerUrlOptions(tunnelStartCommand);
|
|
354
|
-
addAccessTokenOptions(tunnelStartCommand, "Instafy access token (defaults to saved `instafy login` token)");
|
|
355
|
-
addServiceTokenOptions(tunnelStartCommand, "Instafy service token (advanced)");
|
|
356
|
-
tunnelStartCommand
|
|
357
|
-
.option("--no-detach", "Run in foreground until interrupted")
|
|
358
|
-
.option("--rathole-bin <path>", "Path to rathole binary (or set RATHOLE_BIN)")
|
|
359
|
-
.option("--log-file <path>", "Write tunnel logs to a file (default: ~/.instafy/cli-tunnel-logs/*)")
|
|
360
|
-
.option("--json", "Output JSON")
|
|
361
|
-
.action(async (opts) => {
|
|
362
|
-
try {
|
|
363
|
-
const port = opts.port ? Number(opts.port) : undefined;
|
|
364
|
-
const controllerToken = opts.serviceToken ??
|
|
365
|
-
opts.controllerToken ??
|
|
366
|
-
opts.accessToken ??
|
|
367
|
-
opts.controllerAccessToken;
|
|
368
|
-
if (opts.detach === false) {
|
|
369
|
-
await runTunnelCommand({
|
|
370
|
-
project: opts.project,
|
|
371
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
372
|
-
controllerToken,
|
|
373
|
-
port,
|
|
374
|
-
ratholeBin: opts.ratholeBin,
|
|
375
|
-
});
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const started = await startTunnelDetached({
|
|
379
|
-
project: opts.project,
|
|
380
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
381
|
-
controllerToken,
|
|
382
|
-
port,
|
|
383
|
-
ratholeBin: opts.ratholeBin,
|
|
384
|
-
logFile: opts.logFile,
|
|
385
|
-
});
|
|
386
|
-
if (opts.json) {
|
|
387
|
-
console.log(JSON.stringify(started, null, 2));
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
console.log(kleur.green(`Tunnel started: ${started.url} (tunnelId=${started.tunnelId})`));
|
|
391
|
-
console.log(kleur.gray(`pid=${started.pid} · port=${started.localPort}`));
|
|
392
|
-
console.log(kleur.gray(`log: ${started.logFile}`));
|
|
393
|
-
console.log("");
|
|
394
|
-
console.log("Next:");
|
|
395
|
-
console.log(`- ${kleur.cyan(`instafy tunnel list`)}`);
|
|
396
|
-
console.log(`- ${kleur.cyan(`instafy tunnel logs ${started.tunnelId} --follow`)}`);
|
|
397
|
-
console.log(`- ${kleur.cyan(`instafy tunnel stop ${started.tunnelId}`)}`);
|
|
398
|
-
if (process.platform !== "win32") {
|
|
399
|
-
console.log(kleur.gray(`(or) tail -n 200 -f ${started.logFile}`));
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
catch (error) {
|
|
403
|
-
console.error(kleur.red(String(error)));
|
|
404
|
-
process.exit(1);
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
tunnelCommand
|
|
408
|
-
.command("list")
|
|
409
|
-
.description("List local tunnel sessions started by this CLI")
|
|
410
|
-
.option("--all", "Include stopped/stale tunnels")
|
|
411
|
-
.option("--json", "Output JSON")
|
|
412
|
-
.action(async (opts) => {
|
|
413
|
-
try {
|
|
414
|
-
const tunnels = listTunnelSessions({ all: Boolean(opts.all), json: Boolean(opts.json) });
|
|
415
|
-
if (opts.json) {
|
|
416
|
-
console.log(JSON.stringify(tunnels, null, 2));
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
if (tunnels.length === 0) {
|
|
420
|
-
console.log(kleur.yellow("No tunnels found."));
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
for (const tunnel of tunnels) {
|
|
424
|
-
console.log(`${tunnel.tunnelId} · ${tunnel.url} · port=${tunnel.localPort} · pid=${tunnel.pid}`);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
catch (error) {
|
|
428
|
-
console.error(kleur.red(String(error)));
|
|
429
|
-
process.exit(1);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
tunnelCommand
|
|
433
|
-
.command("stop")
|
|
434
|
-
.description("Stop a local tunnel session and revoke it")
|
|
435
|
-
.argument("[tunnelId]", "Tunnel ID (defaults to the only active tunnel)")
|
|
436
|
-
.option("--server-url <url>", "Instafy server URL")
|
|
437
|
-
.option("--access-token <token>", "Instafy access token (defaults to saved `instafy login` token)")
|
|
438
|
-
.option("--service-token <token>", "Instafy service token (advanced)")
|
|
439
|
-
.option("--json", "Output JSON")
|
|
440
|
-
.action(async (tunnelId, opts) => {
|
|
441
|
-
try {
|
|
442
|
-
const result = await stopTunnelSession({
|
|
443
|
-
tunnelId,
|
|
444
|
-
controllerUrl: opts.serverUrl,
|
|
445
|
-
controllerToken: opts.serviceToken ?? opts.accessToken,
|
|
446
|
-
json: opts.json,
|
|
447
|
-
});
|
|
448
|
-
if (opts.json) {
|
|
449
|
-
console.log(JSON.stringify(result, null, 2));
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
console.log(kleur.green(`Tunnel stopped: ${result.tunnelId}`));
|
|
453
|
-
}
|
|
454
|
-
catch (error) {
|
|
455
|
-
console.error(kleur.red(String(error)));
|
|
456
|
-
process.exit(1);
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
tunnelCommand
|
|
460
|
-
.command("logs")
|
|
461
|
-
.description("Show logs for a local tunnel session")
|
|
462
|
-
.argument("[tunnelId]", "Tunnel ID (defaults to the only active tunnel)")
|
|
463
|
-
.option("--lines <n>", "Number of lines to show", "200")
|
|
464
|
-
.option("--follow", "Follow log output (like tail -f)")
|
|
465
|
-
.option("--json", "Output JSON")
|
|
466
|
-
.action(async (tunnelId, opts) => {
|
|
467
|
-
try {
|
|
468
|
-
const lines = typeof opts.lines === "string" ? Number(opts.lines) : undefined;
|
|
469
|
-
await tailTunnelLogs({
|
|
470
|
-
tunnelId,
|
|
471
|
-
lines,
|
|
472
|
-
follow: Boolean(opts.follow),
|
|
473
|
-
json: Boolean(opts.json),
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
console.error(kleur.red(String(error)));
|
|
478
|
-
process.exit(1);
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
const orgCommand = program
|
|
482
|
-
.command("org")
|
|
483
|
-
.description("Organization utilities");
|
|
484
|
-
orgCommand.action(() => orgCommand.outputHelp());
|
|
485
|
-
const orgListCommand = orgCommand
|
|
486
|
-
.command("list")
|
|
487
|
-
.description("List organizations for your account");
|
|
488
|
-
addServerUrlOptions(orgListCommand);
|
|
489
|
-
orgListCommand
|
|
490
|
-
.option("--access-token <token>", "Instafy or Supabase access token")
|
|
491
|
-
.option("--json", "Output JSON")
|
|
492
|
-
.action(async (opts) => {
|
|
493
|
-
try {
|
|
494
|
-
await (await import("./org.js")).listOrganizations({
|
|
495
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
496
|
-
accessToken: opts.accessToken,
|
|
497
|
-
json: opts.json,
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
catch (error) {
|
|
501
|
-
console.error(kleur.red(String(error)));
|
|
502
|
-
process.exit(1);
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
const profileCommand = program
|
|
506
|
-
.command("profile")
|
|
507
|
-
.description("Manage saved CLI profiles (~/.instafy/profiles)");
|
|
508
|
-
profileCommand.action(() => profileCommand.outputHelp());
|
|
509
|
-
profileCommand
|
|
510
|
-
.command("list")
|
|
511
|
-
.description("List saved CLI profiles")
|
|
512
|
-
.option("--json", "Output JSON")
|
|
513
|
-
.action(async (opts) => {
|
|
514
|
-
try {
|
|
515
|
-
const names = listInstafyProfileNames();
|
|
516
|
-
const profiles = names.map((name) => {
|
|
517
|
-
const config = readInstafyProfileConfig(name);
|
|
518
|
-
return {
|
|
519
|
-
name,
|
|
520
|
-
path: getInstafyProfileConfigPath(name),
|
|
521
|
-
controllerUrl: config.controllerUrl ?? null,
|
|
522
|
-
studioUrl: config.studioUrl ?? null,
|
|
523
|
-
accessTokenSet: Boolean(config.accessToken),
|
|
524
|
-
updatedAt: config.updatedAt ?? null,
|
|
525
|
-
};
|
|
526
|
-
});
|
|
527
|
-
if (opts.json) {
|
|
528
|
-
console.log(JSON.stringify({ profiles }, null, 2));
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
if (profiles.length === 0) {
|
|
532
|
-
console.log(kleur.yellow("No profiles found."));
|
|
533
|
-
console.log(`Create one with: ${kleur.cyan("instafy login --profile <name>")}`);
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
console.log(kleur.green("Instafy CLI profiles"));
|
|
537
|
-
for (const profile of profiles) {
|
|
538
|
-
const token = profile.accessTokenSet ? kleur.green("token") : kleur.yellow("no-token");
|
|
539
|
-
console.log(`- ${kleur.cyan(profile.name)} (${token})`);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
catch (error) {
|
|
543
|
-
console.error(kleur.red(String(error)));
|
|
544
|
-
process.exit(1);
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
function configureApiCommand(command, method) {
|
|
548
|
-
addServerUrlOptions(command);
|
|
549
|
-
addAccessTokenOptions(command, "Instafy access token");
|
|
550
|
-
addServiceTokenOptions(command, "Instafy service token (advanced)");
|
|
551
|
-
command
|
|
552
|
-
.option("--query <key=value>", "Query param (repeatable)", collectStringOption, [])
|
|
553
|
-
.option("--header <header>", "Extra header (repeatable, Key: Value)", collectStringOption, [])
|
|
554
|
-
.option("--json <json>", "JSON body as string")
|
|
555
|
-
.option("--json-file <path>", "JSON body read from file")
|
|
556
|
-
.option("--no-pretty", "Disable JSON pretty-printing")
|
|
557
|
-
.action(async (pathArg, opts) => {
|
|
558
|
-
try {
|
|
559
|
-
await requestControllerApi({
|
|
560
|
-
method,
|
|
561
|
-
path: pathArg,
|
|
562
|
-
controllerUrl: opts.serverUrl ?? opts.controllerUrl,
|
|
563
|
-
accessToken: opts.accessToken ?? opts.controllerAccessToken,
|
|
564
|
-
serviceToken: opts.serviceToken ?? opts.controllerToken,
|
|
565
|
-
query: opts.query,
|
|
566
|
-
headers: opts.header,
|
|
567
|
-
json: opts.json,
|
|
568
|
-
jsonFile: opts.jsonFile,
|
|
569
|
-
pretty: opts.pretty,
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
catch (error) {
|
|
573
|
-
console.error(kleur.red(String(error)));
|
|
574
|
-
process.exit(1);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
const apiCommand = program
|
|
579
|
-
.command("api", { hidden: true })
|
|
580
|
-
.description("Advanced: authenticated requests to the controller API");
|
|
581
|
-
apiCommand.action(() => apiCommand.outputHelp());
|
|
582
|
-
const apiGetCommand = apiCommand
|
|
583
|
-
.command("get")
|
|
584
|
-
.description("Advanced: authenticated GET request to the controller API")
|
|
585
|
-
.argument("<path>", "API path (or full URL), e.g. /conversations/<id>/messages?limit=50");
|
|
586
|
-
configureApiCommand(apiGetCommand, "GET");
|
|
587
|
-
const apiPostCommand = apiCommand
|
|
588
|
-
.command("post")
|
|
589
|
-
.description("Advanced: authenticated POST request to the controller API")
|
|
590
|
-
.argument("<path>", "API path (or full URL)");
|
|
591
|
-
configureApiCommand(apiPostCommand, "POST");
|
|
592
|
-
const apiPatchCommand = apiCommand
|
|
593
|
-
.command("patch")
|
|
594
|
-
.description("Advanced: authenticated PATCH request to the controller API")
|
|
595
|
-
.argument("<path>", "API path (or full URL)");
|
|
596
|
-
configureApiCommand(apiPatchCommand, "PATCH");
|
|
597
|
-
const apiDeleteCommand = apiCommand
|
|
598
|
-
.command("delete")
|
|
599
|
-
.description("Advanced: authenticated DELETE request to the controller API")
|
|
600
|
-
.argument("<path>", "API path (or full URL)");
|
|
601
|
-
configureApiCommand(apiDeleteCommand, "DELETE");
|
|
602
|
-
export async function runCli(argv = process.argv) {
|
|
603
|
-
if (argv.length <= 2) {
|
|
604
|
-
program.outputHelp();
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
const args = argv.slice(2);
|
|
608
|
-
if (args[0] === "git") {
|
|
609
|
-
if (args[1] === "credential") {
|
|
610
|
-
try {
|
|
611
|
-
await runGitCredentialHelper(args[2] ?? "");
|
|
612
|
-
}
|
|
613
|
-
catch (error) {
|
|
614
|
-
console.error(String(error));
|
|
615
|
-
process.exitCode = 1;
|
|
616
|
-
}
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
if (args[1] === "sync") {
|
|
620
|
-
const code = await runInstafyGitSync(args.slice(2));
|
|
621
|
-
process.exitCode = code;
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
const code = runInstafyGit(args.slice(1));
|
|
625
|
-
process.exitCode = code;
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
await program.parseAsync(argv);
|
|
629
|
-
}
|
|
630
|
-
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
631
|
-
void runCli(process.argv);
|
|
632
|
-
}
|
|
633
|
-
// Re-export programmatic APIs for embedders (e.g., VS Code extension).
|
|
634
|
-
export { runtimeStart as startRuntime, runtimeStatus as getRuntimeStatus, runtimeStop as stopRuntime, runtimeToken as mintRuntimeToken, mintRuntimeAccessToken, findProjectManifest, } from "./runtime.js";
|
|
635
|
-
export { projectInit, listProjects } from "./project.js";
|
|
636
|
-
export { listOrganizations } from "./org.js";
|
package/dist/org.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import kleur from "kleur";
|
|
2
|
-
import { resolveControllerUrl, resolveUserAccessTokenWithSource } from "./config.js";
|
|
3
|
-
import { formatAuthRejectedError, formatAuthRequiredError } from "./errors.js";
|
|
4
|
-
import { fetchWithControllerAuth } from "./controller-fetch.js";
|
|
5
|
-
export async function listOrganizations(params) {
|
|
6
|
-
const controllerUrl = resolveControllerUrl({ controllerUrl: params.controllerUrl ?? null });
|
|
7
|
-
const resolved = resolveUserAccessTokenWithSource({ accessToken: params.accessToken ?? null });
|
|
8
|
-
if (!resolved.token) {
|
|
9
|
-
throw formatAuthRequiredError({ retryCommand: "instafy org list" });
|
|
10
|
-
}
|
|
11
|
-
const { response } = await fetchWithControllerAuth({
|
|
12
|
-
url: `${controllerUrl}/orgs`,
|
|
13
|
-
accessToken: resolved.token,
|
|
14
|
-
tokenSource: resolved.source,
|
|
15
|
-
profile: resolved.profile,
|
|
16
|
-
cwd: process.cwd(),
|
|
17
|
-
});
|
|
18
|
-
if (!response.ok) {
|
|
19
|
-
const text = await response.text().catch(() => "");
|
|
20
|
-
if (response.status === 401 || response.status === 403) {
|
|
21
|
-
throw formatAuthRejectedError({
|
|
22
|
-
status: response.status,
|
|
23
|
-
responseBody: text,
|
|
24
|
-
retryCommand: "instafy org list",
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
throw new Error(`Organization list failed (${response.status} ${response.statusText}): ${text}`);
|
|
28
|
-
}
|
|
29
|
-
const body = (await response.json());
|
|
30
|
-
const orgs = Array.isArray(body.orgs) ? body.orgs : [];
|
|
31
|
-
if (params.json) {
|
|
32
|
-
console.log(JSON.stringify(orgs, null, 2));
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
if (orgs.length === 0) {
|
|
36
|
-
console.log(kleur.yellow("No organizations found for this account."));
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
for (const org of orgs) {
|
|
40
|
-
const role = org.role ? ` [${org.role}]` : "";
|
|
41
|
-
console.log(`${kleur.green(org.name)} (${org.id}${role})`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return orgs;
|
|
46
|
-
}
|