@covro/covro 0.2.1-dev.5 → 0.2.1-dev.7

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 (133) hide show
  1. package/README.md +12 -4
  2. package/README.zh-CN.md +9 -1
  3. package/dist/backups/factory.js +22 -0
  4. package/dist/backups/factory.js.map +7 -0
  5. package/dist/backups/lock.js +22 -0
  6. package/dist/backups/lock.js.map +7 -0
  7. package/dist/backups/manager.js +170 -0
  8. package/dist/backups/manager.js.map +7 -0
  9. package/dist/backups/restore.js +188 -0
  10. package/dist/backups/restore.js.map +7 -0
  11. package/dist/backups/store.js +274 -0
  12. package/dist/backups/store.js.map +7 -0
  13. package/dist/cli/backup.js +84 -0
  14. package/dist/cli/backup.js.map +7 -0
  15. package/dist/cli/daemon.js +7 -0
  16. package/dist/cli/daemon.js.map +2 -2
  17. package/dist/cli/main.js +35 -5
  18. package/dist/cli/main.js.map +2 -2
  19. package/dist/cli/paths.js.map +2 -2
  20. package/dist/codex/auto-review.js +55 -0
  21. package/dist/codex/auto-review.js.map +2 -2
  22. package/dist/server/db/history.js +60 -0
  23. package/dist/server/db/history.js.map +7 -0
  24. package/dist/server/db/index.js +11 -1
  25. package/dist/server/db/index.js.map +2 -2
  26. package/dist/server/db/migrate.js +8 -18
  27. package/dist/server/db/migrate.js.map +2 -2
  28. package/dist/server/http.js +21 -3
  29. package/dist/server/http.js.map +2 -2
  30. package/dist/server/main.js +14 -3
  31. package/dist/server/main.js.map +2 -2
  32. package/dist/server/project-clones.js +53 -17
  33. package/dist/server/project-clones.js.map +2 -2
  34. package/dist/server/service.js +9 -5
  35. package/dist/server/service.js.map +2 -2
  36. package/dist/shared/backups.js +55 -0
  37. package/dist/shared/backups.js.map +7 -0
  38. package/dist/shared/database.js +15 -0
  39. package/dist/shared/database.js.map +7 -0
  40. package/dist/update-worker.cjs +934 -388
  41. package/dist/updates/files.js +2 -1
  42. package/dist/updates/files.js.map +2 -2
  43. package/dist/updates/transaction.js +3 -24
  44. package/dist/updates/transaction.js.map +2 -2
  45. package/dist/updates/worker.js +69 -19
  46. package/dist/updates/worker.js.map +2 -2
  47. package/dist/web/assets/{abnfDiagram-WEYOIA3C-CwLX554E.js → abnfDiagram-WEYOIA3C-Baw8Q2RL.js} +1 -1
  48. package/dist/web/assets/{arc-DAaDyyqc.js → arc-BvZHXzPr.js} +1 -1
  49. package/dist/web/assets/{architecture-WOLXFQ4H-y6MnEqN0.js → architecture-WOLXFQ4H-DrQ2OxuY.js} +1 -1
  50. package/dist/web/assets/{architectureDiagram-ZHVYKT53-_B_4k-Pp.js → architectureDiagram-ZHVYKT53-D96hX75H.js} +1 -1
  51. package/dist/web/assets/{blockDiagram-RJAE7QA3-C9jZ7FHy.js → blockDiagram-RJAE7QA3-Csce-aWb.js} +1 -1
  52. package/dist/web/assets/{c4Diagram-XDPPPE54-DQAtMvqN.js → c4Diagram-XDPPPE54-Dfu8ZQ6Y.js} +1 -1
  53. package/dist/web/assets/channel-DQhtAfM4.js +1 -0
  54. package/dist/web/assets/{chunk-2E7WHVMD-Bu427yab.js → chunk-2E7WHVMD-Vb63e-lu.js} +1 -1
  55. package/dist/web/assets/{chunk-4EMNKR2T-BrGrBG7B.js → chunk-4EMNKR2T-DrY1P7q3.js} +1 -1
  56. package/dist/web/assets/{chunk-55XCU76K-l4f0OZWA.js → chunk-55XCU76K-D70bjQ9E.js} +1 -1
  57. package/dist/web/assets/{chunk-7S6XSTFO-D7ixF313.js → chunk-7S6XSTFO-CfW90MUC.js} +1 -1
  58. package/dist/web/assets/{chunk-AQDTSKZB-Cesd-BF2.js → chunk-AQDTSKZB-u4KDDGBt.js} +1 -1
  59. package/dist/web/assets/{chunk-DSNLSHJZ-B7dim5uT.js → chunk-DSNLSHJZ-Cax3giJD.js} +1 -1
  60. package/dist/web/assets/{chunk-HAGFOTED-B-f2I7TA.js → chunk-HAGFOTED-BG9UMwzK.js} +1 -1
  61. package/dist/web/assets/{chunk-HNE4Q36P-CoIvaeX6.js → chunk-HNE4Q36P-BNxIfOgZ.js} +1 -1
  62. package/dist/web/assets/{chunk-NQOKRVIF-BybRxR7n.js → chunk-NQOKRVIF-DJ60e0Al.js} +1 -1
  63. package/dist/web/assets/{chunk-UHW7PFBP-CV5WG4tq.js → chunk-UHW7PFBP-C9gHYcjJ.js} +1 -1
  64. package/dist/web/assets/{chunk-VQ5W62QI-BO4AjXi1.js → chunk-VQ5W62QI-TyHPGVfQ.js} +1 -1
  65. package/dist/web/assets/{chunk-WQQL4CDK-CADNDGXO.js → chunk-WQQL4CDK-DeAauheh.js} +1 -1
  66. package/dist/web/assets/{chunk-XXDRQBXY-C6QZT7KW.js → chunk-XXDRQBXY-V-L20Tbi.js} +1 -1
  67. package/dist/web/assets/{chunk-YZO67HFG-Cm6eGReX.js → chunk-YZO67HFG-LV5QVBiU.js} +1 -1
  68. package/dist/web/assets/{chunk-ZAUX2LTX-CUBoGbKg.js → chunk-ZAUX2LTX-CBsBBk7L.js} +1 -1
  69. package/dist/web/assets/{chunk-ZCHMQSOR-B0ImOOtq.js → chunk-ZCHMQSOR-a2_9JHHn.js} +1 -1
  70. package/dist/web/assets/{classDiagram-v2-4MYWR3UA-D5NWZ9vm.js → classDiagram-v2-4MYWR3UA-77eiBCO3.js} +1 -1
  71. package/dist/web/assets/{cose-bilkent-JH36ORCC-BzckEyjA.js → cose-bilkent-JH36ORCC-DDP73pnY.js} +1 -1
  72. package/dist/web/assets/{cynefin-EF2NZ3EQ-Da_J6-Jb.js → cynefin-EF2NZ3EQ-onpnpyxc.js} +1 -1
  73. package/dist/web/assets/{cynefinDiagram-WF24UDRP-b4g_B1A-.js → cynefinDiagram-WF24UDRP-BmLplbnH.js} +1 -1
  74. package/dist/web/assets/{dagre-NK4GIZVX-89H2mfs9.js → dagre-NK4GIZVX-BhaMf_Gx.js} +1 -1
  75. package/dist/web/assets/{diagram-CBK3MWTC-CW4f_P0l.js → diagram-CBK3MWTC-BaalTqFt.js} +1 -1
  76. package/dist/web/assets/{diagram-I5XIIV2D-Cv5Qndgc.js → diagram-I5XIIV2D-4Tdshcyt.js} +1 -1
  77. package/dist/web/assets/{diagram-ODIL2UCW-LrXxeoCt.js → diagram-ODIL2UCW-SlEcZgod.js} +1 -1
  78. package/dist/web/assets/{diagram-PFBEJUXE-uJV2PooB.js → diagram-PFBEJUXE-CosCAXbh.js} +1 -1
  79. package/dist/web/assets/{diagram-RJA3I4VV-DlY0PGRs.js → diagram-RJA3I4VV-HQElVL4B.js} +1 -1
  80. package/dist/web/assets/{diagram-TYUNFSNR-B1KoXBEE.js → diagram-TYUNFSNR-BT2WDc21.js} +1 -1
  81. package/dist/web/assets/{dist-B4eX4BCP.js → dist-CrpGQKqw.js} +1 -1
  82. package/dist/web/assets/{ebnfDiagram-V4P3TTPT-xCvQVbdj.js → ebnfDiagram-V4P3TTPT-BhK6AM0_.js} +1 -1
  83. package/dist/web/assets/{elk-QONTBCTQ-Cl8Hu-Uy.js → elk-QONTBCTQ-CS7DfCnD.js} +1 -1
  84. package/dist/web/assets/{erDiagram-KYQIGQAA-Xp-AvSwE.js → erDiagram-KYQIGQAA-DxVnuqFK.js} +1 -1
  85. package/dist/web/assets/{eventmodeling-K75KTNOO-C0truZGU.js → eventmodeling-K75KTNOO-oC_YeomD.js} +1 -1
  86. package/dist/web/assets/flowDiagram-IUGLLWBU-Bspg0rQz.js +1 -0
  87. package/dist/web/assets/{ganttDiagram-R7GPNTJY-rPaYp-D7.js → ganttDiagram-R7GPNTJY-CquUpiE1.js} +1 -1
  88. package/dist/web/assets/{gitGraph-VSP46ZUC-Bgfpho41.js → gitGraph-VSP46ZUC-BTtGQYsh.js} +1 -1
  89. package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-kDcmuv6k.js → gitGraphDiagram-PDYL7XHY-BsokGXYo.js} +1 -1
  90. package/dist/web/assets/index-B8tsymVC.js +147 -0
  91. package/dist/web/assets/{index-B7tnf28H.css → index-COSho7m2.css} +1 -1
  92. package/dist/web/assets/{info-OHQRW6UA-CAWg5k9R.js → info-OHQRW6UA-CvGN4gWh.js} +1 -1
  93. package/dist/web/assets/{infoDiagram-MVDRKAX5-Cd08ebhn.js → infoDiagram-MVDRKAX5-BF9Rp3BT.js} +1 -1
  94. package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-tAXBLt9k.js → ishikawaDiagram-HPEHV2GE-DtD20ngU.js} +1 -1
  95. package/dist/web/assets/{journeyDiagram-BOSHW7O7-ZgnWqXkg.js → journeyDiagram-BOSHW7O7-gB16trHV.js} +1 -1
  96. package/dist/web/assets/{kanban-definition-FNSA4HC5-BUjtjd-h.js → kanban-definition-FNSA4HC5-D0aKOsE2.js} +1 -1
  97. package/dist/web/assets/{line-DG48HRVK.js → line-BR5dqPmF.js} +1 -1
  98. package/dist/web/assets/{linear-CqnXVCVw.js → linear-OsiQaPpK.js} +1 -1
  99. package/dist/web/assets/{mermaid-parser.core-gIvgB9WK.js → mermaid-parser.core-MEuwYVot.js} +3 -3
  100. package/dist/web/assets/{mermaid.core-C_R7Y1XB.js → mermaid.core-CVKnnz65.js} +4 -4
  101. package/dist/web/assets/{mindmap-definition-6OY57UG3-CwUEEl_y.js → mindmap-definition-6OY57UG3-5aHA-kPJ.js} +1 -1
  102. package/dist/web/assets/{packet-JDAUHWVQ-BrXmpRQ3.js → packet-JDAUHWVQ-uj48AF5r.js} +1 -1
  103. package/dist/web/assets/{pegDiagram-ECIUJNBX-lLApO85Q.js → pegDiagram-ECIUJNBX-BkVIHLBX.js} +1 -1
  104. package/dist/web/assets/{pie-XZMESJXO-C_8kR5WX.js → pie-XZMESJXO-D3hy3nD7.js} +1 -1
  105. package/dist/web/assets/{pieDiagram-GNMPY74T-CawGmJZn.js → pieDiagram-GNMPY74T-CBAqGMEo.js} +1 -1
  106. package/dist/web/assets/{quadrantDiagram-D57K4MC3-Dg6Yq3s_.js → quadrantDiagram-D57K4MC3-C35kvNRB.js} +1 -1
  107. package/dist/web/assets/{radar-ABXABTNO-Bs1xY09D.js → radar-ABXABTNO-3LWE6J2Y.js} +1 -1
  108. package/dist/web/assets/{railroad-I3PHUGI6-Bw_qS6e3.js → railroad-I3PHUGI6-B6Mc9Djl.js} +1 -1
  109. package/dist/web/assets/{railroad-abnf-LNEFI6M7-CQr33CuI.js → railroad-abnf-LNEFI6M7-DJnbwbpn.js} +1 -1
  110. package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-BY9nk5pg.js → railroad-ebnf-DWYD2UWJ-BFXAvY4k.js} +1 -1
  111. package/dist/web/assets/{railroad-peg-JR7BVNR7-CcFsAEI4.js → railroad-peg-JR7BVNR7-JYGb2Oq5.js} +1 -1
  112. package/dist/web/assets/{railroadDiagram-Y72NRBL7-rkZbchmc.js → railroadDiagram-Y72NRBL7-uBIggR0w.js} +1 -1
  113. package/dist/web/assets/{requirementDiagram-EQYSW5RA-CSOcijj5.js → requirementDiagram-EQYSW5RA-CDWglrxJ.js} +1 -1
  114. package/dist/web/assets/{sankeyDiagram-SY24JHO5-E0uo0rRp.js → sankeyDiagram-SY24JHO5-BT16hnTl.js} +1 -1
  115. package/dist/web/assets/{sequenceDiagram-BLEHNHQU-BKWAAcRu.js → sequenceDiagram-BLEHNHQU-eFJ27rVk.js} +1 -1
  116. package/dist/web/assets/{src-F6L8HcEC.js → src-BlOCBHYS.js} +1 -1
  117. package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-BBk2tpPh.js → stateDiagram-v2-A6IESKWZ-CK_s-2Qv.js} +1 -1
  118. package/dist/web/assets/{swimlanes-B3ENRKFQ-CAUrhGwF.js → swimlanes-B3ENRKFQ-WLMrk9Lm.js} +1 -1
  119. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-DmjebfnI.js +8 -0
  120. package/dist/web/assets/{timeline-definition-JXYKGLGB-D0FWj9fa.js → timeline-definition-JXYKGLGB-D0-xZS_V.js} +1 -1
  121. package/dist/web/assets/{treeView-D4JQ5SDB-CkJOmf93.js → treeView-D4JQ5SDB-TTivyB8T.js} +1 -1
  122. package/dist/web/assets/{treemap-SAJKECNS-BSFsardB.js → treemap-SAJKECNS-DtU16wOO.js} +1 -1
  123. package/dist/web/assets/{usecaseDiagram-WPOLBNNX-B2U-2o4g.js → usecaseDiagram-WPOLBNNX-DLFybW0F.js} +1 -1
  124. package/dist/web/assets/{vennDiagram-Q3Y3IDCW-BijTH0fT.js → vennDiagram-Q3Y3IDCW-DRDuYw70.js} +1 -1
  125. package/dist/web/assets/{wardley-7MLQ67FV-DDOa5RzL.js → wardley-7MLQ67FV-tZ-5qrqv.js} +1 -1
  126. package/dist/web/assets/{wardleyDiagram-IVAIDKWA-mbb5GvW5.js → wardleyDiagram-IVAIDKWA-wRKeGCMl.js} +1 -1
  127. package/dist/web/assets/{xychartDiagram-4URNHDU4-DHd60D_Y.js → xychartDiagram-4URNHDU4-B5-k-DHF.js} +1 -1
  128. package/dist/web/index.html +4 -4
  129. package/package.json +10 -3
  130. package/dist/web/assets/channel-ByzMCsOB.js +0 -1
  131. package/dist/web/assets/flowDiagram-IUGLLWBU-T67jQ-T_.js +0 -1
  132. package/dist/web/assets/index-3DUP8YCe.js +0 -142
  133. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-BCnJymLL.js +0 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cli/paths.ts"],
4
- "sourcesContent": ["import { createHash, randomUUID } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { readFileSync } from 'node:fs';\nimport { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';\n\nexport const packageRoot = fileURLToPath(new URL('../../', import.meta.url));\nexport const packageInfo = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n engines: { node: string };\n covroCodex?: unknown;\n covroCommit?: string;\n covroChannel?: 'stable' | 'beta' | 'dev';\n};\nexport function paths(configPath?: string) {\n const home = resolve(process.env.COVRO_HOME ?? join(homedir(), '.covro'));\n const config = resolve(configPath ?? join(home, 'config.json'));\n const key = createHash('sha256').update(config).digest('hex').slice(0, 16);\n const state = join(home, 'instances', key);\n const socket =\n process.platform === 'win32' ? `\\\\\\\\.\\\\pipe\\\\covro-${key}` : join(home, `c-${key}.sock`);\n return { home, config, key, state, socket, log: join(state, 'covro.log') };\n}\nexport type CovroPaths = ReturnType<typeof paths>;\nexport async function writeJson(filename: string, value: unknown) {\n await mkdir(dirname(filename), { recursive: true, mode: 0o700 });\n const temporary = `${filename}.${randomUUID()}.tmp`;\n await writeFile(temporary, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporary, filename);\n}\nexport async function ensureConfig(location: CovroPaths) {\n await mkdir(location.home, { recursive: true, mode: 0o700 });\n await chmod(location.home, 0o700);\n await mkdir(dirname(location.config), { recursive: true, mode: 0o700 });\n try {\n await readFile(location.config);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n await writeFile(\n location.config,\n `${JSON.stringify(\n {\n host: '127.0.0.1',\n port: 8787,\n publicOrigin: ['http://127.0.0.1:8787', 'http://localhost:8787'],\n dataDir: './data',\n codex: { binary: process.env.COVRO_CODEX_BINARY ?? 'codex' },\n projects: [],\n },\n null,\n 2,\n )}\\n`,\n { flag: 'wx', mode: 0o600 },\n ).catch((failure: NodeJS.ErrnoException) => {\n if (failure.code !== 'EEXIST') throw failure;\n });\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,YAAY,kBAAkB;AACvC,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,OAAO,OAAO,UAAU,QAAQ,iBAAiB;AAEnD,MAAM,cAAc,cAAc,IAAI,IAAI,UAAU,YAAY,GAAG,CAAC;AACpE,MAAM,cAAc,KAAK,MAAM,aAAa,KAAK,aAAa,cAAc,GAAG,MAAM,CAAC;AAQtF,SAAS,MAAM,YAAqB;AACzC,QAAM,OAAO,QAAQ,QAAQ,IAAI,cAAc,KAAK,QAAQ,GAAG,QAAQ,CAAC;AACxE,QAAM,SAAS,QAAQ,cAAc,KAAK,MAAM,aAAa,CAAC;AAC9D,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACzE,QAAM,QAAQ,KAAK,MAAM,aAAa,GAAG;AACzC,QAAM,SACJ,QAAQ,aAAa,UAAU,sBAAsB,GAAG,KAAK,KAAK,MAAM,KAAK,GAAG,OAAO;AACzF,SAAO,EAAE,MAAM,QAAQ,KAAK,OAAO,QAAQ,KAAK,KAAK,OAAO,WAAW,EAAE;AAC3E;AAEA,eAAsB,UAAU,UAAkB,OAAgB;AAChE,QAAM,MAAM,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC/D,QAAM,YAAY,GAAG,QAAQ,IAAI,WAAW,CAAC;AAC7C,QAAM,UAAU,WAAW,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AACjF,QAAM,OAAO,WAAW,QAAQ;AAClC;AACA,eAAsB,aAAa,UAAsB;AACvD,QAAM,MAAM,SAAS,MAAM,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC3D,QAAM,MAAM,SAAS,MAAM,GAAK;AAChC,QAAM,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACtE,MAAI;AACF,UAAM,SAAS,SAAS,MAAM;AAAA,EAChC,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU,OAAM;AAC9D,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,GAAG,KAAK;AAAA,QACN;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,cAAc,CAAC,yBAAyB,uBAAuB;AAAA,UAC/D,SAAS;AAAA,UACT,OAAO,EAAE,QAAQ,QAAQ,IAAI,sBAAsB,QAAQ;AAAA,UAC3D,UAAU,CAAC;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA;AAAA,MACD,EAAE,MAAM,MAAM,MAAM,IAAM;AAAA,IAC5B,EAAE,MAAM,CAAC,YAAmC;AAC1C,UAAI,QAAQ,SAAS,SAAU,OAAM;AAAA,IACvC,CAAC;AAAA,EACH;AACF;",
4
+ "sourcesContent": ["import { createHash, randomUUID } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { readFileSync } from 'node:fs';\nimport { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';\n\nexport const packageRoot = fileURLToPath(new URL('../../', import.meta.url));\nexport const packageInfo = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n engines: { node: string };\n covroCodex?: unknown;\n covroDatabase?: unknown;\n covroCommit?: string;\n covroChannel?: 'stable' | 'beta' | 'dev';\n};\nexport function paths(configPath?: string) {\n const home = resolve(process.env.COVRO_HOME ?? join(homedir(), '.covro'));\n const config = resolve(configPath ?? join(home, 'config.json'));\n const key = createHash('sha256').update(config).digest('hex').slice(0, 16);\n const state = join(home, 'instances', key);\n const socket =\n process.platform === 'win32' ? `\\\\\\\\.\\\\pipe\\\\covro-${key}` : join(home, `c-${key}.sock`);\n return { home, config, key, state, socket, log: join(state, 'covro.log') };\n}\nexport type CovroPaths = ReturnType<typeof paths>;\nexport async function writeJson(filename: string, value: unknown) {\n await mkdir(dirname(filename), { recursive: true, mode: 0o700 });\n const temporary = `${filename}.${randomUUID()}.tmp`;\n await writeFile(temporary, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporary, filename);\n}\nexport async function ensureConfig(location: CovroPaths) {\n await mkdir(location.home, { recursive: true, mode: 0o700 });\n await chmod(location.home, 0o700);\n await mkdir(dirname(location.config), { recursive: true, mode: 0o700 });\n try {\n await readFile(location.config);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n await writeFile(\n location.config,\n `${JSON.stringify(\n {\n host: '127.0.0.1',\n port: 8787,\n publicOrigin: ['http://127.0.0.1:8787', 'http://localhost:8787'],\n dataDir: './data',\n codex: { binary: process.env.COVRO_CODEX_BINARY ?? 'codex' },\n projects: [],\n },\n null,\n 2,\n )}\\n`,\n { flag: 'wx', mode: 0o600 },\n ).catch((failure: NodeJS.ErrnoException) => {\n if (failure.code !== 'EEXIST') throw failure;\n });\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAAY,kBAAkB;AACvC,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,OAAO,OAAO,UAAU,QAAQ,iBAAiB;AAEnD,MAAM,cAAc,cAAc,IAAI,IAAI,UAAU,YAAY,GAAG,CAAC;AACpE,MAAM,cAAc,KAAK,MAAM,aAAa,KAAK,aAAa,cAAc,GAAG,MAAM,CAAC;AAStF,SAAS,MAAM,YAAqB;AACzC,QAAM,OAAO,QAAQ,QAAQ,IAAI,cAAc,KAAK,QAAQ,GAAG,QAAQ,CAAC;AACxE,QAAM,SAAS,QAAQ,cAAc,KAAK,MAAM,aAAa,CAAC;AAC9D,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACzE,QAAM,QAAQ,KAAK,MAAM,aAAa,GAAG;AACzC,QAAM,SACJ,QAAQ,aAAa,UAAU,sBAAsB,GAAG,KAAK,KAAK,MAAM,KAAK,GAAG,OAAO;AACzF,SAAO,EAAE,MAAM,QAAQ,KAAK,OAAO,QAAQ,KAAK,KAAK,OAAO,WAAW,EAAE;AAC3E;AAEA,eAAsB,UAAU,UAAkB,OAAgB;AAChE,QAAM,MAAM,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC/D,QAAM,YAAY,GAAG,QAAQ,IAAI,WAAW,CAAC;AAC7C,QAAM,UAAU,WAAW,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AACjF,QAAM,OAAO,WAAW,QAAQ;AAClC;AACA,eAAsB,aAAa,UAAsB;AACvD,QAAM,MAAM,SAAS,MAAM,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC3D,QAAM,MAAM,SAAS,MAAM,GAAK;AAChC,QAAM,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACtE,MAAI;AACF,UAAM,SAAS,SAAS,MAAM;AAAA,EAChC,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU,OAAM;AAC9D,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,GAAG,KAAK;AAAA,QACN;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,cAAc,CAAC,yBAAyB,uBAAuB;AAAA,UAC/D,SAAS;AAAA,UACT,OAAO,EAAE,QAAQ,QAAQ,IAAI,sBAAsB,QAAQ;AAAA,UAC3D,UAAU,CAAC;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA;AAAA,MACD,EAAE,MAAM,MAAM,MAAM,IAAM;AAAA,IAC5B,EAAE,MAAM,CAAC,YAAmC;AAC1C,UAAI,QAAQ,SAAS,SAAU,OAAM;AAAA,IACvC,CAAC;AAAA,EACH;AACF;",
6
6
  "names": []
7
7
  }
@@ -82,6 +82,60 @@ ${action.target}`
82
82
  return { actionLabel: "\u64CD\u4F5C\u5BA1\u6838", actionSummary: "\u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u64CD\u4F5C\u8BE6\u60C5" };
83
83
  }
84
84
  }
85
+ function actionPresentation(action) {
86
+ const raw = (value) => ({ label: "raw", value });
87
+ switch (action.type) {
88
+ case "command":
89
+ return { kind: action.type, parts: [raw(action.command)] };
90
+ case "execve":
91
+ return {
92
+ kind: action.type,
93
+ parts: [
94
+ { label: "program", value: action.program },
95
+ { label: "arguments", value: action.argv.map((arg) => JSON.stringify(arg)).join(" ") }
96
+ ]
97
+ };
98
+ case "writeStdin":
99
+ return {
100
+ kind: action.type,
101
+ parts: [{ label: "process", value: action.processId }, raw(action.stdin)]
102
+ };
103
+ case "applyPatch":
104
+ return { kind: action.type, parts: action.files.map(raw) };
105
+ case "networkAccess":
106
+ return {
107
+ kind: action.type,
108
+ parts: [raw(`${action.protocol}://${action.host}:${action.port}`), raw(action.target)]
109
+ };
110
+ case "mcpToolCall":
111
+ return {
112
+ kind: action.type,
113
+ parts: [
114
+ raw(
115
+ [action.connectorName, `${action.server}/${action.toolName}`, action.toolTitle].filter(Boolean).join(" \xB7 ")
116
+ )
117
+ ]
118
+ };
119
+ case "requestPermissions": {
120
+ const parts = [];
121
+ if (action.reason) parts.push(raw(action.reason));
122
+ const network = action.permissions.network?.enabled;
123
+ if (network != null)
124
+ parts.push({ label: network ? "networkAllowed" : "networkRestricted", value: "" });
125
+ const files = action.permissions.fileSystem;
126
+ for (const path of files?.read ?? []) parts.push({ label: "read", value: path });
127
+ for (const path of files?.write ?? []) parts.push({ label: "write", value: path });
128
+ for (const entry of files?.entries ?? [])
129
+ parts.push({
130
+ label: entry.access,
131
+ value: entry.path.type === "path" ? entry.path.path : JSON.stringify(entry.path)
132
+ });
133
+ if (files?.globScanMaxDepth !== void 0)
134
+ parts.push({ label: "depth", value: String(files.globScanMaxDepth) });
135
+ return { kind: action.type, parts };
136
+ }
137
+ }
138
+ }
85
139
  function mapAutoReview(params) {
86
140
  const review = params.review;
87
141
  return {
@@ -89,6 +143,7 @@ function mapAutoReview(params) {
89
143
  ...params.targetItemId === null ? {} : { targetItemId: params.targetItemId },
90
144
  status: ["inProgress", "approved", "denied", "timedOut", "aborted"].includes(review.status) ? review.status : "unknown",
91
145
  ...describeAction(params.action),
146
+ presentation: actionPresentation(params.action),
92
147
  ...review.rationale === null ? {} : { rationale: review.rationale },
93
148
  ...review.riskLevel === null ? {} : { riskLevel: review.riskLevel },
94
149
  ...review.userAuthorization === null ? {} : { userAuthorization: review.userAuthorization },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/codex/auto-review.ts"],
4
- "sourcesContent": ["import type { AutoReviewView } from '../shared/types.js';\nimport type { GuardianApprovalReviewAction } from './generated/v2/GuardianApprovalReviewAction.js';\nimport type { FileSystemPath } from './generated/v2/FileSystemPath.js';\nimport type { ItemGuardianApprovalReviewStartedNotification } from './generated/v2/ItemGuardianApprovalReviewStartedNotification.js';\nimport type { ItemGuardianApprovalReviewCompletedNotification } from './generated/v2/ItemGuardianApprovalReviewCompletedNotification.js';\n\ntype Notification =\n ItemGuardianApprovalReviewStartedNotification | ItemGuardianApprovalReviewCompletedNotification;\n\nfunction pathLabel(path: FileSystemPath): string {\n if (path.type === 'path') return path.path;\n if (path.type === 'glob_pattern') return `\u5339\u914D\uFF1A${path.pattern}`;\n const special = path.value;\n const subpath =\n 'subpath' in special && special.subpath !== null ? `\uFF08\u5B50\u8DEF\u5F84\uFF1A${special.subpath}\uFF09` : '';\n switch (special.kind) {\n case 'root':\n return '\u6574\u4E2A\u6587\u4EF6\u7CFB\u7EDF\uFF08/\uFF09';\n case 'minimal':\n return '\u7CFB\u7EDF\u57FA\u7840\u8FD0\u884C\u76EE\u5F55';\n case 'project_roots':\n return `\u9879\u76EE\u6839\u76EE\u5F55${subpath}`;\n case 'tmpdir':\n return '\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\uFF08TMPDIR\uFF09';\n case 'slash_tmp':\n return '/tmp';\n case 'unknown':\n return `\u7279\u6B8A\u8DEF\u5F84\uFF1A${special.path}${subpath}`;\n }\n}\n\nfunction describeAction(\n action: GuardianApprovalReviewAction,\n): Pick<AutoReviewView, 'actionLabel' | 'actionSummary' | 'cwd'> {\n switch (action.type) {\n case 'command':\n return { actionLabel: '\u547D\u4EE4\u6267\u884C', actionSummary: action.command, cwd: action.cwd };\n case 'execve':\n return {\n actionLabel: '\u7A0B\u5E8F\u6267\u884C',\n actionSummary: `\u7A0B\u5E8F\uFF1A${action.program}\\n\u53C2\u6570\uFF1A${action.argv.map((arg) => JSON.stringify(arg)).join(' ')}`,\n cwd: action.cwd,\n };\n case 'writeStdin':\n return {\n actionLabel: '\u7EC8\u7AEF\u8F93\u5165',\n actionSummary: `\u8FDB\u7A0B ${action.processId}\\n${action.stdin}`,\n cwd: action.cwd,\n };\n case 'applyPatch':\n return {\n actionLabel: '\u6587\u4EF6\u53D8\u66F4',\n actionSummary: action.files.join('\\n') || '\u672A\u63D0\u4F9B\u6587\u4EF6\u8DEF\u5F84',\n cwd: action.cwd,\n };\n case 'networkAccess':\n return {\n actionLabel: '\u7F51\u7EDC\u8BBF\u95EE',\n actionSummary: `${action.protocol}://${action.host}:${action.port}\\n${action.target}`,\n };\n case 'mcpToolCall':\n return {\n actionLabel: '\u5DE5\u5177\u8C03\u7528',\n actionSummary: [\n action.connectorName,\n `${action.server}/${action.toolName}`,\n action.toolTitle,\n ]\n .filter(Boolean)\n .join(' \u00B7 '),\n };\n case 'requestPermissions': {\n const lines: string[] = [];\n if (action.reason) lines.push(action.reason);\n if (\n action.permissions.network?.enabled !== null &&\n action.permissions.network?.enabled !== undefined\n )\n lines.push(`\u7F51\u7EDC\u8BBF\u95EE\uFF1A${action.permissions.network.enabled ? '\u5141\u8BB8' : '\u4E0D\u5F00\u653E\u989D\u5916\u6743\u9650'}`);\n const files = action.permissions.fileSystem;\n if (files) {\n for (const path of files.read ?? []) lines.push(`\u8BFB\u53D6\uFF1A${path}`);\n for (const path of files.write ?? []) lines.push(`\u5199\u5165\uFF1A${path}`);\n for (const entry of files.entries ?? [])\n lines.push(\n `${{ read: '\u8BFB\u53D6', write: '\u5199\u5165', deny: '\u7981\u6B62\u8BBF\u95EE' }[entry.access]}\uFF1A${pathLabel(entry.path)}`,\n );\n if (files.globScanMaxDepth !== undefined)\n lines.push(`\u76EE\u5F55\u5339\u914D\u641C\u7D22\u6DF1\u5EA6\uFF1A${files.globScanMaxDepth}`);\n }\n return {\n actionLabel: '\u6743\u9650\u53D8\u66F4',\n actionSummary: lines.join('\\n') || '\u672A\u8BF7\u6C42\u989D\u5916\u7F51\u7EDC\u6216\u6587\u4EF6\u8BBF\u95EE\u6743\u9650',\n };\n }\n default:\n return { actionLabel: '\u64CD\u4F5C\u5BA1\u6838', actionSummary: '\u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u64CD\u4F5C\u8BE6\u60C5' };\n }\n}\n\n/** Display-only data. Notifications never become a PendingAction or a permission response. */\nexport function mapAutoReview(params: Notification): AutoReviewView {\n const review = params.review;\n return {\n reviewId: params.reviewId,\n ...(params.targetItemId === null ? {} : { targetItemId: params.targetItemId }),\n status: ['inProgress', 'approved', 'denied', 'timedOut', 'aborted'].includes(review.status)\n ? review.status\n : 'unknown',\n ...describeAction(params.action),\n ...(review.rationale === null ? {} : { rationale: review.rationale }),\n ...(review.riskLevel === null ? {} : { riskLevel: review.riskLevel }),\n ...(review.userAuthorization === null ? {} : { userAuthorization: review.userAuthorization }),\n startedAtMs: params.startedAtMs,\n ...('completedAtMs' in params ? { completedAtMs: params.completedAtMs } : {}),\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { AutoReviewView } from '../shared/types.js';\nimport type { GuardianApprovalReviewAction } from './generated/v2/GuardianApprovalReviewAction.js';\nimport type { FileSystemPath } from './generated/v2/FileSystemPath.js';\nimport type { ItemGuardianApprovalReviewStartedNotification } from './generated/v2/ItemGuardianApprovalReviewStartedNotification.js';\nimport type { ItemGuardianApprovalReviewCompletedNotification } from './generated/v2/ItemGuardianApprovalReviewCompletedNotification.js';\n\ntype Notification =\n ItemGuardianApprovalReviewStartedNotification | ItemGuardianApprovalReviewCompletedNotification;\n\nfunction pathLabel(path: FileSystemPath): string {\n if (path.type === 'path') return path.path;\n if (path.type === 'glob_pattern') return `\u5339\u914D\uFF1A${path.pattern}`;\n const special = path.value;\n const subpath =\n 'subpath' in special && special.subpath !== null ? `\uFF08\u5B50\u8DEF\u5F84\uFF1A${special.subpath}\uFF09` : '';\n switch (special.kind) {\n case 'root':\n return '\u6574\u4E2A\u6587\u4EF6\u7CFB\u7EDF\uFF08/\uFF09';\n case 'minimal':\n return '\u7CFB\u7EDF\u57FA\u7840\u8FD0\u884C\u76EE\u5F55';\n case 'project_roots':\n return `\u9879\u76EE\u6839\u76EE\u5F55${subpath}`;\n case 'tmpdir':\n return '\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\uFF08TMPDIR\uFF09';\n case 'slash_tmp':\n return '/tmp';\n case 'unknown':\n return `\u7279\u6B8A\u8DEF\u5F84\uFF1A${special.path}${subpath}`;\n }\n}\n\nfunction describeAction(\n action: GuardianApprovalReviewAction,\n): Pick<AutoReviewView, 'actionLabel' | 'actionSummary' | 'cwd'> {\n switch (action.type) {\n case 'command':\n return { actionLabel: '\u547D\u4EE4\u6267\u884C', actionSummary: action.command, cwd: action.cwd };\n case 'execve':\n return {\n actionLabel: '\u7A0B\u5E8F\u6267\u884C',\n actionSummary: `\u7A0B\u5E8F\uFF1A${action.program}\\n\u53C2\u6570\uFF1A${action.argv.map((arg) => JSON.stringify(arg)).join(' ')}`,\n cwd: action.cwd,\n };\n case 'writeStdin':\n return {\n actionLabel: '\u7EC8\u7AEF\u8F93\u5165',\n actionSummary: `\u8FDB\u7A0B ${action.processId}\\n${action.stdin}`,\n cwd: action.cwd,\n };\n case 'applyPatch':\n return {\n actionLabel: '\u6587\u4EF6\u53D8\u66F4',\n actionSummary: action.files.join('\\n') || '\u672A\u63D0\u4F9B\u6587\u4EF6\u8DEF\u5F84',\n cwd: action.cwd,\n };\n case 'networkAccess':\n return {\n actionLabel: '\u7F51\u7EDC\u8BBF\u95EE',\n actionSummary: `${action.protocol}://${action.host}:${action.port}\\n${action.target}`,\n };\n case 'mcpToolCall':\n return {\n actionLabel: '\u5DE5\u5177\u8C03\u7528',\n actionSummary: [\n action.connectorName,\n `${action.server}/${action.toolName}`,\n action.toolTitle,\n ]\n .filter(Boolean)\n .join(' \u00B7 '),\n };\n case 'requestPermissions': {\n const lines: string[] = [];\n if (action.reason) lines.push(action.reason);\n if (\n action.permissions.network?.enabled !== null &&\n action.permissions.network?.enabled !== undefined\n )\n lines.push(`\u7F51\u7EDC\u8BBF\u95EE\uFF1A${action.permissions.network.enabled ? '\u5141\u8BB8' : '\u4E0D\u5F00\u653E\u989D\u5916\u6743\u9650'}`);\n const files = action.permissions.fileSystem;\n if (files) {\n for (const path of files.read ?? []) lines.push(`\u8BFB\u53D6\uFF1A${path}`);\n for (const path of files.write ?? []) lines.push(`\u5199\u5165\uFF1A${path}`);\n for (const entry of files.entries ?? [])\n lines.push(\n `${{ read: '\u8BFB\u53D6', write: '\u5199\u5165', deny: '\u7981\u6B62\u8BBF\u95EE' }[entry.access]}\uFF1A${pathLabel(entry.path)}`,\n );\n if (files.globScanMaxDepth !== undefined)\n lines.push(`\u76EE\u5F55\u5339\u914D\u641C\u7D22\u6DF1\u5EA6\uFF1A${files.globScanMaxDepth}`);\n }\n return {\n actionLabel: '\u6743\u9650\u53D8\u66F4',\n actionSummary: lines.join('\\n') || '\u672A\u8BF7\u6C42\u989D\u5916\u7F51\u7EDC\u6216\u6587\u4EF6\u8BBF\u95EE\u6743\u9650',\n };\n }\n default:\n return { actionLabel: '\u64CD\u4F5C\u5BA1\u6838', actionSummary: '\u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u64CD\u4F5C\u8BE6\u60C5' };\n }\n}\n\nfunction actionPresentation(\n action: GuardianApprovalReviewAction,\n): NonNullable<AutoReviewView['presentation']> {\n const raw = (value: string) => ({ label: 'raw', value });\n switch (action.type) {\n case 'command':\n return { kind: action.type, parts: [raw(action.command)] };\n case 'execve':\n return {\n kind: action.type,\n parts: [\n { label: 'program', value: action.program },\n { label: 'arguments', value: action.argv.map((arg) => JSON.stringify(arg)).join(' ') },\n ],\n };\n case 'writeStdin':\n return {\n kind: action.type,\n parts: [{ label: 'process', value: action.processId }, raw(action.stdin)],\n };\n case 'applyPatch':\n return { kind: action.type, parts: action.files.map(raw) };\n case 'networkAccess':\n return {\n kind: action.type,\n parts: [raw(`${action.protocol}://${action.host}:${action.port}`), raw(action.target)],\n };\n case 'mcpToolCall':\n return {\n kind: action.type,\n parts: [\n raw(\n [action.connectorName, `${action.server}/${action.toolName}`, action.toolTitle]\n .filter(Boolean)\n .join(' \u00B7 '),\n ),\n ],\n };\n case 'requestPermissions': {\n const parts: { label: string; value: string }[] = [];\n if (action.reason) parts.push(raw(action.reason));\n const network = action.permissions.network?.enabled;\n if (network != null)\n parts.push({ label: network ? 'networkAllowed' : 'networkRestricted', value: '' });\n const files = action.permissions.fileSystem;\n for (const path of files?.read ?? []) parts.push({ label: 'read', value: path });\n for (const path of files?.write ?? []) parts.push({ label: 'write', value: path });\n for (const entry of files?.entries ?? [])\n parts.push({\n label: entry.access,\n value: entry.path.type === 'path' ? entry.path.path : JSON.stringify(entry.path),\n });\n if (files?.globScanMaxDepth !== undefined)\n parts.push({ label: 'depth', value: String(files.globScanMaxDepth) });\n return { kind: action.type, parts };\n }\n }\n}\n\n/** Display-only data. Notifications never become a PendingAction or a permission response. */\nexport function mapAutoReview(params: Notification): AutoReviewView {\n const review = params.review;\n return {\n reviewId: params.reviewId,\n ...(params.targetItemId === null ? {} : { targetItemId: params.targetItemId }),\n status: ['inProgress', 'approved', 'denied', 'timedOut', 'aborted'].includes(review.status)\n ? review.status\n : 'unknown',\n ...describeAction(params.action),\n presentation: actionPresentation(params.action),\n ...(review.rationale === null ? {} : { rationale: review.rationale }),\n ...(review.riskLevel === null ? {} : { riskLevel: review.riskLevel }),\n ...(review.userAuthorization === null ? {} : { userAuthorization: review.userAuthorization }),\n startedAtMs: params.startedAtMs,\n ...('completedAtMs' in params ? { completedAtMs: params.completedAtMs } : {}),\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,60 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ function readMigrations(folder) {
5
+ const journal = JSON.parse(readFileSync(join(folder, "meta/_journal.json"), "utf8"));
6
+ let last = 0;
7
+ return journal.entries.map((entry, index) => {
8
+ if (!/^[a-zA-Z0-9_-]+$/.test(entry.tag) || entry.idx !== index || entry.when <= last)
9
+ throw new Error("Invalid database migration journal");
10
+ last = entry.when;
11
+ const source = readFileSync(join(folder, `${entry.tag}.sql`), "utf8");
12
+ return {
13
+ hash: createHash("sha256").update(source).digest("hex"),
14
+ createdAt: entry.when,
15
+ sql: source.split("--> statement-breakpoint")
16
+ };
17
+ });
18
+ }
19
+ function inspectDatabase(sqlite, migrations) {
20
+ const recorded = sqlite.pragma("user_version", { simple: true });
21
+ const tables = sqlite.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all();
22
+ const applied = tables.some((table) => table.name === "__drizzle_migrations") ? sqlite.prepare("SELECT hash, created_at FROM __drizzle_migrations ORDER BY created_at").all() : [];
23
+ if (!applied.length && tables.some((table) => table.name !== "__drizzle_migrations") || applied.some(
24
+ (entry, index) => entry.hash !== migrations[index]?.hash || entry.created_at !== migrations[index]?.createdAt
25
+ ) || recorded !== 0 && recorded !== applied.length)
26
+ throw new Error(
27
+ "\u6570\u636E\u5E93 Schema \u6216\u8FC1\u79FB\u5386\u53F2\u4E0D\u517C\u5BB9\uFF1B\u8BF7\u4F7F\u7528\u517C\u5BB9\u7248\u672C\u6216\u6062\u590D\u5347\u7EA7\u524D\u5907\u4EFD\uFF0C\u4E0D\u4F1A\u6539\u5199\u6216\u91CD\u5EFA\u6570\u636E\u5E93\u3002"
28
+ );
29
+ return {
30
+ schemaVersion: applied.length,
31
+ legacy: recorded === 0,
32
+ migrationHashes: applied.map((entry) => entry.hash)
33
+ };
34
+ }
35
+ function requireRestorable(version, contract) {
36
+ if (version < contract.minRestorableSchemaVersion || version > contract.schemaVersion)
37
+ throw new Error(
38
+ `\u5907\u4EFD Schema ${version} \u4E0D\u517C\u5BB9\u76EE\u6807\u7248\u672C\uFF08\u652F\u6301 ${contract.minRestorableSchemaVersion}\u2013${contract.schemaVersion}\uFF09\u3002`
39
+ );
40
+ }
41
+ function migrateSqlite(sqlite, migrations) {
42
+ const before = inspectDatabase(sqlite, migrations);
43
+ sqlite.transaction(() => {
44
+ sqlite.exec(
45
+ "CREATE TABLE IF NOT EXISTS __drizzle_migrations (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)"
46
+ );
47
+ for (const migration of migrations.slice(before.schemaVersion)) {
48
+ for (const statement of migration.sql) sqlite.exec(statement);
49
+ sqlite.prepare("INSERT INTO __drizzle_migrations (hash, created_at) VALUES (?, ?)").run(migration.hash, migration.createdAt);
50
+ }
51
+ sqlite.pragma(`user_version = ${migrations.length}`);
52
+ })();
53
+ }
54
+ export {
55
+ inspectDatabase,
56
+ migrateSqlite,
57
+ readMigrations,
58
+ requireRestorable
59
+ };
60
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/server/db/history.ts"],
4
+ "sourcesContent": ["import { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type Database from 'better-sqlite3';\nimport type { DatabaseCompatibility } from '../../shared/database.js';\n\nexport interface Migration {\n hash: string;\n createdAt: number;\n sql: string[];\n}\n\nexport function readMigrations(folder: string): Migration[] {\n const journal = JSON.parse(readFileSync(join(folder, 'meta/_journal.json'), 'utf8')) as {\n entries: { idx: number; tag: string; when: number }[];\n };\n let last = 0;\n return journal.entries.map((entry, index) => {\n if (!/^[a-zA-Z0-9_-]+$/.test(entry.tag) || entry.idx !== index || entry.when <= last)\n throw new Error('Invalid database migration journal');\n last = entry.when;\n const source = readFileSync(join(folder, `${entry.tag}.sql`), 'utf8');\n return {\n hash: createHash('sha256').update(source).digest('hex'),\n createdAt: entry.when,\n sql: source.split('--> statement-breakpoint'),\n };\n });\n}\n\n/** A public ordinal never replaces validation of the immutable migration chain. */\nexport function inspectDatabase(sqlite: Database.Database, migrations: Migration[]) {\n const recorded = sqlite.pragma('user_version', { simple: true }) as number;\n const tables = sqlite\n .prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'\")\n .all() as { name: string }[];\n const applied = tables.some((table) => table.name === '__drizzle_migrations')\n ? (sqlite\n .prepare('SELECT hash, created_at FROM __drizzle_migrations ORDER BY created_at')\n .all() as { hash: string; created_at: number }[])\n : [];\n if (\n (!applied.length && tables.some((table) => table.name !== '__drizzle_migrations')) ||\n applied.some(\n (entry, index) =>\n entry.hash !== migrations[index]?.hash || entry.created_at !== migrations[index]?.createdAt,\n ) ||\n (recorded !== 0 && recorded !== applied.length)\n )\n throw new Error(\n '\u6570\u636E\u5E93 Schema \u6216\u8FC1\u79FB\u5386\u53F2\u4E0D\u517C\u5BB9\uFF1B\u8BF7\u4F7F\u7528\u517C\u5BB9\u7248\u672C\u6216\u6062\u590D\u5347\u7EA7\u524D\u5907\u4EFD\uFF0C\u4E0D\u4F1A\u6539\u5199\u6216\u91CD\u5EFA\u6570\u636E\u5E93\u3002',\n );\n return {\n schemaVersion: applied.length,\n legacy: recorded === 0,\n migrationHashes: applied.map((entry) => entry.hash),\n };\n}\n\nexport function requireRestorable(version: number, contract: DatabaseCompatibility) {\n if (version < contract.minRestorableSchemaVersion || version > contract.schemaVersion)\n throw new Error(\n `\u5907\u4EFD Schema ${version} \u4E0D\u517C\u5BB9\u76EE\u6807\u7248\u672C\uFF08\u652F\u6301 ${contract.minRestorableSchemaVersion}\u2013${contract.schemaVersion}\uFF09\u3002`,\n );\n}\n\n/** SQL, Drizzle's existing journal and the public version commit together. */\nexport function migrateSqlite(sqlite: Database.Database, migrations: Migration[]) {\n const before = inspectDatabase(sqlite, migrations);\n sqlite.transaction(() => {\n sqlite.exec(\n 'CREATE TABLE IF NOT EXISTS __drizzle_migrations (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)',\n );\n for (const migration of migrations.slice(before.schemaVersion)) {\n for (const statement of migration.sql) sqlite.exec(statement);\n sqlite\n .prepare('INSERT INTO __drizzle_migrations (hash, created_at) VALUES (?, ?)')\n .run(migration.hash, migration.createdAt);\n }\n sqlite.pragma(`user_version = ${migrations.length}`);\n })();\n}\n"],
5
+ "mappings": "AAAA,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AAUd,SAAS,eAAe,QAA6B;AAC1D,QAAM,UAAU,KAAK,MAAM,aAAa,KAAK,QAAQ,oBAAoB,GAAG,MAAM,CAAC;AAGnF,MAAI,OAAO;AACX,SAAO,QAAQ,QAAQ,IAAI,CAAC,OAAO,UAAU;AAC3C,QAAI,CAAC,mBAAmB,KAAK,MAAM,GAAG,KAAK,MAAM,QAAQ,SAAS,MAAM,QAAQ;AAC9E,YAAM,IAAI,MAAM,oCAAoC;AACtD,WAAO,MAAM;AACb,UAAM,SAAS,aAAa,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM;AACpE,WAAO;AAAA,MACL,MAAM,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK;AAAA,MACtD,WAAW,MAAM;AAAA,MACjB,KAAK,OAAO,MAAM,0BAA0B;AAAA,IAC9C;AAAA,EACF,CAAC;AACH;AAGO,SAAS,gBAAgB,QAA2B,YAAyB;AAClF,QAAM,WAAW,OAAO,OAAO,gBAAgB,EAAE,QAAQ,KAAK,CAAC;AAC/D,QAAM,SAAS,OACZ,QAAQ,kFAAkF,EAC1F,IAAI;AACP,QAAM,UAAU,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,sBAAsB,IACvE,OACE,QAAQ,uEAAuE,EAC/E,IAAI,IACP,CAAC;AACL,MACG,CAAC,QAAQ,UAAU,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,sBAAsB,KAChF,QAAQ;AAAA,IACN,CAAC,OAAO,UACN,MAAM,SAAS,WAAW,KAAK,GAAG,QAAQ,MAAM,eAAe,WAAW,KAAK,GAAG;AAAA,EACtF,KACC,aAAa,KAAK,aAAa,QAAQ;AAExC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,SAAO;AAAA,IACL,eAAe,QAAQ;AAAA,IACvB,QAAQ,aAAa;AAAA,IACrB,iBAAiB,QAAQ,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,EACpD;AACF;AAEO,SAAS,kBAAkB,SAAiB,UAAiC;AAClF,MAAI,UAAU,SAAS,8BAA8B,UAAU,SAAS;AACtE,UAAM,IAAI;AAAA,MACR,uBAAa,OAAO,iEAAe,SAAS,0BAA0B,SAAI,SAAS,aAAa;AAAA,IAClG;AACJ;AAGO,SAAS,cAAc,QAA2B,YAAyB;AAChF,QAAM,SAAS,gBAAgB,QAAQ,UAAU;AACjD,SAAO,YAAY,MAAM;AACvB,WAAO;AAAA,MACL;AAAA,IACF;AACA,eAAW,aAAa,WAAW,MAAM,OAAO,aAAa,GAAG;AAC9D,iBAAW,aAAa,UAAU,IAAK,QAAO,KAAK,SAAS;AAC5D,aACG,QAAQ,mEAAmE,EAC3E,IAAI,UAAU,MAAM,UAAU,SAAS;AAAA,IAC5C;AACA,WAAO,OAAO,kBAAkB,WAAW,MAAM,EAAE;AAAA,EACrD,CAAC,EAAE;AACL;",
6
+ "names": []
7
+ }
@@ -1,9 +1,19 @@
1
- import { chmodSync, mkdirSync } from "node:fs";
1
+ import { inspectDatabase, readMigrations } from "./history.js";
2
+ import { runtimeMigrationsFolder } from "./migrate.js";
3
+ import { chmodSync, mkdirSync, existsSync } from "node:fs";
2
4
  import { dirname } from "node:path";
3
5
  import Database from "better-sqlite3";
4
6
  import { drizzle } from "drizzle-orm/better-sqlite3";
5
7
  import * as schema from "./schema.js";
6
8
  function openDatabase(filename) {
9
+ if (filename !== ":memory:" && existsSync(filename)) {
10
+ const preflight = new Database(filename, { readonly: true, fileMustExist: true });
11
+ try {
12
+ inspectDatabase(preflight, readMigrations(runtimeMigrationsFolder));
13
+ } finally {
14
+ preflight.close();
15
+ }
16
+ }
7
17
  if (filename !== ":memory:") {
8
18
  mkdirSync(dirname(filename), { recursive: true, mode: 448 });
9
19
  chmodSync(dirname(filename), 448);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/server/db/index.ts"],
4
- "sourcesContent": ["import { chmodSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport Database from 'better-sqlite3';\nimport { drizzle, type BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport * as schema from './schema.js';\n\nexport type AppDatabase = BetterSQLite3Database<typeof schema>;\n\n/** The caller must hold the data directory instance lock before opening/migrating. */\nexport function openDatabase(filename: string): { database: AppDatabase; close: () => void } {\n if (filename !== ':memory:') {\n mkdirSync(dirname(filename), { recursive: true, mode: 0o700 });\n chmodSync(dirname(filename), 0o700);\n }\n const sqlite = new Database(filename);\n sqlite.pragma('foreign_keys = ON');\n sqlite.pragma('journal_mode = WAL');\n sqlite.pragma('busy_timeout = 5000');\n if (filename !== ':memory:') chmodSync(filename, 0o600);\n return { database: drizzle(sqlite, { schema }), close: () => sqlite.close() };\n}\n"],
5
- "mappings": "AAAA,SAAS,WAAW,iBAAiB;AACrC,SAAS,eAAe;AACxB,OAAO,cAAc;AACrB,SAAS,eAA2C;AACpD,YAAY,YAAY;AAKjB,SAAS,aAAa,UAAgE;AAC3F,MAAI,aAAa,YAAY;AAC3B,cAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC7D,cAAU,QAAQ,QAAQ,GAAG,GAAK;AAAA,EACpC;AACA,QAAM,SAAS,IAAI,SAAS,QAAQ;AACpC,SAAO,OAAO,mBAAmB;AACjC,SAAO,OAAO,oBAAoB;AAClC,SAAO,OAAO,qBAAqB;AACnC,MAAI,aAAa,WAAY,WAAU,UAAU,GAAK;AACtD,SAAO,EAAE,UAAU,QAAQ,QAAQ,EAAE,OAAO,CAAC,GAAG,OAAO,MAAM,OAAO,MAAM,EAAE;AAC9E;",
4
+ "sourcesContent": ["import { inspectDatabase, readMigrations } from './history.js';\nimport { runtimeMigrationsFolder } from './migrate.js';\nimport { chmodSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport Database from 'better-sqlite3';\nimport { drizzle, type BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport * as schema from './schema.js';\n\nexport type AppDatabase = BetterSQLite3Database<typeof schema> & { $client: Database.Database };\n\n/** The caller must hold the data directory instance lock before opening/migrating. */\nexport function openDatabase(filename: string): { database: AppDatabase; close: () => void } {\n if (filename !== ':memory:' && existsSync(filename)) {\n const preflight = new Database(filename, { readonly: true, fileMustExist: true });\n try {\n inspectDatabase(preflight, readMigrations(runtimeMigrationsFolder));\n } finally {\n preflight.close();\n }\n }\n if (filename !== ':memory:') {\n mkdirSync(dirname(filename), { recursive: true, mode: 0o700 });\n chmodSync(dirname(filename), 0o700);\n }\n const sqlite = new Database(filename);\n sqlite.pragma('foreign_keys = ON');\n sqlite.pragma('journal_mode = WAL');\n sqlite.pragma('busy_timeout = 5000');\n if (filename !== ':memory:') chmodSync(filename, 0o600);\n return { database: drizzle(sqlite, { schema }), close: () => sqlite.close() };\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB,sBAAsB;AAChD,SAAS,+BAA+B;AACxC,SAAS,WAAW,WAAW,kBAAkB;AACjD,SAAS,eAAe;AACxB,OAAO,cAAc;AACrB,SAAS,eAA2C;AACpD,YAAY,YAAY;AAKjB,SAAS,aAAa,UAAgE;AAC3F,MAAI,aAAa,cAAc,WAAW,QAAQ,GAAG;AACnD,UAAM,YAAY,IAAI,SAAS,UAAU,EAAE,UAAU,MAAM,eAAe,KAAK,CAAC;AAChF,QAAI;AACF,sBAAgB,WAAW,eAAe,uBAAuB,CAAC;AAAA,IACpE,UAAE;AACA,gBAAU,MAAM;AAAA,IAClB;AAAA,EACF;AACA,MAAI,aAAa,YAAY;AAC3B,cAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC7D,cAAU,QAAQ,QAAQ,GAAG,GAAK;AAAA,EACpC;AACA,QAAM,SAAS,IAAI,SAAS,QAAQ;AACpC,SAAO,OAAO,mBAAmB;AACjC,SAAO,OAAO,oBAAoB;AAClC,SAAO,OAAO,qBAAqB;AACnC,MAAI,aAAa,WAAY,WAAU,UAAU,GAAK;AACtD,SAAO,EAAE,UAAU,QAAQ,QAAQ,EAAE,OAAO,CAAC,GAAG,OAAO,MAAM,OAAO,MAAM,EAAE;AAC9E;",
6
6
  "names": []
7
7
  }
@@ -1,26 +1,16 @@
1
1
  import { fileURLToPath } from "node:url";
2
- import { migrate } from "drizzle-orm/better-sqlite3/migrator";
3
- import { readMigrationFiles } from "drizzle-orm/migrator";
4
- import { sql } from "drizzle-orm";
2
+ import { existsSync } from "node:fs";
3
+ import { migrateSqlite, readMigrations } from "./history.js";
5
4
  const defaultMigrationsFolder = fileURLToPath(new URL("../../../drizzle", import.meta.url));
5
+ const runtimeMigrationsFolder = existsSync(
6
+ fileURLToPath(new URL("../../drizzle", import.meta.url))
7
+ ) ? fileURLToPath(new URL("../../drizzle", import.meta.url)) : defaultMigrationsFolder;
6
8
  function migrateDatabase(database, migrationsFolder = defaultMigrationsFolder) {
7
- const table = database.get(
8
- sql`SELECT name FROM sqlite_master WHERE name = '__drizzle_migrations'`
9
- );
10
- if (table) {
11
- const applied = database.all(
12
- sql`SELECT hash FROM __drizzle_migrations ORDER BY created_at`
13
- );
14
- const migrations = readMigrationFiles({ migrationsFolder });
15
- if (applied.some((entry, i) => entry.hash !== migrations[i]?.hash))
16
- throw new Error(
17
- "\u5F53\u524D\u5B89\u88C5\u4E0D\u517C\u5BB9\u6570\u636E\u5E93\u8FC1\u79FB\u5386\u53F2\uFF1B\u8BF7\u4F7F\u7528\u517C\u5BB9\u7248\u672C\u6216\u5347\u7EA7\u524D\u5907\u4EFD\uFF0C\u4E0D\u4F1A\u6539\u5199\u6216\u91CD\u5EFA\u6570\u636E\u5E93\u3002"
18
- );
19
- }
20
- migrate(database, { migrationsFolder });
9
+ migrateSqlite(database.$client, readMigrations(migrationsFolder));
21
10
  }
22
11
  export {
23
12
  defaultMigrationsFolder,
24
- migrateDatabase
13
+ migrateDatabase,
14
+ runtimeMigrationsFolder
25
15
  };
26
16
  //# sourceMappingURL=migrate.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/server/db/migrate.ts"],
4
- "sourcesContent": ["import { fileURLToPath } from 'node:url';\nimport { migrate } from 'drizzle-orm/better-sqlite3/migrator';\nimport { readMigrationFiles } from 'drizzle-orm/migrator';\nimport { sql } from 'drizzle-orm';\nimport type { AppDatabase } from './index.js';\n\n/** Source and unbundled dist/server/db resolve to repository/dist drizzle respectively. */\nexport const defaultMigrationsFolder = fileURLToPath(new URL('../../../drizzle', import.meta.url));\n\nexport function migrateDatabase(\n database: AppDatabase,\n migrationsFolder = defaultMigrationsFolder,\n): void {\n const table = database.get(\n sql`SELECT name FROM sqlite_master WHERE name = '__drizzle_migrations'`,\n );\n if (table) {\n const applied = database.all<{ hash: string }>(\n sql`SELECT hash FROM __drizzle_migrations ORDER BY created_at`,\n );\n const migrations = readMigrationFiles({ migrationsFolder });\n if (applied.some((entry, i) => entry.hash !== migrations[i]?.hash))\n throw new Error(\n '\u5F53\u524D\u5B89\u88C5\u4E0D\u517C\u5BB9\u6570\u636E\u5E93\u8FC1\u79FB\u5386\u53F2\uFF1B\u8BF7\u4F7F\u7528\u517C\u5BB9\u7248\u672C\u6216\u5347\u7EA7\u524D\u5907\u4EFD\uFF0C\u4E0D\u4F1A\u6539\u5199\u6216\u91CD\u5EFA\u6570\u636E\u5E93\u3002',\n );\n }\n migrate(database, { migrationsFolder });\n}\n"],
5
- "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,0BAA0B;AACnC,SAAS,WAAW;AAIb,MAAM,0BAA0B,cAAc,IAAI,IAAI,oBAAoB,YAAY,GAAG,CAAC;AAE1F,SAAS,gBACd,UACA,mBAAmB,yBACb;AACN,QAAM,QAAQ,SAAS;AAAA,IACrB;AAAA,EACF;AACA,MAAI,OAAO;AACT,UAAM,UAAU,SAAS;AAAA,MACvB;AAAA,IACF;AACA,UAAM,aAAa,mBAAmB,EAAE,iBAAiB,CAAC;AAC1D,QAAI,QAAQ,KAAK,CAAC,OAAO,MAAM,MAAM,SAAS,WAAW,CAAC,GAAG,IAAI;AAC/D,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,EACJ;AACA,UAAQ,UAAU,EAAE,iBAAiB,CAAC;AACxC;",
4
+ "sourcesContent": ["import { fileURLToPath } from 'node:url';\nimport { existsSync } from 'node:fs';\nimport type { AppDatabase } from './index.js';\nimport { migrateSqlite, readMigrations } from './history.js';\n\n/** Source and unbundled dist/server/db resolve to repository/dist drizzle respectively. */\nexport const defaultMigrationsFolder = fileURLToPath(new URL('../../../drizzle', import.meta.url));\nexport const runtimeMigrationsFolder = existsSync(\n fileURLToPath(new URL('../../drizzle', import.meta.url)),\n)\n ? fileURLToPath(new URL('../../drizzle', import.meta.url))\n : defaultMigrationsFolder;\n\nexport function migrateDatabase(\n database: AppDatabase,\n migrationsFolder = defaultMigrationsFolder,\n): void {\n migrateSqlite(database.$client, readMigrations(migrationsFolder));\n}\n"],
5
+ "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAE3B,SAAS,eAAe,sBAAsB;AAGvC,MAAM,0BAA0B,cAAc,IAAI,IAAI,oBAAoB,YAAY,GAAG,CAAC;AAC1F,MAAM,0BAA0B;AAAA,EACrC,cAAc,IAAI,IAAI,iBAAiB,YAAY,GAAG,CAAC;AACzD,IACI,cAAc,IAAI,IAAI,iBAAiB,YAAY,GAAG,CAAC,IACvD;AAEG,SAAS,gBACd,UACA,mBAAmB,yBACb;AACN,gBAAc,SAAS,SAAS,eAAe,gBAAgB,CAAC;AAClE;",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,5 @@
1
+ import { backupIdSchema } from "../shared/backups.js";
2
+ import { backupRequestSchema } from "../backups/manager.js";
1
3
  import { createHash } from "node:crypto";
2
4
  import { Hono } from "hono";
3
5
  import { bodyLimit } from "hono/body-limit";
@@ -19,7 +21,8 @@ function createApp({
19
21
  service,
20
22
  staticDir,
21
23
  authenticate = createAuthenticator(config),
22
- updates
24
+ updates,
25
+ backups
23
26
  }) {
24
27
  const app = new Hono();
25
28
  app.onError((error, c) => {
@@ -42,10 +45,25 @@ function createApp({
42
45
  );
43
46
  app.use("/api/*", async (c, next) => {
44
47
  c.header("Cache-Control", "no-store");
45
- if (service.isInMaintenance() && !["GET", "HEAD", "OPTIONS"].includes(c.req.method) && !c.req.path.startsWith("/api/updates"))
46
- throw new AppError("UPDATE_MAINTENANCE", "\u6B63\u5728\u5347\u7EA7\uFF0C\u8BF7\u7B49\u5F85\u670D\u52A1\u91CD\u65B0\u8FDE\u63A5", 503);
48
+ if (service.isInMaintenance() && !["GET", "HEAD", "OPTIONS"].includes(c.req.method) && !c.req.path.startsWith("/api/updates") && !c.req.path.startsWith("/api/backups"))
49
+ throw service.maintenanceError();
47
50
  await next();
48
51
  });
52
+ if (backups) {
53
+ app.get("/api/backups", async (c) => c.json(await backups.status()));
54
+ app.post(
55
+ "/api/backups",
56
+ async (c) => c.json(await backups.start(backupRequestSchema.parse(await c.req.json())), 202)
57
+ );
58
+ app.post(
59
+ "/api/backups/:id/cancel",
60
+ async (c) => c.json(await backups.cancel(backupIdSchema.parse(c.req.param("id"))))
61
+ );
62
+ app.post(
63
+ "/api/backups/:id/verify",
64
+ async (c) => c.json(await backups.verify(backupIdSchema.parse(c.req.param("id"))))
65
+ );
66
+ }
49
67
  if (updates) {
50
68
  app.get("/api/updates", async (c) => c.json(await updates.status()));
51
69
  app.post("/api/updates/check", async (c) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/server/http.ts"],
4
- "sourcesContent": ["import { createHash } from 'node:crypto';\nimport { Hono } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport { upgradeWebSocket, type HttpBindings } from '@hono/node-server';\nimport type { ZodType } from 'zod';\nimport { ZodError } from 'zod';\nimport { AppError } from '../shared/errors.js';\nimport { IMAGE_REQUEST_BYTES } from '../shared/images.js';\nimport * as schemas from '../shared/validation.js';\nimport type { Operation } from '../shared/types.js';\nimport type { AppConfig } from './config.js';\nimport { ConfigStore } from './config-store.js';\nimport { createAuthenticator, type Authenticator, type Identity } from './auth.js';\nimport type { GatewayService } from './service.js';\nimport { socketHandlers } from './websocket.js';\nimport { z } from 'zod';\nimport { releaseChannels, type UpdateController } from '../shared/updates.js';\nimport { settingsSchema, updateRequestSchema } from '../updates/manager.js';\nimport { startShellSchema } from '../shared/shell.js';\nexport interface HttpDependencies {\n config: AppConfig;\n service: GatewayService;\n staticDir: string;\n authenticate?: Authenticator;\n updates?: UpdateController;\n}\nexport function createApp({\n config,\n service,\n staticDir,\n authenticate = createAuthenticator(config),\n updates,\n}: HttpDependencies) {\n const app = new Hono<{\n Bindings: HttpBindings;\n Variables: { identity: Identity; operationId?: string };\n }>();\n app.onError((error, c) => {\n const failure =\n error instanceof AppError\n ? error\n : error instanceof ZodError || error instanceof SyntaxError\n ? new AppError('VALIDATION_FAILED', 'Invalid request data', 400)\n : new AppError('INTERNAL_ERROR', 'An internal error occurred', 500);\n return c.json({ error: failure.toJSON(c.get('operationId')) }, failure.status as 400);\n });\n app.get('/api/health', (c) => c.json({ ok: true }));\n app.use('*', async (c, next) => {\n c.set('identity', await authenticate(c.req.raw, c.req.path === '/ws'));\n await next();\n });\n app.use('/api/*', (c, next) =>\n bodyLimit({\n maxSize: /^\\/api\\/threads\\/[^/]+\\/(turns|steer)$/.test(c.req.path)\n ? IMAGE_REQUEST_BYTES\n : 512 * 1024,\n onError: () => {\n throw new AppError('BODY_TOO_LARGE', 'Request body exceeds limit', 413);\n },\n })(c, next),\n );\n app.use('/api/*', async (c, next) => {\n c.header('Cache-Control', 'no-store');\n if (\n service.isInMaintenance() &&\n !['GET', 'HEAD', 'OPTIONS'].includes(c.req.method) &&\n !c.req.path.startsWith('/api/updates')\n )\n throw new AppError('UPDATE_MAINTENANCE', '\u6B63\u5728\u5347\u7EA7\uFF0C\u8BF7\u7B49\u5F85\u670D\u52A1\u91CD\u65B0\u8FDE\u63A5', 503);\n await next();\n });\n if (updates) {\n app.get('/api/updates', async (c) => c.json(await updates.status()));\n app.post('/api/updates/check', async (c) => {\n const input = z\n .object({ channel: z.enum(releaseChannels).optional() })\n .strict()\n .parse(await c.req.json());\n return c.json(await updates.check(input.channel));\n });\n app.post('/api/updates/settings', async (c) =>\n c.json(await updates.configure(settingsSchema.parse(await c.req.json()))),\n );\n app.post('/api/updates/run', async (c) =>\n c.json(await updates.start(updateRequestSchema.parse(await c.req.json())), 202),\n );\n }\n const id = (value: string) => schemas.idSchema.parse(value);\n const parse = async <T>(\n c: { req: { json: () => Promise<unknown> }; set: (key: 'operationId', value: string) => void },\n schema: ZodType<T>,\n ): Promise<T> => {\n const value: unknown = await c.req.json();\n if (\n value &&\n typeof value === 'object' &&\n 'clientOperationId' in value &&\n typeof value.clientOperationId === 'string'\n )\n c.set('operationId', value.clientOperationId);\n return schema.parse(value);\n };\n const status = (op: Operation) =>\n op.status === 'dispatching' || op.status === 'accepted' ? (202 as const) : (200 as const);\n const configuration = new ConfigStore(config);\n app.use('/api/config*', async (c, next) => {\n c.header('Cache-Control', 'no-store');\n await next();\n });\n app.get('/api/config', async (c) => c.json(await configuration.snapshot()));\n app.post('/api/config', async (c) => c.json(await configuration.save(await c.req.json())));\n app.post('/api/config/import', async (c) =>\n c.json(await configuration.previewImport(await c.req.json())),\n );\n app.get('/api/config/export', async (c) => {\n c.header('Content-Disposition', 'attachment; filename=\"codex-web-config.json\"');\n return c.json(await configuration.export());\n });\n app.get('/api/history-cache-context', async (c) => {\n const identity = c.get('identity');\n if (config.auth.mode !== 'local' && !identity.subject)\n throw new AppError('UNAUTHENTICATED', '\u65E0\u6CD5\u786E\u8BA4\u7F13\u5B58\u6240\u5C5E\u7528\u6237', 401);\n const projects = await service.listProjects();\n // A restart, user change or project/permission change creates a new namespace.\n // The subject is hashed on the server and is never exposed to browser storage.\n const scope = createHash('sha256')\n .update(\n JSON.stringify([\n service.events.serverEpoch,\n service.getSystem().codexEpoch,\n config.auth.mode,\n identity.subject ?? 'local',\n projects.map((project) => [project.id, project.rootPath, project.available]),\n ]),\n )\n .digest('hex');\n return c.json({ scope });\n });\n app.get('/api/system', (c) => c.json(service.getSystem()));\n app.get('/api/shell', (c) =>\n c.json(\n service.shell.snapshot(\n c.req.query('epoch'),\n z.coerce\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER)\n .default(0)\n .parse(c.req.query('after')),\n ),\n ),\n );\n app.post('/api/projects/:projectId/shell', async (c) => {\n const op = await service.startShell(\n id(c.req.param('projectId')),\n await parse(c, startShellSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/shell/:commandId/interrupt', async (c) => {\n const op = await service.interruptShell(\n id(c.req.param('commandId')),\n await parse(c, schemas.operationSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/system/compatibility/confirm', async (c) => {\n const op = await service.confirmCompatibility(\n await parse(c, schemas.confirmCompatibilitySchema),\n );\n return c.json(op, status(op));\n });\n app.get('/api/projects', async (c) => c.json({ data: await service.listProjects() }));\n app.get('/api/unassigned/runtime-settings', async (c) =>\n c.json(await service.readRuntimeSettings(null)),\n );\n app.post('/api/unassigned/model-defaults', async (c) => {\n const op = await service.saveModelDefaults(\n null,\n await parse(c, schemas.saveModelDefaultsSchema),\n );\n return c.json(op, status(op));\n });\n app.get('/api/unassigned/threads', async (c) =>\n c.json(\n await service.listThreadSummaries(\n null,\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.post('/api/unassigned/threads', async (c) => {\n const op = await service.createThread(null, await parse(c, schemas.createThreadSchema));\n return c.json(op, status(op));\n });\n app.post('/api/project-clones', async (c) =>\n c.json(service.cloneProject(await parse(c, schemas.cloneProjectSchema)), 202),\n );\n app.get('/api/project-clones/:cloneId', (c) =>\n c.json(service.projectClones.get(id(c.req.param('cloneId')))),\n );\n app.post('/api/project-clones/:cloneId/cancel', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.projectClones.cancel(id(c.req.param('cloneId'))));\n });\n app.post('/api/project-clones/:cloneId/register', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.projectClones.retryRegistration(id(c.req.param('cloneId'))));\n });\n app.get('/api/projects/:projectId/runtime-settings', async (c) =>\n c.json(await service.readRuntimeSettings(id(c.req.param('projectId')))),\n );\n app.post('/api/projects/:projectId/model-defaults', async (c) => {\n const op = await service.saveModelDefaults(\n id(c.req.param('projectId')),\n await parse(c, schemas.saveModelDefaultsSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/projects', async (c) =>\n c.json(service.addProject(await parse(c, schemas.createProjectSchema))),\n );\n app.post('/api/projects/:projectId/rename', async (c) =>\n c.json(\n service.renameProject(\n id(c.req.param('projectId')),\n await parse(c, schemas.renameProjectSchema),\n ),\n ),\n );\n app.post('/api/projects/:projectId/remove', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.removeProject(id(c.req.param('projectId'))));\n });\n app.get('/api/projects/:projectId/threads', async (c) =>\n c.json(\n await service.listThreadSummaries(\n id(c.req.param('projectId')),\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.get('/api/threads', async (c) =>\n c.json(\n await service.listThreads(\n id(c.req.query('projectId') ?? ''),\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.post('/api/threads/:threadId/archive', async (c) => {\n return c.json(\n await service.setThreadArchived(\n id(c.req.param('threadId')),\n await parse(c, schemas.archiveThreadSchema),\n ),\n );\n });\n app.get('/api/threads/:threadId', async (c) =>\n c.json(await service.getThread(id(c.req.param('threadId')))),\n );\n app.get('/api/threads/:threadId/history', async (c) =>\n c.json(await service.getThreadHistory(id(c.req.param('threadId')), c.req.query('cursor'))),\n );\n app.get('/api/threads/:threadId/metadata', async (c) =>\n c.json(await service.getThreadMetadata(id(c.req.param('threadId')))),\n );\n app.get('/api/threads/:threadId/export', async (c) => {\n const exported = await service.exportThread(id(c.req.param('threadId')));\n c.header('Content-Type', 'text/markdown; charset=utf-8');\n c.header('Content-Disposition', `attachment; filename=\"${exported.filename}\"`);\n c.header('Cache-Control', 'no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('X-Export-Completeness', exported.partial ? 'partial' : 'saved-history');\n return c.body(exported.markdown);\n });\n app.get('/api/threads/:threadId/images', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n c.header('Content-Security-Policy', \"default-src 'none'; sandbox\");\n const image = await service.getThreadImage(id(c.req.param('threadId')), c.req.query('path'));\n return c.body(image.bytes, 200, {\n 'Content-Type': image.contentType,\n 'Content-Length': String(image.bytes.length),\n });\n });\n app.get('/api/threads/:threadId/markdown', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n return c.json(\n await service.getThreadMarkdown(id(c.req.param('threadId')), c.req.query('path')),\n );\n });\n app.get('/api/threads/:threadId/json', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n return c.json(await service.getThreadJson(id(c.req.param('threadId')), c.req.query('path')));\n });\n app.get('/api/operations/:operationId', (c) =>\n c.json(service.getOperation(id(c.req.param('operationId')))),\n );\n app.post('/api/projects/:projectId/threads', async (c) => {\n const op = await service.createThread(\n id(c.req.param('projectId')),\n await parse(c, schemas.createThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/resume', async (c) => {\n const op = await service.resumeThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.resumeThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/fork', async (c) => {\n const op = await service.forkThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.forkThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/rename', async (c) => {\n const op = await service.renameThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.renameThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/turns', async (c) => {\n const op = await service.startTurn(\n id(c.req.param('threadId')),\n await parse(c, schemas.startTurnSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/review', async (c) => {\n const op = await service.startReview(\n id(c.req.param('threadId')),\n await parse(c, schemas.startReviewSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/steer', async (c) => {\n const op = await service.steer(\n id(c.req.param('threadId')),\n await parse(c, schemas.steerSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/compact', async (c) => {\n const op = await service.compactThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.operationSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/interrupt', async (c) => {\n const op = await service.interrupt(\n id(c.req.param('threadId')),\n await parse(c, schemas.interruptSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/actions/:actionId/resolve', async (c) => {\n const op = await service.resolveAction(\n id(c.req.param('actionId')),\n await parse(c, schemas.resolveActionSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/operations/:operationId/reconcile', async (c) => {\n const op = await service.reconcileOperation(\n id(c.req.param('operationId')),\n await parse(c, schemas.reconcileSchema),\n );\n return c.json(op, status(op));\n });\n app.get(\n '/ws',\n upgradeWebSocket((c) =>\n socketHandlers(service, config, c.get('identity'), c.req.query('overview') === '1'),\n ),\n );\n app.all('/api/*', () => {\n throw new AppError('NOT_FOUND', 'API route not found', 404);\n });\n app.all('/api', () => {\n throw new AppError('NOT_FOUND', 'API route not found', 404);\n });\n app.all('/ws/*', () => {\n throw new AppError('NOT_FOUND', 'WebSocket route not found', 404);\n });\n app.use('*', async (c, next) => {\n if (!c.req.path.startsWith('/assets/')) c.header('Cache-Control', 'no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'same-origin');\n c.header(\n 'Content-Security-Policy',\n // Remote Markdown images load directly in the browser, including HTTPS redirects.\n // Keep scripts, connections and all other resource policies restricted as before.\n \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'\",\n );\n await next();\n });\n app.get('*', serveStatic({ root: staticDir }));\n app.get('*', async (c, next) => {\n if (!c.req.header('accept')?.includes('text/html') || /\\.[^/]+$/.test(c.req.path))\n return c.json({ error: { code: 'NOT_FOUND', message: 'Resource not found' } }, 404);\n return serveStatic({ path: `${staticDir}/index.html` })(c, next);\n });\n app.notFound((c) => c.json({ error: { code: 'NOT_FOUND', message: 'Resource not found' } }, 404));\n return app;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BackupController } from '../shared/backups.js';\nimport { backupIdSchema } from '../shared/backups.js';\nimport { backupRequestSchema } from '../backups/manager.js';\nimport { createHash } from 'node:crypto';\nimport { Hono } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport { upgradeWebSocket, type HttpBindings } from '@hono/node-server';\nimport type { ZodType } from 'zod';\nimport { ZodError } from 'zod';\nimport { AppError } from '../shared/errors.js';\nimport { IMAGE_REQUEST_BYTES } from '../shared/images.js';\nimport * as schemas from '../shared/validation.js';\nimport type { Operation } from '../shared/types.js';\nimport type { AppConfig } from './config.js';\nimport { ConfigStore } from './config-store.js';\nimport { createAuthenticator, type Authenticator, type Identity } from './auth.js';\nimport type { GatewayService } from './service.js';\nimport { socketHandlers } from './websocket.js';\nimport { z } from 'zod';\nimport { releaseChannels, type UpdateController } from '../shared/updates.js';\nimport { settingsSchema, updateRequestSchema } from '../updates/manager.js';\nimport { startShellSchema } from '../shared/shell.js';\nexport interface HttpDependencies {\n config: AppConfig;\n service: GatewayService;\n staticDir: string;\n authenticate?: Authenticator;\n updates?: UpdateController;\n backups?: BackupController;\n}\nexport function createApp({\n config,\n service,\n staticDir,\n authenticate = createAuthenticator(config),\n updates,\n backups,\n}: HttpDependencies) {\n const app = new Hono<{\n Bindings: HttpBindings;\n Variables: { identity: Identity; operationId?: string };\n }>();\n app.onError((error, c) => {\n const failure =\n error instanceof AppError\n ? error\n : error instanceof ZodError || error instanceof SyntaxError\n ? new AppError('VALIDATION_FAILED', 'Invalid request data', 400)\n : new AppError('INTERNAL_ERROR', 'An internal error occurred', 500);\n return c.json({ error: failure.toJSON(c.get('operationId')) }, failure.status as 400);\n });\n app.get('/api/health', (c) => c.json({ ok: true }));\n app.use('*', async (c, next) => {\n c.set('identity', await authenticate(c.req.raw, c.req.path === '/ws'));\n await next();\n });\n app.use('/api/*', (c, next) =>\n bodyLimit({\n maxSize: /^\\/api\\/threads\\/[^/]+\\/(turns|steer)$/.test(c.req.path)\n ? IMAGE_REQUEST_BYTES\n : 512 * 1024,\n onError: () => {\n throw new AppError('BODY_TOO_LARGE', 'Request body exceeds limit', 413);\n },\n })(c, next),\n );\n app.use('/api/*', async (c, next) => {\n c.header('Cache-Control', 'no-store');\n if (\n service.isInMaintenance() &&\n !['GET', 'HEAD', 'OPTIONS'].includes(c.req.method) &&\n !c.req.path.startsWith('/api/updates') &&\n !c.req.path.startsWith('/api/backups')\n )\n throw service.maintenanceError();\n await next();\n });\n if (backups) {\n app.get('/api/backups', async (c) => c.json(await backups.status()));\n app.post('/api/backups', async (c) =>\n c.json(await backups.start(backupRequestSchema.parse(await c.req.json())), 202),\n );\n app.post('/api/backups/:id/cancel', async (c) =>\n c.json(await backups.cancel(backupIdSchema.parse(c.req.param('id')))),\n );\n app.post('/api/backups/:id/verify', async (c) =>\n c.json(await backups.verify(backupIdSchema.parse(c.req.param('id')))),\n );\n }\n if (updates) {\n app.get('/api/updates', async (c) => c.json(await updates.status()));\n app.post('/api/updates/check', async (c) => {\n const input = z\n .object({ channel: z.enum(releaseChannels).optional() })\n .strict()\n .parse(await c.req.json());\n return c.json(await updates.check(input.channel));\n });\n app.post('/api/updates/settings', async (c) =>\n c.json(await updates.configure(settingsSchema.parse(await c.req.json()))),\n );\n app.post('/api/updates/run', async (c) =>\n c.json(await updates.start(updateRequestSchema.parse(await c.req.json())), 202),\n );\n }\n const id = (value: string) => schemas.idSchema.parse(value);\n const parse = async <T>(\n c: { req: { json: () => Promise<unknown> }; set: (key: 'operationId', value: string) => void },\n schema: ZodType<T>,\n ): Promise<T> => {\n const value: unknown = await c.req.json();\n if (\n value &&\n typeof value === 'object' &&\n 'clientOperationId' in value &&\n typeof value.clientOperationId === 'string'\n )\n c.set('operationId', value.clientOperationId);\n return schema.parse(value);\n };\n const status = (op: Operation) =>\n op.status === 'dispatching' || op.status === 'accepted' ? (202 as const) : (200 as const);\n const configuration = new ConfigStore(config);\n app.use('/api/config*', async (c, next) => {\n c.header('Cache-Control', 'no-store');\n await next();\n });\n app.get('/api/config', async (c) => c.json(await configuration.snapshot()));\n app.post('/api/config', async (c) => c.json(await configuration.save(await c.req.json())));\n app.post('/api/config/import', async (c) =>\n c.json(await configuration.previewImport(await c.req.json())),\n );\n app.get('/api/config/export', async (c) => {\n c.header('Content-Disposition', 'attachment; filename=\"codex-web-config.json\"');\n return c.json(await configuration.export());\n });\n app.get('/api/history-cache-context', async (c) => {\n const identity = c.get('identity');\n if (config.auth.mode !== 'local' && !identity.subject)\n throw new AppError('UNAUTHENTICATED', '\u65E0\u6CD5\u786E\u8BA4\u7F13\u5B58\u6240\u5C5E\u7528\u6237', 401);\n const projects = await service.listProjects();\n // A restart, user change or project/permission change creates a new namespace.\n // The subject is hashed on the server and is never exposed to browser storage.\n const scope = createHash('sha256')\n .update(\n JSON.stringify([\n service.events.serverEpoch,\n service.getSystem().codexEpoch,\n config.auth.mode,\n identity.subject ?? 'local',\n projects.map((project) => [project.id, project.rootPath, project.available]),\n ]),\n )\n .digest('hex');\n return c.json({ scope });\n });\n app.get('/api/system', (c) => c.json(service.getSystem()));\n app.get('/api/shell', (c) =>\n c.json(\n service.shell.snapshot(\n c.req.query('epoch'),\n z.coerce\n .number()\n .int()\n .min(0)\n .max(Number.MAX_SAFE_INTEGER)\n .default(0)\n .parse(c.req.query('after')),\n ),\n ),\n );\n app.post('/api/projects/:projectId/shell', async (c) => {\n const op = await service.startShell(\n id(c.req.param('projectId')),\n await parse(c, startShellSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/shell/:commandId/interrupt', async (c) => {\n const op = await service.interruptShell(\n id(c.req.param('commandId')),\n await parse(c, schemas.operationSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/system/compatibility/confirm', async (c) => {\n const op = await service.confirmCompatibility(\n await parse(c, schemas.confirmCompatibilitySchema),\n );\n return c.json(op, status(op));\n });\n app.get('/api/projects', async (c) => c.json({ data: await service.listProjects() }));\n app.get('/api/unassigned/runtime-settings', async (c) =>\n c.json(await service.readRuntimeSettings(null)),\n );\n app.post('/api/unassigned/model-defaults', async (c) => {\n const op = await service.saveModelDefaults(\n null,\n await parse(c, schemas.saveModelDefaultsSchema),\n );\n return c.json(op, status(op));\n });\n app.get('/api/unassigned/threads', async (c) =>\n c.json(\n await service.listThreadSummaries(\n null,\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.post('/api/unassigned/threads', async (c) => {\n const op = await service.createThread(null, await parse(c, schemas.createThreadSchema));\n return c.json(op, status(op));\n });\n app.post('/api/project-clones', async (c) =>\n c.json(service.cloneProject(await parse(c, schemas.cloneProjectSchema)), 202),\n );\n app.get('/api/project-clones/:cloneId', (c) =>\n c.json(service.projectClones.get(id(c.req.param('cloneId')))),\n );\n app.post('/api/project-clones/:cloneId/cancel', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.projectClones.cancel(id(c.req.param('cloneId'))));\n });\n app.post('/api/project-clones/:cloneId/register', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.projectClones.retryRegistration(id(c.req.param('cloneId'))));\n });\n app.get('/api/projects/:projectId/runtime-settings', async (c) =>\n c.json(await service.readRuntimeSettings(id(c.req.param('projectId')))),\n );\n app.post('/api/projects/:projectId/model-defaults', async (c) => {\n const op = await service.saveModelDefaults(\n id(c.req.param('projectId')),\n await parse(c, schemas.saveModelDefaultsSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/projects', async (c) =>\n c.json(service.addProject(await parse(c, schemas.createProjectSchema))),\n );\n app.post('/api/projects/:projectId/rename', async (c) =>\n c.json(\n service.renameProject(\n id(c.req.param('projectId')),\n await parse(c, schemas.renameProjectSchema),\n ),\n ),\n );\n app.post('/api/projects/:projectId/remove', async (c) => {\n await parse(c, schemas.removeProjectSchema);\n return c.json(service.removeProject(id(c.req.param('projectId'))));\n });\n app.get('/api/projects/:projectId/threads', async (c) =>\n c.json(\n await service.listThreadSummaries(\n id(c.req.param('projectId')),\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.get('/api/threads', async (c) =>\n c.json(\n await service.listThreads(\n id(c.req.query('projectId') ?? ''),\n c.req.query('cursor') === undefined\n ? undefined\n : schemas.cursorSchema.parse(c.req.query('cursor')),\n schemas.archivedQuerySchema.parse(c.req.query('archived')),\n ),\n ),\n );\n app.post('/api/threads/:threadId/archive', async (c) => {\n return c.json(\n await service.setThreadArchived(\n id(c.req.param('threadId')),\n await parse(c, schemas.archiveThreadSchema),\n ),\n );\n });\n app.get('/api/threads/:threadId', async (c) =>\n c.json(await service.getThread(id(c.req.param('threadId')))),\n );\n app.get('/api/threads/:threadId/history', async (c) =>\n c.json(await service.getThreadHistory(id(c.req.param('threadId')), c.req.query('cursor'))),\n );\n app.get('/api/threads/:threadId/metadata', async (c) =>\n c.json(await service.getThreadMetadata(id(c.req.param('threadId')))),\n );\n app.get('/api/threads/:threadId/export', async (c) => {\n const exported = await service.exportThread(id(c.req.param('threadId')));\n c.header('Content-Type', 'text/markdown; charset=utf-8');\n c.header('Content-Disposition', `attachment; filename=\"${exported.filename}\"`);\n c.header('Cache-Control', 'no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('X-Export-Completeness', exported.partial ? 'partial' : 'saved-history');\n return c.body(exported.markdown);\n });\n app.get('/api/threads/:threadId/images', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n c.header('Content-Security-Policy', \"default-src 'none'; sandbox\");\n const image = await service.getThreadImage(id(c.req.param('threadId')), c.req.query('path'));\n return c.body(image.bytes, 200, {\n 'Content-Type': image.contentType,\n 'Content-Length': String(image.bytes.length),\n });\n });\n app.get('/api/threads/:threadId/markdown', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n return c.json(\n await service.getThreadMarkdown(id(c.req.param('threadId')), c.req.query('path')),\n );\n });\n app.get('/api/threads/:threadId/json', async (c) => {\n c.header('Cache-Control', 'private, no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Cross-Origin-Resource-Policy', 'same-origin');\n return c.json(await service.getThreadJson(id(c.req.param('threadId')), c.req.query('path')));\n });\n app.get('/api/operations/:operationId', (c) =>\n c.json(service.getOperation(id(c.req.param('operationId')))),\n );\n app.post('/api/projects/:projectId/threads', async (c) => {\n const op = await service.createThread(\n id(c.req.param('projectId')),\n await parse(c, schemas.createThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/resume', async (c) => {\n const op = await service.resumeThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.resumeThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/fork', async (c) => {\n const op = await service.forkThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.forkThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/rename', async (c) => {\n const op = await service.renameThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.renameThreadSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/turns', async (c) => {\n const op = await service.startTurn(\n id(c.req.param('threadId')),\n await parse(c, schemas.startTurnSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/review', async (c) => {\n const op = await service.startReview(\n id(c.req.param('threadId')),\n await parse(c, schemas.startReviewSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/steer', async (c) => {\n const op = await service.steer(\n id(c.req.param('threadId')),\n await parse(c, schemas.steerSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/compact', async (c) => {\n const op = await service.compactThread(\n id(c.req.param('threadId')),\n await parse(c, schemas.operationSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/threads/:threadId/interrupt', async (c) => {\n const op = await service.interrupt(\n id(c.req.param('threadId')),\n await parse(c, schemas.interruptSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/actions/:actionId/resolve', async (c) => {\n const op = await service.resolveAction(\n id(c.req.param('actionId')),\n await parse(c, schemas.resolveActionSchema),\n );\n return c.json(op, status(op));\n });\n app.post('/api/operations/:operationId/reconcile', async (c) => {\n const op = await service.reconcileOperation(\n id(c.req.param('operationId')),\n await parse(c, schemas.reconcileSchema),\n );\n return c.json(op, status(op));\n });\n app.get(\n '/ws',\n upgradeWebSocket((c) =>\n socketHandlers(service, config, c.get('identity'), c.req.query('overview') === '1'),\n ),\n );\n app.all('/api/*', () => {\n throw new AppError('NOT_FOUND', 'API route not found', 404);\n });\n app.all('/api', () => {\n throw new AppError('NOT_FOUND', 'API route not found', 404);\n });\n app.all('/ws/*', () => {\n throw new AppError('NOT_FOUND', 'WebSocket route not found', 404);\n });\n app.use('*', async (c, next) => {\n if (!c.req.path.startsWith('/assets/')) c.header('Cache-Control', 'no-store');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'same-origin');\n c.header(\n 'Content-Security-Policy',\n // Remote Markdown images load directly in the browser, including HTTPS redirects.\n // Keep scripts, connections and all other resource policies restricted as before.\n \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'\",\n );\n await next();\n });\n app.get('*', serveStatic({ root: staticDir }));\n app.get('*', async (c, next) => {\n if (!c.req.header('accept')?.includes('text/html') || /\\.[^/]+$/.test(c.req.path))\n return c.json({ error: { code: 'NOT_FOUND', message: 'Resource not found' } }, 404);\n return serveStatic({ path: `${staticDir}/index.html` })(c, next);\n });\n app.notFound((c) => c.json({ error: { code: 'NOT_FOUND', message: 'Resource not found' } }, 404));\n return app;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,13 @@
1
+ import { BackupManager } from "../backups/manager.js";
2
+ import { createBackupStore } from "../backups/factory.js";
3
+ import { assertNoPendingRestore } from "../backups/restore.js";
1
4
  import { fileURLToPath } from "node:url";
2
5
  import { join } from "node:path";
3
6
  import { existsSync, realpathSync } from "node:fs";
4
7
  import { serve } from "@hono/node-server";
5
8
  import { WebSocketServer } from "ws";
6
9
  import { CodexAdapter } from "../codex/adapter.js";
7
- import { loadConfig } from "./config.js";
10
+ import { loadConfig, configSource } from "./config.js";
8
11
  import { acquireInstanceLock } from "./instance-lock.js";
9
12
  import { openDatabase } from "./db/index.js";
10
13
  import { migrateDatabase } from "./db/migrate.js";
@@ -18,8 +21,12 @@ async function startGateway(config, overrides = {}) {
18
21
  const release = await acquireInstanceLock(config.dataDir);
19
22
  let closeDatabase;
20
23
  let codex;
24
+ let backups = overrides.backups;
21
25
  const updates = overrides.updates ?? new UpdateManager(void 0, void 0, () => codex?.diagnostics().codexVersion ?? null);
22
26
  try {
27
+ const source = configSource(config);
28
+ const backupStore = source ? createBackupStore(source.path, config.dataDir, overrides.migrationsDir) : void 0;
29
+ if (backupStore) await assertNoPendingRestore(backupStore.options.directory);
23
30
  const db = openDatabase(join(config.dataDir, "app.sqlite"));
24
31
  closeDatabase = db.close;
25
32
  const packagedMigrations = fileURLToPath(new URL("../drizzle", import.meta.url));
@@ -38,6 +45,7 @@ async function startGateway(config, overrides = {}) {
38
45
  demo: config.demo
39
46
  });
40
47
  service.setMaintenance(overrides.maintenance ?? false);
48
+ backups ??= backupStore ? new BackupManager(backupStore, service) : void 0;
41
49
  try {
42
50
  await codex.start();
43
51
  } catch {
@@ -47,7 +55,8 @@ async function startGateway(config, overrides = {}) {
47
55
  config,
48
56
  service,
49
57
  staticDir: overrides.staticDir ?? fileURLToPath(new URL("../web", import.meta.url)),
50
- updates
58
+ updates,
59
+ backups
51
60
  });
52
61
  const server = serve({
53
62
  fetch: app.fetch,
@@ -71,6 +80,7 @@ async function startGateway(config, overrides = {}) {
71
80
  }
72
81
  wss.close();
73
82
  try {
83
+ await backups?.close();
74
84
  await service.shutdown();
75
85
  } finally {
76
86
  if ("closeAllConnections" in server) server.closeAllConnections();
@@ -82,9 +92,10 @@ async function startGateway(config, overrides = {}) {
82
92
  }
83
93
  }
84
94
  })();
85
- return { app, server, service, codex, close, updates };
95
+ return { app, server, service, codex, close, updates, backups };
86
96
  } catch (error) {
87
97
  updates.close();
98
+ await backups?.close();
88
99
  try {
89
100
  await codex?.stop();
90
101
  } finally {