@instafy/cli 0.1.8 → 0.1.10
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/README.md +16 -9
- package/dist/api.js +50 -16
- package/dist/auth.js +510 -26
- package/dist/config-command.js +2 -0
- package/dist/config.js +187 -6
- package/dist/controller-fetch.js +33 -0
- package/dist/errors.js +63 -0
- package/dist/git-credential.js +205 -0
- package/dist/git-setup.js +56 -0
- package/dist/git-wrapper.js +502 -0
- package/dist/git.js +11 -5
- package/dist/index.js +293 -108
- package/dist/org.js +19 -9
- package/dist/project-manifest.js +24 -0
- package/dist/project.js +285 -45
- package/dist/rathole.js +14 -10
- package/dist/runtime.js +86 -45
- package/dist/supabase-session.js +89 -0
- package/dist/tunnel.js +293 -21
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -7,22 +7,29 @@ Run Instafy projects locally and connect them back to Instafy Studio — from an
|
|
|
7
7
|
## Quickstart
|
|
8
8
|
|
|
9
9
|
0. Log in once: `instafy login`
|
|
10
|
+
- Opens a Studio URL; the CLI continues automatically after you sign in.
|
|
11
|
+
- Also enables Git auth (credential helper) for Instafy Git Service. Disable with `instafy login --no-git-setup`.
|
|
12
|
+
- Multiple accounts: `instafy login --profile work` (then bind folders with `instafy project init --profile work` or `instafy project profile work`).
|
|
10
13
|
- Optional: set defaults with `instafy config set controller-url <url>` / `instafy config set studio-url <url>`
|
|
11
14
|
1. Link a folder to a project:
|
|
12
15
|
- VS Code: install the Instafy extension and run `Instafy: Link Workspace to Project`, or
|
|
13
|
-
- Terminal: `instafy project
|
|
14
|
-
2. Start the runtime: `instafy runtime
|
|
16
|
+
- Terminal: `instafy project init`
|
|
17
|
+
2. Start the runtime: `instafy runtime start`
|
|
15
18
|
3. Check status / stop:
|
|
16
|
-
- `instafy runtime
|
|
17
|
-
- `instafy runtime
|
|
19
|
+
- `instafy runtime status`
|
|
20
|
+
- `instafy runtime stop`
|
|
18
21
|
|
|
19
22
|
## Common commands
|
|
20
23
|
|
|
21
|
-
- `instafy runtime
|
|
22
|
-
- `instafy runtime
|
|
23
|
-
- `instafy runtime
|
|
24
|
-
- `instafy
|
|
25
|
-
- `instafy
|
|
24
|
+
- `instafy runtime start` — start a local runtime (agent + origin).
|
|
25
|
+
- `instafy runtime status` — show health of the last started runtime.
|
|
26
|
+
- `instafy runtime stop` — stop the last started runtime.
|
|
27
|
+
- `instafy git <args...>` — run git commands against an Instafy canonical checkout (`.instafy/.git`) when present.
|
|
28
|
+
- `instafy tunnel start` — start a detached tunnel for a local port.
|
|
29
|
+
- `instafy tunnel list` — list local tunnels started by the CLI.
|
|
30
|
+
- `instafy tunnel logs <tunnelId> --follow` — tail tunnel logs.
|
|
31
|
+
- `instafy tunnel stop <tunnelId>` — stop + revoke a tunnel.
|
|
32
|
+
- `instafy api get` — query controller endpoints (conversations, messages, runs, etc).
|
|
26
33
|
|
|
27
34
|
Run `instafy --help` for the full command list and options.
|
|
28
35
|
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import { resolveConfiguredAccessToken } from "./config.js";
|
|
2
|
+
import { resolveActiveProfileName, resolveConfiguredAccessToken } from "./config.js";
|
|
3
|
+
import { formatAuthRejectedError } from "./errors.js";
|
|
4
|
+
import { fetchWithControllerAuth } from "./controller-fetch.js";
|
|
3
5
|
function normalizeUrl(raw) {
|
|
4
6
|
const value = (raw ?? "").trim();
|
|
5
7
|
if (!value)
|
|
@@ -12,15 +14,31 @@ function normalizeToken(raw) {
|
|
|
12
14
|
const trimmed = raw.trim();
|
|
13
15
|
return trimmed.length ? trimmed : null;
|
|
14
16
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
function resolveBearerTokenWithSource(options) {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
const profile = resolveActiveProfileName({ cwd });
|
|
20
|
+
const stored = resolveConfiguredAccessToken({ profile, cwd });
|
|
21
|
+
const explicit = normalizeToken(options.accessToken) ?? normalizeToken(options.serviceToken);
|
|
22
|
+
if (explicit) {
|
|
23
|
+
return { token: explicit, source: "explicit", profile };
|
|
24
|
+
}
|
|
25
|
+
const envKeys = [
|
|
26
|
+
"CONTROLLER_ACCESS_TOKEN",
|
|
27
|
+
"INSTAFY_ACCESS_TOKEN",
|
|
28
|
+
"INSTAFY_SERVICE_TOKEN",
|
|
29
|
+
"CONTROLLER_TOKEN",
|
|
30
|
+
"SUPABASE_ACCESS_TOKEN",
|
|
31
|
+
];
|
|
32
|
+
for (const key of envKeys) {
|
|
33
|
+
const value = normalizeToken(process.env[key]);
|
|
34
|
+
if (value) {
|
|
35
|
+
return { token: value, source: "env", profile };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (stored) {
|
|
39
|
+
return { token: stored, source: "config", profile };
|
|
40
|
+
}
|
|
41
|
+
return { token: null, source: "none", profile };
|
|
24
42
|
}
|
|
25
43
|
function parseKeyValue(raw) {
|
|
26
44
|
const trimmed = raw.trim();
|
|
@@ -98,12 +116,10 @@ function maybePrettyPrintJson(text, pretty) {
|
|
|
98
116
|
}
|
|
99
117
|
export async function requestControllerApi(options) {
|
|
100
118
|
const url = buildRequestUrl(options);
|
|
101
|
-
const
|
|
119
|
+
const resolved = resolveBearerTokenWithSource(options);
|
|
120
|
+
const bearer = resolved.token;
|
|
102
121
|
const headers = new Headers();
|
|
103
122
|
headers.set("accept", "application/json");
|
|
104
|
-
if (bearer) {
|
|
105
|
-
headers.set("authorization", `Bearer ${bearer}`);
|
|
106
|
-
}
|
|
107
123
|
for (const header of options.headers ?? []) {
|
|
108
124
|
const { key, value } = parseHeader(header);
|
|
109
125
|
headers.set(key, value);
|
|
@@ -112,17 +128,35 @@ export async function requestControllerApi(options) {
|
|
|
112
128
|
if (body !== undefined && !headers.has("content-type")) {
|
|
113
129
|
headers.set("content-type", "application/json");
|
|
114
130
|
}
|
|
115
|
-
const
|
|
131
|
+
const init = {
|
|
116
132
|
method: options.method,
|
|
117
133
|
headers,
|
|
118
134
|
body,
|
|
119
|
-
}
|
|
135
|
+
};
|
|
136
|
+
const response = bearer
|
|
137
|
+
? (await fetchWithControllerAuth({
|
|
138
|
+
url: url.toString(),
|
|
139
|
+
init,
|
|
140
|
+
accessToken: bearer,
|
|
141
|
+
tokenSource: resolved.source,
|
|
142
|
+
profile: resolved.profile,
|
|
143
|
+
cwd: process.cwd(),
|
|
144
|
+
})).response
|
|
145
|
+
: await fetch(url, init);
|
|
120
146
|
const responseText = await response.text().catch(() => "");
|
|
121
147
|
const contentType = response.headers.get("content-type") ?? "";
|
|
122
148
|
const isJson = contentType.includes("application/json") || contentType.includes("+json");
|
|
123
149
|
const pretty = options.pretty !== false;
|
|
124
150
|
const formattedBody = isJson ? maybePrettyPrintJson(responseText, pretty) : responseText;
|
|
125
151
|
if (!response.ok) {
|
|
152
|
+
if (response.status === 401 || response.status === 403) {
|
|
153
|
+
throw formatAuthRejectedError({
|
|
154
|
+
status: response.status,
|
|
155
|
+
responseBody: responseText,
|
|
156
|
+
retryCommand: "instafy login",
|
|
157
|
+
advancedHint: "pass --access-token / --service-token, or set INSTAFY_ACCESS_TOKEN / INSTAFY_SERVICE_TOKEN",
|
|
158
|
+
});
|
|
159
|
+
}
|
|
126
160
|
const prefix = `Request failed (${response.status} ${response.statusText})`;
|
|
127
161
|
const suffix = formattedBody.trim() ? `: ${formattedBody}` : "";
|
|
128
162
|
throw new Error(`${prefix}${suffix}`);
|