@bitkyc08/opencodex 2.15.1 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/gui/dist/assets/{index-CMCDkQ7U.js → index-DOKr6RBR.js} +10 -10
  2. package/gui/dist/index.html +1 -1
  3. package/package.json +1 -1
  4. package/src/adapters/base.ts +2 -0
  5. package/src/adapters/google-antigravity-replay.ts +9 -1
  6. package/src/adapters/kiro-thinking.ts +8 -0
  7. package/src/adapters/kiro.ts +45 -42
  8. package/src/adapters/openai-chat.ts +5 -2
  9. package/src/adapters/openai-responses.ts +5 -1
  10. package/src/cli/dispatch.ts +6 -3
  11. package/src/cli/export-command.ts +19 -7
  12. package/src/cli/help.ts +1 -1
  13. package/src/cli/index.ts +1 -0
  14. package/src/cli/registry.ts +2 -2
  15. package/src/clients/config-export.ts +165 -3
  16. package/src/generated/compatibility-version.json +59 -31
  17. package/src/integrations/config-io.ts +119 -1
  18. package/src/integrations/omp-yaml-source.ts +232 -99
  19. package/src/integrations/registry.ts +14 -0
  20. package/src/integrations/serialize.ts +80 -1
  21. package/src/integrations/state.ts +38 -6
  22. package/src/integrations/writer-lock.ts +98 -0
  23. package/src/integrations/writer.ts +152 -19
  24. package/src/lab/automation/orchestrator.ts +19 -0
  25. package/src/lib/lab-activation.ts +161 -0
  26. package/src/lib/lab-passive-linker-registration.ts +26 -0
  27. package/src/lib/optional-shutdown-hooks.ts +57 -0
  28. package/src/lib/shadow-call.ts +6 -14
  29. package/src/lib/translator-budget.ts +34 -0
  30. package/src/providers/antigravity-models.ts +65 -10
  31. package/src/routing/compatibility/assemble.ts +21 -107
  32. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  33. package/src/routing/compatibility/provider-slot.ts +56 -0
  34. package/src/server/index.ts +8 -17
  35. package/src/server/lifecycle.ts +5 -3
  36. package/src/server/management/integration-routes.ts +21 -14
  37. package/src/server/management/routing-profile-routes.ts +9 -1
  38. package/src/server/management-api.ts +37 -6
  39. package/src/server/passive-route-linker.ts +66 -0
  40. package/src/server/responses/core.ts +20 -21
  41. package/src/types.ts +15 -5
@@ -10,7 +10,7 @@
10
10
  },
11
11
  {
12
12
  "path": "package.json",
13
- "sha256": "9db72337e10283bebce7752061492ab1be0a14fe85b2c9dbd32bcf1395cf5f2f"
13
+ "sha256": "b8810736c02b3cf34dbd0119082924f56a48e435cd9a0768c68c428f8e128cda"
14
14
  },
15
15
  {
16
16
  "path": "scripts/model-metadata.source.json",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  {
44
44
  "path": "src/adapters/base.ts",
45
- "sha256": "67f50a3e0e45514f55f08d19726acfcab6fe4a9bd5e88bb7455b5af236a10663"
45
+ "sha256": "f20fdca89cd4bac4ec049ab46e200f2aa6435dae548c5994b7edf5b6d73f1bd5"
46
46
  },
47
47
  {
48
48
  "path": "src/adapters/client-fingerprint.ts",
@@ -182,7 +182,7 @@
182
182
  },
183
183
  {
184
184
  "path": "src/adapters/google-antigravity-replay.ts",
185
- "sha256": "230da5cd5c6a94c2f520eeea2905294df6320e95e6f6e42569a4bfe04724193d"
185
+ "sha256": "52704bcd65eab346025e6faffe70d0c1d07e39651e4139f34bc67759fbaa4f08"
186
186
  },
187
187
  {
188
188
  "path": "src/adapters/google-antigravity-wire.ts",
@@ -242,7 +242,7 @@
242
242
  },
243
243
  {
244
244
  "path": "src/adapters/kiro-thinking.ts",
245
- "sha256": "d4016e1314c8b91bada92fff3ec4b94d0e1d88c4e51db49c29a482584844dfe0"
245
+ "sha256": "c7093dd20dc16156aee4d6a37de0b71f6e646c09f2ba99be8f3c6a388703a981"
246
246
  },
247
247
  {
248
248
  "path": "src/adapters/kiro-tool-fallback.ts",
@@ -262,7 +262,7 @@
262
262
  },
263
263
  {
264
264
  "path": "src/adapters/kiro.ts",
265
- "sha256": "c396bcf9810a1381f71957f95ed8399a13e240f5dc6be878c8836dfa7ca66f52"
265
+ "sha256": "fe61e9e4f8d7eada8baab90e09e9b2b03641c114eabe7846f2947cb0667996f1"
266
266
  },
267
267
  {
268
268
  "path": "src/adapters/mimo-free.ts",
@@ -274,7 +274,7 @@
274
274
  },
275
275
  {
276
276
  "path": "src/adapters/openai-chat.ts",
277
- "sha256": "1fcd9a2da1e675026fa2ac03b396cefa7cd62e3c1baf27844bbe7fd589c70275"
277
+ "sha256": "c87e922e32ccf8c224891e9a3a42e86139eb7db8d97b9c46613f01a132afc6fa"
278
278
  },
279
279
  {
280
280
  "path": "src/adapters/openai-responses-url.ts",
@@ -282,7 +282,7 @@
282
282
  },
283
283
  {
284
284
  "path": "src/adapters/openai-responses.ts",
285
- "sha256": "9c8d4483c0dacf3bf0562f08fe61b43d3c3107f1a978d66fc916c3da5dfe1d17"
285
+ "sha256": "8d4809ac4228beea1fa08716cd43c9ab7a87fdeaed5f30f39336ee808375b98d"
286
286
  },
287
287
  {
288
288
  "path": "src/adapters/run-turn-queue.ts",
@@ -446,7 +446,7 @@
446
446
  },
447
447
  {
448
448
  "path": "src/cli/dispatch.ts",
449
- "sha256": "2cba2f25e64bef2b08f1299a8b94757517bdf8bcd56e9ce2c7d46e50be3cce47"
449
+ "sha256": "478bd9539c26322ec5365e80f44674d507c708ccff6d09605a6e7804abedee79"
450
450
  },
451
451
  {
452
452
  "path": "src/cli/doctor.ts",
@@ -454,15 +454,15 @@
454
454
  },
455
455
  {
456
456
  "path": "src/cli/export-command.ts",
457
- "sha256": "c00b92f6cdaa188334e1635aa98b161bfbb2ce269f4435c4cfacff263478264d"
457
+ "sha256": "55489975589c8a411cab9d16835390f46a2059968c35344503aff9ffc4bc6e42"
458
458
  },
459
459
  {
460
460
  "path": "src/cli/help.ts",
461
- "sha256": "a696a035ce31447412ff5f025d07019ed445dd12c253c8a83ac5ee6c4679d1cb"
461
+ "sha256": "91c302e213e4d40d5612aee041c5a938d74a06c9a55310eccd45d2ceb08bce4a"
462
462
  },
463
463
  {
464
464
  "path": "src/cli/index.ts",
465
- "sha256": "8e3e096dac1115ae5a1a8c12d740b72766f4a1a1ece1e96c7e05d11b83080adb"
465
+ "sha256": "63e8747afb606295340bd30598d7112b75efb2a89353234a874df42c5fc7e1a7"
466
466
  },
467
467
  {
468
468
  "path": "src/cli/init.ts",
@@ -514,7 +514,7 @@
514
514
  },
515
515
  {
516
516
  "path": "src/cli/registry.ts",
517
- "sha256": "cf65a3022a6b8c97f7926f6057b69c47a9cdc71540798420fc5a06b861e64588"
517
+ "sha256": "1eb67cf2d3fb58a0b380d4a8cf71fee1ac3ac2123df6f52a4ee878da0e8a60db"
518
518
  },
519
519
  {
520
520
  "path": "src/cli/root.ts",
@@ -558,7 +558,7 @@
558
558
  },
559
559
  {
560
560
  "path": "src/clients/config-export.ts",
561
- "sha256": "65344216431c824d1e38d4cee44d955ac4d6115e19e3ff784582bfabec2df70a"
561
+ "sha256": "4631957993e4d31bc41ecd56791ffed1e6356e3dd9d5107aca1bc9e4c5297de8"
562
562
  },
563
563
  {
564
564
  "path": "src/codex/account-id.ts",
@@ -1038,7 +1038,7 @@
1038
1038
  },
1039
1039
  {
1040
1040
  "path": "src/integrations/config-io.ts",
1041
- "sha256": "5193f6718cab71d9b7117faec5feb3a413bc1ccfc1b1f5649451cba909b5bf15"
1041
+ "sha256": "5271736a6499bc4bcb68bde2ccefd8ef8ce7953bddf13e764fb1b9ee66433fe3"
1042
1042
  },
1043
1043
  {
1044
1044
  "path": "src/integrations/journal.ts",
@@ -1054,7 +1054,7 @@
1054
1054
  },
1055
1055
  {
1056
1056
  "path": "src/integrations/omp-yaml-source.ts",
1057
- "sha256": "b9e4355893d74cfff01892c2b2a0e164420d07beb5222818e14cddaff0c3d718"
1057
+ "sha256": "ba30982af0520ffe5c841b7254ab6d73e2a9fb53636f3c5096c9fa6ccfc41005"
1058
1058
  },
1059
1059
  {
1060
1060
  "path": "src/integrations/ownership.ts",
@@ -1062,23 +1062,27 @@
1062
1062
  },
1063
1063
  {
1064
1064
  "path": "src/integrations/registry.ts",
1065
- "sha256": "5666d2e9e1a9086074cd99a9ad66cb6c649a470182b3c7bad4e8cc785b3d87f2"
1065
+ "sha256": "299064969a383a4202e5c243d52d7b8f677a675db04a0661f66be01ae74e25d6"
1066
1066
  },
1067
1067
  {
1068
1068
  "path": "src/integrations/serialize.ts",
1069
- "sha256": "e7a23ead6a5a6445ddc7803af9aa8cfebc745e2d6ab325828b95689a50c9b29d"
1069
+ "sha256": "0560601276b25d82eaf6e5460c815e0a67ecb4cf1cf6e378952c60dedfb333e6"
1070
1070
  },
1071
1071
  {
1072
1072
  "path": "src/integrations/state.ts",
1073
- "sha256": "65dd695356bce8ac9593e4cbec64ab85ca9d54784a0e7c8ae7294b9e9a81fba0"
1073
+ "sha256": "2b31611ea745ae22d4292719c2deb453efe6d5ea0cecba62d6d4352a30744e77"
1074
1074
  },
1075
1075
  {
1076
1076
  "path": "src/integrations/store.ts",
1077
1077
  "sha256": "195fe1af41fdaf567bfdaef5c457ee2452a77c43fc13475fccc7968676a2b199"
1078
1078
  },
1079
+ {
1080
+ "path": "src/integrations/writer-lock.ts",
1081
+ "sha256": "4e133b69db94784460351a2ce947172fd6499235029fdf866fa3eff2afc477b5"
1082
+ },
1079
1083
  {
1080
1084
  "path": "src/integrations/writer.ts",
1081
- "sha256": "e2857bcc0351f1b6de8ba7d2fb6da27eff621e35ff69d40138e789ac24b116d6"
1085
+ "sha256": "788709e9e0505cc717f5c015110d8fa17246dc5b33185fafc99d8136236f1606"
1082
1086
  },
1083
1087
  {
1084
1088
  "path": "src/lab/artifacts/sanitize.ts",
@@ -1118,7 +1122,7 @@
1118
1122
  },
1119
1123
  {
1120
1124
  "path": "src/lab/automation/orchestrator.ts",
1121
- "sha256": "ea12b23eceb13af13e6139a90ecd6b62ddd9485be118ef15027aff8c75621b6b"
1125
+ "sha256": "5f10d45593ea6464f6ecd1db6ee922bc7627fc6578fe6f3f93b7a35c1b479df8"
1122
1126
  },
1123
1127
  {
1124
1128
  "path": "src/lab/automation/persistence.ts",
@@ -1548,6 +1552,10 @@
1548
1552
  "path": "src/lib/injection-debug-log.ts",
1549
1553
  "sha256": "ab3b8e53c546c0ff43dc129d29c0b11c2d258f86e9d12475d87bf55510eb02c9"
1550
1554
  },
1555
+ {
1556
+ "path": "src/lib/lab-activation.ts",
1557
+ "sha256": "7cdfb758543a789a75354ebfba730c516d264a4d6a10648456f57e2654034dec"
1558
+ },
1551
1559
  {
1552
1560
  "path": "src/lib/lab-live-execution-authority.ts",
1553
1561
  "sha256": "7a4c488521b861ad70a87f560d85cb5c9f552e16493c5d44e19734947b4ac714"
@@ -1564,6 +1572,10 @@
1564
1572
  "path": "src/lib/lab-live-route-production.ts",
1565
1573
  "sha256": "fb890cceb6390cd2d846c86c97e0d490ea8b58783cd7410d032b6d8573a07f49"
1566
1574
  },
1575
+ {
1576
+ "path": "src/lib/lab-passive-linker-registration.ts",
1577
+ "sha256": "5f88d3428f87f1773f944e43d812356b96e881dcb8bd13d34baf504ce509e54c"
1578
+ },
1567
1579
  {
1568
1580
  "path": "src/lib/local-management-attestation.ts",
1569
1581
  "sha256": "1bccf8f85ecd89cb017224024ca3d199d97c8ce88f5ac936dbc1419845a77f6e"
@@ -1580,6 +1592,10 @@
1580
1592
  "path": "src/lib/open-url.ts",
1581
1593
  "sha256": "a6db7ec7181ccb4e95411b2c7499fdd00f3dd48bebcdaca099da086c0dae2e59"
1582
1594
  },
1595
+ {
1596
+ "path": "src/lib/optional-shutdown-hooks.ts",
1597
+ "sha256": "ba1fb3f46ddd1ad7d1cf90e22ae8df5dd2969dbb99449beaf8fac3100425a908"
1598
+ },
1583
1599
  {
1584
1600
  "path": "src/lib/pinned-http.ts",
1585
1601
  "sha256": "27a69c4eac63db31ef754c84d7f5f2e2949221b5fe27e066420f91b40fcc51d7"
@@ -1622,7 +1638,7 @@
1622
1638
  },
1623
1639
  {
1624
1640
  "path": "src/lib/shadow-call.ts",
1625
- "sha256": "c7e58016fa10385efb4acf23660859f7739afd945c25f593fc774da550316197"
1641
+ "sha256": "2e55cf6e560b18337ac1911b38f20a27c1bd985a65e9496783f2a7cf85014bc6"
1626
1642
  },
1627
1643
  {
1628
1644
  "path": "src/lib/sidecar-tracker.ts",
@@ -1658,7 +1674,7 @@
1658
1674
  },
1659
1675
  {
1660
1676
  "path": "src/lib/translator-budget.ts",
1661
- "sha256": "872d5d35eb0d2ee099fc4ab4bf3b9331c6207d4282f61f2c1b11a5a36c00d981"
1677
+ "sha256": "4d79fed2d10e23b87af2c67ea0a979ce580eb232ac35e1f6851b5f02ef5a07d7"
1662
1678
  },
1663
1679
  {
1664
1680
  "path": "src/lib/upstream-reachability.ts",
@@ -1822,7 +1838,7 @@
1822
1838
  },
1823
1839
  {
1824
1840
  "path": "src/providers/antigravity-models.ts",
1825
- "sha256": "e7a2b7352997cfdc4268c733def555dae8632ba58a3f889dfc78d812b885d072"
1841
+ "sha256": "cbe65f34a127ad44fd8f6bd2214553b238449b4f10d948d5ed67f4b163964874"
1826
1842
  },
1827
1843
  {
1828
1844
  "path": "src/providers/api-keys.ts",
@@ -1990,7 +2006,7 @@
1990
2006
  },
1991
2007
  {
1992
2008
  "path": "src/routing/compatibility/assemble.ts",
1993
- "sha256": "00f0802e3ef8a2bf79779fbe27b62a73e92a94cff11bf5594784fef35dbda495"
2009
+ "sha256": "186010fe58a02823530819cf7bbf06cefdbb3224850ea8321736d1017f32783f"
1994
2010
  },
1995
2011
  {
1996
2012
  "path": "src/routing/compatibility/behavior.ts",
@@ -2004,10 +2020,18 @@
2004
2020
  "path": "src/routing/compatibility/endpoint.ts",
2005
2021
  "sha256": "38578440e02ce712f8d84fa97ec2d1bc3396f31983be9b6e5b0010ef6edd146b"
2006
2022
  },
2023
+ {
2024
+ "path": "src/routing/compatibility/lab-evidence-provider.ts",
2025
+ "sha256": "352a65b6d95c8e6eaa7e6f81fca49284b49a9ddf7bd1895be192b858784fd861"
2026
+ },
2007
2027
  {
2008
2028
  "path": "src/routing/compatibility/policy.ts",
2009
2029
  "sha256": "d903d561ef2ae16c86d16c7ec157556ee0c78557aaa7e83dad46c1abc0e6530c"
2010
2030
  },
2031
+ {
2032
+ "path": "src/routing/compatibility/provider-slot.ts",
2033
+ "sha256": "809c7b5dbe13b6e90d5abf51cadf33825f8d82b5fd1c7355d9ef25b736371bdc"
2034
+ },
2011
2035
  {
2012
2036
  "path": "src/routing/compatibility/reader.ts",
2013
2037
  "sha256": "c48943c0b660609bbdf4d47896de6338cd46b2c9144f1c916646221fe437a678"
@@ -2114,11 +2138,11 @@
2114
2138
  },
2115
2139
  {
2116
2140
  "path": "src/server/index.ts",
2117
- "sha256": "cff5571eb50f6ec315fa2f3ddd835d3bdd25b59c94a5b991771f066ad3e3ffc2"
2141
+ "sha256": "cc6461e629f1f5e373d81ebee0720a9ba85c7deedded457bbd398ac962e0e404"
2118
2142
  },
2119
2143
  {
2120
2144
  "path": "src/server/lifecycle.ts",
2121
- "sha256": "ee926ab2c5bb9925f91ce908ba8ce707859690bae1d07227afc38b259f40ea73"
2145
+ "sha256": "02d0691de03c510419c971341a7015507491599b9a91bec369fd7144f85b05a3"
2122
2146
  },
2123
2147
  {
2124
2148
  "path": "src/server/live.ts",
@@ -2134,7 +2158,7 @@
2134
2158
  },
2135
2159
  {
2136
2160
  "path": "src/server/management-api.ts",
2137
- "sha256": "ccd670a1618afc1ec6611771ec2519ea6c216d0ef43aa9e1114a3a98a9f0e030"
2161
+ "sha256": "0a513030e2b730393d86c87ad237f1e9f35e64586d8736c91c69fed6aaabb60d"
2138
2162
  },
2139
2163
  {
2140
2164
  "path": "src/server/management-auth.ts",
@@ -2170,7 +2194,7 @@
2170
2194
  },
2171
2195
  {
2172
2196
  "path": "src/server/management/integration-routes.ts",
2173
- "sha256": "37d1cdb0e3f993c0cc190e7079dea20ba6daafcfcde314f4f37fdc93bcdcbf79"
2197
+ "sha256": "a049e2dd40f82793c33b7ac584f14ae6ead7e2524a5b1ee3a218caddc9a3bd86"
2174
2198
  },
2175
2199
  {
2176
2200
  "path": "src/server/management/lab-automation-routes.ts",
@@ -2214,7 +2238,7 @@
2214
2238
  },
2215
2239
  {
2216
2240
  "path": "src/server/management/routing-profile-routes.ts",
2217
- "sha256": "1185f47d963c31efa7da224baf9f2a447a15a7afee0705c05e6c110e75b465ff"
2241
+ "sha256": "08484dcc92a3672450122316dad9939707a2669eabf396084bfb93fa9dde35f9"
2218
2242
  },
2219
2243
  {
2220
2244
  "path": "src/server/management/shared.ts",
@@ -2248,6 +2272,10 @@
2248
2272
  "path": "src/server/memory-watchdog.ts",
2249
2273
  "sha256": "d2f7f5cd03316cdfb0bd23abd77b4c28d87986a9a1cb9e0f53e3890695f07f4c"
2250
2274
  },
2275
+ {
2276
+ "path": "src/server/passive-route-linker.ts",
2277
+ "sha256": "6a20d1e864efe80cd9d6c69df9616bc6092a6102cd8d339f0cb376f8821bed0b"
2278
+ },
2251
2279
  {
2252
2280
  "path": "src/server/port-reclaim.ts",
2253
2281
  "sha256": "5b1a9e7e5e3d752ee7dd0dca1ea8737eeaf7945e2c9a4e3a0aed9805cc72d253"
@@ -2334,7 +2362,7 @@
2334
2362
  },
2335
2363
  {
2336
2364
  "path": "src/server/responses/core.ts",
2337
- "sha256": "c67fdae5470a8d0c234e24d7d062bf351ec35c911550363c8d73199f4059fc95"
2365
+ "sha256": "b8e42c1e0be113256d7318ee6dc3dc4cb7d045867e9e5412ccdfd64fa07111cb"
2338
2366
  },
2339
2367
  {
2340
2368
  "path": "src/server/responses/encrypted-payload.ts",
@@ -2482,7 +2510,7 @@
2482
2510
  },
2483
2511
  {
2484
2512
  "path": "src/types.ts",
2485
- "sha256": "d911cdcf36b5694e58918b7e76b94b42c3bf94962ef4a41b93ae01629be36016"
2513
+ "sha256": "b04403f46247c96634d0c8c6344c1ecc44979980b0456c28140e3aa1da4ab6ca"
2486
2514
  },
2487
2515
  {
2488
2516
  "path": "src/update/badge.ts",
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { mkdirSync, readFileSync, rmSync, statSync } from "node:fs";
11
11
  import type { ConfigFormat } from "../clients/config-export";
12
+ import { MAX_JSON_NESTING } from "./serialize";
12
13
  import { atomicWriteFile } from "../config";
13
14
  import type { JournalEntry } from "./journal";
14
15
  import type { OwnershipRecord } from "./ownership";
@@ -23,12 +24,129 @@ import type { IntegrationClientId } from "./registry";
23
24
  */
24
25
  export const PARSE_FAILED = Symbol("parse-failed");
25
26
 
27
+ /**
28
+ * What `JSON.parse` has already discarded by the time we hold the parsed value,
29
+ * and a rewrite would therefore silently change. Both classes are invisible in
30
+ * the parsed object, which is why this scans the RAW text — same reasoning as
31
+ * the TOML inf/nan guard below.
32
+ *
33
+ * Numbers: `1e999` overflows to Infinity (a rewrite bakes in `null` — the merge
34
+ * layer's JSON clone does it even before the serializer could refuse), `1e-9999`
35
+ * underflows to `+0`, an integer literal may have been rounded (a rewrite then
36
+ * hands consumers that read JSON integers exactly — python, jq, BigInt revivers
37
+ * — a different value), and `-0` re-serializes as `0`. Only literals whose value
38
+ * actually changed are refused: `1e21`, `1e-320` or 2^54 round-trip exactly and
39
+ * stay usable.
40
+ *
41
+ * Duplicate members: `{"a":1,"a":2}` parses to a single `a`, so rewriting the
42
+ * document DELETES the earlier member. That is content loss, not the formatting
43
+ * normalization we promise, and this classifier is what makes the rewrite of a
44
+ * user-edited file reachable at all — so it fails closed here.
45
+ *
46
+ * Depth: the same pass counts container nesting against MAX_JSON_NESTING
47
+ * (shared with the serializer, see serialize.ts). JSON.parse handles hundreds
48
+ * of thousands of levels iteratively, but the downstream merge and
49
+ * JSON.stringify recurse — a 100KB file nested 50k deep sailed through parse
50
+ * and guard, then blew up serialization with a raw RangeError after a
51
+ * multi-GB allocation spike. A hand-written scan rather than a JSON.parse
52
+ * source-access reviver on purpose: the reviver walk recurses internally, so
53
+ * its depth limit would be an unpredictable stack size instead of this
54
+ * deterministic ceiling.
55
+ */
56
+ function jsonTextSafeToRewrite(text: string): boolean {
57
+ /**
58
+ * One frame per open container; a Set of member names for objects, null for
59
+ * arrays. Its length is the current nesting depth.
60
+ */
61
+ const containers: Array<Set<string> | null> = [];
62
+ /** The most recent string literal — the member name if a `:` follows. */
63
+ let lastString: string | null = null;
64
+ let inString = false;
65
+ let escaped = false;
66
+ let stringStart = 0;
67
+ for (let i = 0; i < text.length; i += 1) {
68
+ const ch = text[i]!;
69
+ if (inString) {
70
+ if (escaped) escaped = false;
71
+ else if (ch === "\\") escaped = true;
72
+ else if (ch === "\"") {
73
+ inString = false;
74
+ lastString = text.slice(stringStart, i + 1);
75
+ }
76
+ continue;
77
+ }
78
+ if (ch === "\"") { inString = true; stringStart = i; continue; }
79
+ if (ch === "{" || ch === "[") {
80
+ containers.push(ch === "{" ? new Set<string>() : null);
81
+ if (containers.length > MAX_JSON_NESTING) return false;
82
+ lastString = null;
83
+ continue;
84
+ }
85
+ if (ch === "}" || ch === "]") { containers.pop(); lastString = null; continue; }
86
+ if (ch === ":") {
87
+ const members = containers[containers.length - 1];
88
+ if (members && lastString !== null) {
89
+ /*
90
+ * Decoded, not raw: `"a"` and `"a"` are spellings of ONE member,
91
+ * and JSON.parse keeps only the last of them.
92
+ */
93
+ let name: string;
94
+ try { name = JSON.parse(lastString) as string; } catch { return false; }
95
+ if (members.has(name)) return false;
96
+ members.add(name);
97
+ }
98
+ lastString = null;
99
+ continue;
100
+ }
101
+ if (ch !== "-" && (ch < "0" || ch > "9")) continue;
102
+ let end = i + 1;
103
+ while (end < text.length && /[0-9+\-.eE]/.test(text[end]!)) end += 1;
104
+ const literal = text.slice(i, end);
105
+ i = end - 1;
106
+ const value = Number(literal);
107
+ if (!Number.isFinite(value)) return false;
108
+ if (value === 0) {
109
+ /*
110
+ * `-0` (re-serializes as `0`) and underflow: `1e-9999` is a nonzero
111
+ * value the parse already flattened to `+0`. The significand alone
112
+ * decides, so genuine zero spellings (`0`, `0.0`, `0e10`) stay usable.
113
+ */
114
+ if (literal.startsWith("-") || /[1-9]/.test(literal.split(/[eE]/)[0]!)) return false;
115
+ }
116
+ /*
117
+ * Deliberately plain digit runs only. They are the one spelling real
118
+ * consumers read with exact integer semantics (python's json yields an
119
+ * arbitrary-precision int, jq preserves big integer literals), so baking
120
+ * in the rounded double changes what those consumers extract. Decimal or
121
+ * exponent spellings of the same value (`9007199254740993e0`, `…3.0`) are
122
+ * float semantics for every consumer — they round identically before and
123
+ * after a rewrite, and shortest-round-trip stringify preserves what any
124
+ * reader can observe, so refusing them would only manufacture dead ends
125
+ * (`1e308` is not exactly representable either, yet rewrites losslessly
126
+ * for every possible reader).
127
+ */
128
+ const digits = literal[0] === "-" ? literal.slice(1) : literal;
129
+ if (/^[0-9]{16,}$/.test(digits) && BigInt(literal) !== BigInt(value)) return false;
130
+ }
131
+ return true;
132
+ }
133
+
26
134
  /** Parse a client config, tolerating absence. PARSE_FAILED on garbage. */
27
135
  export function parseConfig(text: string | null, format: ConfigFormat): unknown | typeof PARSE_FAILED {
28
136
  if (text === null || text.trim().length === 0) return {};
29
137
  try {
30
138
  switch (format) {
31
- case "json": return JSON.parse(text);
139
+ case "json": {
140
+ /*
141
+ * Scanned BEFORE parsing: the guard is text-only, and refusing first
142
+ * means a hostile document is never materialized — the depth ceiling
143
+ * would otherwise cap the rewrite only after JSON.parse had already
144
+ * built the 50k-deep object graph. The outcome is unchanged: invalid
145
+ * JSON still returns PARSE_FAILED, from the catch below.
146
+ */
147
+ if (!jsonTextSafeToRewrite(text)) return PARSE_FAILED;
148
+ return JSON.parse(text);
149
+ }
32
150
  case "json5": return Bun.JSON5.parse(text);
33
151
  case "yaml": return Bun.YAML.parse(text);
34
152
  case "toml": {