@usefillo/cli 0.5.0 → 0.8.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/dist/index.js CHANGED
@@ -1,57 +1,1907 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
+ import {
5
+ chmodSync,
6
+ cpSync,
7
+ existsSync,
8
+ lstatSync,
9
+ mkdirSync,
10
+ realpathSync,
11
+ readdirSync,
12
+ readFileSync,
13
+ renameSync,
14
+ rmSync,
15
+ writeFileSync
16
+ } from "fs";
17
+ import { randomUUID } from "crypto";
5
18
  import { homedir } from "os";
6
- import { isAbsolute, join, resolve } from "path";
19
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "path";
7
20
  import { spawn } from "child_process";
8
- import { pathToFileURL } from "url";
21
+ import { fileURLToPath, pathToFileURL } from "url";
22
+
23
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
24
+ var _a;
25
+ // @__NO_SIDE_EFFECTS__
26
+ function $constructor(name, initializer2, params) {
27
+ function init2(inst, def) {
28
+ if (!inst._zod) {
29
+ Object.defineProperty(inst, "_zod", {
30
+ value: {
31
+ def,
32
+ constr: _,
33
+ traits: /* @__PURE__ */ new Set()
34
+ },
35
+ enumerable: false
36
+ });
37
+ }
38
+ if (inst._zod.traits.has(name)) {
39
+ return;
40
+ }
41
+ inst._zod.traits.add(name);
42
+ initializer2(inst, def);
43
+ const proto = _.prototype;
44
+ const keys = Object.keys(proto);
45
+ for (let i = 0; i < keys.length; i++) {
46
+ const k = keys[i];
47
+ if (!(k in inst)) {
48
+ inst[k] = proto[k].bind(inst);
49
+ }
50
+ }
51
+ }
52
+ const Parent = params?.Parent ?? Object;
53
+ class Definition extends Parent {
54
+ }
55
+ Object.defineProperty(Definition, "name", { value: name });
56
+ function _(def) {
57
+ var _a2;
58
+ const inst = params?.Parent ? new Definition() : this;
59
+ init2(inst, def);
60
+ (_a2 = inst._zod).deferred ?? (_a2.deferred = []);
61
+ for (const fn of inst._zod.deferred) {
62
+ fn();
63
+ }
64
+ return inst;
65
+ }
66
+ Object.defineProperty(_, "init", { value: init2 });
67
+ Object.defineProperty(_, Symbol.hasInstance, {
68
+ value: (inst) => {
69
+ if (params?.Parent && inst instanceof params.Parent)
70
+ return true;
71
+ return inst?._zod?.traits?.has(name);
72
+ }
73
+ });
74
+ Object.defineProperty(_, "name", { value: name });
75
+ return _;
76
+ }
77
+ var $ZodAsyncError = class extends Error {
78
+ constructor() {
79
+ super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
80
+ }
81
+ };
82
+ (_a = globalThis).__zod_globalConfig ?? (_a.__zod_globalConfig = {});
83
+ var globalConfig = globalThis.__zod_globalConfig;
84
+ function config(newConfig) {
85
+ if (newConfig)
86
+ Object.assign(globalConfig, newConfig);
87
+ return globalConfig;
88
+ }
89
+
90
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js
91
+ function getEnumValues(entries) {
92
+ const numericValues = Object.values(entries).filter((v) => typeof v === "number");
93
+ const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
94
+ return values;
95
+ }
96
+ function jsonStringifyReplacer(_, value) {
97
+ if (typeof value === "bigint")
98
+ return value.toString();
99
+ return value;
100
+ }
101
+ function cached(getter) {
102
+ const set = false;
103
+ return {
104
+ get value() {
105
+ if (!set) {
106
+ const value = getter();
107
+ Object.defineProperty(this, "value", { value });
108
+ return value;
109
+ }
110
+ throw new Error("cached value already set");
111
+ }
112
+ };
113
+ }
114
+ function nullish(input) {
115
+ return input === null || input === void 0;
116
+ }
117
+ function cleanRegex(source) {
118
+ const start = source.startsWith("^") ? 1 : 0;
119
+ const end = source.endsWith("$") ? source.length - 1 : source.length;
120
+ return source.slice(start, end);
121
+ }
122
+ var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
123
+ function defineLazy(object2, key, getter) {
124
+ let value = void 0;
125
+ Object.defineProperty(object2, key, {
126
+ get() {
127
+ if (value === EVALUATING) {
128
+ return void 0;
129
+ }
130
+ if (value === void 0) {
131
+ value = EVALUATING;
132
+ value = getter();
133
+ }
134
+ return value;
135
+ },
136
+ set(v) {
137
+ Object.defineProperty(object2, key, {
138
+ value: v
139
+ // configurable: true,
140
+ });
141
+ },
142
+ configurable: true
143
+ });
144
+ }
145
+ var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {
146
+ };
147
+ function isObject(data) {
148
+ return typeof data === "object" && data !== null && !Array.isArray(data);
149
+ }
150
+ function isPlainObject(o) {
151
+ if (isObject(o) === false)
152
+ return false;
153
+ const ctor = o.constructor;
154
+ if (ctor === void 0)
155
+ return true;
156
+ if (typeof ctor !== "function")
157
+ return true;
158
+ const prot = ctor.prototype;
159
+ if (isObject(prot) === false)
160
+ return false;
161
+ if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) {
162
+ return false;
163
+ }
164
+ return true;
165
+ }
166
+ function shallowClone(o) {
167
+ if (isPlainObject(o))
168
+ return { ...o };
169
+ if (Array.isArray(o))
170
+ return [...o];
171
+ if (o instanceof Map)
172
+ return new Map(o);
173
+ if (o instanceof Set)
174
+ return new Set(o);
175
+ return o;
176
+ }
177
+ var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
178
+ function escapeRegex(str2) {
179
+ return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
180
+ }
181
+ function clone(inst, def, params) {
182
+ const cl = new inst._zod.constr(def ?? inst._zod.def);
183
+ if (!def || params?.parent)
184
+ cl._zod.parent = inst;
185
+ return cl;
186
+ }
187
+ function normalizeParams(_params) {
188
+ const params = _params;
189
+ if (!params)
190
+ return {};
191
+ if (typeof params === "string")
192
+ return { error: () => params };
193
+ if (params?.message !== void 0) {
194
+ if (params?.error !== void 0)
195
+ throw new Error("Cannot specify both `message` and `error` params");
196
+ params.error = params.message;
197
+ }
198
+ delete params.message;
199
+ if (typeof params.error === "string")
200
+ return { ...params, error: () => params.error };
201
+ return params;
202
+ }
203
+ function optionalKeys(shape) {
204
+ return Object.keys(shape).filter((k) => {
205
+ return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional";
206
+ });
207
+ }
208
+ var NUMBER_FORMAT_RANGES = {
209
+ safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],
210
+ int32: [-2147483648, 2147483647],
211
+ uint32: [0, 4294967295],
212
+ float32: [-34028234663852886e22, 34028234663852886e22],
213
+ float64: [-Number.MAX_VALUE, Number.MAX_VALUE]
214
+ };
215
+ function aborted(x, startIndex = 0) {
216
+ if (x.aborted === true)
217
+ return true;
218
+ for (let i = startIndex; i < x.issues.length; i++) {
219
+ if (x.issues[i]?.continue !== true) {
220
+ return true;
221
+ }
222
+ }
223
+ return false;
224
+ }
225
+ function explicitlyAborted(x, startIndex = 0) {
226
+ if (x.aborted === true)
227
+ return true;
228
+ for (let i = startIndex; i < x.issues.length; i++) {
229
+ if (x.issues[i]?.continue === false) {
230
+ return true;
231
+ }
232
+ }
233
+ return false;
234
+ }
235
+ function prefixIssues(path, issues) {
236
+ return issues.map((iss) => {
237
+ var _a2;
238
+ (_a2 = iss).path ?? (_a2.path = []);
239
+ iss.path.unshift(path);
240
+ return iss;
241
+ });
242
+ }
243
+ function unwrapMessage(message) {
244
+ return typeof message === "string" ? message : message?.message;
245
+ }
246
+ function finalizeIssue(iss, ctx, config2) {
247
+ const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config2.customError?.(iss)) ?? unwrapMessage(config2.localeError?.(iss)) ?? "Invalid input";
248
+ const { inst: _inst, continue: _continue, input: _input, ...rest } = iss;
249
+ rest.path ?? (rest.path = []);
250
+ rest.message = message;
251
+ if (ctx?.reportInput) {
252
+ rest.input = _input;
253
+ }
254
+ return rest;
255
+ }
256
+ function getLengthableOrigin(input) {
257
+ if (Array.isArray(input))
258
+ return "array";
259
+ if (typeof input === "string")
260
+ return "string";
261
+ return "unknown";
262
+ }
263
+
264
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js
265
+ var initializer = (inst, def) => {
266
+ inst.name = "$ZodError";
267
+ Object.defineProperty(inst, "_zod", {
268
+ value: inst._zod,
269
+ enumerable: false
270
+ });
271
+ Object.defineProperty(inst, "issues", {
272
+ value: def,
273
+ enumerable: false
274
+ });
275
+ inst.message = JSON.stringify(def, jsonStringifyReplacer, 2);
276
+ Object.defineProperty(inst, "toString", {
277
+ value: () => inst.message,
278
+ enumerable: false
279
+ });
280
+ };
281
+ var $ZodError = $constructor("$ZodError", initializer);
282
+ var $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error });
283
+
284
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js
285
+ var _parse = (_Err) => (schema, value, _ctx, _params) => {
286
+ const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
287
+ const result = schema._zod.run({ value, issues: [] }, ctx);
288
+ if (result instanceof Promise) {
289
+ throw new $ZodAsyncError();
290
+ }
291
+ if (result.issues.length) {
292
+ const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
293
+ captureStackTrace(e, _params?.callee);
294
+ throw e;
295
+ }
296
+ return result.value;
297
+ };
298
+ var parse = /* @__PURE__ */ _parse($ZodRealError);
299
+ var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
300
+ const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
301
+ let result = schema._zod.run({ value, issues: [] }, ctx);
302
+ if (result instanceof Promise)
303
+ result = await result;
304
+ if (result.issues.length) {
305
+ const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
306
+ captureStackTrace(e, params?.callee);
307
+ throw e;
308
+ }
309
+ return result.value;
310
+ };
311
+ var parseAsync = /* @__PURE__ */ _parseAsync($ZodRealError);
312
+ var _safeParse = (_Err) => (schema, value, _ctx) => {
313
+ const ctx = _ctx ? { ..._ctx, async: false } : { async: false };
314
+ const result = schema._zod.run({ value, issues: [] }, ctx);
315
+ if (result instanceof Promise) {
316
+ throw new $ZodAsyncError();
317
+ }
318
+ return result.issues.length ? {
319
+ success: false,
320
+ error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())))
321
+ } : { success: true, data: result.value };
322
+ };
323
+ var safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
324
+ var _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
325
+ const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
326
+ let result = schema._zod.run({ value, issues: [] }, ctx);
327
+ if (result instanceof Promise)
328
+ result = await result;
329
+ return result.issues.length ? {
330
+ success: false,
331
+ error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config())))
332
+ } : { success: true, data: result.value };
333
+ };
334
+ var safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
335
+
336
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js
337
+ var email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
338
+ var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
339
+ var date = /* @__PURE__ */ new RegExp(`^${dateSource}$`);
340
+ var string = (params) => {
341
+ const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
342
+ return new RegExp(`^${regex}$`);
343
+ };
344
+ var number = /^-?\d+(?:\.\d+)?$/;
345
+
346
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js
347
+ var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
348
+ var _a2;
349
+ inst._zod ?? (inst._zod = {});
350
+ inst._zod.def = def;
351
+ (_a2 = inst._zod).onattach ?? (_a2.onattach = []);
352
+ });
353
+ var numericOriginMap = {
354
+ number: "number",
355
+ bigint: "bigint",
356
+ object: "date"
357
+ };
358
+ var $ZodCheckGreaterThan = /* @__PURE__ */ $constructor("$ZodCheckGreaterThan", (inst, def) => {
359
+ $ZodCheck.init(inst, def);
360
+ const origin = numericOriginMap[typeof def.value];
361
+ inst._zod.onattach.push((inst2) => {
362
+ const bag = inst2._zod.bag;
363
+ const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY;
364
+ if (def.value > curr) {
365
+ if (def.inclusive)
366
+ bag.minimum = def.value;
367
+ else
368
+ bag.exclusiveMinimum = def.value;
369
+ }
370
+ });
371
+ inst._zod.check = (payload) => {
372
+ if (def.inclusive ? payload.value >= def.value : payload.value > def.value) {
373
+ return;
374
+ }
375
+ payload.issues.push({
376
+ origin,
377
+ code: "too_small",
378
+ minimum: typeof def.value === "object" ? def.value.getTime() : def.value,
379
+ input: payload.value,
380
+ inclusive: def.inclusive,
381
+ inst,
382
+ continue: !def.abort
383
+ });
384
+ };
385
+ });
386
+ var $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (inst, def) => {
387
+ var _a2;
388
+ $ZodCheck.init(inst, def);
389
+ (_a2 = inst._zod.def).when ?? (_a2.when = (payload) => {
390
+ const val = payload.value;
391
+ return !nullish(val) && val.length !== void 0;
392
+ });
393
+ inst._zod.onattach.push((inst2) => {
394
+ const curr = inst2._zod.bag.maximum ?? Number.POSITIVE_INFINITY;
395
+ if (def.maximum < curr)
396
+ inst2._zod.bag.maximum = def.maximum;
397
+ });
398
+ inst._zod.check = (payload) => {
399
+ const input = payload.value;
400
+ const length = input.length;
401
+ if (length <= def.maximum)
402
+ return;
403
+ const origin = getLengthableOrigin(input);
404
+ payload.issues.push({
405
+ origin,
406
+ code: "too_big",
407
+ maximum: def.maximum,
408
+ inclusive: true,
409
+ input,
410
+ inst,
411
+ continue: !def.abort
412
+ });
413
+ };
414
+ });
415
+ var $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (inst, def) => {
416
+ var _a2;
417
+ $ZodCheck.init(inst, def);
418
+ (_a2 = inst._zod.def).when ?? (_a2.when = (payload) => {
419
+ const val = payload.value;
420
+ return !nullish(val) && val.length !== void 0;
421
+ });
422
+ inst._zod.onattach.push((inst2) => {
423
+ const curr = inst2._zod.bag.minimum ?? Number.NEGATIVE_INFINITY;
424
+ if (def.minimum > curr)
425
+ inst2._zod.bag.minimum = def.minimum;
426
+ });
427
+ inst._zod.check = (payload) => {
428
+ const input = payload.value;
429
+ const length = input.length;
430
+ if (length >= def.minimum)
431
+ return;
432
+ const origin = getLengthableOrigin(input);
433
+ payload.issues.push({
434
+ origin,
435
+ code: "too_small",
436
+ minimum: def.minimum,
437
+ inclusive: true,
438
+ input,
439
+ inst,
440
+ continue: !def.abort
441
+ });
442
+ };
443
+ });
444
+ var $ZodCheckStringFormat = /* @__PURE__ */ $constructor("$ZodCheckStringFormat", (inst, def) => {
445
+ var _a2, _b;
446
+ $ZodCheck.init(inst, def);
447
+ inst._zod.onattach.push((inst2) => {
448
+ const bag = inst2._zod.bag;
449
+ bag.format = def.format;
450
+ if (def.pattern) {
451
+ bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set());
452
+ bag.patterns.add(def.pattern);
453
+ }
454
+ });
455
+ if (def.pattern)
456
+ (_a2 = inst._zod).check ?? (_a2.check = (payload) => {
457
+ def.pattern.lastIndex = 0;
458
+ if (def.pattern.test(payload.value))
459
+ return;
460
+ payload.issues.push({
461
+ origin: "string",
462
+ code: "invalid_format",
463
+ format: def.format,
464
+ input: payload.value,
465
+ ...def.pattern ? { pattern: def.pattern.toString() } : {},
466
+ inst,
467
+ continue: !def.abort
468
+ });
469
+ });
470
+ else
471
+ (_b = inst._zod).check ?? (_b.check = () => {
472
+ });
473
+ });
474
+
475
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js
476
+ var version = {
477
+ major: 4,
478
+ minor: 4,
479
+ patch: 3
480
+ };
481
+
482
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js
483
+ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
484
+ var _a2;
485
+ inst ?? (inst = {});
486
+ inst._zod.def = def;
487
+ inst._zod.bag = inst._zod.bag || {};
488
+ inst._zod.version = version;
489
+ const checks = [...inst._zod.def.checks ?? []];
490
+ if (inst._zod.traits.has("$ZodCheck")) {
491
+ checks.unshift(inst);
492
+ }
493
+ for (const ch of checks) {
494
+ for (const fn of ch._zod.onattach) {
495
+ fn(inst);
496
+ }
497
+ }
498
+ if (checks.length === 0) {
499
+ (_a2 = inst._zod).deferred ?? (_a2.deferred = []);
500
+ inst._zod.deferred?.push(() => {
501
+ inst._zod.run = inst._zod.parse;
502
+ });
503
+ } else {
504
+ const runChecks = (payload, checks2, ctx) => {
505
+ let isAborted = aborted(payload);
506
+ let asyncResult;
507
+ for (const ch of checks2) {
508
+ if (ch._zod.def.when) {
509
+ if (explicitlyAborted(payload))
510
+ continue;
511
+ const shouldRun = ch._zod.def.when(payload);
512
+ if (!shouldRun)
513
+ continue;
514
+ } else if (isAborted) {
515
+ continue;
516
+ }
517
+ const currLen = payload.issues.length;
518
+ const _ = ch._zod.check(payload);
519
+ if (_ instanceof Promise && ctx?.async === false) {
520
+ throw new $ZodAsyncError();
521
+ }
522
+ if (asyncResult || _ instanceof Promise) {
523
+ asyncResult = (asyncResult ?? Promise.resolve()).then(async () => {
524
+ await _;
525
+ const nextLen = payload.issues.length;
526
+ if (nextLen === currLen)
527
+ return;
528
+ if (!isAborted)
529
+ isAborted = aborted(payload, currLen);
530
+ });
531
+ } else {
532
+ const nextLen = payload.issues.length;
533
+ if (nextLen === currLen)
534
+ continue;
535
+ if (!isAborted)
536
+ isAborted = aborted(payload, currLen);
537
+ }
538
+ }
539
+ if (asyncResult) {
540
+ return asyncResult.then(() => {
541
+ return payload;
542
+ });
543
+ }
544
+ return payload;
545
+ };
546
+ const handleCanaryResult = (canary, payload, ctx) => {
547
+ if (aborted(canary)) {
548
+ canary.aborted = true;
549
+ return canary;
550
+ }
551
+ const checkResult = runChecks(payload, checks, ctx);
552
+ if (checkResult instanceof Promise) {
553
+ if (ctx.async === false)
554
+ throw new $ZodAsyncError();
555
+ return checkResult.then((checkResult2) => inst._zod.parse(checkResult2, ctx));
556
+ }
557
+ return inst._zod.parse(checkResult, ctx);
558
+ };
559
+ inst._zod.run = (payload, ctx) => {
560
+ if (ctx.skipChecks) {
561
+ return inst._zod.parse(payload, ctx);
562
+ }
563
+ if (ctx.direction === "backward") {
564
+ const canary = inst._zod.parse({ value: payload.value, issues: [] }, { ...ctx, skipChecks: true });
565
+ if (canary instanceof Promise) {
566
+ return canary.then((canary2) => {
567
+ return handleCanaryResult(canary2, payload, ctx);
568
+ });
569
+ }
570
+ return handleCanaryResult(canary, payload, ctx);
571
+ }
572
+ const result = inst._zod.parse(payload, ctx);
573
+ if (result instanceof Promise) {
574
+ if (ctx.async === false)
575
+ throw new $ZodAsyncError();
576
+ return result.then((result2) => runChecks(result2, checks, ctx));
577
+ }
578
+ return runChecks(result, checks, ctx);
579
+ };
580
+ }
581
+ defineLazy(inst, "~standard", () => ({
582
+ validate: (value) => {
583
+ try {
584
+ const r = safeParse(inst, value);
585
+ return r.success ? { value: r.data } : { issues: r.error?.issues };
586
+ } catch (_) {
587
+ return safeParseAsync(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
588
+ }
589
+ },
590
+ vendor: "zod",
591
+ version: 1
592
+ }));
593
+ });
594
+ var $ZodString = /* @__PURE__ */ $constructor("$ZodString", (inst, def) => {
595
+ $ZodType.init(inst, def);
596
+ inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string(inst._zod.bag);
597
+ inst._zod.parse = (payload, _) => {
598
+ if (def.coerce)
599
+ try {
600
+ payload.value = String(payload.value);
601
+ } catch (_2) {
602
+ }
603
+ if (typeof payload.value === "string")
604
+ return payload;
605
+ payload.issues.push({
606
+ expected: "string",
607
+ code: "invalid_type",
608
+ input: payload.value,
609
+ inst
610
+ });
611
+ return payload;
612
+ };
613
+ });
614
+ var $ZodStringFormat = /* @__PURE__ */ $constructor("$ZodStringFormat", (inst, def) => {
615
+ $ZodCheckStringFormat.init(inst, def);
616
+ $ZodString.init(inst, def);
617
+ });
618
+ var $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => {
619
+ def.pattern ?? (def.pattern = email);
620
+ $ZodStringFormat.init(inst, def);
621
+ });
622
+ var $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
623
+ $ZodType.init(inst, def);
624
+ inst._zod.pattern = inst._zod.bag.pattern ?? number;
625
+ inst._zod.parse = (payload, _ctx) => {
626
+ if (def.coerce)
627
+ try {
628
+ payload.value = Number(payload.value);
629
+ } catch (_) {
630
+ }
631
+ const input = payload.value;
632
+ if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) {
633
+ return payload;
634
+ }
635
+ const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0;
636
+ payload.issues.push({
637
+ expected: "number",
638
+ code: "invalid_type",
639
+ input,
640
+ inst,
641
+ ...received ? { received } : {}
642
+ });
643
+ return payload;
644
+ };
645
+ });
646
+ var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
647
+ $ZodType.init(inst, def);
648
+ inst._zod.parse = (payload) => payload;
649
+ });
650
+ function handleArrayResult(result, final, index) {
651
+ if (result.issues.length) {
652
+ final.issues.push(...prefixIssues(index, result.issues));
653
+ }
654
+ final.value[index] = result.value;
655
+ }
656
+ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
657
+ $ZodType.init(inst, def);
658
+ inst._zod.parse = (payload, ctx) => {
659
+ const input = payload.value;
660
+ if (!Array.isArray(input)) {
661
+ payload.issues.push({
662
+ expected: "array",
663
+ code: "invalid_type",
664
+ input,
665
+ inst
666
+ });
667
+ return payload;
668
+ }
669
+ payload.value = Array(input.length);
670
+ const proms = [];
671
+ for (let i = 0; i < input.length; i++) {
672
+ const item = input[i];
673
+ const result = def.element._zod.run({
674
+ value: item,
675
+ issues: []
676
+ }, ctx);
677
+ if (result instanceof Promise) {
678
+ proms.push(result.then((result2) => handleArrayResult(result2, payload, i)));
679
+ } else {
680
+ handleArrayResult(result, payload, i);
681
+ }
682
+ }
683
+ if (proms.length) {
684
+ return Promise.all(proms).then(() => payload);
685
+ }
686
+ return payload;
687
+ };
688
+ });
689
+ function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) {
690
+ const isPresent = key in input;
691
+ if (result.issues.length) {
692
+ if (isOptionalIn && isOptionalOut && !isPresent) {
693
+ return;
694
+ }
695
+ final.issues.push(...prefixIssues(key, result.issues));
696
+ }
697
+ if (!isPresent && !isOptionalIn) {
698
+ if (!result.issues.length) {
699
+ final.issues.push({
700
+ code: "invalid_type",
701
+ expected: "nonoptional",
702
+ input: void 0,
703
+ path: [key]
704
+ });
705
+ }
706
+ return;
707
+ }
708
+ if (result.value === void 0) {
709
+ if (isPresent) {
710
+ final.value[key] = void 0;
711
+ }
712
+ } else {
713
+ final.value[key] = result.value;
714
+ }
715
+ }
716
+ function normalizeDef(def) {
717
+ const keys = Object.keys(def.shape);
718
+ for (const k of keys) {
719
+ if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) {
720
+ throw new Error(`Invalid element at key "${k}": expected a Zod schema`);
721
+ }
722
+ }
723
+ const okeys = optionalKeys(def.shape);
724
+ return {
725
+ ...def,
726
+ keys,
727
+ keySet: new Set(keys),
728
+ numKeys: keys.length,
729
+ optionalKeys: new Set(okeys)
730
+ };
731
+ }
732
+ function handleCatchall(proms, input, payload, ctx, def, inst) {
733
+ const unrecognized = [];
734
+ const keySet = def.keySet;
735
+ const _catchall = def.catchall._zod;
736
+ const t = _catchall.def.type;
737
+ const isOptionalIn = _catchall.optin === "optional";
738
+ const isOptionalOut = _catchall.optout === "optional";
739
+ for (const key in input) {
740
+ if (key === "__proto__")
741
+ continue;
742
+ if (keySet.has(key))
743
+ continue;
744
+ if (t === "never") {
745
+ unrecognized.push(key);
746
+ continue;
747
+ }
748
+ const r = _catchall.run({ value: input[key], issues: [] }, ctx);
749
+ if (r instanceof Promise) {
750
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut)));
751
+ } else {
752
+ handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
753
+ }
754
+ }
755
+ if (unrecognized.length) {
756
+ payload.issues.push({
757
+ code: "unrecognized_keys",
758
+ keys: unrecognized,
759
+ input,
760
+ inst
761
+ });
762
+ }
763
+ if (!proms.length)
764
+ return payload;
765
+ return Promise.all(proms).then(() => {
766
+ return payload;
767
+ });
768
+ }
769
+ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
770
+ $ZodType.init(inst, def);
771
+ const desc = Object.getOwnPropertyDescriptor(def, "shape");
772
+ if (!desc?.get) {
773
+ const sh = def.shape;
774
+ Object.defineProperty(def, "shape", {
775
+ get: () => {
776
+ const newSh = { ...sh };
777
+ Object.defineProperty(def, "shape", {
778
+ value: newSh
779
+ });
780
+ return newSh;
781
+ }
782
+ });
783
+ }
784
+ const _normalized = cached(() => normalizeDef(def));
785
+ defineLazy(inst._zod, "propValues", () => {
786
+ const shape = def.shape;
787
+ const propValues = {};
788
+ for (const key in shape) {
789
+ const field2 = shape[key]._zod;
790
+ if (field2.values) {
791
+ propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
792
+ for (const v of field2.values)
793
+ propValues[key].add(v);
794
+ }
795
+ }
796
+ return propValues;
797
+ });
798
+ const isObject2 = isObject;
799
+ const catchall = def.catchall;
800
+ let value;
801
+ inst._zod.parse = (payload, ctx) => {
802
+ value ?? (value = _normalized.value);
803
+ const input = payload.value;
804
+ if (!isObject2(input)) {
805
+ payload.issues.push({
806
+ expected: "object",
807
+ code: "invalid_type",
808
+ input,
809
+ inst
810
+ });
811
+ return payload;
812
+ }
813
+ payload.value = {};
814
+ const proms = [];
815
+ const shape = value.shape;
816
+ for (const key of value.keys) {
817
+ const el = shape[key];
818
+ const isOptionalIn = el._zod.optin === "optional";
819
+ const isOptionalOut = el._zod.optout === "optional";
820
+ const r = el._zod.run({ value: input[key], issues: [] }, ctx);
821
+ if (r instanceof Promise) {
822
+ proms.push(r.then((r2) => handlePropertyResult(r2, payload, key, input, isOptionalIn, isOptionalOut)));
823
+ } else {
824
+ handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
825
+ }
826
+ }
827
+ if (!catchall) {
828
+ return proms.length ? Promise.all(proms).then(() => payload) : payload;
829
+ }
830
+ return handleCatchall(proms, input, payload, ctx, _normalized.value, inst);
831
+ };
832
+ });
833
+ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
834
+ $ZodType.init(inst, def);
835
+ inst._zod.parse = (payload, ctx) => {
836
+ const input = payload.value;
837
+ if (!isPlainObject(input)) {
838
+ payload.issues.push({
839
+ expected: "record",
840
+ code: "invalid_type",
841
+ input,
842
+ inst
843
+ });
844
+ return payload;
845
+ }
846
+ const proms = [];
847
+ const values = def.keyType._zod.values;
848
+ if (values) {
849
+ payload.value = {};
850
+ const recordKeys = /* @__PURE__ */ new Set();
851
+ for (const key of values) {
852
+ if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
853
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
854
+ const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
855
+ if (keyResult instanceof Promise) {
856
+ throw new Error("Async schemas not supported in object keys currently");
857
+ }
858
+ if (keyResult.issues.length) {
859
+ payload.issues.push({
860
+ code: "invalid_key",
861
+ origin: "record",
862
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
863
+ input: key,
864
+ path: [key],
865
+ inst
866
+ });
867
+ continue;
868
+ }
869
+ const outKey = keyResult.value;
870
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
871
+ if (result instanceof Promise) {
872
+ proms.push(result.then((result2) => {
873
+ if (result2.issues.length) {
874
+ payload.issues.push(...prefixIssues(key, result2.issues));
875
+ }
876
+ payload.value[outKey] = result2.value;
877
+ }));
878
+ } else {
879
+ if (result.issues.length) {
880
+ payload.issues.push(...prefixIssues(key, result.issues));
881
+ }
882
+ payload.value[outKey] = result.value;
883
+ }
884
+ }
885
+ }
886
+ let unrecognized;
887
+ for (const key in input) {
888
+ if (!recordKeys.has(key)) {
889
+ unrecognized = unrecognized ?? [];
890
+ unrecognized.push(key);
891
+ }
892
+ }
893
+ if (unrecognized && unrecognized.length > 0) {
894
+ payload.issues.push({
895
+ code: "unrecognized_keys",
896
+ input,
897
+ inst,
898
+ keys: unrecognized
899
+ });
900
+ }
901
+ } else {
902
+ payload.value = {};
903
+ for (const key of Reflect.ownKeys(input)) {
904
+ if (key === "__proto__")
905
+ continue;
906
+ if (!Object.prototype.propertyIsEnumerable.call(input, key))
907
+ continue;
908
+ let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
909
+ if (keyResult instanceof Promise) {
910
+ throw new Error("Async schemas not supported in object keys currently");
911
+ }
912
+ const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
913
+ if (checkNumericKey) {
914
+ const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
915
+ if (retryResult instanceof Promise) {
916
+ throw new Error("Async schemas not supported in object keys currently");
917
+ }
918
+ if (retryResult.issues.length === 0) {
919
+ keyResult = retryResult;
920
+ }
921
+ }
922
+ if (keyResult.issues.length) {
923
+ if (def.mode === "loose") {
924
+ payload.value[key] = input[key];
925
+ } else {
926
+ payload.issues.push({
927
+ code: "invalid_key",
928
+ origin: "record",
929
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
930
+ input: key,
931
+ path: [key],
932
+ inst
933
+ });
934
+ }
935
+ continue;
936
+ }
937
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
938
+ if (result instanceof Promise) {
939
+ proms.push(result.then((result2) => {
940
+ if (result2.issues.length) {
941
+ payload.issues.push(...prefixIssues(key, result2.issues));
942
+ }
943
+ payload.value[keyResult.value] = result2.value;
944
+ }));
945
+ } else {
946
+ if (result.issues.length) {
947
+ payload.issues.push(...prefixIssues(key, result.issues));
948
+ }
949
+ payload.value[keyResult.value] = result.value;
950
+ }
951
+ }
952
+ }
953
+ if (proms.length) {
954
+ return Promise.all(proms).then(() => payload);
955
+ }
956
+ return payload;
957
+ };
958
+ });
959
+ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
960
+ $ZodType.init(inst, def);
961
+ const values = getEnumValues(def.entries);
962
+ const valuesSet = new Set(values);
963
+ inst._zod.values = valuesSet;
964
+ inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`);
965
+ inst._zod.parse = (payload, _ctx) => {
966
+ const input = payload.value;
967
+ if (valuesSet.has(input)) {
968
+ return payload;
969
+ }
970
+ payload.issues.push({
971
+ code: "invalid_value",
972
+ values,
973
+ input,
974
+ inst
975
+ });
976
+ return payload;
977
+ };
978
+ });
979
+ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
980
+ $ZodType.init(inst, def);
981
+ if (def.values.length === 0) {
982
+ throw new Error("Cannot create literal schema with no valid values");
983
+ }
984
+ const values = new Set(def.values);
985
+ inst._zod.values = values;
986
+ inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
987
+ inst._zod.parse = (payload, _ctx) => {
988
+ const input = payload.value;
989
+ if (values.has(input)) {
990
+ return payload;
991
+ }
992
+ payload.issues.push({
993
+ code: "invalid_value",
994
+ values: def.values,
995
+ input,
996
+ inst
997
+ });
998
+ return payload;
999
+ };
1000
+ });
1001
+ function handleOptionalResult(result, input) {
1002
+ if (input === void 0 && (result.issues.length || result.fallback)) {
1003
+ return { issues: [], value: void 0 };
1004
+ }
1005
+ return result;
1006
+ }
1007
+ var $ZodOptional = /* @__PURE__ */ $constructor("$ZodOptional", (inst, def) => {
1008
+ $ZodType.init(inst, def);
1009
+ inst._zod.optin = "optional";
1010
+ inst._zod.optout = "optional";
1011
+ defineLazy(inst._zod, "values", () => {
1012
+ return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0;
1013
+ });
1014
+ defineLazy(inst._zod, "pattern", () => {
1015
+ const pattern = def.innerType._zod.pattern;
1016
+ return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0;
1017
+ });
1018
+ inst._zod.parse = (payload, ctx) => {
1019
+ if (def.innerType._zod.optin === "optional") {
1020
+ const input = payload.value;
1021
+ const result = def.innerType._zod.run(payload, ctx);
1022
+ if (result instanceof Promise)
1023
+ return result.then((r) => handleOptionalResult(r, input));
1024
+ return handleOptionalResult(result, input);
1025
+ }
1026
+ if (payload.value === void 0) {
1027
+ return payload;
1028
+ }
1029
+ return def.innerType._zod.run(payload, ctx);
1030
+ };
1031
+ });
1032
+ var $ZodDefault = /* @__PURE__ */ $constructor("$ZodDefault", (inst, def) => {
1033
+ $ZodType.init(inst, def);
1034
+ inst._zod.optin = "optional";
1035
+ defineLazy(inst._zod, "values", () => def.innerType._zod.values);
1036
+ inst._zod.parse = (payload, ctx) => {
1037
+ if (ctx.direction === "backward") {
1038
+ return def.innerType._zod.run(payload, ctx);
1039
+ }
1040
+ if (payload.value === void 0) {
1041
+ payload.value = def.defaultValue;
1042
+ return payload;
1043
+ }
1044
+ const result = def.innerType._zod.run(payload, ctx);
1045
+ if (result instanceof Promise) {
1046
+ return result.then((result2) => handleDefaultResult(result2, def));
1047
+ }
1048
+ return handleDefaultResult(result, def);
1049
+ };
1050
+ });
1051
+ function handleDefaultResult(payload, def) {
1052
+ if (payload.value === void 0) {
1053
+ payload.value = def.defaultValue;
1054
+ }
1055
+ return payload;
1056
+ }
1057
+
1058
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js
1059
+ // @__NO_SIDE_EFFECTS__
1060
+ function _string(Class, params) {
1061
+ return new Class({
1062
+ type: "string",
1063
+ ...normalizeParams(params)
1064
+ });
1065
+ }
1066
+ // @__NO_SIDE_EFFECTS__
1067
+ function _email(Class, params) {
1068
+ return new Class({
1069
+ type: "string",
1070
+ format: "email",
1071
+ check: "string_format",
1072
+ abort: false,
1073
+ ...normalizeParams(params)
1074
+ });
1075
+ }
1076
+ // @__NO_SIDE_EFFECTS__
1077
+ function _number(Class, params) {
1078
+ return new Class({
1079
+ type: "number",
1080
+ checks: [],
1081
+ ...normalizeParams(params)
1082
+ });
1083
+ }
1084
+ // @__NO_SIDE_EFFECTS__
1085
+ function _unknown(Class) {
1086
+ return new Class({
1087
+ type: "unknown"
1088
+ });
1089
+ }
1090
+ // @__NO_SIDE_EFFECTS__
1091
+ function _gte(value, params) {
1092
+ return new $ZodCheckGreaterThan({
1093
+ check: "greater_than",
1094
+ ...normalizeParams(params),
1095
+ value,
1096
+ inclusive: true
1097
+ });
1098
+ }
1099
+ // @__NO_SIDE_EFFECTS__
1100
+ function _nonnegative(params) {
1101
+ return /* @__PURE__ */ _gte(0, params);
1102
+ }
1103
+ // @__NO_SIDE_EFFECTS__
1104
+ function _maxLength(maximum, params) {
1105
+ const ch = new $ZodCheckMaxLength({
1106
+ check: "max_length",
1107
+ ...normalizeParams(params),
1108
+ maximum
1109
+ });
1110
+ return ch;
1111
+ }
1112
+ // @__NO_SIDE_EFFECTS__
1113
+ function _minLength(minimum, params) {
1114
+ return new $ZodCheckMinLength({
1115
+ check: "min_length",
1116
+ ...normalizeParams(params),
1117
+ minimum
1118
+ });
1119
+ }
1120
+
1121
+ // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/schemas.js
1122
+ var ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
1123
+ if (!inst._zod)
1124
+ throw new Error("Uninitialized schema in ZodMiniType.");
1125
+ $ZodType.init(inst, def);
1126
+ inst.def = def;
1127
+ inst.type = def.type;
1128
+ inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse });
1129
+ inst.safeParse = (data, params) => safeParse(inst, data, params);
1130
+ inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync });
1131
+ inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params);
1132
+ inst.check = (...checks) => {
1133
+ return inst.clone({
1134
+ ...def,
1135
+ checks: [
1136
+ ...def.checks ?? [],
1137
+ ...checks.map((ch) => typeof ch === "function" ? {
1138
+ _zod: { check: ch, def: { check: "custom" }, onattach: [] }
1139
+ } : ch)
1140
+ ]
1141
+ }, { parent: true });
1142
+ };
1143
+ inst.with = inst.check;
1144
+ inst.clone = (_def, params) => clone(inst, _def, params);
1145
+ inst.brand = () => inst;
1146
+ inst.register = ((reg, meta2) => {
1147
+ reg.add(inst, meta2);
1148
+ return inst;
1149
+ });
1150
+ inst.apply = (fn) => fn(inst);
1151
+ });
1152
+ var ZodMiniString = /* @__PURE__ */ $constructor("ZodMiniString", (inst, def) => {
1153
+ $ZodString.init(inst, def);
1154
+ ZodMiniType.init(inst, def);
1155
+ });
1156
+ // @__NO_SIDE_EFFECTS__
1157
+ function string2(params) {
1158
+ return _string(ZodMiniString, params);
1159
+ }
1160
+ var ZodMiniStringFormat = /* @__PURE__ */ $constructor("ZodMiniStringFormat", (inst, def) => {
1161
+ $ZodStringFormat.init(inst, def);
1162
+ ZodMiniString.init(inst, def);
1163
+ });
1164
+ var ZodMiniEmail = /* @__PURE__ */ $constructor("ZodMiniEmail", (inst, def) => {
1165
+ $ZodEmail.init(inst, def);
1166
+ ZodMiniStringFormat.init(inst, def);
1167
+ });
1168
+ // @__NO_SIDE_EFFECTS__
1169
+ function email2(params) {
1170
+ return _email(ZodMiniEmail, params);
1171
+ }
1172
+ var ZodMiniNumber = /* @__PURE__ */ $constructor("ZodMiniNumber", (inst, def) => {
1173
+ $ZodNumber.init(inst, def);
1174
+ ZodMiniType.init(inst, def);
1175
+ });
1176
+ // @__NO_SIDE_EFFECTS__
1177
+ function number2(params) {
1178
+ return _number(ZodMiniNumber, params);
1179
+ }
1180
+ var ZodMiniUnknown = /* @__PURE__ */ $constructor("ZodMiniUnknown", (inst, def) => {
1181
+ $ZodUnknown.init(inst, def);
1182
+ ZodMiniType.init(inst, def);
1183
+ });
1184
+ // @__NO_SIDE_EFFECTS__
1185
+ function unknown() {
1186
+ return _unknown(ZodMiniUnknown);
1187
+ }
1188
+ var ZodMiniArray = /* @__PURE__ */ $constructor("ZodMiniArray", (inst, def) => {
1189
+ $ZodArray.init(inst, def);
1190
+ ZodMiniType.init(inst, def);
1191
+ });
1192
+ // @__NO_SIDE_EFFECTS__
1193
+ function array(element, params) {
1194
+ return new ZodMiniArray({
1195
+ type: "array",
1196
+ element,
1197
+ ...normalizeParams(params)
1198
+ });
1199
+ }
1200
+ var ZodMiniObject = /* @__PURE__ */ $constructor("ZodMiniObject", (inst, def) => {
1201
+ $ZodObject.init(inst, def);
1202
+ ZodMiniType.init(inst, def);
1203
+ defineLazy(inst, "shape", () => def.shape);
1204
+ });
1205
+ // @__NO_SIDE_EFFECTS__
1206
+ function object(shape, params) {
1207
+ const def = {
1208
+ type: "object",
1209
+ shape: shape ?? {},
1210
+ ...normalizeParams(params)
1211
+ };
1212
+ return new ZodMiniObject(def);
1213
+ }
1214
+ // @__NO_SIDE_EFFECTS__
1215
+ function looseObject(shape, params) {
1216
+ return new ZodMiniObject({
1217
+ type: "object",
1218
+ shape,
1219
+ catchall: /* @__PURE__ */ unknown(),
1220
+ ...normalizeParams(params)
1221
+ });
1222
+ }
1223
+ var ZodMiniRecord = /* @__PURE__ */ $constructor("ZodMiniRecord", (inst, def) => {
1224
+ $ZodRecord.init(inst, def);
1225
+ ZodMiniType.init(inst, def);
1226
+ });
1227
+ // @__NO_SIDE_EFFECTS__
1228
+ function record(keyType, valueType, params) {
1229
+ if (!valueType || !valueType._zod) {
1230
+ return new ZodMiniRecord({
1231
+ type: "record",
1232
+ keyType: /* @__PURE__ */ string2(),
1233
+ valueType: keyType,
1234
+ ...normalizeParams(valueType)
1235
+ });
1236
+ }
1237
+ return new ZodMiniRecord({
1238
+ type: "record",
1239
+ keyType,
1240
+ valueType,
1241
+ ...normalizeParams(params)
1242
+ });
1243
+ }
1244
+ var ZodMiniEnum = /* @__PURE__ */ $constructor("ZodMiniEnum", (inst, def) => {
1245
+ $ZodEnum.init(inst, def);
1246
+ ZodMiniType.init(inst, def);
1247
+ inst.options = Object.values(def.entries);
1248
+ });
1249
+ // @__NO_SIDE_EFFECTS__
1250
+ function _enum(values, params) {
1251
+ const entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
1252
+ return new ZodMiniEnum({
1253
+ type: "enum",
1254
+ entries,
1255
+ ...normalizeParams(params)
1256
+ });
1257
+ }
1258
+ var ZodMiniLiteral = /* @__PURE__ */ $constructor("ZodMiniLiteral", (inst, def) => {
1259
+ $ZodLiteral.init(inst, def);
1260
+ ZodMiniType.init(inst, def);
1261
+ });
1262
+ // @__NO_SIDE_EFFECTS__
1263
+ function literal(value, params) {
1264
+ return new ZodMiniLiteral({
1265
+ type: "literal",
1266
+ values: Array.isArray(value) ? value : [value],
1267
+ ...normalizeParams(params)
1268
+ });
1269
+ }
1270
+ var ZodMiniOptional = /* @__PURE__ */ $constructor("ZodMiniOptional", (inst, def) => {
1271
+ $ZodOptional.init(inst, def);
1272
+ ZodMiniType.init(inst, def);
1273
+ });
1274
+ // @__NO_SIDE_EFFECTS__
1275
+ function optional(innerType) {
1276
+ return new ZodMiniOptional({
1277
+ type: "optional",
1278
+ innerType
1279
+ });
1280
+ }
1281
+ var ZodMiniDefault = /* @__PURE__ */ $constructor("ZodMiniDefault", (inst, def) => {
1282
+ $ZodDefault.init(inst, def);
1283
+ ZodMiniType.init(inst, def);
1284
+ });
1285
+ // @__NO_SIDE_EFFECTS__
1286
+ function _default(innerType, defaultValue) {
1287
+ return new ZodMiniDefault({
1288
+ type: "default",
1289
+ innerType,
1290
+ get defaultValue() {
1291
+ return typeof defaultValue === "function" ? defaultValue() : shallowClone(defaultValue);
1292
+ }
1293
+ });
1294
+ }
1295
+
1296
+ // ../core/dist/index.js
1297
+ var C = (iso2, name, dialCode, lengths = [], groups = [], example = "") => ({ iso2, name, dialCode, lengths, groups, example });
1298
+ var PHONE_COUNTRIES = [
1299
+ C("US", "United States", "1", [10], [3, 3, 4], "2015550123"),
1300
+ C("CA", "Canada", "1", [10], [3, 3, 4], "5145550123"),
1301
+ C("GB", "United Kingdom", "44", [10], [4, 6], "7400123456"),
1302
+ C("AU", "Australia", "61", [9], [3, 3, 3], "412345678"),
1303
+ C("DE", "Germany", "49", [10, 11], [4, 7], "15123456789"),
1304
+ C("FR", "France", "33", [9], [1, 2, 2, 2, 2], "612345678"),
1305
+ C("IN", "India", "91", [10], [5, 5], "8123456789"),
1306
+ C("DK", "Denmark", "45", [8], [2, 2, 2, 2], "32123456"),
1307
+ C("SE", "Sweden", "46", [9], [2, 3, 4], "701234567"),
1308
+ C("NO", "Norway", "47", [8], [3, 2, 3], "40612345"),
1309
+ C("FI", "Finland", "358", [9, 10], [2, 3, 4], "412345678"),
1310
+ C("NL", "Netherlands", "31", [9], [1, 4, 4], "612345678"),
1311
+ C("BE", "Belgium", "32", [9], [3, 2, 2, 2], "470123456"),
1312
+ C("ES", "Spain", "34", [9], [3, 3, 3], "612345678"),
1313
+ C("IT", "Italy", "39", [9, 10], [3, 3, 4], "3123456789"),
1314
+ C("PT", "Portugal", "351", [9], [3, 3, 3], "912345678"),
1315
+ C("IE", "Ireland", "353", [9], [2, 3, 4], "851234567"),
1316
+ C("CH", "Switzerland", "41", [9], [2, 3, 2, 2], "781234567"),
1317
+ C("AT", "Austria", "43", [10, 11], [3, 7], "6641234567"),
1318
+ C("PL", "Poland", "48", [9], [3, 3, 3], "512345678"),
1319
+ C("CZ", "Czechia", "420", [9], [3, 3, 3], "601123456"),
1320
+ C("GR", "Greece", "30", [10], [3, 3, 4], "6912345678"),
1321
+ C("RO", "Romania", "40", [9], [3, 3, 3], "712345678"),
1322
+ C("HU", "Hungary", "36", [9], [2, 3, 4], "201234567"),
1323
+ C("UA", "Ukraine", "380", [9], [2, 3, 2, 2], "501234567"),
1324
+ C("RU", "Russia", "7", [10], [3, 3, 2, 2], "9123456789"),
1325
+ C("TR", "Turkey", "90", [10], [3, 3, 2, 2], "5012345678"),
1326
+ C("IL", "Israel", "972", [9], [2, 3, 4], "501234567"),
1327
+ C("AE", "United Arab Emirates", "971", [9], [2, 3, 4], "501234567"),
1328
+ C("SA", "Saudi Arabia", "966", [9], [2, 3, 4], "512345678"),
1329
+ C("ZA", "South Africa", "27", [9], [2, 3, 4], "711234567"),
1330
+ C("NG", "Nigeria", "234", [10], [3, 3, 4], "8021234567"),
1331
+ C("KE", "Kenya", "254", [9], [3, 3, 3], "712123456"),
1332
+ C("EG", "Egypt", "20", [10], [3, 3, 4], "1001234567"),
1333
+ C("BR", "Brazil", "55", [10, 11], [2, 5, 4], "11961234567"),
1334
+ C("MX", "Mexico", "52", [10], [3, 3, 4], "2221234567"),
1335
+ C("AR", "Argentina", "54", [10], [4, 6], "1123456789"),
1336
+ C("CL", "Chile", "56", [9], [1, 4, 4], "221234567"),
1337
+ C("CO", "Colombia", "57", [10], [3, 3, 4], "3211234567"),
1338
+ C("PE", "Peru", "51", [9], [3, 3, 3], "912345678"),
1339
+ C("CN", "China", "86", [11], [3, 4, 4], "13123456789"),
1340
+ C("JP", "Japan", "81", [10], [2, 4, 4], "9012345678"),
1341
+ C("KR", "South Korea", "82", [9, 10], [2, 4, 4], "1023456789"),
1342
+ C("SG", "Singapore", "65", [8], [4, 4], "81234567"),
1343
+ C("HK", "Hong Kong", "852", [8], [4, 4], "51234567"),
1344
+ C("TW", "Taiwan", "886", [9], [3, 3, 3], "912345678"),
1345
+ C("MY", "Malaysia", "60", [9, 10], [2, 3, 4], "123456789"),
1346
+ C("ID", "Indonesia", "62", [10, 11], [3, 4, 4], "81234567890"),
1347
+ C("TH", "Thailand", "66", [9], [2, 3, 4], "812345678"),
1348
+ C("PH", "Philippines", "63", [10], [3, 3, 4], "9171234567"),
1349
+ C("VN", "Vietnam", "84", [9], [3, 3, 3], "912345678"),
1350
+ C("PK", "Pakistan", "92", [10], [3, 3, 4], "3012345678"),
1351
+ C("BD", "Bangladesh", "880", [10], [2, 4, 4], "1812345678"),
1352
+ C("NZ", "New Zealand", "64", [9, 10], [2, 3, 4], "211234567"),
1353
+ C("SK", "Slovakia", "421", [9], [3, 3, 3], "912123456"),
1354
+ C("BG", "Bulgaria", "359", [9], [2, 3, 4], "481234567"),
1355
+ C("HR", "Croatia", "385", [8, 9], [2, 3, 4], "921234567"),
1356
+ C("RS", "Serbia", "381", [8, 9], [2, 3, 4], "601234567"),
1357
+ C("SI", "Slovenia", "386", [8], [2, 3, 3], "31234567"),
1358
+ C("LT", "Lithuania", "370", [8], [3, 2, 3], "61234567"),
1359
+ C("LV", "Latvia", "371", [8], [2, 3, 3], "21234567"),
1360
+ C("EE", "Estonia", "372", [7, 8], [3, 4], "51234567"),
1361
+ C("IS", "Iceland", "354", [7], [3, 4], "6111234"),
1362
+ C("LU", "Luxembourg", "352", [9], [3, 3, 3], "628123456"),
1363
+ C("MA", "Morocco", "212", [9], [3, 3, 3], "650123456"),
1364
+ C("CR", "Costa Rica", "506", [8], [4, 4], "83123456"),
1365
+ C("EC", "Ecuador", "593", [9], [2, 3, 4], "991234567"),
1366
+ C("UY", "Uruguay", "598", [8], [1, 3, 4], "94231234"),
1367
+ C("QA", "Qatar", "974", [8], [4, 4], "33123456"),
1368
+ C("KW", "Kuwait", "965", [8], [4, 4], "50012345")
1369
+ ];
1370
+ var byIso = new Map(PHONE_COUNTRIES.map((c) => [c.iso2, c]));
1371
+ var fileValueSchema = object({
1372
+ fileId: string2().check(_minLength(1)),
1373
+ name: string2(),
1374
+ size: number2().check(_nonnegative()),
1375
+ mime: string2(),
1376
+ url: optional(string2())
1377
+ });
1378
+ var FIELD_KINDS = [
1379
+ "short_text",
1380
+ "long_text",
1381
+ "email",
1382
+ "url",
1383
+ "phone",
1384
+ "number",
1385
+ "select",
1386
+ "multi_select",
1387
+ "dropdown",
1388
+ "checkbox",
1389
+ "rating",
1390
+ "linear_scale",
1391
+ "ranking",
1392
+ "matrix",
1393
+ "signature",
1394
+ "date",
1395
+ "file_upload",
1396
+ "hidden",
1397
+ "custom"
1398
+ ];
1399
+ var CONTENT_KINDS2 = ["heading", "paragraph", "divider"];
1400
+ var ALL_KINDS = [...FIELD_KINDS, ...CONTENT_KINDS2];
1401
+ var idSchema = string2().check(_minLength(1), _maxLength(128));
1402
+ var optionSchema = looseObject({
1403
+ id: idSchema,
1404
+ label: string2().check(_maxLength(1e3)),
1405
+ icon: optional(unknown())
1406
+ });
1407
+ var blockSchema = looseObject({
1408
+ id: idSchema,
1409
+ kind: _enum(ALL_KINDS),
1410
+ label: optional(string2().check(_maxLength(2e3))),
1411
+ options: optional(array(optionSchema).check(_maxLength(200))),
1412
+ rows: optional(array(optionSchema).check(_maxLength(200))),
1413
+ columns: optional(array(optionSchema).check(_maxLength(200)))
1414
+ });
1415
+ var pageSchema = object({
1416
+ id: idSchema,
1417
+ title: optional(string2().check(_maxLength(500))),
1418
+ blocks: array(blockSchema).check(_maxLength(500))
1419
+ });
1420
+ var schemaShape = object({
1421
+ version: literal(1),
1422
+ title: _default(optional(string2().check(_maxLength(2e3))), ""),
1423
+ description: optional(string2().check(_maxLength(5e3))),
1424
+ pages: array(pageSchema).check(_minLength(1), _maxLength(50)),
1425
+ settings: _default(optional(record(string2(), unknown())), {})
1426
+ });
1427
+ var MAX_SCHEMA_VERSION = 1;
1428
+ var FILLO_SCHEMA_VERSION = 1;
1429
+ var FILLO_SDK_VERSION = true ? "0.8.0" : "0.0.0-dev";
1430
+ function str(value, max, fallback = "") {
1431
+ return typeof value === "string" ? value.trim().slice(0, max) : fallback;
1432
+ }
1433
+ function optionalStr(value, max) {
1434
+ const s = str(value, max);
1435
+ return s === "" ? void 0 : s;
1436
+ }
1437
+ function bool(value) {
1438
+ return typeof value === "boolean" ? value : void 0;
1439
+ }
1440
+ function finite(value) {
1441
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1442
+ }
1443
+ function int(value, min, max, fallback) {
1444
+ const n = finite(value);
1445
+ if (n === void 0) return fallback;
1446
+ return Math.max(min, Math.min(max, Math.round(n)));
1447
+ }
1448
+ function options(value, max = 200) {
1449
+ if (!Array.isArray(value)) return [];
1450
+ return value.slice(0, max).flatMap((item) => {
1451
+ if (!item || typeof item !== "object") return [];
1452
+ const rec = item;
1453
+ const id = str(rec.id, 128);
1454
+ const label = str(rec.label, 1e3);
1455
+ const icon = rec.icon === "thumbs_up" || rec.icon === "thumbs_down" ? rec.icon : void 0;
1456
+ return id && label ? [cleanObject({ id, label, icon })] : [];
1457
+ });
1458
+ }
1459
+ function duplicateOptionId(items) {
1460
+ const ids = /* @__PURE__ */ new Set();
1461
+ for (const { id } of items) {
1462
+ if (ids.has(id)) return id;
1463
+ ids.add(id);
1464
+ }
1465
+ return void 0;
1466
+ }
1467
+ function conditions(value) {
1468
+ if (!Array.isArray(value)) return void 0;
1469
+ const normalized = value.slice(0, 20).flatMap((item) => {
1470
+ if (!item || typeof item !== "object") return [];
1471
+ const rec = item;
1472
+ const op = rec.op;
1473
+ if (op !== "eq" && op !== "neq" && op !== "contains" && op !== "gt" && op !== "lt" && op !== "answered" && op !== "not_answered") {
1474
+ return [];
1475
+ }
1476
+ const fieldId = str(rec.fieldId, 128);
1477
+ if (!fieldId) return [];
1478
+ const raw = rec.value;
1479
+ const value2 = typeof raw === "string" || typeof raw === "number" || typeof raw === "boolean" ? raw : void 0;
1480
+ return [{ fieldId, op, ...value2 !== void 0 ? { value: value2 } : {} }];
1481
+ });
1482
+ return normalized.length ? normalized : void 0;
1483
+ }
1484
+ function baseBlock(rec) {
1485
+ return {
1486
+ id: str(rec.id, 128),
1487
+ visibleIf: conditions(rec.visibleIf)
1488
+ };
1489
+ }
1490
+ function baseField(rec, kind) {
1491
+ const base = baseBlock(rec);
1492
+ return {
1493
+ ...base,
1494
+ kind,
1495
+ label: str(rec.label, 2e3, "Untitled field"),
1496
+ description: optionalStr(rec.description, 5e3),
1497
+ required: bool(rec.required),
1498
+ placeholder: optionalStr(rec.placeholder, 500)
1499
+ };
1500
+ }
1501
+ function normalizeUrl(value) {
1502
+ const raw = optionalStr(value, 2e3);
1503
+ if (!raw) return void 0;
1504
+ try {
1505
+ const url = new URL(raw);
1506
+ return url.protocol === "http:" || url.protocol === "https:" ? raw : void 0;
1507
+ } catch {
1508
+ return void 0;
1509
+ }
1510
+ }
1511
+ function normalizeResponseLimit(value) {
1512
+ if (!value || typeof value !== "object") return void 0;
1513
+ const rec = value;
1514
+ const by = rec.by === "browser" || rec.by === "field" || rec.by === "identify" ? rec.by : void 0;
1515
+ if (!by) return void 0;
1516
+ const field2 = by === "field" ? optionalStr(rec.field, 128) : void 0;
1517
+ if (by === "field" && !field2) return void 0;
1518
+ const scopeField = optionalStr(rec.scopeField, 128);
1519
+ const onRepeat = rec.onRepeat === "update" && by === "identify" ? "update" : "keep";
1520
+ return {
1521
+ by,
1522
+ ...field2 ? { field: field2 } : {},
1523
+ ...scopeField ? { scopeField } : {},
1524
+ onRepeat
1525
+ };
1526
+ }
1527
+ function normalizeSettings(value) {
1528
+ const rec = value && typeof value === "object" ? value : {};
1529
+ const submitMode = rec.submitMode === "button" || rec.submitMode === "auto" ? rec.submitMode : void 0;
1530
+ return {
1531
+ submitMode,
1532
+ submitLabel: optionalStr(rec.submitLabel, 100),
1533
+ successTitle: optionalStr(rec.successTitle, 200),
1534
+ successMessage: optionalStr(rec.successMessage, 5e3),
1535
+ redirectUrl: normalizeUrl(rec.redirectUrl),
1536
+ showProgress: bool(rec.showProgress),
1537
+ responseLimit: normalizeResponseLimit(rec.responseLimit),
1538
+ notifyEmail: email2().check(_maxLength(254)).safeParse(rec.notifyEmail).success ? rec.notifyEmail : void 0,
1539
+ sendReceipt: bool(rec.sendReceipt),
1540
+ saveProgress: bool(rec.saveProgress),
1541
+ draftAnswersVisible: bool(rec.draftAnswersVisible),
1542
+ resumeEmails: bool(rec.resumeEmails),
1543
+ resumeUrl: normalizeUrl(rec.resumeUrl),
1544
+ draftDigest: bool(rec.draftDigest)
1545
+ };
1546
+ }
1547
+ function cleanObject(obj) {
1548
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== void 0));
1549
+ }
1550
+ function normalizeBlock(input) {
1551
+ if (!input || typeof input !== "object") return null;
1552
+ const rec = input;
1553
+ const kind = rec.kind;
1554
+ const base = baseBlock(rec);
1555
+ if (!base.id || typeof kind !== "string") return null;
1556
+ switch (kind) {
1557
+ case "heading":
1558
+ return cleanObject({ ...base, kind, text: str(rec.text, 2e3, "Section") });
1559
+ case "paragraph":
1560
+ return cleanObject({ ...base, kind, text: str(rec.text, 5e3) });
1561
+ case "divider":
1562
+ return cleanObject({ ...base, kind });
1563
+ case "short_text":
1564
+ case "email":
1565
+ case "url":
1566
+ return cleanObject({
1567
+ ...baseField(rec, kind),
1568
+ maxLength: finite(rec.maxLength) === void 0 ? void 0 : int(rec.maxLength, 1, 2e3, 2e3)
1569
+ });
1570
+ case "phone": {
1571
+ const cc = optionalStr(rec.defaultCountry, 2)?.toUpperCase();
1572
+ return cleanObject({
1573
+ ...baseField(rec, kind),
1574
+ defaultCountry: cc && /^[A-Z]{2}$/.test(cc) ? cc : void 0
1575
+ });
1576
+ }
1577
+ case "long_text":
1578
+ return cleanObject({
1579
+ ...baseField(rec, kind),
1580
+ maxLength: finite(rec.maxLength) === void 0 ? void 0 : int(rec.maxLength, 1, 2e4, 2e4)
1581
+ });
1582
+ case "number":
1583
+ return cleanObject({ ...baseField(rec, kind), min: finite(rec.min), max: finite(rec.max) });
1584
+ case "select":
1585
+ case "multi_select":
1586
+ case "dropdown": {
1587
+ const opts = options(rec.options);
1588
+ if (opts.length === 0) return null;
1589
+ return cleanObject({
1590
+ ...baseField(rec, kind),
1591
+ options: opts,
1592
+ allowOther: bool(rec.allowOther),
1593
+ shuffleOptions: bool(rec.shuffleOptions)
1594
+ });
1595
+ }
1596
+ case "checkbox": {
1597
+ const appearance = rec.appearance === "toggle" ? "toggle" : void 0;
1598
+ return cleanObject({
1599
+ ...baseField(rec, kind),
1600
+ appearance
1601
+ });
1602
+ }
1603
+ case "signature":
1604
+ case "date":
1605
+ return cleanObject(baseField(rec, kind));
1606
+ case "rating": {
1607
+ const max = int(rec.max, 1, 10, 5);
1608
+ return cleanObject({
1609
+ ...baseField(rec, kind),
1610
+ max,
1611
+ insightsMetric: rec.insightsMetric === "csat" && max === 5 ? "csat" : void 0
1612
+ });
1613
+ }
1614
+ case "linear_scale": {
1615
+ const min = int(rec.min, 0, 9, 1);
1616
+ const max = int(rec.max, min + 1, 10, 10);
1617
+ const insightsMetric = rec.insightsMetric === "nps" && min === 0 && max === 10 ? "nps" : rec.insightsMetric === "csat" && min === 1 && max === 5 ? "csat" : void 0;
1618
+ return cleanObject({
1619
+ ...baseField(rec, kind),
1620
+ min,
1621
+ max,
1622
+ minLabel: optionalStr(rec.minLabel, 100),
1623
+ maxLabel: optionalStr(rec.maxLabel, 100),
1624
+ insightsMetric
1625
+ });
1626
+ }
1627
+ case "ranking": {
1628
+ const opts = options(rec.options);
1629
+ if (opts.length < 2) return null;
1630
+ return cleanObject({ ...baseField(rec, kind), options: opts });
1631
+ }
1632
+ case "matrix": {
1633
+ const rows = options(rec.rows);
1634
+ const columns = options(rec.columns);
1635
+ if (rows.length === 0 || columns.length === 0) return null;
1636
+ return cleanObject({ ...baseField(rec, kind), rows, columns });
1637
+ }
1638
+ case "hidden":
1639
+ return cleanObject({
1640
+ ...baseField(rec, kind),
1641
+ // Hidden fields render nothing, so a required one with no matching URL
1642
+ // param / default would be permanently unsubmittable — never required.
1643
+ required: false,
1644
+ paramName: optionalStr(rec.paramName, 128),
1645
+ defaultValue: optionalStr(rec.defaultValue, 1e3)
1646
+ });
1647
+ case "file_upload":
1648
+ return cleanObject({
1649
+ ...baseField(rec, kind),
1650
+ maxFiles: int(rec.maxFiles, 1, 20, 1),
1651
+ maxFileSizeMb: int(rec.maxFileSizeMb, 1, 5e3, 500),
1652
+ accept: Array.isArray(rec.accept) ? rec.accept.flatMap((v) => {
1653
+ const item = optionalStr(v, 100);
1654
+ return item ? [item] : [];
1655
+ }).slice(0, 50) : void 0
1656
+ });
1657
+ case "custom":
1658
+ return cleanObject({
1659
+ ...baseField(rec, kind),
1660
+ component: str(rec.component, 128),
1661
+ config: rec.config && typeof rec.config === "object" && !Array.isArray(rec.config) ? rec.config : void 0
1662
+ });
1663
+ default:
1664
+ return null;
1665
+ }
1666
+ }
1667
+ function normalizeFormSchema(input) {
1668
+ const parsed = schemaShape.safeParse(input);
1669
+ if (!parsed.success) {
1670
+ const first = parsed.error.issues[0];
1671
+ const path = first?.path.join(".");
1672
+ return { ok: false, error: first ? `${path ? `${path}: ` : ""}${first.message}` : "Invalid schema" };
1673
+ }
1674
+ if (parsed.data.version > MAX_SCHEMA_VERSION) {
1675
+ return { ok: false, error: `Unsupported schema version: ${parsed.data.version}` };
1676
+ }
1677
+ const pages = parsed.data.pages.map((page) => {
1678
+ const blocks = page.blocks.flatMap((raw) => {
1679
+ const block = normalizeBlock(raw);
1680
+ return block ? [block] : [];
1681
+ });
1682
+ return cleanObject({
1683
+ id: str(page.id, 128),
1684
+ title: optionalStr(page.title, 500),
1685
+ blocks
1686
+ });
1687
+ });
1688
+ const pageIds = /* @__PURE__ */ new Set();
1689
+ const seen = /* @__PURE__ */ new Set();
1690
+ for (const page of pages) {
1691
+ if (!page.id) return { ok: false, error: "Page ids cannot be blank" };
1692
+ if (pageIds.has(page.id)) return { ok: false, error: `Duplicate page id: ${page.id}` };
1693
+ pageIds.add(page.id);
1694
+ for (const block of page.blocks) {
1695
+ if (seen.has(block.id)) return { ok: false, error: `Duplicate block id: ${block.id}` };
1696
+ seen.add(block.id);
1697
+ if (block.kind === "number" && block.min !== void 0 && block.max !== void 0 && block.min > block.max) {
1698
+ return { ok: false, error: `Field ${block.id} has min greater than max` };
1699
+ }
1700
+ if (block.kind === "select" || block.kind === "multi_select" || block.kind === "dropdown" || block.kind === "ranking") {
1701
+ const duplicate = duplicateOptionId(block.options);
1702
+ if (duplicate) {
1703
+ return { ok: false, error: `Duplicate option id in field ${block.id}: ${duplicate}` };
1704
+ }
1705
+ } else if (block.kind === "matrix") {
1706
+ const duplicateRow = duplicateOptionId(block.rows);
1707
+ if (duplicateRow) {
1708
+ return { ok: false, error: `Duplicate matrix row id in field ${block.id}: ${duplicateRow}` };
1709
+ }
1710
+ const duplicateColumn = duplicateOptionId(block.columns);
1711
+ if (duplicateColumn) {
1712
+ return {
1713
+ ok: false,
1714
+ error: `Duplicate matrix column id in field ${block.id}: ${duplicateColumn}`
1715
+ };
1716
+ }
1717
+ }
1718
+ }
1719
+ }
1720
+ if (pages.every((page) => page.blocks.length === 0)) {
1721
+ return { ok: false, error: "Schema must contain at least one valid block" };
1722
+ }
1723
+ const schema = {
1724
+ version: FILLO_SCHEMA_VERSION,
1725
+ title: str(parsed.data.title, 2e3),
1726
+ pages,
1727
+ settings: normalizeSettings(parsed.data.settings)
1728
+ };
1729
+ const description = optionalStr(parsed.data.description, 5e3);
1730
+ if (description) schema.description = description;
1731
+ return { ok: true, schema };
1732
+ }
1733
+ function validateFormSchema(input) {
1734
+ try {
1735
+ return normalizeFormSchema(input);
1736
+ } catch (err) {
1737
+ return { ok: false, error: err instanceof Error ? err.message : "Invalid schema" };
1738
+ }
1739
+ }
1740
+ var ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1741
+ var MASK = 256 - 256 % ALPHABET.length;
1742
+ var S3_PART_TIMEOUT_MS = 5 * 6e4;
1743
+ var UPLOAD_CONTROL_TIMEOUT_MS = 10 * 6e4;
1744
+ var CLIENT_HEADER = { "X-Fillo-Client": `@usefillo/core@${FILLO_SDK_VERSION}` };
1745
+ var FilloJsxError = class extends Error {
1746
+ constructor(code, message) {
1747
+ super(`[fillo] ${message} \u2014 https://fillo.so/docs/troubleshooting#jsx-${code.toLowerCase()}`);
1748
+ this.code = code;
1749
+ this.name = "FilloJsxError";
1750
+ }
1751
+ code;
1752
+ };
1753
+ var BRAND = /* @__PURE__ */ Symbol.for("fillo.block");
1754
+ var FIELD_BASE = ["label", "description", "required", "placeholder"];
1755
+ var field = (name, kind, extra, opts = {}) => ({
1756
+ name,
1757
+ kind,
1758
+ props: [...FIELD_BASE, ...extra],
1759
+ ...opts
1760
+ });
1761
+ var content = (name, kind, textChildren) => ({
1762
+ name,
1763
+ kind,
1764
+ props: textChildren ? ["text"] : [],
1765
+ textChildren,
1766
+ content: true
1767
+ });
1768
+ var CHOICE_EXTRA = ["options", "allowOther", "shuffleOptions"];
1769
+ var JSX_BLOCK_SPECS = [
1770
+ field("Text", "short_text", ["maxLength"]),
1771
+ field("LongText", "long_text", ["maxLength"]),
1772
+ field("Email", "email", ["maxLength"]),
1773
+ field("Url", "url", ["maxLength"]),
1774
+ field("Phone", "phone", ["defaultCountry"]),
1775
+ field("Number", "number", ["min", "max"]),
1776
+ field("Select", "select", CHOICE_EXTRA, { optionChildren: true }),
1777
+ field("MultiSelect", "multi_select", CHOICE_EXTRA, { optionChildren: true }),
1778
+ field("Dropdown", "dropdown", CHOICE_EXTRA, { optionChildren: true }),
1779
+ field("Checkbox", "checkbox", ["appearance"]),
1780
+ field("Rating", "rating", ["max", "insightsMetric"]),
1781
+ field("Scale", "linear_scale", ["min", "max", "minLabel", "maxLabel", "insightsMetric"]),
1782
+ field("Ranking", "ranking", ["options"], { optionChildren: true }),
1783
+ field("Matrix", "matrix", ["rows", "columns"]),
1784
+ field("Signature", "signature", []),
1785
+ field("Date", "date", []),
1786
+ field("FileUpload", "file_upload", ["maxFiles", "maxFileSizeMb", "accept"]),
1787
+ field("Hidden", "hidden", ["paramName", "defaultValue"]),
1788
+ field("Custom", "custom", ["component", "config"]),
1789
+ content("Heading", "heading", true),
1790
+ content("Paragraph", "paragraph", true),
1791
+ { name: "Divider", kind: "divider", props: [], content: true }
1792
+ ];
1793
+ var PAGE_SPEC = { name: "Page", kind: "__page", props: ["title"] };
1794
+ var OPTION_SPEC = { name: "Option", kind: "__option", props: ["label", "icon"] };
1795
+ function makeInert(spec) {
1796
+ const component = () => {
1797
+ throw new FilloJsxError(
1798
+ "RENDERED_INERT",
1799
+ `<Fillo.${spec.name}> was rendered by React. Fillo fields are schema declarations, valid only inside <Fillo.Form> or Fillo.defineForm(). If this form lives in a server component, move it to a client module ("use client")`
1800
+ );
1801
+ };
1802
+ component[BRAND] = spec;
1803
+ return component;
1804
+ }
1805
+ var JSX_BLOCK_COMPONENTS = Object.fromEntries([
1806
+ ...JSX_BLOCK_SPECS.map((spec) => [spec.name, makeInert(spec)]),
1807
+ ["Page", makeInert(PAGE_SPEC)],
1808
+ ["Option", makeInert(OPTION_SPEC)]
1809
+ ]);
1810
+
1811
+ // src/index.ts
9
1812
  var API = (process.env.FILLO_API ?? "https://fillo.so").replace(/\/$/, "");
10
1813
  var CONFIG_DIR = join(homedir(), ".fillo");
11
1814
  var CONFIG_PATH = join(CONFIG_DIR, "config.json");
12
- var bold = (s) => `\x1B[1m${s}\x1B[0m`;
13
- var dim = (s) => `\x1B[2m${s}\x1B[0m`;
1815
+ var BUNDLED_SKILL_DIR = fileURLToPath(new URL("./skill/build-with-fillo", import.meta.url));
1816
+ var REQUEST_TIMEOUT_MS = 3e4;
1817
+ var MAX_STDIN_SCHEMA_BYTES = 1024 * 1024;
1818
+ var SYNC_TOKEN_ENV = "FILLO_SYNC_TOKEN";
1819
+ function terminalText(value) {
1820
+ return value.replace(/\b(?:fcli|fsync)_[A-Za-z0-9._~-]+\b/g, "[redacted]").replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim();
1821
+ }
1822
+ var bold = (s) => `\x1B[1m${terminalText(s)}\x1B[0m`;
1823
+ var dim = (s) => `\x1B[2m${terminalText(s)}\x1B[0m`;
14
1824
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
15
1825
  function die(msg) {
16
- console.error(`\x1B[31m\u2717\x1B[0m ${msg}`);
1826
+ console.error(`\x1B[31m\u2717\x1B[0m ${terminalText(msg)}`);
17
1827
  process.exit(1);
18
1828
  }
19
1829
  function readConfig() {
20
1830
  try {
21
- return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
1831
+ const parsed = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
1832
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
1833
+ const record2 = parsed;
1834
+ return {
1835
+ ...typeof record2.token === "string" ? { token: record2.token } : {},
1836
+ ...typeof record2.tokenApi === "string" ? { tokenApi: record2.tokenApi } : {},
1837
+ ...typeof record2.pk === "string" ? { pk: record2.pk } : {},
1838
+ ...typeof record2.claimUrl === "string" ? { claimUrl: record2.claimUrl } : {}
1839
+ };
22
1840
  } catch {
23
1841
  return {};
24
1842
  }
25
1843
  }
26
1844
  function writeConfig(c) {
27
1845
  mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
1846
+ try {
1847
+ chmodSync(CONFIG_DIR, 448);
1848
+ } catch {
1849
+ }
28
1850
  writeFileSync(CONFIG_PATH, JSON.stringify(c, null, 2), { mode: 384 });
29
1851
  try {
30
1852
  chmodSync(CONFIG_PATH, 384);
31
1853
  } catch {
32
1854
  }
33
1855
  }
1856
+ function requireTokenFor(apiBase) {
1857
+ const config2 = readConfig();
1858
+ if (typeof config2.token !== "string" || !config2.token) {
1859
+ die("Not logged in. Run `fillo login` first.");
1860
+ }
1861
+ if (typeof config2.tokenApi !== "string" || !config2.tokenApi) {
1862
+ die("This login cannot be used safely. Run `fillo login` again, then retry.");
1863
+ }
1864
+ const tokenApi = config2.tokenApi.replace(/\/$/, "");
1865
+ if (apiBase.replace(/\/$/, "") !== tokenApi) {
1866
+ die(
1867
+ `This login belongs to ${terminalText(tokenApi)}. Log in to the requested Fillo deployment, then try again.`
1868
+ );
1869
+ }
1870
+ return config2.token;
1871
+ }
34
1872
  function requireToken() {
35
- const t = readConfig().token;
36
- if (!t) die("Not logged in. Run `fillo login` first.");
37
- return t;
1873
+ return requireTokenFor(API);
38
1874
  }
39
1875
  function openBrowser(url) {
40
- if (!/^https?:\/\//i.test(url)) return;
1876
+ let safeUrl;
1877
+ try {
1878
+ const parsed = new URL(url);
1879
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
1880
+ safeUrl = parsed.toString();
1881
+ } catch {
1882
+ return;
1883
+ }
41
1884
  try {
42
1885
  if (process.platform === "win32") {
43
- spawn("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true }).unref();
1886
+ const child = spawn("cmd", ["/c", "start", "", safeUrl], { stdio: "ignore", detached: true });
1887
+ child.on("error", () => {
1888
+ });
1889
+ child.unref();
44
1890
  } else {
45
1891
  const cmd = process.platform === "darwin" ? "open" : "xdg-open";
46
- spawn(cmd, [url], { stdio: "ignore", detached: true }).unref();
1892
+ const child = spawn(cmd, [safeUrl], { stdio: "ignore", detached: true });
1893
+ child.on("error", () => {
1894
+ });
1895
+ child.unref();
47
1896
  }
48
1897
  } catch {
49
1898
  }
50
1899
  }
51
- async function api(path, init2 = {}) {
1900
+ async function api(path, init2 = {}, apiBase = API) {
52
1901
  const { token, ...rest } = init2;
53
- return fetch(`${API}/api/v1${path}`, {
1902
+ return fetch(`${apiBase}/api/v1${path}`, {
54
1903
  ...rest,
1904
+ signal: rest.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS),
55
1905
  headers: {
56
1906
  "Content-Type": "application/json",
57
1907
  ...token ? { Authorization: `Bearer ${token}` } : {},
@@ -59,13 +1909,39 @@ async function api(path, init2 = {}) {
59
1909
  }
60
1910
  });
61
1911
  }
62
- async function login() {
63
- const res = await api("/device/code", { method: "POST" });
1912
+ async function readJson(res) {
1913
+ const text = await res.text();
1914
+ try {
1915
+ return text ? JSON.parse(text) : {};
1916
+ } catch {
1917
+ die(`Unexpected non-JSON response from ${API} (${res.status}).`);
1918
+ }
1919
+ }
1920
+ async function login(flags) {
1921
+ const apiBase = flagString(flags, "api")?.replace(/\/$/, "") ?? API;
1922
+ const run = flagString(flags, "run");
1923
+ const progressToken = flagString(flags, "token");
1924
+ if (Boolean(run) !== Boolean(progressToken)) {
1925
+ die("--run and --token must be provided together for an agent handoff login.");
1926
+ }
1927
+ const res = await api(
1928
+ "/device/code",
1929
+ {
1930
+ method: "POST",
1931
+ ...run ? {
1932
+ body: JSON.stringify({
1933
+ agent_run_id: run,
1934
+ agent_run_token: progressToken
1935
+ })
1936
+ } : {}
1937
+ },
1938
+ apiBase
1939
+ );
64
1940
  if (!res.ok) die(`Couldn't start login (${res.status}).`);
65
- const d = await res.json();
1941
+ const d = await readJson(res);
66
1942
  console.log(`
67
1943
  Your code: ${bold(d.user_code)}`);
68
- console.log(` Approve it at ${d.verification_uri} \u2014 opening your browser\u2026
1944
+ console.log(` Approve it at ${terminalText(d.verification_uri)} \u2014 opening your browser\u2026
69
1945
  `);
70
1946
  openBrowser(d.verification_uri_complete);
71
1947
  const deadline = Date.now() + d.expires_in * 1e3;
@@ -74,18 +1950,28 @@ async function login() {
74
1950
  while (Date.now() < deadline) {
75
1951
  await sleep(interval);
76
1952
  process.stdout.write(".");
77
- const r = await api("/device/token", {
78
- method: "POST",
79
- body: JSON.stringify({ device_code: d.device_code })
80
- });
81
- const body = await r.json();
1953
+ const r = await api(
1954
+ "/device/token",
1955
+ {
1956
+ method: "POST",
1957
+ body: JSON.stringify({ device_code: d.device_code })
1958
+ },
1959
+ apiBase
1960
+ );
1961
+ const body = await readJson(r);
1962
+ if (!r.ok && !body.error) die(`
1963
+ Login failed (${r.status}).`);
82
1964
  if (body.access_token) {
83
- writeConfig({ token: body.access_token });
1965
+ writeConfig({ ...readConfig(), token: body.access_token, tokenApi: apiBase });
84
1966
  console.log("\n");
85
- await whoami();
86
- console.log(`
1967
+ await whoami(apiBase);
1968
+ console.log(
1969
+ run ? `
1970
+ ${dim("Return to the Fillo setup prompt and run its next command.")}
1971
+ ` : `
87
1972
  ${dim("Now run:")} fillo push form.json
88
- `);
1973
+ `
1974
+ );
89
1975
  return;
90
1976
  }
91
1977
  if (body.error === "slow_down") interval += 2e3;
@@ -94,23 +1980,49 @@ Login failed: ${body.error}`);
94
1980
  }
95
1981
  die("\nLogin timed out \u2014 run `fillo login` again.");
96
1982
  }
97
- async function whoami() {
98
- const res = await api("/cli/whoami", { token: requireToken() });
1983
+ async function whoami(apiBase = API) {
1984
+ const res = await api("/cli/whoami", { token: requireTokenFor(apiBase) }, apiBase);
99
1985
  if (res.status === 401) die("Token invalid \u2014 run `fillo login` again.");
100
1986
  if (!res.ok) die(`whoami failed (${res.status}).`);
101
- const me = await res.json();
102
- console.log(` \x1B[32m\u2713\x1B[0m ${bold(me.email)} ${dim("\xB7")} ${me.workspace}`);
1987
+ const me = await readJson(res);
1988
+ if (typeof me.workspace !== "string" || !terminalText(me.workspace)) {
1989
+ die("Fillo returned an invalid workspace identity.");
1990
+ }
1991
+ console.log(` \x1B[32m\u2713\x1B[0m Connected to ${bold(terminalText(me.workspace))}`);
103
1992
  }
104
1993
  async function list() {
105
1994
  const res = await api("/cli/forms", { token: requireToken() });
106
1995
  if (!res.ok) die(`list failed (${res.status}).`);
107
- const { forms } = await res.json();
1996
+ const { forms } = await readJson(res);
108
1997
  if (!forms.length) return console.log(" No forms yet.");
109
1998
  for (const f of forms) {
110
- console.log(` ${f.status === "published" ? "\x1B[32m\u25CF\x1B[0m" : "\u25CB"} ${f.name} ${dim(f.id)}`);
1999
+ console.log(
2000
+ ` ${f.status === "published" ? "\x1B[32m\u25CF\x1B[0m" : "\u25CB"} ${terminalText(f.name)} ${dim(f.id)}`
2001
+ );
111
2002
  }
112
2003
  }
113
2004
  async function loadSchema(file, allowCode) {
2005
+ if (file === "-") {
2006
+ try {
2007
+ const chunks = [];
2008
+ let bytes = 0;
2009
+ for await (const chunk of process.stdin) {
2010
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2011
+ bytes += buffer.byteLength;
2012
+ if (bytes > MAX_STDIN_SCHEMA_BYTES) {
2013
+ die("The schema on stdin is too large (maximum 1 MB).");
2014
+ }
2015
+ chunks.push(buffer);
2016
+ }
2017
+ const input = Buffer.concat(chunks).toString("utf8");
2018
+ if (!input.trim()) die("stdin is empty - pipe one JSON form schema to `fillo push -`.");
2019
+ const parsed = JSON.parse(input);
2020
+ if (parsed == null) die("stdin must contain a form schema.");
2021
+ return parsed;
2022
+ } catch (error) {
2023
+ die(`Couldn't read the schema from stdin: ${error.message}`);
2024
+ }
2025
+ }
114
2026
  const abs = isAbsolute(file) ? file : resolve(process.cwd(), file);
115
2027
  if (!abs.endsWith(".json") && !allowCode) {
116
2028
  die(
@@ -118,9 +2030,19 @@ async function loadSchema(file, allowCode) {
118
2030
  );
119
2031
  }
120
2032
  try {
121
- if (abs.endsWith(".json")) return JSON.parse(readFileSync(abs, "utf8"));
2033
+ if (abs.endsWith(".json")) {
2034
+ const parsed = JSON.parse(readFileSync(abs, "utf8"));
2035
+ if (parsed == null) die(`${file} is empty \u2014 it must contain a form schema.`);
2036
+ return parsed;
2037
+ }
122
2038
  const mod = await import(pathToFileURL(abs).href);
123
- return mod.default ?? mod.schema ?? mod.form ?? mod.forms ?? mod.MARKETING_FORMS;
2039
+ const schema = mod.default ?? mod.schema ?? mod.form ?? mod.forms ?? mod.MARKETING_FORMS;
2040
+ if (schema == null) {
2041
+ die(
2042
+ `${file} doesn't export a form schema \u2014 default-export it (or export \`schema\`/\`form\`/\`forms\`) and push again.`
2043
+ );
2044
+ }
2045
+ return schema;
124
2046
  } catch (e) {
125
2047
  die(`Couldn't read ${file}: ${e.message}`);
126
2048
  }
@@ -130,6 +2052,7 @@ function isRecord(value) {
130
2052
  }
131
2053
  function toPushItems(value, handle) {
132
2054
  const values = Array.isArray(value) ? value : [value];
2055
+ if (values.length === 0) die("The schema file contains no forms to push.");
133
2056
  return values.map((item, index) => {
134
2057
  if (isRecord(item) && "schema" in item) {
135
2058
  const ownHandle = typeof item.id === "string" ? item.id : void 0;
@@ -141,81 +2064,198 @@ function toPushItems(value, handle) {
141
2064
  return { handle, schema: item };
142
2065
  });
143
2066
  }
144
- function printPushed(formId, url, updated, staged) {
2067
+ function printPushed(formId, url, updated, draft = false) {
2068
+ const label = draft ? "Created draft" : updated ? "Updated" : "Created";
145
2069
  console.log(`
146
- \x1B[32m\u2713\x1B[0m ${updated ? "Updated" : "Created"} ${bold(formId)}`);
147
- if (staged) console.log(` ${dim("Staged as a draft \u2014 publish it from the dashboard.")}`);
148
- else if (url) console.log(` Live at ${url}`);
149
- console.log(` Embed: <FilloForm formId="${formId}" />
2070
+ \x1B[32m\u2713\x1B[0m ${label} ${bold(formId)}`);
2071
+ if (draft) console.log(` ${dim("Review and publish it from the Fillo dashboard.")}`);
2072
+ else if (url) console.log(` Live at ${terminalText(url)}`);
2073
+ console.log(` Embed: <FilloForm formId="${terminalText(formId)}" />
150
2074
  `);
151
2075
  }
2076
+ function syncError(response, body, credential) {
2077
+ const code = body.syncError?.code ?? body.code;
2078
+ const serverMessage = body.syncError?.message ?? body.error;
2079
+ if (code === "trusted_sync_required") {
2080
+ return `This workspace accepts schema changes only from an authenticated CLI or sync token. Run \`fillo login\`, then retry with \`fillo push <file> --handle <id> --stage\`, or set ${SYNC_TOKEN_ENV} from Settings > Developers.`;
2081
+ }
2082
+ if (response.status === 401 && credential === "sync_token") {
2083
+ return `${SYNC_TOKEN_ENV} was rejected. Create a replacement in Settings > Developers, update the CI secret, and retry.`;
2084
+ }
2085
+ if (response.status === 401 && credential === "account") {
2086
+ return "Your CLI login was rejected. Run `fillo login` again, then retry the staged push.";
2087
+ }
2088
+ return serverMessage ?? `push failed (${response.status}).`;
2089
+ }
2090
+ function readSyncToken() {
2091
+ const raw = process.env[SYNC_TOKEN_ENV];
2092
+ if (raw === void 0) return void 0;
2093
+ const token = raw.trim();
2094
+ if (!token.startsWith("fsync_") || token.length < 16 || token.length > 512 || /\s/.test(token)) {
2095
+ die(`${SYNC_TOKEN_ENV} must contain a valid fsync_ token from Settings > Developers.`);
2096
+ }
2097
+ return token;
2098
+ }
2099
+ function requireStableHandle(item) {
2100
+ if (item.handle) return item.handle;
2101
+ die("Staging needs a stable form id. Add --handle <name> or an id beside schema in the input.");
2102
+ }
2103
+ function printSynced(body, requestedStage) {
2104
+ const formId = body.formId;
2105
+ const changed = body.staged === true || body.status === "draft";
2106
+ const label = changed ? body.status === "draft" ? "Draft ready" : "Staged changes" : requestedStage ? "Checked" : "Synced";
2107
+ console.log(`
2108
+ \x1B[32m\u2713\x1B[0m ${label} for ${bold(formId)}`);
2109
+ if (changed) {
2110
+ console.log(` ${dim("Review and publish it from the Fillo dashboard.")}`);
2111
+ } else if (requestedStage && body.status === "published") {
2112
+ console.log(` ${dim("Nothing to stage - the published version already matches.")}`);
2113
+ } else if (body.slug) {
2114
+ console.log(` Live at ${terminalText(`${API}/f/${body.slug}`)}`);
2115
+ }
2116
+ if (body.warning) console.log(` ${dim(`Before publishing: ${body.warning}`)}`);
2117
+ console.log(` Embed: <FilloForm formId="${terminalText(formId)}" />
2118
+ `);
2119
+ }
2120
+ async function pushWithSync(items, credential, requestedStage) {
2121
+ for (const item of items) {
2122
+ const handle = requireStableHandle(item);
2123
+ const validation = validateFormSchema(item.schema);
2124
+ if (!validation.ok) {
2125
+ die(`Invalid schema for "${handle}" \u2014 ${validation.error ?? "schema is not valid"}`);
2126
+ }
2127
+ const res = await api("/forms/sync", {
2128
+ method: "POST",
2129
+ ...credential.token ? { token: credential.token } : {},
2130
+ body: JSON.stringify({
2131
+ ...credential.key ? { key: credential.key } : {},
2132
+ id: handle,
2133
+ schema: item.schema,
2134
+ theme: item.theme ?? null
2135
+ })
2136
+ });
2137
+ const body = await readJson(res);
2138
+ if (!res.ok || body.syncError || !body.formId) {
2139
+ die(syncError(res, body, credential.kind));
2140
+ }
2141
+ printSynced(body, requestedStage);
2142
+ }
2143
+ }
152
2144
  async function push(file, flags) {
153
- if (!file) die("Usage: fillo push <form.json> [--handle name] [--draft] [--allow-code]");
2145
+ if (!file) {
2146
+ die("Usage: fillo push <form.json|-> [--handle name] [--stage] [--allow-code]");
2147
+ }
2148
+ const cfg = readConfig();
2149
+ const explicitStage = flags.stage === true;
2150
+ const legacyDraft = flags.draft === true;
2151
+ const stage = explicitStage || legacyDraft;
2152
+ const syncToken = readSyncToken();
2153
+ if (syncToken && !stage) {
2154
+ die(`${SYNC_TOKEN_ENV} can only stage changes. Add --stage to this push.`);
2155
+ }
2156
+ const accountToken = !syncToken && cfg.token ? requireToken() : void 0;
2157
+ if (!syncToken && !accountToken && stage && cfg.pk) {
2158
+ die(
2159
+ "This local setup is an unclaimed preview, where publishable-key sync applies changes immediately. Omit --stage for the preview, or claim it and run `fillo login` before staging for review."
2160
+ );
2161
+ }
2162
+ if (!syncToken && !accountToken && stage) {
2163
+ die(`To stage changes, run \`fillo login\` or set ${SYNC_TOKEN_ENV} from Settings > Developers.`);
2164
+ }
154
2165
  const handle = typeof flags.handle === "string" ? flags.handle : void 0;
155
2166
  const items = toPushItems(await loadSchema(file, flags["allow-code"] === true), handle);
156
2167
  if (items.length > 1 && handle) die("--handle can only be used when pushing one form.");
157
- const cfg = readConfig();
158
- if (cfg.token) {
2168
+ if (syncToken) {
2169
+ await pushWithSync(items, { kind: "sync_token", token: syncToken }, true);
2170
+ return;
2171
+ }
2172
+ if (accountToken) {
2173
+ if (stage) {
2174
+ for (const item of items) {
2175
+ if (item.handle || explicitStage || !legacyDraft) {
2176
+ await pushWithSync([item], { kind: "account", token: accountToken }, true);
2177
+ continue;
2178
+ }
2179
+ const res = await api("/cli/forms", {
2180
+ method: "POST",
2181
+ token: accountToken,
2182
+ body: JSON.stringify({
2183
+ schema: item.schema,
2184
+ theme: item.theme ?? null,
2185
+ publish: false
2186
+ })
2187
+ });
2188
+ const body = await readJson(res);
2189
+ if (!res.ok || !body.formId) die(body.error ?? `push failed (${res.status}).`);
2190
+ printPushed(body.formId, body.url, !!body.updated, true);
2191
+ }
2192
+ return;
2193
+ }
159
2194
  for (const item of items) {
160
2195
  const res = await api("/cli/forms", {
161
2196
  method: "POST",
162
- token: cfg.token,
2197
+ token: accountToken,
163
2198
  body: JSON.stringify({
164
2199
  schema: item.schema,
165
2200
  theme: item.theme ?? null,
166
2201
  handle: item.handle,
167
- publish: !flags.draft
2202
+ publish: true
168
2203
  })
169
2204
  });
170
- const body = await res.json();
2205
+ const body = await readJson(res);
171
2206
  if (!res.ok || !body.formId) die(body.error ?? `push failed (${res.status}).`);
172
- printPushed(body.formId, body.url, !!body.updated, !!flags.draft);
2207
+ printPushed(body.formId, body.url, !!body.updated);
173
2208
  }
174
2209
  return;
175
2210
  }
176
2211
  if (cfg.pk) {
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
- }
2212
+ await pushWithSync(items, { kind: "publishable_key", key: cfg.pk }, false);
192
2213
  return;
193
2214
  }
194
- die("Not set up yet. Run `fillo init` (no account needed) or `fillo login`.");
2215
+ die("Not set up yet. Run `fillo init --email you@company.com` or `fillo login`.");
195
2216
  }
196
2217
  async function init(flags) {
197
- const email = typeof flags.email === "string" ? flags.email : void 0;
2218
+ const email3 = typeof flags.email === "string" ? flags.email.trim() : "";
2219
+ if (!email3) {
2220
+ die("Usage: fillo init --email you@company.com (or run `fillo login` for an existing account).");
2221
+ }
198
2222
  const res = await api("/workspaces/provision", {
199
2223
  method: "POST",
200
- body: JSON.stringify({ email, source: "cli" })
2224
+ body: JSON.stringify({ email: email3, source: "cli" })
201
2225
  });
202
- const body = await res.json();
2226
+ const body = await readJson(res);
203
2227
  if (!res.ok || !body.key) die(body.error ?? `init failed (${res.status}).`);
204
- writeConfig({ ...readConfig(), pk: body.key, claimUrl: body.claim?.url ?? void 0 });
2228
+ const { claimUrl: _legacyWorkspaceLink, ...current } = readConfig();
2229
+ writeConfig({ ...current, pk: body.key });
205
2230
  console.log(`
206
- \x1B[32m\u2713\x1B[0m Workspace ready \u2014 no signup needed.`);
2231
+ \x1B[32m\u2713\x1B[0m Workspace ready. A workspace link was sent to ${bold(terminalText(email3))}.`);
207
2232
  if (body.limits) {
208
- const days = Math.max(1, Math.round((Date.parse(body.limits.expiresAt) - Date.now()) / 864e5));
209
- console.log(` ${dim(`Preview: up to ${body.limits.responses} responses for ~${days} days.`)}`);
2233
+ const expiry = Date.parse(body.limits.expiresAt);
2234
+ if (Number.isFinite(expiry)) {
2235
+ const days = Math.max(1, Math.round((expiry - Date.now()) / 864e5));
2236
+ console.log(` ${dim(`Preview: up to ${body.limits.responses} responses for ~${days} days.`)}`);
2237
+ }
210
2238
  }
211
2239
  console.log(`
212
2240
  ${bold("Next:")} fillo push form.json --handle my-form`);
213
- if (body.claim?.url) {
214
- console.log(`
215
- ${dim("Keep your responses \u2014 claim it (signup, one click):")}`);
216
- console.log(` ${body.claim.url}
2241
+ console.log(` ${dim("Open the emailed link whenever you want to save it to an account.")}
217
2242
  `);
2243
+ }
2244
+ var AGENT_ACTIONS = ["claim_required", "storage_required", "publish_required"];
2245
+ var FORM_STATUSES = ["draft", "published"];
2246
+ function enumFlag(flags, key, allowed) {
2247
+ const value = flags[key];
2248
+ if (value === void 0) return void 0;
2249
+ if (typeof value !== "string" || !allowed.includes(value)) {
2250
+ die(`--${key} must be one of: ${allowed.join(", ")}`);
218
2251
  }
2252
+ return value;
2253
+ }
2254
+ function optionalStringFlag(flags, key) {
2255
+ const value = flags[key];
2256
+ if (value === void 0) return void 0;
2257
+ if (typeof value !== "string" || !value.trim()) die(`--${key} requires a value.`);
2258
+ return value;
219
2259
  }
220
2260
  async function agent(subcommand, flags) {
221
2261
  const apiBase = flagString(flags, "api")?.replace(/\/$/, "") ?? API;
@@ -227,36 +2267,231 @@ async function agent(subcommand, flags) {
227
2267
  if (!run || !token) {
228
2268
  die("Usage: fillo agent <connect|event> --run <id> --token <token> [--api <url>]");
229
2269
  }
2270
+ if (flags.account !== void 0 && flags.account !== true) {
2271
+ die("--account does not take a value.");
2272
+ }
230
2273
  if (subcommand === "connect") {
2274
+ const account = flags.account === true ? await attachAgentAccount(apiBase, run, token) : void 0;
231
2275
  await postAgentEvent(apiBase, run, token, {
232
2276
  status: "connected",
233
2277
  message: "Agent connected. Reading the app now."
234
2278
  });
235
2279
  console.log(` \x1B[32m\u2713\x1B[0m Live progress connected.`);
2280
+ if (account) {
2281
+ console.log(` \x1B[32m\u2713\x1B[0m ${bold(account.workspace)}`);
2282
+ console.log(` ${dim("Publishable key:")} ${account.publishableKey}`);
2283
+ }
236
2284
  console.log(` ${dim("Report next steps with:")}`);
237
2285
  console.log(
238
- ` fillo agent event --api ${apiBase} --run ${run} --token <same-token> --status editing --message "Editing the form screen"`
2286
+ ` fillo agent event --api ${terminalText(apiBase)} --run ${terminalText(run)} --token <same-token> --status editing --message "Editing the form screen"`
239
2287
  );
240
2288
  return;
241
2289
  }
2290
+ if (flags.account === true) {
2291
+ die("--account can only be used with `fillo agent connect`.");
2292
+ }
242
2293
  if (subcommand === "event") {
243
2294
  const status = flagString(flags, "status");
244
2295
  const message = flagString(flags, "message");
245
2296
  if (!status) die("Usage: fillo agent event --status <status> --message <short update>");
2297
+ const action = enumFlag(flags, "action", AGENT_ACTIONS);
2298
+ const formStatus = enumFlag(flags, "form-status", FORM_STATUSES);
2299
+ const formId = optionalStringFlag(flags, "form-id");
2300
+ if ((status === "done" || status === "needs_action") && !formId) {
2301
+ die(`--form-id is required when --status is ${status}.`);
2302
+ }
2303
+ if (status === "needs_action" && !action) {
2304
+ die("--action is required when --status is needs_action.");
2305
+ }
246
2306
  await postAgentEvent(apiBase, run, token, {
247
2307
  status,
248
2308
  message,
249
- claimUrl: flagString(flags, "claim-url"),
250
- dashboardUrl: flagString(flags, "dashboard-url"),
251
2309
  appUrl: flagString(flags, "app-url"),
252
- formId: flagString(flags, "form-id"),
253
- formName: flagString(flags, "form-name")
2310
+ action,
2311
+ formId,
2312
+ formName: flagString(flags, "form-name"),
2313
+ formStatus
254
2314
  });
255
2315
  console.log(` \x1B[32m\u2713\x1B[0m Progress sent.`);
256
2316
  return;
257
2317
  }
258
2318
  die(`Unknown agent command: ${subcommand}`);
259
2319
  }
2320
+ var SKILL_AGENTS = [
2321
+ "agents",
2322
+ "codex",
2323
+ "claude",
2324
+ "cursor",
2325
+ "copilot",
2326
+ "gemini"
2327
+ ];
2328
+ function isSkillAgent(value) {
2329
+ return SKILL_AGENTS.some((agent2) => agent2 === value);
2330
+ }
2331
+ function findProjectRoot(start) {
2332
+ let current = resolve(start);
2333
+ while (true) {
2334
+ if (existsSync(join(current, ".git"))) return current;
2335
+ const parent = dirname(current);
2336
+ if (parent === current) return resolve(start);
2337
+ current = parent;
2338
+ }
2339
+ }
2340
+ function detectSkillAgent() {
2341
+ if (process.env.CLAUDECODE === "1" || process.env.CLAUDE_CODE === "1") {
2342
+ return "claude";
2343
+ }
2344
+ return "agents";
2345
+ }
2346
+ function parseSkillAgent(flags) {
2347
+ if (flags.agent === true || flags.agent === "") {
2348
+ die(`--agent requires one of: ${SKILL_AGENTS.join(", ")}`);
2349
+ }
2350
+ const value = flagString(flags, "agent") ?? detectSkillAgent();
2351
+ if (isSkillAgent(value)) return value;
2352
+ die(`--agent must be one of: ${SKILL_AGENTS.join(", ")}`);
2353
+ }
2354
+ function skillFiles(root, relative2 = "") {
2355
+ const directory = join(root, relative2);
2356
+ const files = [];
2357
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
2358
+ const next = join(relative2, entry.name);
2359
+ if (entry.isDirectory()) files.push(...skillFiles(root, next));
2360
+ else if (entry.isFile()) files.push(next);
2361
+ }
2362
+ return files.sort();
2363
+ }
2364
+ function sameSkillBundle(source, target) {
2365
+ try {
2366
+ const sourceFiles = skillFiles(source);
2367
+ const targetFiles = skillFiles(target);
2368
+ if (sourceFiles.length !== targetFiles.length) return false;
2369
+ return sourceFiles.every(
2370
+ (file, index) => file === targetFiles[index] && readFileSync(join(source, file)).equals(readFileSync(join(target, file)))
2371
+ );
2372
+ } catch {
2373
+ return false;
2374
+ }
2375
+ }
2376
+ function pathEntryExists(path) {
2377
+ try {
2378
+ lstatSync(path);
2379
+ return true;
2380
+ } catch (error) {
2381
+ if (error.code === "ENOENT") return false;
2382
+ throw error;
2383
+ }
2384
+ }
2385
+ var MANAGED_SKILL_MARKER = ".fillo-managed.json";
2386
+ function isCliManagedFilloSkill(target) {
2387
+ try {
2388
+ const marker = JSON.parse(
2389
+ readFileSync(join(target, MANAGED_SKILL_MARKER), "utf8")
2390
+ );
2391
+ return marker.managedBy === "@usefillo/cli" && marker.skill === "build-with-fillo" && marker.format === 1 && marker.allowAutomaticUpdates === true;
2392
+ } catch {
2393
+ return false;
2394
+ }
2395
+ }
2396
+ function assertSafeSkillDestination(scopeRoot, parts) {
2397
+ const realScopeRoot = realpathSync(scopeRoot);
2398
+ let current = scopeRoot;
2399
+ for (const part of parts) {
2400
+ current = join(current, part);
2401
+ if (!pathEntryExists(current)) return;
2402
+ if (lstatSync(current).isSymbolicLink()) {
2403
+ throw new Error(`Refusing to install through symlinked path ${current}.`);
2404
+ }
2405
+ const resolved = realpathSync(current);
2406
+ const fromScope = relative(realScopeRoot, resolved);
2407
+ if (fromScope === ".." || fromScope.startsWith(`..${sep}`) || isAbsolute(fromScope)) {
2408
+ throw new Error(`Refusing to install outside ${scopeRoot}.`);
2409
+ }
2410
+ }
2411
+ }
2412
+ function moveSkillIntoPlace(staging, target) {
2413
+ if (!pathEntryExists(target)) {
2414
+ renameSync(staging, target);
2415
+ return;
2416
+ }
2417
+ const backup = `${target}.backup-${randomUUID()}`;
2418
+ renameSync(target, backup);
2419
+ try {
2420
+ renameSync(staging, target);
2421
+ } catch (error) {
2422
+ try {
2423
+ renameSync(backup, target);
2424
+ } catch {
2425
+ throw new Error(`Skill install failed. The previous copy is preserved at ${backup}.`);
2426
+ }
2427
+ throw error;
2428
+ }
2429
+ try {
2430
+ rmSync(backup, { recursive: true, force: true });
2431
+ } catch {
2432
+ console.warn(` ${dim(`Previous skill copy could not be removed: ${backup}`)}`);
2433
+ }
2434
+ }
2435
+ function installSkill(flags) {
2436
+ if (flags.global === true && flags.project === true) {
2437
+ die("Choose either --project or --global, not both.");
2438
+ }
2439
+ const agent2 = parseSkillAgent(flags);
2440
+ const global = flags.global === true;
2441
+ const agentDirectory = agent2 === "claude" ? ".claude" : ".agents";
2442
+ const scopeRoot = global ? homedir() : findProjectRoot(process.cwd());
2443
+ const skillsRoot = join(scopeRoot, agentDirectory, "skills");
2444
+ const target = join(skillsRoot, "build-with-fillo");
2445
+ const destinationParts = [agentDirectory, "skills", "build-with-fillo"];
2446
+ if (!existsSync(BUNDLED_SKILL_DIR)) {
2447
+ die("This CLI package is missing its bundled Fillo skill. Reinstall @usefillo/cli@latest.");
2448
+ }
2449
+ assertSafeSkillDestination(scopeRoot, destinationParts);
2450
+ const targetExists = pathEntryExists(target);
2451
+ const updatingManagedSkill = targetExists && isCliManagedFilloSkill(target);
2452
+ if (targetExists) {
2453
+ if (sameSkillBundle(BUNDLED_SKILL_DIR, target)) {
2454
+ console.log(`
2455
+ \x1B[32m\u2713\x1B[0m Fillo skill is already installed.`);
2456
+ console.log(` ${dim(target)}
2457
+ `);
2458
+ return;
2459
+ }
2460
+ if (!updatingManagedSkill && flags.force !== true) {
2461
+ die(`A different skill already exists at ${target}. Re-run with --force to replace it.`);
2462
+ }
2463
+ }
2464
+ mkdirSync(skillsRoot, { recursive: true });
2465
+ assertSafeSkillDestination(scopeRoot, destinationParts.slice(0, 2));
2466
+ const staging = join(skillsRoot, `.build-with-fillo.install-${randomUUID()}`);
2467
+ try {
2468
+ cpSync(BUNDLED_SKILL_DIR, staging, { recursive: true, errorOnExist: true });
2469
+ assertSafeSkillDestination(scopeRoot, destinationParts);
2470
+ if (!targetExists && pathEntryExists(target)) {
2471
+ throw new Error(`Skill destination changed during install: ${target}`);
2472
+ }
2473
+ moveSkillIntoPlace(staging, target);
2474
+ } finally {
2475
+ if (pathEntryExists(staging)) rmSync(staging, { recursive: true, force: true });
2476
+ }
2477
+ console.log(
2478
+ `
2479
+ \x1B[32m\u2713\x1B[0m ${updatingManagedSkill ? "Updated" : "Installed"} ${bold("Build with Fillo")} for ${agent2}.`
2480
+ );
2481
+ console.log(` ${dim(target)}`);
2482
+ console.log(
2483
+ `
2484
+ Ask your agent to read ${terminalText(join(target, "SKILL.md"))} and add a Fillo form.
2485
+ `
2486
+ );
2487
+ }
2488
+ function skill(subcommand, flags) {
2489
+ if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
2490
+ return skillHelp();
2491
+ }
2492
+ if (subcommand === "install") return installSkill(flags);
2493
+ die(`Unknown skill command: ${subcommand}`);
2494
+ }
260
2495
  async function postAgentEvent(apiBase, run, token, body) {
261
2496
  const res = await fetch(`${apiBase}/api/v1/agent-runs/${encodeURIComponent(run)}/events`, {
262
2497
  method: "POST",
@@ -264,44 +2499,150 @@ async function postAgentEvent(apiBase, run, token, body) {
264
2499
  Authorization: `Bearer ${token}`,
265
2500
  "Content-Type": "application/json"
266
2501
  },
267
- body: JSON.stringify(body)
2502
+ body: JSON.stringify(body),
2503
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
268
2504
  });
269
2505
  const payload = await res.json().catch(() => ({}));
270
2506
  if (!res.ok) die(payload.error ?? `agent progress failed (${res.status}).`);
271
2507
  }
2508
+ async function attachAgentAccount(apiBase, run, progressToken) {
2509
+ const accountToken = requireTokenFor(apiBase);
2510
+ const res = await fetch(
2511
+ `${apiBase}/api/v1/agent-runs/${encodeURIComponent(run)}/account`,
2512
+ {
2513
+ method: "POST",
2514
+ redirect: "error",
2515
+ headers: {
2516
+ Authorization: `Bearer ${accountToken}`,
2517
+ "X-Fillo-Agent-Run-Token": progressToken
2518
+ },
2519
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
2520
+ }
2521
+ );
2522
+ const payload = await res.json().catch(() => ({}));
2523
+ if (!res.ok) {
2524
+ const hint = res.status === 401 ? " Run `fillo login` and try again." : "";
2525
+ die(`${payload.error ?? `account connection failed (${res.status}).`}${hint}`);
2526
+ }
2527
+ if (typeof payload.workspace !== "string" || !terminalText(payload.workspace) || typeof payload.publishableKey !== "string" || !/^pk_[A-Za-z0-9_-]{1,125}$/.test(payload.publishableKey)) {
2528
+ die("Fillo returned an invalid workspace connection.");
2529
+ }
2530
+ return { workspace: terminalText(payload.workspace), publishableKey: payload.publishableKey };
2531
+ }
272
2532
  function agentHelp() {
273
2533
  console.log(`
274
2534
  ${bold("fillo agent")} \u2014 report live progress back to a Fillo prompt modal
275
2535
 
276
2536
  ${bold("Commands")}
277
2537
  agent connect Connect a coding-agent run to the open browser modal
2538
+ ${dim("--account attach the workspace from `fillo login`")}
278
2539
  agent event Send a short progress update
279
- ${dim("--status <created|connected|asking|planning|installing|editing|checking|done|error>")}
2540
+ ${dim("--status <created|connected|asking|planning|installing|editing|checking|needs_action|done|error>")}
280
2541
  ${dim('--message "Short update"')}
281
- ${dim("--claim-url <url> --app-url <url> --form-name <name>")}
2542
+ ${dim("--form-id <id> --form-status <draft|published> --form-name <name>")}
2543
+ ${dim("--action <claim_required|storage_required|publish_required>")}
2544
+ ${dim("--app-url <localhost-url>")}
282
2545
  ${dim("--run <id> --token <token> --api <url>")}
283
2546
  `);
284
2547
  }
2548
+ function skillHelp() {
2549
+ console.log(`
2550
+ ${bold("fillo skill")} \u2014 install the Build with Fillo Agent Skill
2551
+
2552
+ ${bold("Commands")}
2553
+ skill install Install into this project (default)
2554
+ ${dim("--agent <agents|codex|claude|cursor|copilot|gemini>")}
2555
+ ${dim("--global install for the current user")}
2556
+ ${dim("--force replace a different existing copy")}
2557
+
2558
+ ${dim("Codex, Cursor, Copilot, and Gemini use shared .agents/skills; Claude Code uses .claude/skills.")}
2559
+ `);
2560
+ }
2561
+ function printVersion() {
2562
+ try {
2563
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
2564
+ console.log(pkg.version);
2565
+ } catch {
2566
+ console.log("unknown");
2567
+ }
2568
+ }
285
2569
  function help() {
286
2570
  console.log(`
287
2571
  ${bold("fillo")} \u2014 create Fillo forms from your terminal
288
2572
 
289
2573
  ${bold("Commands")}
290
- init Provision a workspace with NO signup \u2014 instant, for first runs
291
- ${dim("--email <addr> optional: also mail a claim link as backup")}
2574
+ init Start a new workspace and email its workspace link
2575
+ ${dim("--email <addr> required")}
292
2576
  login Connect to an existing account (opens the browser)
2577
+ ${dim("--run <id> --token <token> bind a fresh agent handoff login")}
293
2578
  logout Forget the stored credentials
294
- whoami Show the signed-in account + workspace
295
- push <file> Create/update a form from a JSON schema
2579
+ whoami Show the signed-in workspace
2580
+ push <file|-> Create/update a form from JSON (file or stdin)
296
2581
  ${dim("--handle <name> idempotent id for re-pushes")}
297
- ${dim("--draft stage as a draft instead of publishing")}
2582
+ ${dim("--stage stage beside the live form for dashboard review")}
2583
+ ${dim("--draft alias with a handle; legacy one-off draft without")}
298
2584
  ${dim("--allow-code allow a .mjs/.js schema (executes the file)")}
299
2585
  list List the workspace's forms
300
2586
  agent <cmd> Report live progress to a Fillo prompt modal
2587
+ skill install Install the Build with Fillo Agent Skill
301
2588
 
302
2589
  ${dim(`API: ${API} \xB7 set FILLO_API to override`)}
2590
+ ${dim(`${SYNC_TOKEN_ENV}: stage-only server/CI credential; requires --stage`)}
303
2591
  `);
304
2592
  }
2593
+ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
2594
+ "account",
2595
+ "allow-code",
2596
+ "draft",
2597
+ "stage",
2598
+ "force",
2599
+ "global",
2600
+ "help",
2601
+ "h",
2602
+ "project",
2603
+ "version",
2604
+ "v"
2605
+ ]);
2606
+ var GLOBAL_FLAGS = /* @__PURE__ */ new Set(["help", "h", "version", "v"]);
2607
+ var FLAGS_BY_COMMAND = {
2608
+ init: ["email"],
2609
+ login: ["api", "run", "token"],
2610
+ logout: [],
2611
+ whoami: [],
2612
+ push: ["handle", "stage", "draft", "allow-code"],
2613
+ list: [],
2614
+ ls: [],
2615
+ agent: [
2616
+ "run",
2617
+ "token",
2618
+ "api",
2619
+ "account",
2620
+ "status",
2621
+ "message",
2622
+ "app-url",
2623
+ "action",
2624
+ "form-id",
2625
+ "form-name",
2626
+ "form-status"
2627
+ ],
2628
+ skill: ["agent", "global", "project", "force"],
2629
+ help: [],
2630
+ version: []
2631
+ };
2632
+ function validateFlags(command, flags) {
2633
+ const allowed = /* @__PURE__ */ new Set([
2634
+ ...GLOBAL_FLAGS,
2635
+ ...command ? FLAGS_BY_COMMAND[command] ?? [] : []
2636
+ ]);
2637
+ for (const [key, value] of Object.entries(flags)) {
2638
+ if (!allowed.has(key)) die(`Unknown flag for ${command ?? "fillo"}: --${key}`);
2639
+ if (BOOLEAN_FLAGS.has(key)) {
2640
+ if (value !== true) die(`--${key} does not take a value.`);
2641
+ } else if (typeof value !== "string" || value.length === 0) {
2642
+ die(`--${key} requires a value.`);
2643
+ }
2644
+ }
2645
+ }
305
2646
  function flagString(flags, key) {
306
2647
  const value = flags[key];
307
2648
  return typeof value === "string" && value ? value : void 0;
@@ -311,6 +2652,14 @@ function parseFlags(args) {
311
2652
  const positional = [];
312
2653
  for (let i = 0; i < args.length; i++) {
313
2654
  const a = args[i];
2655
+ if (a === "--") {
2656
+ positional.push(...args.slice(i + 1));
2657
+ break;
2658
+ }
2659
+ if (a === "-h" || a === "-v") {
2660
+ flags[a.slice(1)] = true;
2661
+ continue;
2662
+ }
314
2663
  if (!a.startsWith("--")) {
315
2664
  positional.push(a);
316
2665
  continue;
@@ -321,6 +2670,10 @@ function parseFlags(args) {
321
2670
  continue;
322
2671
  }
323
2672
  const key = a.slice(2);
2673
+ if (BOOLEAN_FLAGS.has(key)) {
2674
+ flags[key] = true;
2675
+ continue;
2676
+ }
324
2677
  const next = args[i + 1];
325
2678
  if (next !== void 0 && !next.startsWith("--")) {
326
2679
  flags[key] = next;
@@ -332,17 +2685,25 @@ function parseFlags(args) {
332
2685
  async function main() {
333
2686
  const [cmd, ...rest] = process.argv.slice(2);
334
2687
  const { positional, flags } = parseFlags(rest);
2688
+ validateFlags(cmd, flags);
2689
+ if (cmd === "version" || cmd === "--version" || cmd === "-v" || flags.version === true || flags.v === true) {
2690
+ return printVersion();
2691
+ }
335
2692
  if (flags.help === true || flags.h === true) {
336
- return cmd === "agent" ? agentHelp() : help();
2693
+ if (cmd === "agent") return agentHelp();
2694
+ if (cmd === "skill") return skillHelp();
2695
+ return help();
337
2696
  }
338
2697
  switch (cmd) {
339
2698
  case "init":
340
2699
  return init(flags);
341
2700
  case "login":
342
- return login();
343
- case "logout":
344
- writeConfig({});
2701
+ return login(flags);
2702
+ case "logout": {
2703
+ const { token, tokenApi, ...rest2 } = readConfig();
2704
+ writeConfig(rest2);
345
2705
  return console.log(" Logged out.");
2706
+ }
346
2707
  case "whoami":
347
2708
  return whoami();
348
2709
  case "push":
@@ -352,14 +2713,17 @@ async function main() {
352
2713
  return list();
353
2714
  case "agent":
354
2715
  return agent(positional[0], flags);
2716
+ case "skill":
2717
+ return skill(positional[0], flags);
355
2718
  case void 0:
356
2719
  case "help":
357
2720
  case "--help":
358
2721
  case "-h":
359
2722
  return help();
360
2723
  default:
361
- console.error(`Unknown command: ${cmd}`);
362
- return help();
2724
+ console.error(`Unknown command: ${terminalText(cmd)}`);
2725
+ help();
2726
+ return process.exit(2);
363
2727
  }
364
2728
  }
365
2729
  main().catch((e) => die(e instanceof Error ? e.message : String(e)));