@usefillo/cli 0.1.1 → 0.2.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 +126 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -120,11 +120,27 @@ async function loadSchema(file, allowCode) {
|
|
|
120
120
|
try {
|
|
121
121
|
if (abs.endsWith(".json")) return JSON.parse(readFileSync(abs, "utf8"));
|
|
122
122
|
const mod = await import(pathToFileURL(abs).href);
|
|
123
|
-
return mod.default ?? mod.schema ?? mod.form;
|
|
123
|
+
return mod.default ?? mod.schema ?? mod.form ?? mod.forms ?? mod.MARKETING_FORMS;
|
|
124
124
|
} catch (e) {
|
|
125
125
|
die(`Couldn't read ${file}: ${e.message}`);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
function isRecord(value) {
|
|
129
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
130
|
+
}
|
|
131
|
+
function toPushItems(value, handle) {
|
|
132
|
+
const values = Array.isArray(value) ? value : [value];
|
|
133
|
+
return values.map((item, index) => {
|
|
134
|
+
if (isRecord(item) && "schema" in item) {
|
|
135
|
+
const ownHandle = typeof item.id === "string" ? item.id : void 0;
|
|
136
|
+
return { handle: handle ?? ownHandle, schema: item.schema, theme: item.theme };
|
|
137
|
+
}
|
|
138
|
+
if (values.length > 1 && !handle) {
|
|
139
|
+
die(`Item ${index + 1} needs an id or --handle.`);
|
|
140
|
+
}
|
|
141
|
+
return { handle, schema: item };
|
|
142
|
+
});
|
|
143
|
+
}
|
|
128
144
|
function printPushed(formId, url, updated, staged) {
|
|
129
145
|
console.log(`
|
|
130
146
|
\x1B[32m\u2713\x1B[0m ${updated ? "Updated" : "Created"} ${bold(formId)}`);
|
|
@@ -135,28 +151,45 @@ function printPushed(formId, url, updated, staged) {
|
|
|
135
151
|
}
|
|
136
152
|
async function push(file, flags) {
|
|
137
153
|
if (!file) die("Usage: fillo push <form.json> [--handle name] [--draft] [--allow-code]");
|
|
138
|
-
const schema = await loadSchema(file, flags["allow-code"] === true);
|
|
139
154
|
const handle = typeof flags.handle === "string" ? flags.handle : void 0;
|
|
155
|
+
const items = toPushItems(await loadSchema(file, flags["allow-code"] === true), handle);
|
|
156
|
+
if (items.length > 1 && handle) die("--handle can only be used when pushing one form.");
|
|
140
157
|
const cfg = readConfig();
|
|
141
158
|
if (cfg.token) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
159
|
+
for (const item of items) {
|
|
160
|
+
const res = await api("/cli/forms", {
|
|
161
|
+
method: "POST",
|
|
162
|
+
token: cfg.token,
|
|
163
|
+
body: JSON.stringify({
|
|
164
|
+
schema: item.schema,
|
|
165
|
+
theme: item.theme ?? null,
|
|
166
|
+
handle: item.handle,
|
|
167
|
+
publish: !flags.draft
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
const body = await res.json();
|
|
171
|
+
if (!res.ok || !body.formId) die(body.error ?? `push failed (${res.status}).`);
|
|
172
|
+
printPushed(body.formId, body.url, !!body.updated, !!flags.draft);
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
150
175
|
}
|
|
151
176
|
if (cfg.pk) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
177
|
+
for (const item of items) {
|
|
178
|
+
if (!item.handle) die("Pushing with a provisioned key needs --handle <name> or form.id.");
|
|
179
|
+
const res = await api("/forms/sync", {
|
|
180
|
+
method: "POST",
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
key: cfg.pk,
|
|
183
|
+
id: item.handle,
|
|
184
|
+
schema: item.schema,
|
|
185
|
+
theme: item.theme ?? null
|
|
186
|
+
})
|
|
187
|
+
});
|
|
188
|
+
const body = await res.json();
|
|
189
|
+
if (!res.ok || !body.formId) die(body.error ?? `push failed (${res.status}).`);
|
|
190
|
+
printPushed(body.formId, body.slug ? `${API}/f/${body.slug}` : void 0, false, !!body.staged);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
160
193
|
}
|
|
161
194
|
die("Not set up yet. Run `fillo init` (no account needed) or `fillo login`.");
|
|
162
195
|
}
|
|
@@ -184,6 +217,71 @@ async function init(flags) {
|
|
|
184
217
|
`);
|
|
185
218
|
}
|
|
186
219
|
}
|
|
220
|
+
async function agent(subcommand, flags) {
|
|
221
|
+
const apiBase = flagString(flags, "api")?.replace(/\/$/, "") ?? API;
|
|
222
|
+
const run = flagString(flags, "run");
|
|
223
|
+
const token = flagString(flags, "token");
|
|
224
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
225
|
+
return agentHelp();
|
|
226
|
+
}
|
|
227
|
+
if (!run || !token) {
|
|
228
|
+
die("Usage: fillo agent <connect|event> --run <id> --token <token> [--api <url>]");
|
|
229
|
+
}
|
|
230
|
+
if (subcommand === "connect") {
|
|
231
|
+
await postAgentEvent(apiBase, run, token, {
|
|
232
|
+
status: "connected",
|
|
233
|
+
message: "Agent connected. Reading the app now."
|
|
234
|
+
});
|
|
235
|
+
console.log(` \x1B[32m\u2713\x1B[0m Live progress connected.`);
|
|
236
|
+
console.log(` ${dim("Report next steps with:")}`);
|
|
237
|
+
console.log(
|
|
238
|
+
` fillo agent event --api ${apiBase} --run ${run} --token <same-token> --status editing --message "Editing the form screen"`
|
|
239
|
+
);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (subcommand === "event") {
|
|
243
|
+
const status = flagString(flags, "status");
|
|
244
|
+
const message = flagString(flags, "message");
|
|
245
|
+
if (!status) die("Usage: fillo agent event --status <status> --message <short update>");
|
|
246
|
+
await postAgentEvent(apiBase, run, token, {
|
|
247
|
+
status,
|
|
248
|
+
message,
|
|
249
|
+
claimUrl: flagString(flags, "claim-url"),
|
|
250
|
+
dashboardUrl: flagString(flags, "dashboard-url"),
|
|
251
|
+
appUrl: flagString(flags, "app-url"),
|
|
252
|
+
formId: flagString(flags, "form-id"),
|
|
253
|
+
formName: flagString(flags, "form-name")
|
|
254
|
+
});
|
|
255
|
+
console.log(` \x1B[32m\u2713\x1B[0m Progress sent.`);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
die(`Unknown agent command: ${subcommand}`);
|
|
259
|
+
}
|
|
260
|
+
async function postAgentEvent(apiBase, run, token, body) {
|
|
261
|
+
const res = await fetch(`${apiBase}/api/v1/agent-runs/${encodeURIComponent(run)}/events`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: {
|
|
264
|
+
Authorization: `Bearer ${token}`,
|
|
265
|
+
"Content-Type": "application/json"
|
|
266
|
+
},
|
|
267
|
+
body: JSON.stringify(body)
|
|
268
|
+
});
|
|
269
|
+
const payload = await res.json().catch(() => ({}));
|
|
270
|
+
if (!res.ok) die(payload.error ?? `agent progress failed (${res.status}).`);
|
|
271
|
+
}
|
|
272
|
+
function agentHelp() {
|
|
273
|
+
console.log(`
|
|
274
|
+
${bold("fillo agent")} \u2014 report live progress back to a Fillo prompt modal
|
|
275
|
+
|
|
276
|
+
${bold("Commands")}
|
|
277
|
+
agent connect Connect a coding-agent run to the open browser modal
|
|
278
|
+
agent event Send a short progress update
|
|
279
|
+
${dim("--status <created|connected|asking|planning|installing|editing|checking|done|error>")}
|
|
280
|
+
${dim('--message "Short update"')}
|
|
281
|
+
${dim("--claim-url <url> --app-url <url> --form-name <name>")}
|
|
282
|
+
${dim("--run <id> --token <token> --api <url>")}
|
|
283
|
+
`);
|
|
284
|
+
}
|
|
187
285
|
function help() {
|
|
188
286
|
console.log(`
|
|
189
287
|
${bold("fillo")} \u2014 create Fillo forms from your terminal
|
|
@@ -199,10 +297,15 @@ function help() {
|
|
|
199
297
|
${dim("--draft stage as a draft instead of publishing")}
|
|
200
298
|
${dim("--allow-code allow a .mjs/.js schema (executes the file)")}
|
|
201
299
|
list List the workspace's forms
|
|
300
|
+
agent <cmd> Report live progress to a Fillo prompt modal
|
|
202
301
|
|
|
203
302
|
${dim(`API: ${API} \xB7 set FILLO_API to override`)}
|
|
204
303
|
`);
|
|
205
304
|
}
|
|
305
|
+
function flagString(flags, key) {
|
|
306
|
+
const value = flags[key];
|
|
307
|
+
return typeof value === "string" && value ? value : void 0;
|
|
308
|
+
}
|
|
206
309
|
function parseFlags(args) {
|
|
207
310
|
const flags = {};
|
|
208
311
|
const positional = [];
|
|
@@ -229,6 +332,9 @@ function parseFlags(args) {
|
|
|
229
332
|
async function main() {
|
|
230
333
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
231
334
|
const { positional, flags } = parseFlags(rest);
|
|
335
|
+
if (flags.help === true || flags.h === true) {
|
|
336
|
+
return cmd === "agent" ? agentHelp() : help();
|
|
337
|
+
}
|
|
232
338
|
switch (cmd) {
|
|
233
339
|
case "init":
|
|
234
340
|
return init(flags);
|
|
@@ -244,6 +350,8 @@ async function main() {
|
|
|
244
350
|
case "list":
|
|
245
351
|
case "ls":
|
|
246
352
|
return list();
|
|
353
|
+
case "agent":
|
|
354
|
+
return agent(positional[0], flags);
|
|
247
355
|
case void 0:
|
|
248
356
|
case "help":
|
|
249
357
|
case "--help":
|