@usefillo/cli 0.14.0 → 0.14.1
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/index.js +95 -42
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -91,7 +91,9 @@ function die(msg) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// src/lib/api.ts
|
|
94
|
-
var
|
|
94
|
+
var DEFAULT_API = "https://fillo.so";
|
|
95
|
+
var apiOverride = process.env.FILLO_API?.trim();
|
|
96
|
+
var API = (apiOverride || DEFAULT_API).replace(/\/$/, "");
|
|
95
97
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
96
98
|
var SYNC_TOKEN_ENV = "FILLO_SYNC_TOKEN";
|
|
97
99
|
function requireTokenFor(apiBase) {
|
|
@@ -113,24 +115,51 @@ function requireTokenFor(apiBase) {
|
|
|
113
115
|
function requireToken() {
|
|
114
116
|
return requireTokenFor(API);
|
|
115
117
|
}
|
|
118
|
+
function networkFailure(apiBase, error) {
|
|
119
|
+
const timedOut = error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError");
|
|
120
|
+
const reason = causeCode(error) ?? (timedOut ? `no response within ${REQUEST_TIMEOUT_MS / 1e3}s` : void 0);
|
|
121
|
+
const hint = apiBase === DEFAULT_API ? "Check your network connection and try again." : `The CLI is pointed there by FILLO_API or --api \u2014 unset the override to use ${DEFAULT_API}, or start that deployment.`;
|
|
122
|
+
return new Error(
|
|
123
|
+
`Couldn't reach ${terminalText(apiBase)}${reason ? ` (${reason})` : ""}. ${hint}`,
|
|
124
|
+
{
|
|
125
|
+
cause: error
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
function causeCode(error, depth = 0) {
|
|
130
|
+
if (!error || typeof error !== "object" || depth > 8) return void 0;
|
|
131
|
+
const { code, errors, cause } = error;
|
|
132
|
+
if (typeof code === "string" && code) return code;
|
|
133
|
+
if (Array.isArray(errors)) {
|
|
134
|
+
for (const nested of errors) {
|
|
135
|
+
const found = causeCode(nested, depth + 1);
|
|
136
|
+
if (found) return found;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return causeCode(cause, depth + 1);
|
|
140
|
+
}
|
|
116
141
|
async function api(path, init2 = {}, apiBase = API) {
|
|
117
142
|
const { token, ...rest } = init2;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
143
|
+
try {
|
|
144
|
+
return await fetch(`${apiBase}/api/v1${path}`, {
|
|
145
|
+
...rest,
|
|
146
|
+
signal: rest.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
147
|
+
headers: {
|
|
148
|
+
"Content-Type": "application/json",
|
|
149
|
+
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
150
|
+
...rest.headers
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
} catch (error) {
|
|
154
|
+
throw networkFailure(apiBase, error);
|
|
155
|
+
}
|
|
127
156
|
}
|
|
128
|
-
async function readJson(res) {
|
|
157
|
+
async function readJson(res, apiBase = API) {
|
|
129
158
|
const text = await res.text();
|
|
130
159
|
try {
|
|
131
160
|
return text ? JSON.parse(text) : {};
|
|
132
161
|
} catch {
|
|
133
|
-
die(`Unexpected non-JSON response from ${
|
|
162
|
+
die(`Unexpected non-JSON response from ${apiBase} (${res.status}).`);
|
|
134
163
|
}
|
|
135
164
|
}
|
|
136
165
|
|
|
@@ -722,7 +751,7 @@ function readSecret(promptText) {
|
|
|
722
751
|
// src/commands/init.ts
|
|
723
752
|
var EMAIL_REQUIRED = 'Usage: fillo init --email you@company.com [--name "Your Name"] (or run `fillo login` for an existing account).';
|
|
724
753
|
var execFileAsync = promisify(execFile);
|
|
725
|
-
async function provisionWorkspace(flags, usageHint) {
|
|
754
|
+
async function provisionWorkspace(flags, usageHint, apiBase = API) {
|
|
726
755
|
const json = jsonMode(flags);
|
|
727
756
|
let email3 = flagString(flags, "email")?.trim() ?? "";
|
|
728
757
|
let name = flagString(flags, "name")?.trim() ?? "";
|
|
@@ -752,11 +781,15 @@ async function provisionWorkspace(flags, usageHint) {
|
|
|
752
781
|
}
|
|
753
782
|
}
|
|
754
783
|
}
|
|
755
|
-
const res = await api(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
784
|
+
const res = await api(
|
|
785
|
+
"/workspaces/provision",
|
|
786
|
+
{
|
|
787
|
+
method: "POST",
|
|
788
|
+
body: JSON.stringify({ email: email3, source: "cli", ...name ? { name } : {} })
|
|
789
|
+
},
|
|
790
|
+
apiBase
|
|
791
|
+
);
|
|
792
|
+
const body = await readJson(res, apiBase);
|
|
760
793
|
if (!res.ok || !body.key) die(body.error ?? `Provisioning failed (${res.status}).`);
|
|
761
794
|
const claimToken = claimCookieValue(res);
|
|
762
795
|
const { claimUrl: _legacyWorkspaceLink, ...current } = readConfig();
|
|
@@ -797,7 +830,12 @@ async function init(flags) {
|
|
|
797
830
|
const json = jsonMode(flags);
|
|
798
831
|
const ws = await provisionWorkspace(flags, EMAIL_REQUIRED);
|
|
799
832
|
if (json) {
|
|
800
|
-
return emitResult({
|
|
833
|
+
return emitResult({
|
|
834
|
+
pk: ws.pk,
|
|
835
|
+
email: ws.email,
|
|
836
|
+
name: ws.name || null,
|
|
837
|
+
limits: ws.limits ?? null
|
|
838
|
+
});
|
|
801
839
|
}
|
|
802
840
|
console.log(
|
|
803
841
|
`
|
|
@@ -1059,12 +1097,14 @@ var skillCommand = {
|
|
|
1059
1097
|
|
|
1060
1098
|
// src/commands/agent.ts
|
|
1061
1099
|
var BOOTSTRAP_USAGE = 'To set up a workspace I need an email for your recovery link. Re-run: npx @usefillo/cli@latest agent bootstrap --email you@company.com [--name "Your Name"]. (Already have an account? `fillo login`.)';
|
|
1062
|
-
async function bootstrapStandalone(flags) {
|
|
1100
|
+
async function bootstrapStandalone(flags, apiBase) {
|
|
1063
1101
|
if (flags.account === true) {
|
|
1064
|
-
die(
|
|
1102
|
+
die(
|
|
1103
|
+
"--account is for the browser handoff: `fillo agent bootstrap --run <id> --token <token> --account`."
|
|
1104
|
+
);
|
|
1065
1105
|
}
|
|
1066
1106
|
const json = jsonMode(flags);
|
|
1067
|
-
const ws = await provisionWorkspace(flags, BOOTSTRAP_USAGE);
|
|
1107
|
+
const ws = await provisionWorkspace(flags, BOOTSTRAP_USAGE, apiBase);
|
|
1068
1108
|
const targets = installSkill(flags, { quiet: json });
|
|
1069
1109
|
if (json) {
|
|
1070
1110
|
return emitResult({
|
|
@@ -1079,7 +1119,9 @@ async function bootstrapStandalone(flags) {
|
|
|
1079
1119
|
`
|
|
1080
1120
|
${bold("Ready.")} Workspace provisioned and the Build with Fillo skill installed.`
|
|
1081
1121
|
);
|
|
1082
|
-
console.log(
|
|
1122
|
+
console.log(
|
|
1123
|
+
` ${dim(`A workspace link was sent to ${terminalText(ws.email)} \u2014 claim it anytime with \`fillo claim\`.`)}`
|
|
1124
|
+
);
|
|
1083
1125
|
const preview = previewLimitLine(ws.limits);
|
|
1084
1126
|
if (preview) console.log(` ${dim(preview)}`);
|
|
1085
1127
|
console.log(`
|
|
@@ -1112,7 +1154,7 @@ async function agent(subcommand, flags) {
|
|
|
1112
1154
|
die("--account does not take a value.");
|
|
1113
1155
|
}
|
|
1114
1156
|
if (subcommand === "bootstrap") {
|
|
1115
|
-
if (!run || !token) return bootstrapStandalone(flags);
|
|
1157
|
+
if (!run || !token) return bootstrapStandalone(flags, apiBase);
|
|
1116
1158
|
installSkill(flags);
|
|
1117
1159
|
if (flags.account === true) {
|
|
1118
1160
|
await login({ ...flags, json: false }, { continueToAgentRun: true });
|
|
@@ -1176,29 +1218,39 @@ async function connectAgentRun(apiBase, run, token, attachAccount) {
|
|
|
1176
1218
|
);
|
|
1177
1219
|
}
|
|
1178
1220
|
async function postAgentEvent(apiBase, run, token, body) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1221
|
+
let res;
|
|
1222
|
+
try {
|
|
1223
|
+
res = await fetch(`${apiBase}/api/v1/agent-runs/${encodeURIComponent(run)}/events`, {
|
|
1224
|
+
method: "POST",
|
|
1225
|
+
headers: {
|
|
1226
|
+
Authorization: `Bearer ${token}`,
|
|
1227
|
+
"Content-Type": "application/json"
|
|
1228
|
+
},
|
|
1229
|
+
body: JSON.stringify(body),
|
|
1230
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
1231
|
+
});
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
throw networkFailure(apiBase, error);
|
|
1234
|
+
}
|
|
1188
1235
|
const payload = await res.json().catch(() => ({}));
|
|
1189
1236
|
if (!res.ok) die(payload.error ?? `agent progress failed (${res.status}).`);
|
|
1190
1237
|
}
|
|
1191
1238
|
async function attachAgentAccount(apiBase, run, progressToken) {
|
|
1192
1239
|
const accountToken = requireTokenFor(apiBase);
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1240
|
+
let res;
|
|
1241
|
+
try {
|
|
1242
|
+
res = await fetch(`${apiBase}/api/v1/agent-runs/${encodeURIComponent(run)}/account`, {
|
|
1243
|
+
method: "POST",
|
|
1244
|
+
redirect: "error",
|
|
1245
|
+
headers: {
|
|
1246
|
+
Authorization: `Bearer ${accountToken}`,
|
|
1247
|
+
"X-Fillo-Agent-Run-Token": progressToken
|
|
1248
|
+
},
|
|
1249
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
1250
|
+
});
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
throw networkFailure(apiBase, error);
|
|
1253
|
+
}
|
|
1202
1254
|
const payload = await res.json().catch(() => ({}));
|
|
1203
1255
|
if (!res.ok) {
|
|
1204
1256
|
const hint = res.status === 401 ? " Run `fillo login` and try again." : "";
|
|
@@ -1217,6 +1269,7 @@ function agentHelp() {
|
|
|
1217
1269
|
agent bootstrap Set up a workspace and install the Build with Fillo skill
|
|
1218
1270
|
${dimRaw("--email you@company.com provision a fresh workspace (a TTY confirms your git identity)")}
|
|
1219
1271
|
${dimRaw('--name "Your Name" optional display name')}
|
|
1272
|
+
${dimRaw("--api <url> target a different Fillo deployment (default: FILLO_API or https://fillo.so)")}
|
|
1220
1273
|
${dimRaw("--run <id> --token <token> instead: attach to an open browser modal")}
|
|
1221
1274
|
${dimRaw("--account with --run/--token: approve an existing workspace in the browser")}
|
|
1222
1275
|
agent connect Connect a coding-agent run to the open browser modal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefillo/cli",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Create and publish Fillo forms, and install the Fillo Agent Skill.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup && node scripts/copy-skill.mjs",
|
|
33
|
-
"test": "node scripts/validate-skill-bundle.mjs && node scripts/test-skill-bundle.mjs && node scripts/test-skill-install.mjs && node scripts/test-agent-account.mjs && node scripts/test-stage-push.mjs && node scripts/test-local-validation.mjs && node scripts/test-loopback.mjs && node scripts/test-init.mjs && node scripts/test-init-tty.mjs && node scripts/test-keys-claim.mjs && node scripts/test-responses.mjs && node scripts/test-workspace-commands.mjs",
|
|
33
|
+
"test": "node scripts/validate-skill-bundle.mjs && node scripts/test-skill-bundle.mjs && node scripts/test-skill-install.mjs && node scripts/test-agent-account.mjs && node scripts/test-stage-push.mjs && node scripts/test-local-validation.mjs && node scripts/test-loopback.mjs && node scripts/test-init.mjs && node scripts/test-api-target.mjs && node scripts/test-init-tty.mjs && node scripts/test-keys-claim.mjs && node scripts/test-responses.mjs && node scripts/test-workspace-commands.mjs",
|
|
34
34
|
"typecheck": "tsc --noEmit"
|
|
35
35
|
}
|
|
36
36
|
}
|