@kedge/cli 0.11.0 → 0.11.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.
package/README.md CHANGED
@@ -18,7 +18,8 @@ its dependencies, run as `pnpm kedge <command>`.
18
18
  | `kedge smoke --url <url>` | A test order, placed; run again, the same order |
19
19
  | `kedge upgrade --to <version>` | Every `@kedge` package to a release, with its codemods |
20
20
 
21
- **For agents.** Exit `0` done, `1` refused or failed (the reason on stderr), `2`
21
+ **For agents.** `kedge <command> --help` prints that command's usage and runs
22
+ nothing; `kedge --help` lists them all. Exit `0` done, `1` refused or failed (the reason on stderr), `2`
22
23
  usage, `3` a person must act: the last line of stderr starts `for you:` and is one
23
24
  sentence to pass on. Run the same command again after they do; every command is
24
25
  safe to repeat. With `--json`, stdout is one object, `{"ok": true, ...}`,
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.11.0",
3
- "upgradesFrom": "0.10.1",
2
+ "version": "0.11.2",
3
+ "upgradesFrom": "0.11.1",
4
4
  "doStateFormat": 1,
5
5
  "migrations": {
6
6
  "0000_schema.sql": {
@@ -148,7 +148,7 @@
148
148
  "@kedge/core": {
149
149
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
150
150
  "README.md": "5cffa13dcc33f4c3c39adb020a8c589722a88ed904033de1f16385a8a3e67236",
151
- "package.json": "24c49edc3056d381d5d8ae8ef54af3ccb04ac151e38d65d95c800e3077e39edf",
151
+ "package.json": "a4f59f1f10ef6963204a9d9412436d70298ff646ce3189a28cc6302dab3cb3be",
152
152
  "src/access/audit.ts": "374bf28051543e2cfc3a92f6dd3b27525562eb76d12d0628951da855323be120",
153
153
  "src/access/context.ts": "bf4d50e4473ebe99aea6e6d673b0006595bb5bcf47e9f34c094fa4d9c6fea5e7",
154
154
  "src/access/permissions.ts": "0e71620cf6dcddd414bdba4634986366f6c37c8d94f419c4fdd289131b5771da",
@@ -228,7 +228,7 @@
228
228
  "migrations/0029_cli_session.sql": "a883b970c2820a84ac3e0c65530681df488ecc0546ebf29a43bc9a5778e8c1f9",
229
229
  "migrations/0030_credential_ref.sql": "b06cee4958d222a93d0af1b6a57e260beb98a92a9a1b2ba4c7a895fc40b79201",
230
230
  "migrations/0031_cli_session_origin.sql": "96fbe4ae12064ff4dbd599d8d0939b43b541c7177a9f12dfb4abfe54cdc9f6c9",
231
- "package.json": "c2c1abe84fa9091dc837f325a23400567797821e43626c30db57e2ac2a102596",
231
+ "package.json": "3e81875595c648c2b5f4977139758dfd0a99b44473e0804dde99482aa8a457a6",
232
232
  "src/access-sql.ts": "51481f129f4614ba770218526048042aa0d118274ce7a737e0584037ea59dff0",
233
233
  "src/access.ts": "2a384d4b6f22bc0109aa2f247f628543bc0a80a936416de6be56b693328dce9c",
234
234
  "src/admin.ts": "694d508e2bb51eda9134d163b049240688d5fdcd6783a66e2ae18bf9da21d140",
@@ -270,7 +270,7 @@
270
270
  "@kedge/server": {
271
271
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
272
272
  "README.md": "1fb1bcd08cc11851accb343d6df724383706cf9324d58785d097431476524b26",
273
- "package.json": "03fd0f20a543deb7cfb0ba91ce45b5fab7b7c8588487e6445d9090b40cc2daad",
273
+ "package.json": "440af1e0f33133f8b72fce7cb82901e763b2ddec6a849010198066b5e1d9b979",
274
274
  "src/access.ts": "6544a7b385b7d3391d0a996f1bc867d17741ddd63a0d48e0f0b1d37adcea78b4",
275
275
  "src/admin-routes.ts": "9c1f13283f1b11709c0d27512205d9ead59a9042a4df36fa1bec344184ad7d0e",
276
276
  "src/admin-shell.ts": "3b94e14e3cd8303fd7f3153a65ce7c3339203b58f74656c40839587ca996a7c3",
@@ -293,7 +293,7 @@
293
293
  "@kedge/runtime-cf": {
294
294
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
295
295
  "README.md": "b678c333e82364c5e9349bb1aa4f64d1479678893b471ddc0c4ea41b769adef9",
296
- "package.json": "f30c0aa0725a4943ec11673324dc579ae4ea7f52e0930ddedf885efea05809a9",
296
+ "package.json": "0cfd3894a386bc1a44dd43f8fb0db8f1bd96253216f8b6ec3bbadc7916353079",
297
297
  "src/admin.ts": "2c005857fe2928b4e82777590f13f7a83e26edfa30b24f5463ee0c80932b2ca0",
298
298
  "src/cart-do.ts": "d7be874e440d41b716a96607341b82b0992a9da1656456322fca3634f6be8529",
299
299
  "src/clock-do.ts": "8d68b0ba01d16763fe7d13feee71d315bbc1ebbee7e5f8694a9d186c4ccab3a5",
@@ -320,13 +320,13 @@
320
320
  "@kedge/plugin-sdk": {
321
321
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
322
322
  "README.md": "685a9eede5493ce08535b0525cf30b1290d48ba9e75b3662239fb5b6e08d3baa",
323
- "package.json": "1d465f69c750bb127668ca6fd3e57e1f17d64e1f5af6253106e5d16e9a76056f",
323
+ "package.json": "7c742e41c40ff88a78815effa8c5be04c85d7c805c044a981ce91cb8450da757",
324
324
  "src/index.ts": "cb2aa938e2065f6ca5f01a470b421ec0ca20599f149114051823e2510a76d11b"
325
325
  },
326
326
  "@kedge/testing": {
327
327
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
328
328
  "README.md": "94da183c9b4fdb9617dbe93cfb169b81ce4bd6ed7c9a364d6d6ad3e62578d9cc",
329
- "package.json": "de286a7d84291ce0f9caf704e59c26c2611fabe0c79db64800444976a8130bd6",
329
+ "package.json": "dd9ca56e06a63c714bb178ede39a9ba07ae05c7342b348dc8ee3af92a62c89a7",
330
330
  "src/budgets.ts": "4ffb780a7543d1d2c7c7e5dca7a2d4cdb363e3b0ee2801a928d928da8088e525",
331
331
  "src/http.ts": "59c4bb9d3df6885333103a05cddde0d03cc70008a416c99905422fbead034ee7",
332
332
  "src/index.ts": "c3705394753e6c6ecf3abfd19a3b1e672c61c33bda4ff8f2d54ece10f506b5cd",
@@ -350,18 +350,22 @@
350
350
  "extending/tests.md": "8e2e68427f7e830b0750aebef889846c3285fbf4bdcfb0342947adeb1b896574",
351
351
  "extending/timers.md": "6da7fc0a8eee314df7158df16e5670d194842d5de452032ba8be414b5dac4e7e",
352
352
  "extending/tracks.md": "3d85cd54a5060c35fe70b3bbea848c16ffd0a4e2e21e590b104408690a721ac6",
353
- "index.json": "4d0f56f56cd470c78e93c9b26ce251ee89fdb624dfd20febb1fc411b398182e9",
354
- "package.json": "a048bd97326a86a21fbff0a1377e6823711b9bab15b1246e7422538fdeb97d58",
353
+ "index.json": "eb1c33142a381537964add5f42f12380509a44ec312fd2e124f232d3d507441b",
354
+ "package.json": "7f96281f71ab2b2d110fd36cb454c4dfa7c2313d96626ba83f9677b18df6d50e",
355
355
  "reference/api.md": "114830d766ab3b81a5181f7b07b10012ac5ee15898c87fa9515c71cec60ec374",
356
356
  "reference/errors.md": "c4fa0dcb4d79d5a4888d7fc3ee525a045b21d3cb3ac158f5172dbb02880979f2",
357
+ "reference/events.md": "3b8fc6330b5fca2212d8ffc7c9edcdffc7872ed1f8e114930801c210b7f5fa70",
358
+ "reference/orders.md": "8fd6d5d3ee7dd4f9f44cf8b0131f9eb0cf60bb3b5d0b9a7696cf89d0f7a29012",
357
359
  "skills/kedge-extend/SKILL.md": "7ce215445e99d87e401b7f2669c184f3fa263b75aabced2cdf5eefb398043013",
358
360
  "skills/kedge-plugin/SKILL.md": "21af3f112cfcdf2a1cd2eb8e9148a0558a4aebf29b1a057cb5ece09af8116d99",
359
361
  "skills/kedge-preview-deploy/SKILL.md": "5dfe9c4aeb18f26d811b7bee24b3b50df4ec63dffcccf905320ae9f045d83be6",
360
- "skills/kedge-start/SKILL.md": "9a2c63947d90b1b2dccb50a98ca17c4bfc8b4b3aa906973cb62e9dcc82544851",
362
+ "skills/kedge-start/SKILL.md": "408055af695678394089fb4f05386ebe21f94b44d7747cef2f179736f147c362",
361
363
  "skills/kedge-upgrade/SKILL.md": "97cba305676a22696d6d4e25d2c5e823b47fc0be04b12813d17b9dfd3c5a6c2e",
362
364
  "upgrading/0.10.0.md": "169efc96cdf80af167df6607c0db4d977e29c135858ba0c61f53d50d9facc676",
363
365
  "upgrading/0.10.1.md": "d47ddc49f1724e0f3be55a7136d75cbcd8f0bf1128cc7ed2aa6e17cf884ac893",
364
366
  "upgrading/0.11.0.md": "fb23a255a2316e3c27860080e3ec17cde546885cc85f744b963a76b737570aeb",
367
+ "upgrading/0.11.1.md": "62311682707de91687cd3400c772eb056e8ea8a017a6f00b38ec26eafe6744b7",
368
+ "upgrading/0.11.2.md": "181b2b574847774cc7ad985f918b3f1806d205afaba06c7ffc8a2011f03dce03",
365
369
  "upgrading/0.8.0.md": "b0ddd26993048ea1fdd0e76fb2707060cc4032ffb199a691278020361be95cf8",
366
370
  "upgrading/0.9.0.md": "d632d6143636351289684dd51dd51eb0be3e76975c4a42d65acdcee04549d21d",
367
371
  "upgrading/codemods/add-admin-assets.mjs": "fa5d069a3489889dcc095b309020d0e773004b3a39544457747491963492f0a1",
@@ -375,31 +379,31 @@
375
379
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
376
380
  "README.md": "1ce1a6d2a16995f6342c9bcc40ddbac0e2bc35cdcdf1ad24efe28aa5b85d79a3",
377
381
  "dist/_headers": "b1d979b2fdf27af6c0f41fdaee420f2a2b192f28dc855fec7491f8ffa685c9ba",
378
- "dist/app/assets/account-nyHWydUe.js": "72fbf2aec8590a7921fd03787a703ed6defb355e66f398cad4e1c33a2073f20c",
382
+ "dist/app/assets/account-GJ460eh6.js": "a21fe5c2caf4dc65e68574bdba7f68ab67e0b4ced3ec17c830047c1a3a23a4c1",
379
383
  "dist/app/assets/card-CH9fCW35.js": "995ee7034e88909a04b07d559a7f520fb08df647e960606f54f5ab88c7201a3f",
380
- "dist/app/assets/display-CLAPxMXW.js": "4f4e029a0f62756c966c2da476c9f62b7bc59b521c84fa2af86b0f1e2ce51729",
381
- "dist/app/assets/home-BSbCq4oE.js": "777ad24ab38e8c3cc4efd47aa66613efd537ed47c05b2fc451c97a43697380a9",
382
- "dist/app/assets/index-BA_54h5V.css": "0d7763f516591b37628f3bd5cad733d786783e78a092ff4ad74f0a4045394c73",
383
- "dist/app/assets/index-BbBCe4by.js": "41641e00b3ffb0566a3ff8d4ddb0506055090fca4ea175cfd9d27ee63d795deb",
384
- "dist/app/assets/invite-D1jP1Fll.js": "e148b4f5ab29fd399428a83fe5ece25c9e3576f9ae2ef29c804ad8a12737c1c9",
385
- "dist/app/assets/resource-detail-DgoKUNuA.js": "e7f84cb3aa07706a82f9a1559edbc8bdf35a9e12d100384b6e86bc2bc6822efc",
386
- "dist/app/assets/resource-form-BrN_LHPu.js": "8d4e795ae922843c771b537c2142e36d6fb83d884fd486598f6c847ff5873fce",
387
- "dist/app/assets/resource-list-Bi1UweqT.js": "d7b00d7d43c42a77f4a050953ed45cf43ef96d2032fe81054500fd21aef2b57f",
388
- "dist/app/assets/setup-Bk_lO3sV.js": "37e44261fc7bb523c9a5d869f4749a631e4fde5abfc9e2e6af477fc17b90c1ae",
389
- "dist/app/assets/use-command-CzhIJrhd.js": "3e714901b091fbef8778d83e0ab6842f55e603caf12c3d2eedfe209f4e2de70f",
390
- "dist/app/assets/work-lists-De9QWmyy.js": "4f545b3655ef290de7f67dd6aeff3f5ae4b1090fd4a7f8945a5e178669ce4fee",
384
+ "dist/app/assets/display-DBOMyq_B.js": "6a38291191c4c33fd8307d78b8f87c420e281a065965bda99eed31ebb15657a2",
385
+ "dist/app/assets/home-SVbjuY56.js": "4729b17cd7fc2db51792bea9ad4ff8168e877a40df7c8d839d3b7491bad80f55",
386
+ "dist/app/assets/index-A6QB_53Q.css": "69a091853faa15ae161af250c27e0a9ac1d4546553b9854339c419368cd340a5",
387
+ "dist/app/assets/index-Bxm9wGkx.js": "2b9b9aac4810d8f08e0e3b47223666e1181f5b28bcd7c128b8deb140de75d6e0",
388
+ "dist/app/assets/invite-D54MWzuf.js": "629732b1e09605bb5419c80d4d60829ae95ccc40a5e464530376e7979be7208d",
389
+ "dist/app/assets/resource-detail-Dekov70L.js": "e349522daeca2894f3b7bf87b83d2e78d49abdfc74321a8862f8540a3207180e",
390
+ "dist/app/assets/resource-form-C9T8aoRr.js": "2799113487483a205798ff6f9808309c506acf09296b3b325c7990900cf19110",
391
+ "dist/app/assets/resource-list-DJU-gknY.js": "37df28dc64c86d4fb9d1fa6e42c1f808d958f86b6c8e9ab885964f4104134c9a",
392
+ "dist/app/assets/setup-DBmP0maP.js": "0edeae3bfbf2095d22de7b87a6f24846d53a7294fb6cb67654b3231ecc36d1a2",
393
+ "dist/app/assets/use-command-C-SbE8V0.js": "22a76a3e79165954e450b57db20edbdbb371e066942bd5a5e3ac4321d9235114",
394
+ "dist/app/assets/work-lists-DEL5FPck.js": "d1932cb198e5f3be38c52de67b77636526d897da1ce5a42c40db65da099547c0",
391
395
  "dist/app/boot.js": "3099141f8935b0c2f15a041f205a673c977a9c8bfc7aa30f23a44b44a69bdb1d",
392
- "dist/app/build.json": "9501c02bb88f888c3e1d1372639af38dda1a903303a98f171157d9ef71bc8650",
393
- "dist/app/index.html": "589d09b0163556302d5ea86ff5753819433a9f4a105df112be29917a8966efab",
396
+ "dist/app/build.json": "0fc2dcaa057dd9fc871cdc5f6bc7bae013165b7cacdc44a3b2f99d38caf8ce9d",
397
+ "dist/app/index.html": "4aae15c67b20300637c1d0a8cf445ecce83d560d5325625fc186ba7442a11085",
394
398
  "dist/app/licenses.txt": "7a2bb91cbbc5e4201b72d4d95b2a4d7458f42e80a0d05b01398c9e93f5764f62",
395
- "package.json": "490e457e603233c01f17bce234e211374d76cb8cd6d9dc0f684ed9bf74f58144",
399
+ "package.json": "049e3b8cb2fc25044417895237975f23a9f7ae8a7863166224815e8e8f74faa5",
396
400
  "slots.json": "3252f255e1628537056317d74be5fd2db2fb7e283cd6e8d3f2d49e6dad4b15e5"
397
401
  },
398
402
  "@kedge/cli": {
399
403
  "LICENSE": "5068e060c465b99dee8b5d7ccfecc51f395affd63d6b9651a2d31e71e3a0d9fb",
400
- "README.md": "642be70aa940d01572dc5e91482353b3ecb9c24d4558f3014a4b93fb62a909fd",
404
+ "README.md": "8b6cbd9f74ea766b082cefa0afbd241bbfda3c10e9c7c7ce8b3d728790d1933f",
401
405
  "bin/kedge.mjs": "8279a888842a6ee6c0ae9e26fd4380b97892648ca94979fc69d505ff8af6aa9f",
402
- "package.json": "a1cf74349dcaaee6cf5485f5d567eaef8d6edc815999401e276f34624e83b6e0",
406
+ "package.json": "c63256ac55804475bb3ad8d699834c5dd4bf16aa04ab1f6661abd27b4d5fd194",
403
407
  "src/cf.ts": "bf87715c96490278e9679c87818ad7962a7f66c7b38af3895a9f8323d06d7a2c",
404
408
  "src/check.ts": "273ff4b59d717aea33e166e4d88775f190fa826cc3432642a2ccfa2cad12ddd6",
405
409
  "src/cli-session.ts": "dbff2b69ac8fd50c62ebfc082a4d8344561afe5ceb9b389494d1010a7b34d883",
@@ -414,7 +418,7 @@
414
418
  "src/invariants.ts": "177446f4144571345c6872f816a076dc88f5dc92dc0503281456f3a2164229ae",
415
419
  "src/keys-save.ts": "682e27974af1e0aba6127e70f73b99a848dae7baf31a6db1584d68d64f027581",
416
420
  "src/local-state.ts": "bcfc69f6eb1b3ca134f428e27fe7dd38340755a0a37565587b5c88dfd99cae83",
417
- "src/main.ts": "cc2b9b88d6d63143322fbf5a117085196a31e8592e3bb896eb5a51fdbb672cd1",
421
+ "src/main.ts": "e94c402236e6edc34338bf92f324c8072d2d61273a79bfd5c3a0449bf7b9e757",
418
422
  "src/manifest.ts": "9d52eafd735f9e3d8978588f2b9fb712e17d0e78106170fdb8cd373f39920c87",
419
423
  "src/n1.ts": "17b26eb4114dba819282c44c67ef8bf5fbfcc854674133bee5d87bd250ebdc39",
420
424
  "src/ops.ts": "c7958879d1d3dba8f3f959c2dfd1cff0554b7a56d4dc91a3df2f7b2ccf893eaa",
@@ -423,7 +427,7 @@
423
427
  "src/plugin-lint.ts": "b716e02ee5a2ebaac1ef0bee709d5417fa800aa7ab2b1d3ded1607739091584d",
424
428
  "src/preview.ts": "8d2f4105f62877d4e71a14bcde77356528d084a8aec0fd672afc99e2035a0911",
425
429
  "src/schema.ts": "d0b2b8b1bbb7a9ea1a53e092563ac62f0e98c8c1b27a5172d977e2f1c63453d1",
426
- "src/smoke.ts": "dd722d21d319db8c75a826f799721ae371761497bb3524bf980249a05d94940c",
430
+ "src/smoke.ts": "89051ae975a306aec53cac2e6bd7859c646aa5c3051f5e165a9f072de1e11fbf",
427
431
  "src/sqlite-verify.ts": "1181960dfbbf5b94bd376c024a69d71aaa76bd69c6b92359713acf665e89c3b5",
428
432
  "src/store-api.ts": "146e0aa31041bc9fa8bbf8e87a38e1b9153bb3b6e9c47aa3c3a1549ffbfa6f17",
429
433
  "src/store.ts": "d6b76378ce7ddb2d90b0cf4a44ae599ed5fbc51b2336f2b4f8fe643975706a13",
@@ -432,6 +436,7 @@
432
436
  "src/tz.ts": "5b83e5071d6ce2bdc4d300e7e045be3bc628a239053dcf360a6d3ef11dea9a79",
433
437
  "src/units.ts": "66b6373828802a58d64bf71e8a0e2308afd49fc5f08d0acd816ff539b7309213",
434
438
  "src/upgrade.ts": "06bdb77a35834e92091f92e52612ea2336735df78fd9508c33cfe33789276a36",
439
+ "src/usage.ts": "435a202e3e958a10c28c400fe5e645c829b5d58ff00183dab0d1143f138f4c17",
435
440
  "src/worker-config.ts": "5b4cd682f0430f8239108d72a05ac8586da85639a9ad6a67d4169e5e90237136"
436
441
  }
437
442
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kedge/cli",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,16 +28,16 @@
28
28
  "yaml": "2.9.1",
29
29
  "@babel/parser": "7.29.9",
30
30
  "wrangler": "4.152.0",
31
- "@kedge/core": "0.11.0",
32
- "@kedge/db": "0.11.0",
33
- "@kedge/testing": "0.11.0",
34
- "@kedge/runtime-cf": "0.11.0"
31
+ "@kedge/db": "0.11.2",
32
+ "@kedge/core": "0.11.2",
33
+ "@kedge/testing": "0.11.2",
34
+ "@kedge/runtime-cf": "0.11.2"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "24.19.2",
38
38
  "@cloudflare/workers-types": "5.20261024.1",
39
- "@kedge/plugin-handling-fee": "0.0.0",
40
- "@kedge/plugin-loyalty": "0.0.0"
39
+ "@kedge/plugin-loyalty": "0.0.0",
40
+ "@kedge/plugin-handling-fee": "0.0.0"
41
41
  },
42
42
  "scripts": {
43
43
  "typecheck": "tsc --noEmit -p .",
package/src/main.ts CHANGED
@@ -44,66 +44,9 @@ import { emit, withJsonOutput } from "./output";
44
44
  import { composedTexts, schemaOf } from "./schema";
45
45
  import { storeNames } from "./store";
46
46
  import { compileStoreZone } from "./tz";
47
+ import { JSON_COMMANDS, synopsisOf, USAGE, usageOf } from "./usage";
47
48
  import { strictlyPublic } from "./worker-config";
48
49
 
49
- const USAGE = `usage: kedge generate [--check] [--supersede <op-id>]
50
- kedge check [--fast]
51
- kedge doctor [--json]
52
- kedge dev
53
- kedge migrate [--remote]
54
- kedge deploy [--maintenance-window <from>/<to>] [--var K=V]... [--adopt <name>]...
55
- [--resume | --take-over <op-id> --confirm-stopped | --abort-cutover | --supersede <op-id>]
56
- [--resolve-intent <id> --not-executed] [--record-active --reason <what>]
57
- [--adopt-existing --from-release <version>] [--allow-older]
58
- kedge preview [--name N] [--var K=V]... [--fresh] [--secret-env NAME]...
59
- kedge preview build [--name N] | kedge preview apply <plan.tar|-> [--store S] [--name N]
60
- kedge preview destroy [--name N] [--sweep]
61
- kedge eject <unit> --reason "<why>" | kedge eject --rebase <unit>
62
- kedge upgrade --to <version> [--from-packs <dir>]
63
- kedge doctor --core-diff [--upstream <manifest>] [--strict]
64
- kedge secret put <NAME> | kedge secret delete <NAME>
65
- kedge restore --list
66
- kedge seed --sample apparel --url <url> [--key <sk_…> | --session <token>] [--live]
67
- kedge smoke --url <url> [--run <name>] [--live]
68
- kedge keys create (--publishable [--origin <url>]... | --secret --grant <permission>...)
69
- --url <url> (--session <token> | --sign-in <email> [--answers-stdin] | --save) [--name <name>]
70
- kedge staff invite-owner <email> [--database DB] [--remote] [--url <url>] [--config wrangler.jsonc]
71
- kedge staff recover <email> [--database DB] [--remote] [--config wrangler.jsonc]
72
- kedge keys create --publishable --name <name> [--origin <origin>]... [--pepper-version N]
73
- [--database DB] [--remote] [--config wrangler.jsonc]
74
-
75
- generate compose core, plugin and local migrations into migrations/
76
- and update kedge.lock.json
77
- generate --check fail if generate would write anything (for CI)
78
- dev fresh local secrets once, local migrations, then wrangler dev
79
- migrate local migrations; --remote applies N−1 files to production, refusing a cutover
80
- deploy migrations before the Worker, under an operation in <store>-ops (§6)
81
- preview a separate Worker with its own D1, queue and Durable Objects, capture
82
- sinks for every effect, seeded, then test/scenarios/*.http.ts against it
83
- eject copy one unit of core into src/overrides, its upstream hash recorded
84
- upgrade every @kedge package to a release one supported step on, its codemods,
85
- UPGRADE-TODO.md, then generate and check; nothing is committed
86
- restore --list the restore points; restoring waits for P1.18
87
- smoke a test order on one of this store's own URLs: a cart, completion and
88
- placement, resumed by its --run name until it has its number
89
- check typecheck, generate --check, doctor, then the store's tests;
90
- --fast stops before the tests (the Stop hook's)
91
- doctor the store's offline checks: lock, installed core, error map,
92
- invariant catalog, code lint, wrangler.jsonc
93
- staff invite-owner the first Owner's one-time invite (only while no active Owner exists)
94
- staff recover reset a sole Owner's factors and print a reenrol invite
95
- keys create a storefront and its first publishable key; reads the pepper from
96
- KEDGE_KEY_PEPPER_V<N> in the environment (N defaults to 1)
97
-
98
- The staff and keys commands run one audited batch through wrangler d1 execute
99
- (--local unless --remote) and print the secret once.
100
-
101
- deploy, preview, seed, staff and keys take --json: one object on stdout when they
102
- end ({"ok": true, ...}, or {"ok": false, "error"} / {"ok": false, "handoff"}),
103
- everything else on stderr. Exit 3 means a person must act: the last line of stderr
104
- starts "for you:". --sign-in asks only a terminal; --answers-stdin reads one line
105
- per question from a pipe, waiting 30 seconds for each.`;
106
-
107
50
  /**
108
51
  * The store's origin for the invite link (p0.9 §3.5): `--url`, or with
109
52
  * `--remote` the Worker's workers.dev URL. Null when neither is known, and then
@@ -148,9 +91,10 @@ async function bootstrap(
148
91
  if (o.json) (o.emit ?? emit)(r);
149
92
  };
150
93
  // A usage error is an end too: under --json it's an object, never an empty stdout (codex code r8).
94
+ // The sentence says what's wrong, and the command's own usage follows it (p0.11.1 row 3).
151
95
  const usage = (message: string) => {
152
- console.error(message);
153
- result({ ok: false, error: message.split("\n")[0] });
96
+ console.error(`${message}\n\n${usageOf(command)}`);
97
+ result({ ok: false, error: message });
154
98
  return 2;
155
99
  };
156
100
  // Wrangler's own words are on stderr already; the object says only that the batch didn't finish.
@@ -158,6 +102,26 @@ async function bootstrap(
158
102
  result({ ok: false, error: `wrangler d1 execute exited ${status}` });
159
103
  return status;
160
104
  };
105
+ // The command line first, before credentials, the account or any batch (p0.11.1 §2): a mistake
106
+ // in it is the agent's to fix, exit 2, never a credentials handoff that wouldn't fix it (codex r1).
107
+ const [first, target] = args;
108
+ // A flag first is no subcommand: `kedge keys --url …` needs `create`, not an unknown `--url`.
109
+ const sub = first?.startsWith("-") ? undefined : first;
110
+ const email = sub && target && !target.startsWith("--") ? target : undefined;
111
+ if (command === "staff") {
112
+ if (sub !== "invite-owner" && sub !== "recover")
113
+ return usage(sub ? `unknown command: kedge staff ${sub}` : "kedge staff needs invite-owner or recover");
114
+ if (!email) return usage(`staff ${sub} needs the Owner's email: ${synopsisOf(`staff ${sub}`)[0]?.trim()}`);
115
+ } else {
116
+ if (sub !== "create") return usage(sub ? `unknown command: kedge keys ${sub}` : "kedge keys needs create");
117
+ if (!args.includes("--publishable"))
118
+ return usage("keys create needs --publishable, or --url and a sign-in to create a key through the store's API");
119
+ }
120
+ const name = flag(args, "--name");
121
+ const pepperVersion = Number(flag(args, "--pepper-version") ?? "1");
122
+ if (command === "keys" && !name) return usage("keys create needs --name");
123
+ if (command === "keys" && (!Number.isSafeInteger(pepperVersion) || pepperVersion < 1))
124
+ return usage("--pepper-version takes a whole number from 1");
161
125
  const config = flag(args, "--config");
162
126
  const remote = args.includes("--remote");
163
127
  // Resolved before any write, as every remote command does (p0.10 §4): no credentials is the
@@ -185,43 +149,35 @@ async function bootstrap(
185
149
  : {}),
186
150
  };
187
151
  const now = Date.now();
188
- const [sub, target] = args;
189
- if (command === "staff" && (sub === "invite-owner" || sub === "recover") && target && !target.startsWith("--")) {
190
- const b = sub === "invite-owner" ? await ownerInviteSql(target, now) : await recoverSql(target, now);
152
+ if (command === "staff" && email) {
153
+ const b = sub === "invite-owner" ? await ownerInviteSql(email, now) : await recoverSql(email, now);
191
154
  const status = execute(b, opts);
192
155
  if (status !== 0) return failed(status);
193
156
  const expires = new Date(b.expiresAt).toISOString();
194
- console.log(`invite ${b.inviteId} for ${target}, valid until ${expires}`);
157
+ console.log(`invite ${b.inviteId} for ${email}, valid until ${expires}`);
195
158
  console.log(`accept with POST /auth/admin/invites/accept and this token (shown once):\n${b.token}`);
196
159
  const origin = await inviteOrigin(args, opts.remote, cwd, env, cf);
197
160
  // The token rides in the fragment, which no server log or Referer carries (p0.9 §3.5).
198
161
  const link = origin ? `${origin}/app/invite#${b.token}` : null;
199
162
  if (link) console.log(`or open the admin's invite page:\n${link}`);
200
- result({ ok: true, invite: b.inviteId, email: target, expires_at: expires, token: b.token, link });
163
+ result({ ok: true, invite: b.inviteId, email, expires_at: expires, token: b.token, link });
201
164
  return 0;
202
165
  }
203
- if (command === "keys" && sub === "create" && args.includes("--publishable")) {
204
- const name = flag(args, "--name");
205
- if (!name) return usage("keys create needs --name");
206
- const origins = args.flatMap((a, i) => (a === "--origin" && args[i + 1] ? [args[i + 1] as string] : []));
207
- const pepperVersion = Number(flag(args, "--pepper-version") ?? "1");
208
- const pepper = env[`KEDGE_KEY_PEPPER_V${pepperVersion}`];
209
- if (!Number.isSafeInteger(pepperVersion) || pepperVersion < 1)
210
- return usage("--pepper-version takes a whole number from 1");
211
- // The pepper lives in the merchant's own vault, or only in the Worker: theirs to hand over (p0.10 §5).
212
- if (!pepper)
213
- throw new NeedsPerson(
214
- `set KEDGE_KEY_PEPPER_V${pepperVersion} to the Worker's pepper secret, or create the key with --url and --sign-in, which keeps the pepper in the Worker`,
215
- );
216
- const b = await publishableKeySql({ name, origins, pepperVersion, pepper }, now);
217
- const status = execute(b, opts);
218
- if (status !== 0) return failed(status);
219
- console.log(`storefront ${b.storefrontId}, key ${b.keyId}`);
220
- console.log(`publishable key (send as x-kedge-key; shown once):\n${b.key}`);
221
- result({ ok: true, storefront: b.storefrontId, key_id: b.keyId, key: b.key });
222
- return 0;
223
- }
224
- return usage(USAGE);
166
+ // keys create --publishable, its name and pepper version checked above.
167
+ const origins = args.flatMap((a, i) => (a === "--origin" && args[i + 1] ? [args[i + 1] as string] : []));
168
+ const pepper = env[`KEDGE_KEY_PEPPER_V${pepperVersion}`];
169
+ // The pepper lives in the merchant's own vault, or only in the Worker: theirs to hand over (p0.10 §5).
170
+ if (!pepper)
171
+ throw new NeedsPerson(
172
+ `set KEDGE_KEY_PEPPER_V${pepperVersion} to the Worker's pepper secret, or create the key with --url and --sign-in, which keeps the pepper in the Worker`,
173
+ );
174
+ const b = await publishableKeySql({ name: name as string, origins, pepperVersion, pepper }, now);
175
+ const status = execute(b, opts);
176
+ if (status !== 0) return failed(status);
177
+ console.log(`storefront ${b.storefrontId}, key ${b.keyId}`);
178
+ console.log(`publishable key (send as x-kedge-key; shown once):\n${b.key}`);
179
+ result({ ok: true, storefront: b.storefrontId, key_id: b.keyId, key: b.key });
180
+ return 0;
225
181
  }
226
182
 
227
183
  const INDEX_START = "<!-- kedge:docs-index:start -->";
@@ -297,9 +253,6 @@ interface RunDeps {
297
253
  emit?: (result: Record<string, unknown>) => void;
298
254
  }
299
255
 
300
- /** The commands an agent reads the result of (p0.10 §5); doctor has its own `--json`. */
301
- const JSON_COMMANDS = new Set(["deploy", "preview", "staff", "keys", "seed", "smoke"]);
302
-
303
256
  async function run(argv: string[], cwd: string, deps: RunDeps & { json: boolean }): Promise<number> {
304
257
  const [command, ...flags] = argv;
305
258
  const out = {
@@ -307,7 +260,9 @@ async function run(argv: string[], cwd: string, deps: RunDeps & { json: boolean
307
260
  ...(deps.emit ? { emit: deps.emit } : {}),
308
261
  ...(deps.execute ? { execute: deps.execute } : {}),
309
262
  };
310
- if (command === "keys" && flag(flags, "--url")) {
263
+ // Only `keys create` goes over HTTP: anything else is bootstrap's usage error, before a sign-in
264
+ // or a request, so a mistyped subcommand never creates a key (codex code r2).
265
+ if (command === "keys" && flags[0] === "create" && flag(flags, "--url")) {
311
266
  const d0: CommandDeps = { cwd, env: deps.env ?? process.env, coreDir: coreMigrationsDir(), ...out };
312
267
  return keysOverHttp(flags, d0);
313
268
  }
@@ -410,7 +365,7 @@ async function run(argv: string[], cwd: string, deps: RunDeps & { json: boolean
410
365
  doctor: (c: string) => main(["doctor"], c),
411
366
  });
412
367
  if (command !== "generate") {
413
- console.error(USAGE);
368
+ console.error(command ? `unknown command: ${command}\n\n${USAGE}` : USAGE);
414
369
  return 2;
415
370
  }
416
371
  const check = flags.includes("--check");
@@ -470,6 +425,8 @@ async function run(argv: string[], cwd: string, deps: RunDeps & { json: boolean
470
425
  }
471
426
  }
472
427
 
428
+ const HELP = new Set(["--help", "-h"]);
429
+
473
430
  /**
474
431
  * The CLI. A handoff from any command ends it with exit 3 and one sentence for
475
432
  * whoever runs it to pass on (p0.10 §5).
@@ -477,6 +434,23 @@ async function run(argv: string[], cwd: string, deps: RunDeps & { json: boolean
477
434
  export async function main(argv: string[], cwd: string, deps: RunDeps = {}): Promise<number> {
478
435
  const [command, ...flags] = argv;
479
436
  const json = flags.includes("--json") && JSON_COMMANDS.has(command ?? "");
437
+ // Help runs nothing, whatever else is on the line: an agent asks a command for --help
438
+ // before running it, and `kedge dev --help` that starts the server blocks it until its
439
+ // tool times out (p0.11.1 row 2). One check here, so no command can forget it.
440
+ if (command === "help" || (command && HELP.has(command)) || flags.some((f) => HELP.has(f))) {
441
+ const of = command === "help" || HELP.has(command ?? "") ? flags.find((f) => !f.startsWith("-")) : command;
442
+ const text = of ? usageOf(of) : USAGE;
443
+ if (text === null) {
444
+ console.error(`unknown command: ${of}\n\n${USAGE}`);
445
+ return 2;
446
+ }
447
+ // One object under --json when the command it's for takes --json, `kedge help <command>` too, and
448
+ // doctor, whose --json is its own (codex code r1, r2).
449
+ if (flags.includes("--json") && (!of || of === "doctor" || JSON_COMMANDS.has(of)))
450
+ (deps.emit ?? emit)({ ok: true, usage: text });
451
+ else console.log(text);
452
+ return 0;
453
+ }
480
454
  return withJsonOutput(json, async () => {
481
455
  try {
482
456
  return await run(argv, cwd, { ...deps, json });
package/src/smoke.ts CHANGED
@@ -207,7 +207,8 @@ async function run(db: DatabaseSync, target: StoreTarget, name: string, d: Smoke
207
207
  `the order is ${status}${number ? ` (${number})` : ", with no number"}, so it isn't placed`,
208
208
  );
209
209
  set({ number });
210
- d.log(`order ${number} is open (smoke run ${name})`);
210
+ // An open order's expires_at reads like a hold that lapses, and agents told merchants so (p0.11.1 row 8).
211
+ d.log(`order ${number} is open (smoke run ${name}): placed and unpaid, its unit reserved until it's fulfilled or canceled`);
211
212
  return { run: name, order_id: orderId, number, status };
212
213
  }
213
214
 
package/src/usage.ts ADDED
@@ -0,0 +1,110 @@
1
+ // The `kedge` command's usage, the one home for it (p0.11.1 §2): `kedge --help`
2
+ // prints it all, and `kedge <command> --help` the parts for that command.
3
+
4
+ const SYNOPSIS = `usage: kedge generate [--check] [--supersede <op-id>]
5
+ kedge check [--fast]
6
+ kedge doctor [--remote] [--json]
7
+ kedge dev
8
+ kedge migrate [--remote]
9
+ kedge deploy [--maintenance-window <from>/<to>] [--var K=V]... [--adopt <name>]...
10
+ [--resume | --take-over <op-id> --confirm-stopped | --abort-cutover | --supersede <op-id>]
11
+ [--resolve-intent <id> --not-executed] [--record-active --reason <what>]
12
+ [--adopt-existing --from-release <version>] [--allow-older]
13
+ kedge preview [--name N] [--var K=V]... [--fresh] [--secret-env NAME]...
14
+ kedge preview build [--name N] | kedge preview apply <plan.tar|-> [--store S] [--name N]
15
+ kedge preview destroy [--name N] [--sweep]
16
+ kedge eject <unit> --reason "<why>" | kedge eject --rebase <unit>
17
+ kedge upgrade --to <version> [--from-packs <dir>]
18
+ kedge doctor --core-diff [--upstream <manifest>] [--strict]
19
+ kedge secret put <NAME> | kedge secret delete <NAME>
20
+ kedge restore --list
21
+ kedge seed --sample apparel --url <url> [--key <sk_…> | --session <token>] [--live]
22
+ kedge smoke --url <url> [--run <name>] [--live]
23
+ kedge keys create (--publishable [--origin <url>]... | --secret --grant <permission>...)
24
+ --url <url> (--session <token> | --sign-in <email> [--answers-stdin] | --save) [--name <name>]
25
+ kedge staff invite-owner <email> [--database DB] [--remote] [--url <url>] [--config wrangler.jsonc]
26
+ kedge staff recover <email> [--database DB] [--remote] [--config wrangler.jsonc]
27
+ kedge keys create --publishable --name <name> [--origin <origin>]... [--pepper-version N]
28
+ [--database DB] [--remote] [--config wrangler.jsonc]`;
29
+
30
+ const DESCRIPTIONS = ` generate compose core, plugin and local migrations into migrations/
31
+ and update kedge.lock.json
32
+ generate --check fail if generate would write anything (for CI)
33
+ dev fresh local secrets once, local migrations, then wrangler dev
34
+ migrate local migrations; --remote applies N−1 files to production, refusing a cutover
35
+ deploy migrations before the Worker, under an operation in <store>-ops (§6)
36
+ preview a separate Worker with its own D1, queue and Durable Objects, capture
37
+ sinks for every effect, seeded, then test/scenarios/*.http.ts against it
38
+ secret put or delete one of the Worker's secrets; put reads the value from
39
+ stdin, 32 bytes or more
40
+ eject copy one unit of core into src/overrides, its upstream hash recorded
41
+ upgrade every @kedge package to a release one supported step on, its codemods,
42
+ UPGRADE-TODO.md, then generate and check; nothing is committed
43
+ restore --list the restore points; restoring waits for P1.18
44
+ seed a sample catalogue (--sample apparel) on one of this store's own URLs,
45
+ through its admin API
46
+ smoke a test order on one of this store's own URLs: a cart, completion and
47
+ placement, resumed by its --run name until it has its number
48
+ check typecheck, generate --check, doctor, then the store's tests;
49
+ --fast stops before the tests (the Stop hook's)
50
+ doctor the store's offline checks: lock, installed core, error map,
51
+ invariant catalog, code lint, wrangler.jsonc
52
+ staff invite-owner the first Owner's one-time invite (only while no active Owner exists)
53
+ staff recover reset a sole Owner's factors and print a reenrol invite
54
+ keys create a storefront and its first publishable key, or a secret key. With
55
+ --url, through the store's own API, signed in as staff: the pepper
56
+ stays in the Worker. Without it, --publishable is one D1 batch that
57
+ reads the pepper from KEDGE_KEY_PEPPER_V<N> (N defaults to 1)`;
58
+
59
+ /** The commands an agent reads the result of (p0.10 §5); doctor has its own `--json`. */
60
+ export const JSON_COMMANDS = new Set(["deploy", "preview", "staff", "keys", "seed", "smoke"]);
61
+
62
+ const BOOTSTRAP_NOTE = ` The staff commands, and keys create without --url, run one audited batch through
63
+ wrangler d1 execute (--local unless --remote) and print the secret once.`;
64
+
65
+ const JSON_NOTE = ` deploy, preview, seed, smoke, staff and keys take --json: one object on stdout when
66
+ they end ({"ok": true, ...}, or {"ok": false, "error"} / {"ok": false, "handoff"}),
67
+ everything else on stderr. Exit 3 means a person must act: the last line of stderr
68
+ starts "for you:". --sign-in asks only a terminal; --answers-stdin reads one line
69
+ per question from a pipe, waiting 30 seconds for each.`;
70
+
71
+ export const USAGE = [SYNOPSIS, DESCRIPTIONS, BOOTSTRAP_NOTE, JSON_NOTE].join("\n\n");
72
+
73
+ /** Entries of a block: an entry is its first line and the lines indented past it. */
74
+ function entries(text: string, starts: (line: string) => boolean): string[][] {
75
+ const out: string[][] = [];
76
+ for (const line of text.split("\n")) {
77
+ if (starts(line)) out.push([line]);
78
+ else out.at(-1)?.push(line);
79
+ }
80
+ return out;
81
+ }
82
+
83
+ /** Whether a line's words begin with `words` (`kedge staff` names `kedge staff recover`, never `kedge staffs`). */
84
+ const names = (line: string, words: string) => line === words || line.startsWith(`${words} `);
85
+
86
+ /** The synopsis entries for a command or subcommand (`staff`, `staff invite-owner`), one string each. */
87
+ export function synopsisOf(words: string): string[] {
88
+ return entries(SYNOPSIS, (l) => /^(usage: | {7})kedge /.test(l))
89
+ .filter((e) => names((e[0] as string).replace(/^(usage: | {7})/, ""), `kedge ${words}`))
90
+ .map((e) => e.join("\n"));
91
+ }
92
+
93
+ /**
94
+ * A command's help: its synopsis, its descriptions and the notes that apply to
95
+ * it, or null for a command that isn't one. Every command `run()` dispatches has
96
+ * a synopsis and a description, which a test holds.
97
+ */
98
+ export function usageOf(command: string): string | null {
99
+ const synopsis = synopsisOf(command).map((e) => e.replace(/^(usage: | {7})/, " "));
100
+ if (!synopsis.length) return null;
101
+ const descriptions = entries(DESCRIPTIONS, (l) => /^ {2}\S/.test(l))
102
+ .filter((e) => names((e[0] as string).trim(), command))
103
+ .map((e) => e.join("\n"));
104
+ return [
105
+ `usage: ${synopsis.join("\n").slice(7)}`,
106
+ descriptions.join("\n"),
107
+ ...(command === "staff" || command === "keys" ? [BOOTSTRAP_NOTE] : []),
108
+ ...(JSON_COMMANDS.has(command) ? [JSON_NOTE] : []),
109
+ ].join("\n\n");
110
+ }