void 0.20.0 → 0.20.2

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.
Files changed (93) hide show
  1. package/README.md +5 -1
  2. package/dist/{auth-W9WII-mN.mjs → auth-DPl6kck4.mjs} +46 -26
  3. package/dist/{auth-cmd-CYVhSNFy.mjs → auth-cmd-gniL2fNt.mjs} +5 -4
  4. package/dist/auth-link-NZdjCmSc.mjs +28 -0
  5. package/dist/{build-cmd-CkVD1uOh.mjs → build-cmd-sI18tX_O.mjs} +3 -3
  6. package/dist/{cache-QcUfR-ff.mjs → cache-IHn5MwBC.mjs} +3 -3
  7. package/dist/{cancel-deploy-DsvWKFTe.mjs → cancel-deploy-C5qTOdLi.mjs} +3 -3
  8. package/dist/cf-access-DRsQRe6k.mjs +75 -0
  9. package/dist/cli/cli.mjs +364 -1883
  10. package/dist/cli/env-schema-probe.mjs +11 -2
  11. package/dist/{client-CyCHWSO_.mjs → client-dHfSJvAN.mjs} +336 -58
  12. package/dist/{cloudflare-auth-DRkGe7-s.mjs → cloudflare-auth-6M5llVPC.mjs} +53 -6
  13. package/dist/{cloudflare-cmd-D3ME2GAe.mjs → cloudflare-cmd-4RPGN3KB.mjs} +2 -2
  14. package/dist/{cloudflare-connect-BivMefMA.mjs → cloudflare-connect-t1UU5svD.mjs} +2 -2
  15. package/dist/{cloudflare-operations-CPTpRW6d.mjs → cloudflare-operations-BzWnlC1_.mjs} +1 -1
  16. package/dist/{config-BQFq7QvD.mjs → config-uNGuFsI2.mjs} +1 -1
  17. package/dist/{connect-D9Yr-T5f.mjs → connect-Bfk31O_8.mjs} +6 -6
  18. package/dist/{create-project-DMV-csEm.mjs → create-project-Bk9Z0-Jg.mjs} +6 -5
  19. package/dist/{db-BxoUWL0F.mjs → db-BkRoptAt.mjs} +75 -48
  20. package/dist/{delete-iJOqxBz1.mjs → delete-DouASY9P.mjs} +3 -3
  21. package/dist/{deploy-CcDoeBIf.mjs → deploy-DTaWUS1S.mjs} +137 -128
  22. package/dist/{dev-inbox-DkgRWLkW.mjs → dev-inbox-P0u4tM8Y.mjs} +1 -1
  23. package/dist/{domain-gu_iaHmn.mjs → domain-1RhhOVrC.mjs} +4 -4
  24. package/dist/email-C-lGh51B.mjs +795 -0
  25. package/dist/{env-D4Emu-M_.mjs → env-DBKmK4vc.mjs} +1 -0
  26. package/dist/{env-DmU2To0C.mjs → env-DJHsPE7Z.mjs} +5 -5
  27. package/dist/{env-validation-ENpMy6Ez.mjs → env-validation-CF6KvTRf.mjs} +3 -1
  28. package/dist/{gen-BKw6qHIg.mjs → gen-B_wPnVTK.mjs} +3 -3
  29. package/dist/generate-RTK8_kK1.mjs +47 -0
  30. package/dist/{github-cmd-DJS5Ab-H.mjs → github-cmd-PW7ZnWTp.mjs} +3 -3
  31. package/dist/{headers-D8QfRX9Y.mjs → headers-BAHwgHdW.mjs} +1 -1
  32. package/dist/help-CwOX-zmI.mjs +2216 -0
  33. package/dist/{inbound-BJ70in1n.d.mts → inbound-CH5Mksyy.d.mts} +37 -42
  34. package/dist/{inbound-CNKxb3FY.mjs → inbound-aVHEUhKo.mjs} +143 -101
  35. package/dist/index.mjs +69 -30
  36. package/dist/{init-Dx5cgKqK.mjs → init-BWZ7q5Z4.mjs} +11 -11
  37. package/dist/{link-D_rm5sRH.mjs → link-Rmvu2Wl_.mjs} +4 -4
  38. package/dist/{list-M8XShti7.mjs → list-DEE2S6mY.mjs} +4 -4
  39. package/dist/{local-d1-BE8KBbMy.mjs → local-d1-D2I6Ox5F.mjs} +1 -1
  40. package/dist/{login-C8-UuLnp.mjs → login-Uvferzmm.mjs} +28 -10
  41. package/dist/{logs-DwFU7dMW.mjs → logs-27FenuiC.mjs} +4 -4
  42. package/dist/{mime-BJD7d_qL.mjs → mime-D5Nmdzf7.mjs} +23 -9
  43. package/dist/{node-BkaXcpAc.mjs → node-Ez5KW5rn.mjs} +3 -3
  44. package/dist/operator-auth-B3e08unv.mjs +52 -0
  45. package/dist/operator-client-LUZnlnYk.mjs +82 -0
  46. package/dist/{operator-cmd-DYWRbWUA.mjs → operator-cmd-CjOTmAYE.mjs} +35 -55
  47. package/dist/{output-tFQLLj26.mjs → output-B0cfNSx5.mjs} +316 -2
  48. package/dist/pages/index.mjs +2 -2
  49. package/dist/platform-auth-config-DrbQXXiW.mjs +368 -0
  50. package/dist/platform-auth-protection-Bhtvp0B_.mjs +219 -0
  51. package/dist/platform-auth-recovery-CeOKGVeJ.mjs +310 -0
  52. package/dist/{platform-cmd-BEOVv1PN.mjs → platform-cmd-BFhieCdV.mjs} +16 -6
  53. package/dist/{platform-domain-BszUfiS8.mjs → platform-domain-C74PULqV.mjs} +4 -4
  54. package/dist/{platform-lifecycle-CjSr6xf0.mjs → platform-lifecycle-BwAIgz-t.mjs} +1667 -191
  55. package/dist/{platform-management-W30iCaTL.mjs → platform-management-COogu_Se.mjs} +33 -7
  56. package/dist/{platform-recovery-pHHv4ZSg.mjs → platform-recovery-ewqLefp1.mjs} +6 -5
  57. package/dist/{prepare-CBetXvsN.mjs → prepare-CtDJjoOj.mjs} +2 -2
  58. package/dist/{prepare-BfJvFUtJ.mjs → prepare-blNRQvQl.mjs} +2 -2
  59. package/dist/prerender-render.d.mts +11 -0
  60. package/dist/prerender-render.mjs +111 -0
  61. package/dist/{project-cmd-DCpk1cDt.mjs → project-cmd-DmZK9Hxf.mjs} +32 -14
  62. package/dist/project-team-D8jOJMUJ.mjs +130 -0
  63. package/dist/project-token-DA34bf-C.mjs +75 -0
  64. package/dist/{provision-Blnstcm2.mjs → provision-CSJOjjQk.mjs} +2 -0
  65. package/dist/{requests-Dn8Vheh1.mjs → requests-CUExwGQQ.mjs} +3 -3
  66. package/dist/{rollback-CtlPXEBi.mjs → rollback-CDNGU1gr.mjs} +4 -4
  67. package/dist/{runner-mysql-CgRFl3s6.mjs → runner-mysql-7BPUNGmL.mjs} +1 -1
  68. package/dist/{runner-pg-DCkWPsWS.mjs → runner-pg-BkEza-dX.mjs} +1 -1
  69. package/dist/runtime/ai.mjs +3 -2
  70. package/dist/runtime/email/testing.d.mts +1 -1
  71. package/dist/runtime/email/testing.mjs +3 -3
  72. package/dist/runtime/email-protocol.d.mts +15 -0
  73. package/dist/runtime/email-protocol.mjs +70 -0
  74. package/dist/runtime/email.d.mts +2 -2
  75. package/dist/runtime/email.mjs +189 -96
  76. package/dist/runtime/remote/index.mjs +5 -3
  77. package/dist/{secret-BqTxGqki.mjs → secret-Bzzi2e9E.mjs} +5 -5
  78. package/dist/{skills-Q46GZMO-.mjs → skills-C0RvGjeE.mjs} +1 -1
  79. package/dist/sqlite-validation-BzKMWnO4.mjs +25 -0
  80. package/dist/{subcommand-prompt-WfySCQ7S.mjs → subcommand-prompt-Bmyn5Rlc.mjs} +1 -1
  81. package/dist/{validate-Bihr8WBi.mjs → validate-tBBN_dXH.mjs} +1 -0
  82. package/package.json +12 -7
  83. package/skills/void/SKILL.md +35 -4
  84. package/skills/void/docs/guide/deployment.md +2 -0
  85. package/skills/void/docs/guide/email.md +121 -98
  86. package/skills/void/docs/guide/platform-administration.md +214 -2
  87. package/skills/void/docs/guide/platform-development.md +93 -2
  88. package/skills/void/docs/guide/project-collaboration.md +94 -0
  89. package/skills/void/docs/guide/self-hosted-platform.md +184 -30
  90. package/skills/void/docs/reference/cli.md +294 -15
  91. package/dist/cf-access-AJ1ehiFR.mjs +0 -42
  92. package/dist/cf-access-DsSsZUPr.mjs +0 -67
  93. package/dist/email-r6DHJyAB.mjs +0 -262
@@ -0,0 +1,2216 @@
1
+ import { n as __exportAll } from "./rolldown-runtime-rQ84J-ij.mjs";
2
+ import { o as join } from "./dist-BrsS7cai.mjs";
3
+ import { A as outro, c as import_picocolors, k as note, l as sectionTitle, p as getPackageDir, s as helpLine, t as categoryTitle } from "./output-B0cfNSx5.mjs";
4
+ import { t as OPERATOR_MAX_TIMEOUT_MS } from "./operator-client-LUZnlnYk.mjs";
5
+ import { readFileSync } from "node:fs";
6
+ //#region src/cli/ascii.ts
7
+ const asciiArts = [
8
+ `
9
+ ▄ ▄ ▄▄▄ ▄ ▐▌
10
+ █ █ █ █ ▄ ▐▌
11
+ ▀▄▀ ▀▄▄▄▀ █ ▗▞▀▜▌
12
+ █ ▝▚▄▟▌`,
13
+ `
14
+ oo dP
15
+ 88
16
+ dP .dP .d8888b. dP .d888b88
17
+ 88 d8' 88' \`88 88 88' \`88
18
+ 88 .88' 88. .88 88 88. .88
19
+ 8888P' \`88888P' dP \`88888P8`,
20
+ `
21
+ _ __
22
+ _ ______ (__)___/ /
23
+ | | / / __ \\/ / __ /
24
+ | |/ / /_/ / / /_/ /
25
+ |___/\\____/_/\\__,_/`
26
+ ];
27
+ //#endregion
28
+ //#region src/cli/operator-args.ts
29
+ const operatorCommands = [
30
+ {
31
+ group: "auth",
32
+ action: "login",
33
+ description: "Sign in as a platform administrator",
34
+ path: "/session",
35
+ values: { provider: "OAuth provider" },
36
+ booleans: ["token-stdin"]
37
+ },
38
+ {
39
+ group: "auth",
40
+ action: "logout",
41
+ description: "Revoke the current operator session and remove its local credential",
42
+ path: "/session/logout"
43
+ },
44
+ {
45
+ group: "auth",
46
+ action: "status",
47
+ description: "Inspect operator identity, expiry, and capabilities",
48
+ path: "/session"
49
+ },
50
+ {
51
+ group: "auth",
52
+ action: "token",
53
+ description: "Print an operator token; exchange an API session with --token-stdin",
54
+ path: "/session",
55
+ booleans: ["token-stdin"]
56
+ },
57
+ {
58
+ group: "user",
59
+ action: "list",
60
+ description: "List users",
61
+ path: "/users",
62
+ values: { search: "Search login or email" }
63
+ },
64
+ {
65
+ group: "user",
66
+ action: "show",
67
+ description: "Inspect a user, usage, and projects",
68
+ path: "/users/:id",
69
+ positional: ["id"]
70
+ },
71
+ {
72
+ group: "user",
73
+ action: "plan",
74
+ description: "Change a user plan",
75
+ path: "/users/:id/plan",
76
+ positional: ["id", "plan"],
77
+ method: "POST"
78
+ },
79
+ {
80
+ group: "user",
81
+ action: "suspend",
82
+ description: "Suspend a user and their projects",
83
+ path: "/users/:id/suspend",
84
+ positional: ["id"],
85
+ values: { reason: "Reason for suspension" },
86
+ method: "POST"
87
+ },
88
+ {
89
+ group: "user",
90
+ action: "restore",
91
+ description: "Restore a suspended user",
92
+ path: "/users/:id/restore",
93
+ positional: ["id"],
94
+ method: "POST"
95
+ },
96
+ {
97
+ group: "user",
98
+ action: "delete",
99
+ description: "Delete a user and all owned resources",
100
+ path: "/users/:id/delete",
101
+ positional: ["id"],
102
+ method: "POST"
103
+ },
104
+ {
105
+ group: "project",
106
+ action: "list",
107
+ description: "List tenant projects",
108
+ path: "/projects",
109
+ values: {
110
+ user: "Owner user ID",
111
+ search: "Search projects"
112
+ }
113
+ },
114
+ {
115
+ group: "project",
116
+ action: "show",
117
+ description: "Inspect a project and its resources",
118
+ path: "/projects/:id",
119
+ positional: ["id"]
120
+ },
121
+ {
122
+ group: "project",
123
+ action: "delete",
124
+ description: "Delete a project and its resources",
125
+ path: "/projects/:id/delete",
126
+ positional: ["id"],
127
+ method: "POST"
128
+ },
129
+ {
130
+ group: "project",
131
+ action: "owner",
132
+ description: "Transfer project ownership to another registered user",
133
+ path: "/projects/:id/owner",
134
+ positional: ["id", "userId"],
135
+ method: "POST"
136
+ },
137
+ {
138
+ group: "deployment",
139
+ action: "list",
140
+ description: "List tenant deployments",
141
+ path: "/deployments",
142
+ values: {
143
+ project: "Project ID",
144
+ search: "Search deployments",
145
+ status: "Deployment status"
146
+ }
147
+ },
148
+ {
149
+ group: "deployment",
150
+ action: "show",
151
+ description: "Inspect a deployment",
152
+ path: "/deployments/:id",
153
+ positional: ["id"]
154
+ },
155
+ {
156
+ group: "deployment",
157
+ action: "cancel",
158
+ description: "Cancel a deployment",
159
+ path: "/deployments/:id/cancel",
160
+ positional: ["id"],
161
+ method: "POST"
162
+ },
163
+ {
164
+ group: "deployment",
165
+ action: "logs",
166
+ description: "Read runtime logs (JSON follow emits one object per line)",
167
+ path: "/deployments/:id/logs",
168
+ positional: ["id"],
169
+ values: {
170
+ since: "Duration or ISO timestamp",
171
+ cursor: "Opaque continuation cursor"
172
+ },
173
+ booleans: ["follow"]
174
+ },
175
+ {
176
+ group: "build",
177
+ action: "show",
178
+ description: "Inspect a managed build",
179
+ path: "/builds/:id",
180
+ positional: ["id"]
181
+ },
182
+ {
183
+ group: "build",
184
+ action: "logs",
185
+ description: "Read build logs (JSON follow emits one object per line)",
186
+ path: "/builds/:id/logs",
187
+ positional: ["id"],
188
+ values: { since: "Last received sequence number" },
189
+ booleans: ["follow"]
190
+ },
191
+ {
192
+ group: "signup",
193
+ action: "show",
194
+ description: "Inspect signup restrictions and allowlist",
195
+ path: "/signup"
196
+ },
197
+ {
198
+ group: "signup",
199
+ action: "restrict",
200
+ description: "Restrict signup to the allowlist",
201
+ path: "/signup/restrict",
202
+ method: "POST"
203
+ },
204
+ {
205
+ group: "signup",
206
+ action: "open",
207
+ description: "Open public signup",
208
+ path: "/signup/open",
209
+ method: "POST"
210
+ },
211
+ {
212
+ group: "signup",
213
+ action: "allow",
214
+ description: "Add a GitHub, email, or exact login identity grant",
215
+ path: "/signup/allow",
216
+ positional: ["type", "pattern"],
217
+ usage: ["void platform signup allow <github|email> <pattern> [options]", "void platform signup allow identity <connection-id> <subject> [options]"],
218
+ values: { note: "Allowlist note" },
219
+ method: "POST"
220
+ },
221
+ {
222
+ group: "signup",
223
+ action: "disallow",
224
+ description: "Remove a GitHub, email, or exact login identity grant",
225
+ path: "/signup/disallow",
226
+ positional: ["type", "pattern"],
227
+ usage: ["void platform signup disallow <github|email> <pattern> [options]", "void platform signup disallow identity <connection-id> <subject> [options]"],
228
+ method: "POST"
229
+ },
230
+ {
231
+ group: "signup",
232
+ action: "remove",
233
+ description: "Remove a GitHub or email allowlist pattern (compatibility alias)",
234
+ path: "/signup/remove",
235
+ positional: ["type", "pattern"],
236
+ method: "POST"
237
+ },
238
+ {
239
+ group: "invitation",
240
+ action: "list",
241
+ description: "List invitations",
242
+ path: "/invitations"
243
+ },
244
+ {
245
+ group: "invitation",
246
+ action: "send",
247
+ description: "Send invitations to comma-separated email addresses",
248
+ path: "/invitations/send",
249
+ positional: ["emails"],
250
+ method: "POST"
251
+ },
252
+ {
253
+ group: "invitation",
254
+ action: "revoke",
255
+ description: "Revoke an invitation",
256
+ path: "/invitations/:id/revoke",
257
+ positional: ["id"],
258
+ method: "POST"
259
+ },
260
+ {
261
+ group: "system",
262
+ action: "overview",
263
+ description: "Inspect platform usage and capacity",
264
+ path: "/system/overview"
265
+ },
266
+ {
267
+ group: "system",
268
+ action: "health",
269
+ description: "Check platform health",
270
+ path: "/system/health"
271
+ },
272
+ {
273
+ group: "system",
274
+ action: "cli-versions",
275
+ description: "Inspect CLI version adoption and deployment statistics",
276
+ path: "/system/cli-versions"
277
+ },
278
+ {
279
+ group: "system",
280
+ action: "events",
281
+ description: "List operator audit events",
282
+ path: "/system/events"
283
+ },
284
+ {
285
+ group: "system",
286
+ action: "backfill-queue-tokens",
287
+ description: "Repair missing queue authentication tokens",
288
+ path: "/system/backfill-queue-tokens",
289
+ method: "POST"
290
+ },
291
+ {
292
+ group: "system",
293
+ action: "sandbox-drain",
294
+ description: "Drain and verify managed Sandbox container applications",
295
+ path: "/system/sandbox-drain",
296
+ values: { cursor: "Opaque cursor returned by --plan" },
297
+ method: "POST"
298
+ },
299
+ {
300
+ group: "email",
301
+ action: "policy",
302
+ description: "Show the recipient policy for the shared sender",
303
+ path: "/email/policy"
304
+ },
305
+ {
306
+ group: "email",
307
+ action: "policy-set",
308
+ description: "Set the recipient policy: verified, domains, or any",
309
+ path: "/email/policy",
310
+ positional: ["mode"],
311
+ values: { domains: "Comma-separated recipient domains for mode=domains" },
312
+ method: "POST"
313
+ },
314
+ {
315
+ group: "email",
316
+ action: "settings",
317
+ description: "Show platform email settings",
318
+ path: "/email/settings"
319
+ },
320
+ {
321
+ group: "email",
322
+ action: "settings-set",
323
+ description: "Set who manages email domains: self-serve or admin",
324
+ path: "/email/settings",
325
+ values: { domains: "self-serve or admin" },
326
+ method: "POST"
327
+ },
328
+ {
329
+ group: "email",
330
+ action: "limit",
331
+ description: "Set a project's monthly and burst recipient submission caps",
332
+ path: "/email/projects/:project/limit",
333
+ positional: ["project"],
334
+ values: {
335
+ monthly: "Recipient submissions per UTC calendar month",
336
+ burst: "Recipient submissions per rolling 60-second window"
337
+ },
338
+ method: "POST"
339
+ },
340
+ {
341
+ group: "email",
342
+ action: "logs",
343
+ description: "Inspect retained email receipt and recipient outcomes for a project",
344
+ path: "/email/projects/:project/logs",
345
+ positional: ["project"]
346
+ },
347
+ {
348
+ group: "email",
349
+ action: "attempts",
350
+ description: "List unresolved email send attempts awaiting operator reconciliation",
351
+ path: "/email/attempts",
352
+ values: { project: "Project id or slug" }
353
+ },
354
+ {
355
+ group: "email",
356
+ action: "attempt-resolve",
357
+ description: "Resolve a stopped send as outcome unknown and release its cleanup fence",
358
+ path: "/email/attempts/:id/resolve",
359
+ positional: ["id"],
360
+ values: { reason: "Audit reason without recipient or message content" },
361
+ booleans: ["ended"],
362
+ method: "POST"
363
+ },
364
+ {
365
+ group: "email",
366
+ action: "operation-resolve",
367
+ description: "Resolve an ended ambiguous email setup write with operator attestation",
368
+ path: "/email/operations/:id/resolve",
369
+ positional: ["id"],
370
+ values: {
371
+ outcome: "Provider outcome: applied or not-applied",
372
+ reason: "Audit reason for the verified provider outcome"
373
+ },
374
+ booleans: ["ended"],
375
+ method: "POST"
376
+ },
377
+ {
378
+ group: "email",
379
+ action: "domains",
380
+ description: "List email domains registered on this platform",
381
+ path: "/email/domains",
382
+ values: { project: "Project id or slug" }
383
+ },
384
+ {
385
+ group: "email",
386
+ action: "domain-add",
387
+ description: "Register an email domain for a project with the platform credential",
388
+ path: "/email/domains",
389
+ positional: ["domain"],
390
+ values: { project: "Project id or slug" },
391
+ booleans: ["token-stdin"],
392
+ method: "POST"
393
+ },
394
+ {
395
+ group: "email",
396
+ action: "domain-status",
397
+ description: "Inspect an email domain's setup, credential and relay",
398
+ path: "/email/domains/:domain",
399
+ positional: ["domain"]
400
+ },
401
+ {
402
+ group: "email",
403
+ action: "domain-sync",
404
+ description: "Reconcile an email domain with its Cloudflare setup",
405
+ path: "/email/domains/:domain/sync",
406
+ positional: ["domain"],
407
+ method: "POST"
408
+ },
409
+ {
410
+ group: "email",
411
+ action: "domain-rotate-secret",
412
+ description: "Rotate an email domain's ingress secret",
413
+ path: "/email/domains/:domain/rotate-secret",
414
+ positional: ["domain"],
415
+ method: "POST"
416
+ },
417
+ {
418
+ group: "email",
419
+ action: "domain-remove",
420
+ description: "Remove an email domain and its Cloudflare setup",
421
+ path: "/email/domains/:domain/remove",
422
+ positional: ["domain"],
423
+ booleans: ["token-stdin"],
424
+ method: "POST"
425
+ },
426
+ {
427
+ group: "worker",
428
+ action: "list",
429
+ description: "List hosted platform workers",
430
+ path: "/workers",
431
+ values: { environment: "production or staging" }
432
+ },
433
+ {
434
+ group: "worker",
435
+ action: "show",
436
+ description: "Inspect hosted worker versions",
437
+ path: "/workers/:id",
438
+ positional: ["id"],
439
+ values: { environment: "production or staging" }
440
+ },
441
+ {
442
+ group: "worker",
443
+ action: "rollback",
444
+ description: "Roll back a hosted worker to a version",
445
+ path: "/workers/:id/rollback",
446
+ positional: ["id", "versionId"],
447
+ values: { environment: "production or staging" },
448
+ method: "POST"
449
+ },
450
+ {
451
+ group: "worker",
452
+ action: "rollback-all",
453
+ description: "Roll back all hosted workers to their previous versions",
454
+ path: "/workers/rollback-all",
455
+ values: { environment: "production or staging" },
456
+ method: "POST"
457
+ },
458
+ {
459
+ group: "worker",
460
+ action: "events",
461
+ description: "List hosted worker events or inspect a batch",
462
+ path: "/workers/events",
463
+ positional: ["batchId"],
464
+ optionalPositional: true,
465
+ values: { environment: "production or staging" }
466
+ }
467
+ ];
468
+ const operatorGroups = [...new Set(operatorCommands.map(({ group }) => group))];
469
+ function parseOperatorArgs(args) {
470
+ const positional = [];
471
+ const values = {};
472
+ const flags = /* @__PURE__ */ new Set();
473
+ const booleanFlags = /* @__PURE__ */ new Set([
474
+ "json",
475
+ "plan",
476
+ "yes",
477
+ "follow",
478
+ "token-stdin",
479
+ "force",
480
+ "ended"
481
+ ]);
482
+ for (let index = 0; index < args.length; index++) {
483
+ const arg = args[index];
484
+ if (!arg.startsWith("-")) {
485
+ positional.push(arg);
486
+ continue;
487
+ }
488
+ if (!arg.startsWith("--")) throw new Error(`platform: Unknown flag '${arg}'.`);
489
+ const flag = arg.slice(2);
490
+ if (flags.has(flag) || Object.hasOwn(values, flag)) throw new Error(`platform: Duplicate flag '${arg}'.`);
491
+ if (booleanFlags.has(flag)) flags.add(flag);
492
+ else {
493
+ const value = args[++index];
494
+ if (!value || value.startsWith("-")) throw new Error(`platform: ${arg} requires a value.`);
495
+ values[flag] = value;
496
+ }
497
+ }
498
+ const [group = "", action = "", ...parameters] = positional;
499
+ if (!operatorGroups.includes(group)) throw new Error("platform: Unknown operator command group.");
500
+ const parsed = {
501
+ subcommand: "operator",
502
+ group,
503
+ action,
504
+ connection: values.connection ?? "",
505
+ json: flags.has("json"),
506
+ plan: flags.has("plan"),
507
+ yes: flags.has("yes"),
508
+ follow: flags.has("follow"),
509
+ tokenStdin: flags.has("token-stdin"),
510
+ provider: values.provider ?? "github",
511
+ ...values.provider ? { providerExplicit: true } : {},
512
+ method: "GET",
513
+ path: "",
514
+ query: {},
515
+ body: {}
516
+ };
517
+ if (!action && args.length === 1) return parsed;
518
+ const command = operatorCommands.find((entry) => entry.group === group && entry.action === action);
519
+ if (!command) throw new Error(`platform: Usage: void platform ${group} <${operatorCommands.filter((entry) => entry.group === group).map(({ action }) => action).join("|")}>.`);
520
+ const count = command.positional?.length ?? 0;
521
+ const identitySignupEntry = group === "signup" && ["allow", "disallow"].includes(action) && parameters[0] === "identity";
522
+ if (group === "signup" && action === "remove" && parameters[0] === "identity") throw new Error("platform: Use `void platform signup disallow identity <connection-id> <subject>`.");
523
+ const expectedCount = identitySignupEntry ? 3 : count;
524
+ if (parameters.length > expectedCount || !command.optionalPositional && parameters.length !== expectedCount) throw new Error(`platform: Usage: ${command.usage?.[identitySignupEntry ? 1 : 0]?.replace(/ \[options\]$/, "") ?? `void platform ${group} ${action}${command.positional?.map((name) => ` <${name}>`).join("") ?? ""}`}.`);
525
+ const paged = action === "list" || action === "events" || action === "logs" || action === "attempts";
526
+ const allowed = /* @__PURE__ */ new Set([
527
+ "connection",
528
+ ...command.method ? ["timeout"] : [],
529
+ ...Object.keys(command.values ?? {}),
530
+ ...paged ? ["limit", ...action !== "logs" || group === "email" ? ["page"] : []] : []
531
+ ]);
532
+ for (const name of Object.keys(values)) if (!allowed.has(name)) throw new Error(`platform: Unknown flag '--${name}' for ${group} ${action}.`);
533
+ for (const name of flags) if (![
534
+ "json",
535
+ ...command.method ? ["yes", "plan"] : [],
536
+ ...command.booleans ?? []
537
+ ].includes(name)) throw new Error(`platform: Unknown flag '--${name}' for ${group} ${action}.`);
538
+ if (parsed.plan && parsed.yes) throw new Error("platform: --plan and --yes cannot be combined.");
539
+ parsed.path = command.path;
540
+ parsed.method = command.method ?? "GET";
541
+ if (identitySignupEntry) {
542
+ const connectionId = parameters[1];
543
+ const subject = parameters[2];
544
+ if (!/^[a-z][a-z0-9-]{0,63}$/.test(connectionId)) throw new Error("platform: Invalid login connection ID.");
545
+ if (!subject || subject.length > 255) throw new Error("platform: Identity subject must be 1–255 characters.");
546
+ parsed.body = {
547
+ type: "identity",
548
+ connectionId,
549
+ subject
550
+ };
551
+ } else for (const [index, name] of (command.positional ?? []).entries()) {
552
+ const value = parameters[index];
553
+ if (value === void 0) continue;
554
+ if (value === "." || value === "..") throw new Error("platform: An object ID cannot be a dot path segment.");
555
+ if (parsed.path.includes(`:${name}`)) parsed.path = parsed.path.replace(`:${name}`, encodeURIComponent(value));
556
+ else if (group === "worker" && action === "events") parsed.path += `/${encodeURIComponent(value)}`;
557
+ else parsed.body[name] = name === "emails" ? value.split(",").map((email) => email.trim()) : value;
558
+ }
559
+ for (const [name, value] of Object.entries(values)) {
560
+ if (name === "connection" || name === "provider") continue;
561
+ if (name === "timeout") {
562
+ const maximum = OPERATOR_MAX_TIMEOUT_MS / 1e3;
563
+ if (!/^[1-9]\d*$/.test(value) || Number(value) > maximum) throw new Error(`platform: --timeout must be an integer from 1 to ${maximum} seconds.`);
564
+ parsed.timeoutMs = Number(value) * 1e3;
565
+ continue;
566
+ }
567
+ if (name === "page" || name === "limit") {
568
+ const maximum = name === "limit" ? action === "logs" && group !== "email" ? 500 : 100 : 1e6;
569
+ if (!/^[1-9]\d*$/.test(value) || Number(value) > maximum) throw new Error(`platform: --${name} must be an integer from 1 to ${maximum}.`);
570
+ }
571
+ if (name === "since" && group === "build" && (!/^\d+$/.test(value) || !Number.isSafeInteger(Number(value)))) throw new Error("platform: --since must be a nonnegative safe integer for build logs.");
572
+ if (name === "environment" && !["production", "staging"].includes(value)) throw new Error("platform: --environment must be production or staging.");
573
+ if (parsed.method === "POST") parsed.body[name] = value;
574
+ else parsed.query[name] = value;
575
+ }
576
+ if (parsed.body.type && ![
577
+ "github",
578
+ "email",
579
+ "identity"
580
+ ].includes(String(parsed.body.type))) throw new Error("platform: Signup grant type must be github, email, or identity.");
581
+ for (const name of command.booleans ?? []) if (name !== "token-stdin" && flags.has(name)) parsed.body[name] = true;
582
+ return parsed;
583
+ }
584
+ //#endregion
585
+ //#region src/cli/help.ts
586
+ var help_exports = /* @__PURE__ */ __exportAll({
587
+ getHelpPath: () => getHelpPath,
588
+ printGlobalHelp: () => printGlobalHelp,
589
+ printHelpPage: () => printHelpPage,
590
+ printVoidHeader: () => printVoidHeader
591
+ });
592
+ function operatorHelpTree() {
593
+ return Object.fromEntries(operatorGroups.map((group) => {
594
+ const commands = operatorCommands.filter((entry) => entry.group === group);
595
+ return [group, {
596
+ summary: `Administer platform ${group}. Operator credentials are separate from deployment credentials.`,
597
+ usage: [`void platform ${group} <command> [options]`],
598
+ commands: commands.map((entry) => ({
599
+ command: entry.action,
600
+ description: entry.description
601
+ })),
602
+ children: Object.fromEntries(commands.map((entry) => [entry.action, {
603
+ summary: `${entry.description}.`,
604
+ usage: entry.usage ?? [`void platform ${group} ${entry.action}${entry.positional?.map((name) => entry.optionalPositional ? ` [${name}]` : ` <${name}>`).join("") ?? ""} [options]`],
605
+ options: [
606
+ {
607
+ command: "--connection <id-or-url>",
608
+ description: "Choose a registered connection; otherwise use VOID_API_URL or the active connection"
609
+ },
610
+ {
611
+ command: "--json",
612
+ description: "Write structured JSON to stdout (JSON Lines while following logs)"
613
+ },
614
+ ...entry.method ? [
615
+ {
616
+ command: "--plan",
617
+ description: "Validate and preview without changing anything"
618
+ },
619
+ {
620
+ command: "--yes",
621
+ description: "Apply after preview without prompting; required in unattended scripts"
622
+ },
623
+ {
624
+ command: "--timeout <seconds>",
625
+ description: "Mutation deadline (default 300 seconds; maximum 3600 seconds)"
626
+ }
627
+ ] : [],
628
+ ...[
629
+ "list",
630
+ "events",
631
+ "logs",
632
+ "attempts"
633
+ ].includes(entry.action) ? [{
634
+ command: "--limit <number>",
635
+ description: entry.action === "logs" && group !== "email" ? "Maximum 500 log records" : "Maximum 100 records per page"
636
+ }, ...entry.action !== "logs" || group === "email" ? [{
637
+ command: "--page <number>",
638
+ description: "One-based page number"
639
+ }] : []] : [],
640
+ ...Object.entries(entry.values ?? {}).map(([flag, description]) => ({
641
+ command: `--${flag} <value>`,
642
+ description
643
+ })),
644
+ ...(entry.booleans ?? []).map((flag) => ({
645
+ command: `--${flag}`,
646
+ description: flag === "follow" ? "Poll new logs until interrupted or the build ends" : flag === "ended" ? "Attest that the original provider execution has ended" : flag === "token-stdin" && group === "email" ? entry.action === "domain-remove" ? "Read a replacement Cloudflare token for blocked project cleanup from stdin" : "Read a scoped Cloudflare API token from stdin" : "Read a full API session from stdin for explicit operator session exchange"
647
+ }))
648
+ ]
649
+ }]))
650
+ }];
651
+ }));
652
+ }
653
+ const HELP_TREE = {
654
+ connect: {
655
+ summary: "Connect this project to Cloudflare or an existing Void platform.",
656
+ usage: ["void connect [url] [--platform <cloudflare|void>] [--no-login]"],
657
+ options: [{
658
+ command: "--platform <cloudflare|void>",
659
+ description: "Choose the deployment destination"
660
+ }, {
661
+ command: "--no-login",
662
+ description: "Save a Void connection without authenticating"
663
+ }],
664
+ examples: [
665
+ {
666
+ command: "void connect",
667
+ description: "Choose a destination and sign in"
668
+ },
669
+ {
670
+ command: "void connect https://platform.example.com",
671
+ description: "Join a Void platform"
672
+ },
673
+ {
674
+ command: "void connect --platform cloudflare",
675
+ description: "Sign in and select a Cloudflare account"
676
+ }
677
+ ]
678
+ },
679
+ init: {
680
+ summary: "Set up Void in a new or existing project.",
681
+ usage: ["void init [options]"],
682
+ options: [
683
+ {
684
+ command: "--agents",
685
+ description: "Set up agent instructions and skills"
686
+ },
687
+ {
688
+ command: "--tsconfig",
689
+ description: "Only update tsconfig.json"
690
+ },
691
+ {
692
+ command: "--git",
693
+ description: "Initialize a Git repository without prompting"
694
+ },
695
+ {
696
+ command: "--no-git",
697
+ description: "Skip Git repository initialization"
698
+ },
699
+ {
700
+ command: "--github",
701
+ description: "Only create the GitHub Actions deploy workflow (OIDC, no stored token)"
702
+ }
703
+ ],
704
+ examples: [
705
+ {
706
+ command: "void init",
707
+ description: "Scaffold or configure the current project"
708
+ },
709
+ {
710
+ command: "void init --agents",
711
+ description: "Install agent instructions and skills"
712
+ },
713
+ {
714
+ command: "void init --github",
715
+ description: "Scaffold the GitHub Actions deploy workflow"
716
+ }
717
+ ]
718
+ },
719
+ deploy: {
720
+ summary: "Build and deploy. Offers to link an existing Cloudflare Worker when no destination is configured.",
721
+ usage: ["void deploy [options]"],
722
+ options: [
723
+ {
724
+ command: "--project <name>",
725
+ description: "Deploy target project name"
726
+ },
727
+ {
728
+ command: "--dir <path>",
729
+ description: "Deploy a static directory and skip build"
730
+ },
731
+ {
732
+ command: "--spa",
733
+ description: "Use SPA mode for static deploys"
734
+ },
735
+ {
736
+ command: "--skip-build",
737
+ description: "Skip the build step and use existing output (static deploys on Cloudflare)"
738
+ },
739
+ {
740
+ command: "--platform <cloudflare|void>",
741
+ description: "Override the platform saved by void init"
742
+ },
743
+ {
744
+ command: "--require-email",
745
+ description: "Fail instead of deploying without email when the mail domain is not set up (with --platform cloudflare)"
746
+ },
747
+ {
748
+ command: "--debug",
749
+ description: "Mirror the deploy log to stderr (always written to ~/.void/logs)"
750
+ }
751
+ ],
752
+ examples: [
753
+ {
754
+ command: "void deploy",
755
+ description: "Deploy the linked project"
756
+ },
757
+ {
758
+ command: "void deploy --project my-app",
759
+ description: "Deploy to a specific project"
760
+ },
761
+ {
762
+ command: "void deploy --dir dist --spa",
763
+ description: "Deploy a static SPA directory"
764
+ },
765
+ {
766
+ command: "void deploy --platform cloudflare",
767
+ description: "Deploy to your own Cloudflare account"
768
+ }
769
+ ]
770
+ },
771
+ auth: {
772
+ summary: "Log in, link login methods, log out, and inspect local auth state.",
773
+ usage: ["void auth <command>"],
774
+ commands: [
775
+ {
776
+ command: "login",
777
+ description: "Log in with an enabled platform login method"
778
+ },
779
+ {
780
+ command: "link [connection-id]",
781
+ description: "Link another login method to your account"
782
+ },
783
+ {
784
+ command: "logout",
785
+ description: "Log out and remove credentials"
786
+ },
787
+ {
788
+ command: "whoami",
789
+ description: "Show the logged-in username"
790
+ },
791
+ {
792
+ command: "token",
793
+ description: "Copy auth token to clipboard"
794
+ }
795
+ ],
796
+ children: {
797
+ login: basicSubcommand("Log in with an enabled platform login method.", "void auth login"),
798
+ link: basicSubcommand("Sign in again, then verify and link another login method to your existing account.", "void auth link [connection-id]"),
799
+ logout: basicSubcommand("Log out and remove credentials.", "void auth logout"),
800
+ whoami: basicSubcommand("Show the logged-in username.", "void auth whoami"),
801
+ token: basicSubcommand("Copy auth token to clipboard.", "void auth token")
802
+ }
803
+ },
804
+ cloudflare: {
805
+ summary: "Manage Cloudflare authentication used by Void.",
806
+ usage: ["void cloudflare <command>"],
807
+ commands: [
808
+ {
809
+ command: "login",
810
+ description: "Sign in or switch users with browser OAuth"
811
+ },
812
+ {
813
+ command: "status",
814
+ description: "Show identity, authentication, and the deployment account"
815
+ },
816
+ {
817
+ command: "logout",
818
+ description: "Remove the local browser session"
819
+ }
820
+ ],
821
+ children: {
822
+ login: basicSubcommand("Sign in again or switch Cloudflare users with browser OAuth.", "void cloudflare login"),
823
+ status: basicSubcommand("Show Cloudflare identity, authentication, accessible accounts, and the pinned deployment account.", "void cloudflare status"),
824
+ logout: basicSubcommand("Remove the local browser session.", "void cloudflare logout")
825
+ }
826
+ },
827
+ platform: {
828
+ summary: "Install Void platforms and administer users, projects, access, and operations. Use `void connect` to join one.",
829
+ usage: ["void platform <command>"],
830
+ commands: [
831
+ ...operatorGroups.map((group) => ({
832
+ command: `${group} <command>`,
833
+ description: `Administer platform ${group}`
834
+ })),
835
+ {
836
+ command: "config auth [command]",
837
+ description: "Configure login methods, company protection, and provider recovery"
838
+ },
839
+ {
840
+ command: "list",
841
+ description: "List installed and connected platforms"
842
+ },
843
+ {
844
+ command: "use [id]",
845
+ description: "Select the default Void platform"
846
+ },
847
+ {
848
+ command: "status [id]",
849
+ description: "Inspect a platform and its health"
850
+ },
851
+ {
852
+ command: "discover",
853
+ description: "Recover installations from a Cloudflare account"
854
+ },
855
+ {
856
+ command: "domain set <domain>",
857
+ description: "Add an application domain to a test platform"
858
+ },
859
+ {
860
+ command: "install",
861
+ description: "Install a Void platform in Cloudflare"
862
+ },
863
+ {
864
+ command: "upgrade [id]",
865
+ description: "Upgrade an installed Void platform"
866
+ },
867
+ {
868
+ command: "rollback [id]",
869
+ description: "Restore a compatible earlier platform runtime"
870
+ },
871
+ {
872
+ command: "repair [id]",
873
+ description: "Reconcile an installed Void platform"
874
+ },
875
+ {
876
+ command: "disable [id]",
877
+ description: "Disable traffic without deleting data"
878
+ },
879
+ {
880
+ command: "enable [id]",
881
+ description: "Restore traffic for a disabled platform"
882
+ },
883
+ {
884
+ command: "uninstall [id]",
885
+ description: "Safely remove an installed Void platform"
886
+ }
887
+ ],
888
+ children: {
889
+ ...operatorHelpTree(),
890
+ config: {
891
+ summary: "Configure platform settings.",
892
+ usage: ["void platform config auth [command] [options]"],
893
+ children: { auth: {
894
+ summary: "Manage login methods and independent platform protection. Without a command, opens interactive configuration.",
895
+ usage: ["void platform config auth [list|show|initialize|add|configure|test|enable|disable|link|admission|protection|recover] [method-or-action] [options]"],
896
+ commands: [
897
+ {
898
+ command: "list",
899
+ description: "List configured login methods and platform protection"
900
+ },
901
+ {
902
+ command: "show <id>",
903
+ description: "Inspect a login method without displaying secrets"
904
+ },
905
+ {
906
+ command: "initialize",
907
+ description: "Import existing login settings before first configuration"
908
+ },
909
+ {
910
+ command: "add <github|google|oidc|cloudflare-access>",
911
+ description: "Configure a new login method"
912
+ },
913
+ {
914
+ command: "configure <id>",
915
+ description: "Stage an update to a login method"
916
+ },
917
+ {
918
+ command: "test <id>",
919
+ description: "Verify a login configuration in the browser"
920
+ },
921
+ {
922
+ command: "enable <id>",
923
+ description: "Enable a successfully tested configuration"
924
+ },
925
+ {
926
+ command: "disable <id>",
927
+ description: "Disable a method and revoke its human sessions"
928
+ },
929
+ {
930
+ command: "link <id>",
931
+ description: "Explicitly link a tested identity to your account"
932
+ },
933
+ {
934
+ command: "admission",
935
+ description: "Choose invited, company-approved, or public signup"
936
+ },
937
+ {
938
+ command: "protection <enable|disable|show>",
939
+ description: "Create or connect Access protection independently from login"
940
+ },
941
+ {
942
+ command: "recover <id>",
943
+ description: "Recover an existing administrator using installation authority"
944
+ }
945
+ ],
946
+ options: [
947
+ {
948
+ command: "--connection <id-or-url>",
949
+ description: "Select a registered platform"
950
+ },
951
+ {
952
+ command: "--installation <id>",
953
+ description: "Select recovery authority for protection or provider recovery"
954
+ },
955
+ {
956
+ command: "--id <id>",
957
+ description: "Name a new OIDC or Access connection"
958
+ },
959
+ {
960
+ command: "--file <path>",
961
+ description: "Read nonsecret configuration from JSON"
962
+ },
963
+ {
964
+ command: "--client-secret-env <name>",
965
+ description: "Read the client secret from an environment variable"
966
+ },
967
+ {
968
+ command: "--test-id <id>",
969
+ description: "Use a completed test for enable or link"
970
+ },
971
+ {
972
+ command: "--plan",
973
+ description: "Validate and preview a change"
974
+ },
975
+ {
976
+ command: "--yes",
977
+ description: "Apply without prompting"
978
+ },
979
+ {
980
+ command: "--json",
981
+ description: "Print structured output"
982
+ }
983
+ ]
984
+ } }
985
+ },
986
+ domain: {
987
+ summary: "Add an application domain while keeping existing workers.dev URLs.",
988
+ usage: ["void platform domain set <domain> [options]"],
989
+ children: { set: {
990
+ summary: "Set up DNS and verify HTTPS before making an application domain canonical. Rerun to resume.",
991
+ usage: ["void platform domain set <domain> [options]"],
992
+ options: [
993
+ {
994
+ command: "--installation <id>",
995
+ description: "Choose an installed platform; otherwise select interactively"
996
+ },
997
+ {
998
+ command: "--zone <domain>",
999
+ description: "Containing Cloudflare zone; detected when it already exists"
1000
+ },
1001
+ {
1002
+ command: "--dedicated-zone",
1003
+ description: "Add catch-all routes for a zone dedicated to this platform"
1004
+ },
1005
+ {
1006
+ command: "--plan",
1007
+ description: "Preview without making changes"
1008
+ },
1009
+ {
1010
+ command: "--yes",
1011
+ description: "Apply without an interactive confirmation"
1012
+ }
1013
+ ]
1014
+ } }
1015
+ },
1016
+ list: basicSubcommand("List installed and connected platforms.", "void platform list"),
1017
+ use: basicSubcommand("Select the default Void platform.", "void platform use [id]"),
1018
+ status: basicSubcommand("Inspect a platform and its health.", "void platform status [id]"),
1019
+ discover: {
1020
+ summary: "Recover owned platform installations from Cloudflare.",
1021
+ usage: ["void platform discover [--account <id>] [--installation <id-or-name>]"],
1022
+ options: [{
1023
+ command: "--account <id>",
1024
+ description: "Cloudflare account id"
1025
+ }, {
1026
+ command: "--installation <id-or-name>",
1027
+ description: "Recover only one installation from a shared account"
1028
+ }]
1029
+ },
1030
+ install: {
1031
+ summary: "Install or resume a Void platform with a domain, or workers.dev for testing.",
1032
+ usage: ["void platform install [options]"],
1033
+ options: [
1034
+ {
1035
+ command: "--auth-config <path>",
1036
+ description: "Read login methods and signup policy from nonsecret JSON with environment secret references"
1037
+ },
1038
+ {
1039
+ command: "--name <slug>",
1040
+ description: "Installation name"
1041
+ },
1042
+ {
1043
+ command: "--workers-dev",
1044
+ description: "Use workers.dev for testing; add a domain later"
1045
+ },
1046
+ {
1047
+ command: "--display-name <name>",
1048
+ description: "Human-readable platform name"
1049
+ },
1050
+ {
1051
+ command: "--account <id>",
1052
+ description: "Cloudflare account id"
1053
+ },
1054
+ {
1055
+ command: "--application-domain <domain>",
1056
+ description: "Base domain for applications (zone apex is simplest)"
1057
+ },
1058
+ {
1059
+ command: "--zone <domain>",
1060
+ description: "Cloudflare zone containing the app domain"
1061
+ },
1062
+ {
1063
+ command: "--dedicated-zone",
1064
+ description: "Allow zone-wide application catch-all routes"
1065
+ },
1066
+ {
1067
+ command: "--control-plane-domain <domain>",
1068
+ description: "Optional API hostname"
1069
+ },
1070
+ {
1071
+ command: "--plan",
1072
+ description: "Print the exact plan without changing Cloudflare"
1073
+ },
1074
+ {
1075
+ command: "--resume",
1076
+ description: "Resume the matching local installation"
1077
+ },
1078
+ {
1079
+ command: "--runtime <path>",
1080
+ description: "Deploy an integrity-checked runtime directory instead of the package"
1081
+ },
1082
+ {
1083
+ command: "--yes",
1084
+ description: "Acknowledge changes without an interactive prompt"
1085
+ }
1086
+ ]
1087
+ },
1088
+ upgrade: lifecycleHelp("upgrade", "Upgrade an installed platform without deleting resources."),
1089
+ rollback: {
1090
+ summary: "Restore a compatible earlier runtime without reversing database migrations.",
1091
+ usage: ["void platform rollback [id] --runtime <earlier-path> [--from-runtime <current-path>] [--plan] [--yes]"],
1092
+ options: [
1093
+ {
1094
+ command: "--runtime <path>",
1095
+ description: "Earlier compatible runtime to restore"
1096
+ },
1097
+ {
1098
+ command: "--from-runtime <path>",
1099
+ description: "Current installed runtime when it differs from the packaged runtime"
1100
+ },
1101
+ {
1102
+ command: "--plan",
1103
+ description: "Print the exact plan without making changes"
1104
+ },
1105
+ {
1106
+ command: "--yes",
1107
+ description: "Acknowledge non-interactive Cloudflare changes"
1108
+ }
1109
+ ]
1110
+ },
1111
+ repair: lifecycleHelp("repair", "Reconcile drift using the installation ownership manifest."),
1112
+ disable: lifecycleHelp("disable", "Disable platform traffic without deleting data."),
1113
+ enable: lifecycleHelp("enable", "Restore configured traffic for a disabled platform."),
1114
+ uninstall: {
1115
+ summary: "Safely remove installer-owned platform resources.",
1116
+ usage: ["void platform uninstall [id] [options]"],
1117
+ options: [
1118
+ {
1119
+ command: "--plan",
1120
+ description: "Print the exact deletion and retention plan"
1121
+ },
1122
+ {
1123
+ command: "--yes",
1124
+ description: "Acknowledge changes without an interactive prompt"
1125
+ },
1126
+ {
1127
+ command: "--purge-data",
1128
+ description: "Delete installer-owned data even when it contains apps"
1129
+ },
1130
+ {
1131
+ command: "--keep-zone",
1132
+ description: "Explicitly retain an installer-created zone"
1133
+ }
1134
+ ]
1135
+ }
1136
+ }
1137
+ },
1138
+ project: {
1139
+ summary: "Manage Void projects and deployments.",
1140
+ usage: ["void project <command>"],
1141
+ commands: [
1142
+ {
1143
+ command: "status [name]",
1144
+ description: "Show deployments for a project"
1145
+ },
1146
+ {
1147
+ command: "link [name]",
1148
+ description: "Link this directory to a project"
1149
+ },
1150
+ {
1151
+ command: "list",
1152
+ description: "List your projects"
1153
+ },
1154
+ {
1155
+ command: "token <command>",
1156
+ description: "Manage project-scoped CI deploy credentials"
1157
+ },
1158
+ {
1159
+ command: "team <command>",
1160
+ description: "Manage members and project invitations"
1161
+ },
1162
+ {
1163
+ command: "logs",
1164
+ description: "Show runtime logs from the deployed project"
1165
+ },
1166
+ {
1167
+ command: "requests",
1168
+ description: "Show request-level traffic (status, method, timing)"
1169
+ },
1170
+ {
1171
+ command: "rollback [deployId]",
1172
+ description: "Roll back to a previous deployment"
1173
+ },
1174
+ {
1175
+ command: "cancel [deployId]",
1176
+ description: "Cancel an active deployment"
1177
+ },
1178
+ {
1179
+ command: "delete [name]",
1180
+ description: "Delete a project and all its resources"
1181
+ },
1182
+ {
1183
+ command: "purge-cache",
1184
+ description: "Purge all cached pages"
1185
+ }
1186
+ ],
1187
+ children: {
1188
+ status: basicSubcommand("Show deployments for a project.", "void project status [name]", "void project status my-app"),
1189
+ link: basicSubcommand("Link this directory to a Void project.", "void project link [name]", "void project link my-app"),
1190
+ list: basicSubcommand("List your projects.", "void project list"),
1191
+ token: {
1192
+ summary: "Manage revocable, project-scoped credentials for CI deploys.",
1193
+ usage: ["void project token <create|list|renew|revoke> [options]"],
1194
+ options: [
1195
+ {
1196
+ command: "--project <name>",
1197
+ description: "Project name override"
1198
+ },
1199
+ {
1200
+ command: "--name <label>",
1201
+ description: "Credential label (create only)"
1202
+ },
1203
+ {
1204
+ command: "--expires-in <days>",
1205
+ description: "Expiry from 1 to 90 days"
1206
+ },
1207
+ {
1208
+ command: "--json",
1209
+ description: "Print machine-readable output"
1210
+ }
1211
+ ],
1212
+ examples: [{
1213
+ command: "void project token create --name github-actions --expires-in 30",
1214
+ description: "Create a CI deploy credential"
1215
+ }, {
1216
+ command: "void project token revoke <id>",
1217
+ description: "Revoke a credential now"
1218
+ }]
1219
+ },
1220
+ team: {
1221
+ summary: "Manage members and invitations for Void platform projects.",
1222
+ usage: ["void project team <command>"],
1223
+ commands: [
1224
+ {
1225
+ command: "list",
1226
+ description: "List project members and roles"
1227
+ },
1228
+ {
1229
+ command: "invite <email>",
1230
+ description: "Invite a registered user by email"
1231
+ },
1232
+ {
1233
+ command: "invitations",
1234
+ description: "List invitations sent for a project"
1235
+ },
1236
+ {
1237
+ command: "role <user-id> <role>",
1238
+ description: "Change a member's role"
1239
+ },
1240
+ {
1241
+ command: "remove <user-id>",
1242
+ description: "Remove a project member"
1243
+ },
1244
+ {
1245
+ command: "revoke <invitation-id>",
1246
+ description: "Revoke a project invitation"
1247
+ },
1248
+ {
1249
+ command: "leave",
1250
+ description: "Leave a shared project"
1251
+ },
1252
+ {
1253
+ command: "pending",
1254
+ description: "List invitations awaiting your response"
1255
+ },
1256
+ {
1257
+ command: "accept <invitation-id>",
1258
+ description: "Accept your invitation"
1259
+ },
1260
+ {
1261
+ command: "decline <invitation-id>",
1262
+ description: "Decline your invitation"
1263
+ }
1264
+ ],
1265
+ children: {
1266
+ list: withProjectOption("List project members and roles.", "void project team list [options]"),
1267
+ invite: {
1268
+ summary: "Invite an existing Void platform user by registered email address.",
1269
+ usage: ["void project team invite <email> --role <role> [options]"],
1270
+ options: [{
1271
+ command: "--role <role>",
1272
+ description: "reader, collaborator, or admin"
1273
+ }, {
1274
+ command: "--project <name>",
1275
+ description: "Project name override"
1276
+ }]
1277
+ },
1278
+ invitations: withProjectOption("List invitations sent for a project.", "void project team invitations [options]"),
1279
+ role: withProjectOption("Change a member's role to reader, collaborator, or admin.", "void project team role <user-id> <role> [options]"),
1280
+ remove: withProjectOption("Remove a member from the project.", "void project team remove <user-id> [options]"),
1281
+ revoke: withProjectOption("Revoke a pending project invitation.", "void project team revoke <invitation-id> [options]"),
1282
+ leave: withProjectOption("Leave a shared project.", "void project team leave [options]"),
1283
+ pending: basicSubcommand("List invitations on the active platform connection (VOID_API_URL overrides it).", "void project team pending"),
1284
+ accept: basicSubcommand("Accept your invitation on the active platform connection, preserving project links.", "void project team accept <invitation-id>"),
1285
+ decline: basicSubcommand("Decline your invitation on the active platform connection (VOID_API_URL overrides it).", "void project team decline <invitation-id>")
1286
+ }
1287
+ },
1288
+ logs: {
1289
+ summary: "Show runtime logs from the deployed project.",
1290
+ usage: ["void project logs [options]"],
1291
+ options: [
1292
+ {
1293
+ command: "--filter <text>",
1294
+ description: "Substring search over log messages"
1295
+ },
1296
+ {
1297
+ command: "--level <level>",
1298
+ description: "Filter by level: error|warn|info|log|debug|all (default: all)"
1299
+ },
1300
+ {
1301
+ command: "--range <range>",
1302
+ description: "Time range to query (default: 1h)"
1303
+ },
1304
+ {
1305
+ command: "--deployment <id>",
1306
+ description: "Limit logs to one deployment"
1307
+ }
1308
+ ],
1309
+ examples: [
1310
+ {
1311
+ command: "void project logs --range 30m",
1312
+ description: "Show recent project logs"
1313
+ },
1314
+ {
1315
+ command: "void project logs --level error",
1316
+ description: "Show only error-level entries and exceptions"
1317
+ },
1318
+ {
1319
+ command: "void project logs --filter websocket",
1320
+ description: "Substring search over log messages"
1321
+ }
1322
+ ]
1323
+ },
1324
+ requests: {
1325
+ summary: "Show request-level traffic (status, method, type, timing). Surfaces 5xx that the edge router generated itself and requests to static/SPA projects that never invoke a worker — neither of which appears in `project logs`.",
1326
+ usage: ["void project requests [options]"],
1327
+ options: [{
1328
+ command: "--status <filter>",
1329
+ description: "Filter by status: a class like 5xx or an exact code like 500"
1330
+ }, {
1331
+ command: "--range <range>",
1332
+ description: "Time range to query (default: 1h)"
1333
+ }],
1334
+ examples: [{
1335
+ command: "void project requests --status 5xx",
1336
+ description: "Show recent server-error responses, including edge-generated ones"
1337
+ }, {
1338
+ command: "void project requests --range 24h",
1339
+ description: "Show all request traffic in the last day"
1340
+ }]
1341
+ },
1342
+ rollback: basicSubcommand("Roll back to a previous deployment.", "void project rollback [deployId]"),
1343
+ cancel: basicSubcommand("Cancel an active deployment.", "void project cancel [deployId]"),
1344
+ delete: {
1345
+ summary: "Delete a project and all its resources.",
1346
+ usage: ["void project delete [name] [options]"],
1347
+ options: [{
1348
+ command: "--force, -f",
1349
+ description: "Delete without confirmation"
1350
+ }],
1351
+ examples: [{
1352
+ command: "void project delete my-app",
1353
+ description: "Delete a project"
1354
+ }]
1355
+ },
1356
+ "purge-cache": {
1357
+ summary: "Purge all cached pages for a project.",
1358
+ usage: ["void project purge-cache [options]"],
1359
+ options: [{
1360
+ command: "--project <name>",
1361
+ description: "Project name override"
1362
+ }]
1363
+ }
1364
+ }
1365
+ },
1366
+ secret: {
1367
+ summary: "Manage production secrets for Void projects.",
1368
+ usage: ["void secret <command>"],
1369
+ commands: [
1370
+ {
1371
+ command: "list",
1372
+ description: "List project secrets"
1373
+ },
1374
+ {
1375
+ command: "put <name>",
1376
+ description: "Set a project secret"
1377
+ },
1378
+ {
1379
+ command: "delete <name>",
1380
+ description: "Delete a project secret"
1381
+ },
1382
+ {
1383
+ command: "sync <file>",
1384
+ description: "Sync secrets from a dotenv file"
1385
+ }
1386
+ ],
1387
+ children: {
1388
+ list: withProjectOption("List project secrets.", "void secret list [options]"),
1389
+ put: withProjectOption("Set a project secret.", "void secret put <name> [options]"),
1390
+ delete: withProjectOption("Delete a project secret.", "void secret delete <name> [options]"),
1391
+ sync: withProjectOption("Sync secrets from a dotenv file.", "void secret sync <file> [options]")
1392
+ }
1393
+ },
1394
+ domain: {
1395
+ summary: "Configure custom domains for Void projects.",
1396
+ usage: ["void domain <command>"],
1397
+ commands: [
1398
+ {
1399
+ command: "add <hostname>",
1400
+ description: "Add a custom domain"
1401
+ },
1402
+ {
1403
+ command: "delete <hostname>",
1404
+ description: "Remove a custom domain"
1405
+ },
1406
+ {
1407
+ command: "list",
1408
+ description: "List custom domains and status"
1409
+ },
1410
+ {
1411
+ command: "status <hostname>",
1412
+ description: "Check domain verification status"
1413
+ }
1414
+ ],
1415
+ children: {
1416
+ add: withProjectOption("Add a custom domain.", "void domain add <hostname> [options]"),
1417
+ delete: withProjectOption("Remove a custom domain.", "void domain delete <hostname> [options]"),
1418
+ list: withProjectOption("List custom domains and status.", "void domain list [options]"),
1419
+ status: {
1420
+ summary: "Check domain verification status. Prints a rolled-up state with a one-line diagnostic.",
1421
+ usage: ["void domain status <hostname> [options]"],
1422
+ options: [{
1423
+ command: "--project <name>",
1424
+ description: "Project name override"
1425
+ }, {
1426
+ command: "--verbose",
1427
+ description: "Also print the raw multi-line status breakdown"
1428
+ }]
1429
+ }
1430
+ }
1431
+ },
1432
+ email: {
1433
+ summary: "Inspect email activity, manage verified recipients, and send and receive at your own domain.",
1434
+ usage: ["void email <command>"],
1435
+ commands: [
1436
+ {
1437
+ command: "usage",
1438
+ description: "Show monthly outbound/inbound counts and quota"
1439
+ },
1440
+ {
1441
+ command: "logs",
1442
+ description: "Show recent email delivery activity"
1443
+ },
1444
+ {
1445
+ command: "destinations",
1446
+ description: "List verified recipient addresses"
1447
+ },
1448
+ {
1449
+ command: "allow <address>",
1450
+ description: "Add a recipient and trigger CF verification"
1451
+ },
1452
+ {
1453
+ command: "disallow <address>",
1454
+ description: "Remove a recipient from the allowlist"
1455
+ },
1456
+ {
1457
+ command: "domain <add|status|list|sync|rotate-secret|remove>",
1458
+ description: "Send and receive at your own domain on a Cloudflare zone"
1459
+ },
1460
+ {
1461
+ command: "status --platform cloudflare",
1462
+ description: "Show the email setup state and address map on your own account"
1463
+ },
1464
+ {
1465
+ command: "setup --platform cloudflare",
1466
+ description: "Set email up on your own Cloudflare account (one confirmation)"
1467
+ }
1468
+ ],
1469
+ children: {
1470
+ usage: withProjectOption("Show monthly outbound/inbound counts and quota.", "void email usage [options]"),
1471
+ logs: {
1472
+ summary: "Show recent email delivery activity.",
1473
+ usage: ["void email logs [options]"],
1474
+ options: [{
1475
+ command: "--project <name>",
1476
+ description: "Project name override"
1477
+ }, {
1478
+ command: "--limit <n>",
1479
+ description: "How many entries to show (positive integer)"
1480
+ }]
1481
+ },
1482
+ destinations: withProjectOption("List verified recipient addresses.", "void email destinations [options]"),
1483
+ allow: withProjectOption("Add a recipient and trigger a Cloudflare verification email.", "void email allow <address> [options]"),
1484
+ disallow: withProjectOption("Remove a recipient from the verified allowlist.", "void email disallow <address> [options]"),
1485
+ domain: {
1486
+ summary: "Send and receive at your own domain on a Cloudflare zone.",
1487
+ usage: ["void email domain <verb> [<domain>] [options]"],
1488
+ commands: [
1489
+ {
1490
+ command: "add <domain>",
1491
+ description: "Register the domain with a scoped Cloudflare API token"
1492
+ },
1493
+ {
1494
+ command: "status <domain>",
1495
+ description: "Show inbound, outbound, management, and operation readiness"
1496
+ },
1497
+ {
1498
+ command: "list",
1499
+ description: "List registered email domains"
1500
+ },
1501
+ {
1502
+ command: "rotate-secret <domain>",
1503
+ description: "Rotate the shared zone ingress secret with a deployment probe"
1504
+ },
1505
+ {
1506
+ command: "sync <domain>",
1507
+ description: "Reconcile the zone connection and refresh readiness"
1508
+ },
1509
+ {
1510
+ command: "remove <domain>",
1511
+ description: "Disable the domain assignment and reconcile shared resources"
1512
+ }
1513
+ ],
1514
+ options: [{
1515
+ command: "--subdomain <label|host>",
1516
+ description: "On add: register this subdomain instead of the proposed mail.<domain>"
1517
+ }, {
1518
+ command: "--project <name>",
1519
+ description: "Project name override"
1520
+ }],
1521
+ children: {
1522
+ add: {
1523
+ summary: "Register a domain on a Cloudflare zone you own for sending and receiving. Proposes mail.<domain> when the apex already carries MX.",
1524
+ usage: ["void email domain add <domain> [options]"],
1525
+ options: [{
1526
+ command: "--subdomain <label|host>",
1527
+ description: "Register this subdomain instead of the proposed mail.<domain>"
1528
+ }, {
1529
+ command: "--project <name>",
1530
+ description: "Project name override"
1531
+ }]
1532
+ },
1533
+ status: withProjectOption("Show a registered domain and its recorded readiness.", "void email domain status <domain> [options]"),
1534
+ list: withProjectOption("List registered email domains.", "void email domain list [options]"),
1535
+ "rotate-secret": withProjectOption("Rotate the shared zone ingress secret and verify the deployed generation.", "void email domain rotate-secret <domain> [options]"),
1536
+ sync: withProjectOption("Reconcile the zone connection and refresh readiness.", "void email domain sync <domain> [options]"),
1537
+ remove: withProjectOption("Disable the domain assignment and reconcile shared resources.", "void email domain remove <domain> [options]")
1538
+ }
1539
+ },
1540
+ status: {
1541
+ summary: "Show the email setup state and address map. Exit 1 when not ready.",
1542
+ usage: ["void email status --platform cloudflare"],
1543
+ options: [{
1544
+ command: "--platform cloudflare",
1545
+ description: "Your own Cloudflare account (the only platform with a status today)"
1546
+ }]
1547
+ },
1548
+ setup: {
1549
+ summary: "Set email up on your own Cloudflare account: enable Email Routing, onboard Email Sending, write send_email + addresses into wrangler.jsonc. Asks once before changing the account.",
1550
+ usage: ["void email setup --platform cloudflare"],
1551
+ options: [{
1552
+ command: "--platform cloudflare",
1553
+ description: "Your own Cloudflare account (required; the Void platform needs no setup)"
1554
+ }]
1555
+ }
1556
+ }
1557
+ },
1558
+ github: {
1559
+ summary: "Connect a GitHub repository for automatic deploys.",
1560
+ usage: ["void github <command>"],
1561
+ commands: [
1562
+ {
1563
+ command: "install",
1564
+ description: "Open the GitHub App install page in your browser"
1565
+ },
1566
+ {
1567
+ command: "installations",
1568
+ description: "List your GitHub App installations"
1569
+ },
1570
+ {
1571
+ command: "connect [project]",
1572
+ description: "Connect a repository to a project for auto-deploy"
1573
+ },
1574
+ {
1575
+ command: "update [project]",
1576
+ description: "Update an existing connection's branch, build executor, or deploy workflow"
1577
+ },
1578
+ {
1579
+ command: "status [project]",
1580
+ description: "Show a project's GitHub connection (repo, branch, executor, workflow)"
1581
+ },
1582
+ {
1583
+ command: "disconnect [project]",
1584
+ description: "Disconnect a project from its GitHub repository"
1585
+ },
1586
+ {
1587
+ command: "link",
1588
+ description: "Link your GitHub account to Void"
1589
+ },
1590
+ {
1591
+ command: "join",
1592
+ description: "Join your organization's shared GitHub App installations"
1593
+ }
1594
+ ],
1595
+ children: {
1596
+ install: basicSubcommand("Open the GitHub App install page in your browser.", "void github install"),
1597
+ installations: basicSubcommand("List your GitHub App installations.", "void github installations"),
1598
+ link: basicSubcommand("Link your GitHub account to Void.", "void github link"),
1599
+ join: basicSubcommand("Join your organization's shared GitHub App installations.", "void github join"),
1600
+ connect: {
1601
+ summary: "Connect a repository to a project for automatic deploys.",
1602
+ usage: ["void github connect [project] [options]"],
1603
+ options: [
1604
+ {
1605
+ command: "--project <name>",
1606
+ description: "Project name (alias for positional)"
1607
+ },
1608
+ {
1609
+ command: "--installation <id>",
1610
+ description: "GitHub App installation ID"
1611
+ },
1612
+ {
1613
+ command: "--repo <owner/repo>",
1614
+ description: "Repository full name (owner/repo)"
1615
+ },
1616
+ {
1617
+ command: "--branch <name>",
1618
+ description: "Branch to deploy from (required in non-interactive mode)"
1619
+ },
1620
+ {
1621
+ command: "--executor <type>",
1622
+ description: "Build executor: container (default) | github_actions; prompted interactively when omitted"
1623
+ },
1624
+ {
1625
+ command: "--workflow <path>",
1626
+ description: "Authorized deploy workflow file (default .github/workflows/void-deploy.yml); prompted interactively when using github_actions"
1627
+ }
1628
+ ],
1629
+ examples: [
1630
+ {
1631
+ command: "void github connect [project]",
1632
+ description: "Connect a repository to a project"
1633
+ },
1634
+ {
1635
+ command: "void github connect my-app --installation 42 --repo owner/repo --branch main",
1636
+ description: "Non-interactive connect (all flags explicit)"
1637
+ },
1638
+ {
1639
+ command: "void github connect my-app --repo owner/repo --branch main --executor github_actions",
1640
+ description: "Non-interactive connect using the GitHub Actions executor"
1641
+ }
1642
+ ]
1643
+ },
1644
+ update: {
1645
+ summary: "Update an existing connection's branch, build executor, or deploy workflow.",
1646
+ usage: ["void github update [project] [options]"],
1647
+ options: [
1648
+ {
1649
+ command: "--project <name>",
1650
+ description: "Project name (alias for positional)"
1651
+ },
1652
+ {
1653
+ command: "--branch <name>",
1654
+ description: "New branch to deploy from"
1655
+ },
1656
+ {
1657
+ command: "--executor <type>",
1658
+ description: "New build executor: container | github_actions; prompted interactively when omitted"
1659
+ },
1660
+ {
1661
+ command: "--workflow <path>",
1662
+ description: "New authorized deploy workflow file under .github/workflows/; prompted interactively when using github_actions"
1663
+ }
1664
+ ],
1665
+ examples: [{
1666
+ command: "void github update my-app --executor github_actions",
1667
+ description: "Switch an existing connection to the GitHub Actions executor"
1668
+ }, {
1669
+ command: "void github update my-app --branch release",
1670
+ description: "Change the deploy branch"
1671
+ }]
1672
+ },
1673
+ status: {
1674
+ summary: "Show a project's GitHub connection settings.",
1675
+ usage: ["void github status [project] [options]"],
1676
+ options: [{
1677
+ command: "--project <name>",
1678
+ description: "Project name (alias for positional)"
1679
+ }],
1680
+ examples: [{
1681
+ command: "void github status",
1682
+ description: "Show the linked project's connection"
1683
+ }, {
1684
+ command: "void github status my-app",
1685
+ description: "Show a specific project connection"
1686
+ }]
1687
+ },
1688
+ disconnect: {
1689
+ summary: "Disconnect a project from its GitHub repository.",
1690
+ usage: ["void github disconnect [project] [options]"],
1691
+ options: [{
1692
+ command: "--project <name>",
1693
+ description: "Project name (alias for positional)"
1694
+ }, {
1695
+ command: "--yes",
1696
+ description: "Skip the confirmation prompt (required in non-interactive shells)"
1697
+ }],
1698
+ examples: [{
1699
+ command: "void github disconnect",
1700
+ description: "Disconnect the linked project's repository"
1701
+ }, {
1702
+ command: "void github disconnect my-app --yes",
1703
+ description: "Disconnect a specific project without confirmation"
1704
+ }]
1705
+ }
1706
+ }
1707
+ },
1708
+ build: {
1709
+ summary: "Inspect remote builds.",
1710
+ usage: ["void build <command>"],
1711
+ commands: [{
1712
+ command: "logs [build]",
1713
+ description: "Stream, tail, or download logs for a build"
1714
+ }],
1715
+ children: { logs: {
1716
+ summary: "Stream, tail, or download logs for a build.",
1717
+ usage: ["void build logs [build] [options]"],
1718
+ options: [
1719
+ {
1720
+ command: "--follow, -f",
1721
+ description: "Live-tail until the build finishes"
1722
+ },
1723
+ {
1724
+ command: "--output <file>, -o",
1725
+ description: "Write logs to a file instead of stdout"
1726
+ },
1727
+ {
1728
+ command: "--project <slug>, -p",
1729
+ description: "Target project (else linked / VOID_PROJECT)"
1730
+ }
1731
+ ],
1732
+ examples: [
1733
+ {
1734
+ command: "void build logs",
1735
+ description: "Print the latest build's logs"
1736
+ },
1737
+ {
1738
+ command: "void build logs -f",
1739
+ description: "Follow the latest build until it finishes"
1740
+ },
1741
+ {
1742
+ command: "void build logs bld_123 -o build.log",
1743
+ description: "Download a build's logs to a file"
1744
+ }
1745
+ ]
1746
+ } }
1747
+ },
1748
+ db: {
1749
+ summary: "Manage local and remote database state.",
1750
+ usage: ["void db <command>"],
1751
+ commands: [
1752
+ {
1753
+ command: "push",
1754
+ description: "Push schema to local D1 without migration files"
1755
+ },
1756
+ {
1757
+ command: "generate",
1758
+ description: "Generate SQL migrations from schema changes"
1759
+ },
1760
+ {
1761
+ command: "status",
1762
+ description: "Show migration status (local and remote)"
1763
+ },
1764
+ {
1765
+ command: "reset",
1766
+ description: "Reset local DB and re-run migrations"
1767
+ },
1768
+ {
1769
+ command: "seed",
1770
+ description: "Reset local DB, run migrations, and seed"
1771
+ },
1772
+ {
1773
+ command: "execute <sql>",
1774
+ description: "Run SQL against the database (--remote for deployed)"
1775
+ },
1776
+ {
1777
+ command: "migrate",
1778
+ description: "Apply pending migrations"
1779
+ },
1780
+ {
1781
+ command: "studio",
1782
+ description: "Open Drizzle Studio (--remote for deployed PG)"
1783
+ },
1784
+ {
1785
+ command: "export",
1786
+ description: "Export local database as SQL"
1787
+ },
1788
+ {
1789
+ command: "connect",
1790
+ description: "Connect or provision an external database"
1791
+ },
1792
+ {
1793
+ command: "set-url",
1794
+ description: "Update the external database URL"
1795
+ },
1796
+ {
1797
+ command: "rename-migrations",
1798
+ description: "Rename migrations to timestamp format"
1799
+ }
1800
+ ],
1801
+ children: {
1802
+ push: basicSubcommand("Push schema to local D1 without migration files.", "void db push"),
1803
+ generate: basicSubcommand("Generate SQL migrations from schema changes.", "void db generate"),
1804
+ status: basicSubcommand("Show migration status for local and remote DBs.", "void db status"),
1805
+ reset: basicSubcommand("Reset local DB and re-run migrations.", "void db reset"),
1806
+ seed: {
1807
+ summary: "Reset local DB, run migrations, and seed data.",
1808
+ usage: ["void db seed [options]"],
1809
+ options: [{
1810
+ command: "--file <path>",
1811
+ description: "Seed from a specific file"
1812
+ }]
1813
+ },
1814
+ execute: {
1815
+ summary: "Run SQL against the database (local by default; use --remote for the deployed database).",
1816
+ usage: ["void db execute <sql>", "void db execute --file <path>"],
1817
+ options: [{
1818
+ command: "--file <path>",
1819
+ description: "Run SQL from a file instead"
1820
+ }, {
1821
+ command: "--remote",
1822
+ description: "Run against the deployed database (D1 via proxy; PostgreSQL via direct connection)"
1823
+ }],
1824
+ examples: [
1825
+ {
1826
+ command: "void db execute \"select * from users\"",
1827
+ description: "Run inline SQL"
1828
+ },
1829
+ {
1830
+ command: "void db execute --file query.sql",
1831
+ description: "Run SQL from a file"
1832
+ },
1833
+ {
1834
+ command: "void db execute --remote \"select count(*) from users\"",
1835
+ description: "Query the deployed database"
1836
+ }
1837
+ ]
1838
+ },
1839
+ migrate: {
1840
+ summary: "Apply pending migrations.",
1841
+ usage: ["void db migrate [options]"],
1842
+ options: [{
1843
+ command: "--remote",
1844
+ description: "Apply to the remote database"
1845
+ }]
1846
+ },
1847
+ studio: {
1848
+ summary: "Open Drizzle Studio against the database (local by default; use --remote for the deployed PostgreSQL database; D1 remote not yet supported).",
1849
+ usage: ["void db studio [options]"],
1850
+ options: [{
1851
+ command: "--remote",
1852
+ description: "Open Studio against the deployed PostgreSQL database (D1 remote not yet supported)"
1853
+ }],
1854
+ examples: [{
1855
+ command: "void db studio",
1856
+ description: "Open Studio for the local database"
1857
+ }, {
1858
+ command: "void db studio --remote",
1859
+ description: "Open Studio against the deployed PostgreSQL database"
1860
+ }]
1861
+ },
1862
+ export: {
1863
+ summary: "Export local database contents as SQL.",
1864
+ usage: ["void db export [options]"],
1865
+ options: [
1866
+ {
1867
+ command: "--output <path>",
1868
+ description: "Export to a specific file path"
1869
+ },
1870
+ {
1871
+ command: "--no-data",
1872
+ description: "Schema only (no INSERT statements)"
1873
+ },
1874
+ {
1875
+ command: "--no-schema",
1876
+ description: "Data only (no CREATE TABLE)"
1877
+ },
1878
+ {
1879
+ command: "--table <name>",
1880
+ description: "Export a single table"
1881
+ }
1882
+ ]
1883
+ },
1884
+ connect: {
1885
+ summary: "Connect or provision an external PostgreSQL/MySQL database.",
1886
+ usage: ["void db connect [connection-string]", "void db connect --provider <name-or-module> [options]"],
1887
+ options: [
1888
+ {
1889
+ command: "--provider <name-or-module>",
1890
+ description: "Provision with an adapter"
1891
+ },
1892
+ {
1893
+ command: "--name <name>",
1894
+ description: "Provider project/database name"
1895
+ },
1896
+ {
1897
+ command: "--region <region>",
1898
+ description: "Provider region identifier"
1899
+ },
1900
+ {
1901
+ command: "--local-only",
1902
+ description: "Do not sync a linked Void project"
1903
+ }
1904
+ ],
1905
+ examples: [{
1906
+ command: "void db connect \"postgresql://user:pass@host/db\"",
1907
+ description: "Connect an existing database"
1908
+ }, {
1909
+ command: "void db connect --provider neon --name my-app",
1910
+ description: "Provision a Neon database using NEON_API_KEY"
1911
+ }]
1912
+ },
1913
+ "set-url": basicSubcommand("Update the external database connection string for deployment.", "void db set-url"),
1914
+ "rename-migrations": basicSubcommand("Rename migrations to timestamp-based format.", "void db rename-migrations")
1915
+ }
1916
+ },
1917
+ env: {
1918
+ summary: "Validate env.ts and generate environment types.",
1919
+ usage: ["void env <command>"],
1920
+ commands: [{
1921
+ command: "check",
1922
+ description: "Validate local .env or remote secret names"
1923
+ }, {
1924
+ command: "types",
1925
+ description: "Regenerate .void/env.d.ts from env.ts"
1926
+ }],
1927
+ children: {
1928
+ check: {
1929
+ summary: "Validate local .env or required remote secret names.",
1930
+ usage: ["void env check [options]"],
1931
+ options: [{
1932
+ command: "--remote",
1933
+ description: "Check required server keys as remote secrets"
1934
+ }]
1935
+ },
1936
+ types: basicSubcommand("Regenerate .void/env.d.ts from env.ts.", "void env types")
1937
+ }
1938
+ },
1939
+ gen: {
1940
+ summary: "Scaffold routes, models, background jobs, and framework entries.",
1941
+ usage: ["void gen <command>"],
1942
+ commands: [
1943
+ {
1944
+ command: "model <name> [cols...]",
1945
+ description: "Generate migration, CRUD routes, and DB types"
1946
+ },
1947
+ {
1948
+ command: "migration <name>",
1949
+ description: "Generate an empty migration file"
1950
+ },
1951
+ {
1952
+ command: "route <path>",
1953
+ description: "Generate a route with handler exports"
1954
+ },
1955
+ {
1956
+ command: "middleware <name>",
1957
+ description: "Generate a numbered middleware file"
1958
+ },
1959
+ {
1960
+ command: "ssr",
1961
+ description: "Generate SSR entry, client, and App component"
1962
+ },
1963
+ {
1964
+ command: "cron <name>",
1965
+ description: "Generate a cron job file"
1966
+ },
1967
+ {
1968
+ command: "queue <name>",
1969
+ description: "Generate a queue consumer file"
1970
+ }
1971
+ ],
1972
+ children: {
1973
+ model: {
1974
+ summary: "Generate a migration, CRUD routes, and database types.",
1975
+ usage: ["void gen model <name> [columns...]"],
1976
+ examples: [{
1977
+ command: "void gen model post title:string body:text",
1978
+ description: "Create a model"
1979
+ }]
1980
+ },
1981
+ migration: basicSubcommand("Generate an empty migration file.", "void gen migration <name>"),
1982
+ route: {
1983
+ summary: "Generate a route with handler exports.",
1984
+ usage: ["void gen route <path> [options]"],
1985
+ options: [{
1986
+ command: "--methods <list>",
1987
+ description: "Comma-separated methods (default: get)"
1988
+ }],
1989
+ examples: [{
1990
+ command: "void gen route api/posts --methods get,post",
1991
+ description: "Create a route"
1992
+ }]
1993
+ },
1994
+ middleware: basicSubcommand("Generate a numbered middleware file.", "void gen middleware <name>"),
1995
+ ssr: {
1996
+ summary: "Generate SSR entry, client, and App component.",
1997
+ usage: ["void gen ssr [options]"],
1998
+ options: [
1999
+ {
2000
+ command: "--react",
2001
+ description: "Use React"
2002
+ },
2003
+ {
2004
+ command: "--vue",
2005
+ description: "Use Vue"
2006
+ },
2007
+ {
2008
+ command: "--svelte",
2009
+ description: "Use Svelte"
2010
+ },
2011
+ {
2012
+ command: "--solid",
2013
+ description: "Use Solid"
2014
+ }
2015
+ ]
2016
+ },
2017
+ cron: basicSubcommand("Generate a cron job file.", "void gen cron <name>"),
2018
+ queue: basicSubcommand("Generate a queue consumer file.", "void gen queue <name>")
2019
+ }
2020
+ },
2021
+ prepare: {
2022
+ summary: "Generate .void artifacts without starting Vite.",
2023
+ usage: ["void prepare"],
2024
+ examples: [{
2025
+ command: "void prepare",
2026
+ description: "Refresh generated project types"
2027
+ }]
2028
+ }
2029
+ };
2030
+ function basicSubcommand(summary, usage, example) {
2031
+ return {
2032
+ summary,
2033
+ usage: [usage],
2034
+ examples: example ? [{
2035
+ command: example,
2036
+ description: summary
2037
+ }] : void 0
2038
+ };
2039
+ }
2040
+ function withProjectOption(summary, usage) {
2041
+ return {
2042
+ summary,
2043
+ usage: [usage],
2044
+ options: [{
2045
+ command: "--project <name>",
2046
+ description: "Project name override"
2047
+ }]
2048
+ };
2049
+ }
2050
+ function lifecycleHelp(command, summary) {
2051
+ return {
2052
+ summary,
2053
+ usage: [`void platform ${command} [id] [--plan]${command === "disable" ? "" : " [--runtime <path>]"} [--yes]`],
2054
+ options: [
2055
+ {
2056
+ command: "--plan",
2057
+ description: "Print the exact plan without making changes"
2058
+ },
2059
+ ...command === "disable" ? [] : [{
2060
+ command: "--runtime <path>",
2061
+ description: "Deploy an integrity-checked runtime directory instead of the package"
2062
+ }],
2063
+ {
2064
+ command: "--yes",
2065
+ description: "Acknowledge non-interactive Cloudflare changes"
2066
+ }
2067
+ ]
2068
+ };
2069
+ }
2070
+ function printGlobalHelp() {
2071
+ printVoidHeader();
2072
+ note([
2073
+ globalCommandLine(["init"], "void init"),
2074
+ ...globalOptionLines(["init"]),
2075
+ "",
2076
+ globalCommandLine(["connect"], "void connect [url]"),
2077
+ ...globalOptionLines(["connect"]),
2078
+ "",
2079
+ globalCommandLine(["deploy"], "void deploy"),
2080
+ ...globalOptionLines(["deploy"]),
2081
+ "",
2082
+ ...globalCommandGroup("auth"),
2083
+ "",
2084
+ ...globalCommandGroup("platform"),
2085
+ "",
2086
+ ...globalCommandGroup("project"),
2087
+ "",
2088
+ categoryTitle("secrets"),
2089
+ ...globalCommandLines("secret"),
2090
+ "",
2091
+ ...globalCommandGroup("domain"),
2092
+ "",
2093
+ ...globalCommandGroup("email"),
2094
+ "",
2095
+ ...globalCommandGroup("github"),
2096
+ "",
2097
+ ...globalCommandGroup("build"),
2098
+ "",
2099
+ categoryTitle("database"),
2100
+ ...globalCommandLines("db", {
2101
+ execute: "execute <sql>",
2102
+ export: "export [--output <path>]",
2103
+ seed: "seed [--file <path>]"
2104
+ }),
2105
+ ...globalOptionLines(["db", "execute"]),
2106
+ ...globalOptionLines(["db", "export"]),
2107
+ "",
2108
+ ...globalCommandGroup("env"),
2109
+ ...globalOptionLines(["env", "check"]),
2110
+ "",
2111
+ categoryTitle("codegen"),
2112
+ globalCommandLine(["prepare"], "void prepare"),
2113
+ ...globalCommandLines("gen", { route: "route <path> [--methods]" }),
2114
+ "",
2115
+ categoryTitle("agent"),
2116
+ helpLine("void init --agents", requiredOption(["init"], "--agents").description),
2117
+ "",
2118
+ categoryTitle("help"),
2119
+ helpLine("void help <command>", "Show command-specific help"),
2120
+ helpLine("void <command> --help", "Show command-specific help")
2121
+ ].join("\n"), sectionTitle("Commands"));
2122
+ note([helpLine("VOID_TOKEN", "Auth token (or use `void auth login`)"), helpLine("VOID_PROJECT", "Deploy target project name override")].join("\n"), sectionTitle("Environment"));
2123
+ outro("https://void.cloud");
2124
+ }
2125
+ function printVoidHeader() {
2126
+ const version = JSON.parse(readFileSync(join(getPackageDir(), "package.json"), "utf-8")).version;
2127
+ const art = asciiArts[Math.floor(Math.random() * asciiArts.length)];
2128
+ console.log(import_picocolors.default.blue(`${art} v${version}\n`));
2129
+ }
2130
+ function getHelpPath(args) {
2131
+ if (args.length === 0) return null;
2132
+ const command = args[0];
2133
+ if (command === "help") return args.slice(1);
2134
+ if (command === "--help" || command === "-h") return [];
2135
+ if (args[1] === "help") return [command, ...args.slice(2)];
2136
+ const helpIndex = args.findIndex((arg) => arg === "--help" || arg === "-h");
2137
+ if (helpIndex === -1) return null;
2138
+ return getKnownHelpPrefix(args.slice(0, helpIndex));
2139
+ }
2140
+ function printHelpPage(path) {
2141
+ const page = findHelpPage(path);
2142
+ if (!page) throw new Error(`Unknown help topic: ${formatHelpPath(path)}`);
2143
+ const lines = [
2144
+ page.summary,
2145
+ "",
2146
+ categoryTitle("Usage"),
2147
+ ...page.usage.map((usage) => ` ${usage}`)
2148
+ ];
2149
+ appendHelpSection(lines, "Commands", page.commands);
2150
+ appendHelpSection(lines, "Options", page.options);
2151
+ appendHelpSection(lines, "Examples", page.examples);
2152
+ if (page.commands) lines.push("", `Run \`void help ${path.join(" ")} <command>\` for command-specific help.`);
2153
+ note(lines.join("\n"), sectionTitle(`void ${path.join(" ")}`));
2154
+ }
2155
+ function appendHelpSection(lines, title, entries) {
2156
+ if (!entries || entries.length === 0) return;
2157
+ lines.push("", categoryTitle(title));
2158
+ for (const entry of entries) lines.push(helpLine(entry.command, entry.description));
2159
+ }
2160
+ function globalCommandGroup(group) {
2161
+ return [categoryTitle(group), ...globalCommandLines(group)];
2162
+ }
2163
+ function globalCommandLines(group, commandOverrides) {
2164
+ return (requiredPage([group]).commands ?? []).map((command) => helpLine(`void ${group} ${commandOverrides?.[command.command.split(" ")[0]] ?? command.command}`, command.description));
2165
+ }
2166
+ function globalCommandLine(path, command) {
2167
+ return helpLine(command, formatGlobalDescription(requiredPage(path).summary));
2168
+ }
2169
+ function globalOptionLines(path) {
2170
+ return (requiredPage(path).options ?? []).map((option) => helpLine(` ${option.command}`, option.description));
2171
+ }
2172
+ function requiredOption(path, command) {
2173
+ const option = requiredPage(path).options?.find((entry) => entry.command === command);
2174
+ if (!option) throw new Error(`Missing help option: ${formatHelpPath(path)} ${command}`);
2175
+ return option;
2176
+ }
2177
+ function requiredPage(path) {
2178
+ const page = findHelpPage(path);
2179
+ if (!page) throw new Error(`Missing help page: ${formatHelpPath(path)}`);
2180
+ return page;
2181
+ }
2182
+ function formatGlobalDescription(summary) {
2183
+ return summary.replace(/\.$/, "");
2184
+ }
2185
+ function findHelpPage(path) {
2186
+ let tree = HELP_TREE;
2187
+ let page = null;
2188
+ for (const part of path) {
2189
+ const node = tree?.[part];
2190
+ if (!node) return null;
2191
+ page = node;
2192
+ tree = node.children;
2193
+ }
2194
+ return page;
2195
+ }
2196
+ function getKnownHelpPrefix(args) {
2197
+ let tree = HELP_TREE;
2198
+ const path = [];
2199
+ for (const arg of args) {
2200
+ if (arg.startsWith("-")) break;
2201
+ const node = tree?.[arg];
2202
+ if (!node) {
2203
+ if (path.length === 0) return [arg];
2204
+ if (tree) return [...path, arg];
2205
+ break;
2206
+ }
2207
+ path.push(arg);
2208
+ tree = node.children;
2209
+ }
2210
+ return path;
2211
+ }
2212
+ function formatHelpPath(path) {
2213
+ return path.length === 0 ? "help" : path.join(" ");
2214
+ }
2215
+ //#endregion
2216
+ export { printVoidHeader as a, printHelpPage as i, help_exports as n, operatorGroups as o, printGlobalHelp as r, parseOperatorArgs as s, getHelpPath as t };