@covro/covro 0.3.1-dev.1 → 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/README.zh-CN.md +10 -8
- package/dist/drizzle/0006_project_order.sql +8 -0
- package/dist/drizzle/meta/0006_snapshot.json +488 -0
- package/dist/drizzle/meta/_journal.json +7 -0
- package/dist/server/db/schema.js +1 -0
- package/dist/server/db/schema.js.map +2 -2
- package/dist/server/http.js +10 -0
- package/dist/server/http.js.map +2 -2
- package/dist/server/projects.js +48 -5
- package/dist/server/projects.js.map +2 -2
- package/dist/server/service.js +5 -0
- package/dist/server/service.js.map +2 -2
- package/dist/shared/updates.js.map +2 -2
- package/dist/shared/validation.js +2 -0
- package/dist/shared/validation.js.map +2 -2
- package/dist/update-worker.cjs +4 -3
- package/dist/updates/manager.js +7 -4
- package/dist/updates/manager.js.map +2 -2
- package/dist/updates/registry.js +21 -9
- package/dist/updates/registry.js.map +3 -3
- package/dist/updates/worker.js +3 -3
- package/dist/updates/worker.js.map +2 -2
- package/dist/web/assets/{abnfDiagram-WEYOIA3C-DLvlob5t.js → abnfDiagram-WEYOIA3C-DowTqPD1.js} +1 -1
- package/dist/web/assets/{arc-DgauwgFe.js → arc-avc_XIkY.js} +1 -1
- package/dist/web/assets/{architecture-WOLXFQ4H-DvjLv0QN.js → architecture-WOLXFQ4H-BDozqXmm.js} +1 -1
- package/dist/web/assets/{architectureDiagram-ZHVYKT53-BAyZGlzu.js → architectureDiagram-ZHVYKT53-DtJ12bfc.js} +1 -1
- package/dist/web/assets/{blockDiagram-RJAE7QA3-BVfkmjlt.js → blockDiagram-RJAE7QA3-Ddu2IgY6.js} +1 -1
- package/dist/web/assets/{c4Diagram-XDPPPE54-rTsfyMoB.js → c4Diagram-XDPPPE54-C_Qil9r3.js} +1 -1
- package/dist/web/assets/channel-B77p7Idm.js +1 -0
- package/dist/web/assets/{chunk-2E7WHVMD-CQ_N_vLS.js → chunk-2E7WHVMD-qdMW6Jm-.js} +1 -1
- package/dist/web/assets/{chunk-4EMNKR2T-wBy_gyo6.js → chunk-4EMNKR2T-CkPVCMr1.js} +1 -1
- package/dist/web/assets/{chunk-55XCU76K-DYiwIhmI.js → chunk-55XCU76K-DsU2FgdF.js} +1 -1
- package/dist/web/assets/{chunk-7S6XSTFO-CRGtfVHg.js → chunk-7S6XSTFO-BpDFChC7.js} +1 -1
- package/dist/web/assets/{chunk-AQDTSKZB-1G2Za6bm.js → chunk-AQDTSKZB-DJjzhlKH.js} +1 -1
- package/dist/web/assets/{chunk-DSNLSHJZ-B1LLoYuG.js → chunk-DSNLSHJZ-BNqsnTy_.js} +1 -1
- package/dist/web/assets/{chunk-HAGFOTED-78h1RpHh.js → chunk-HAGFOTED-DpMJutiE.js} +1 -1
- package/dist/web/assets/{chunk-HNE4Q36P-DmR5B27Q.js → chunk-HNE4Q36P-Cf7CfknI.js} +1 -1
- package/dist/web/assets/{chunk-NQOKRVIF-D7WSEPzg.js → chunk-NQOKRVIF-Y6Zum1rk.js} +1 -1
- package/dist/web/assets/{chunk-UHW7PFBP-gl7a5V-l.js → chunk-UHW7PFBP-DTKlhkvC.js} +1 -1
- package/dist/web/assets/{chunk-VQ5W62QI-KaBXxBre.js → chunk-VQ5W62QI-BXMTljva.js} +1 -1
- package/dist/web/assets/{chunk-WQQL4CDK-DDczFoOr.js → chunk-WQQL4CDK-DQ8KPimB.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-3ug4Qhxg.js → chunk-XXDRQBXY--qQCs44_.js} +1 -1
- package/dist/web/assets/{chunk-YZO67HFG-BpWOuCXP.js → chunk-YZO67HFG-6PJrNASc.js} +1 -1
- package/dist/web/assets/{chunk-ZAUX2LTX-1ojPb1if.js → chunk-ZAUX2LTX-CaUWGpV1.js} +1 -1
- package/dist/web/assets/{chunk-ZCHMQSOR-D2kK2cPj.js → chunk-ZCHMQSOR-DiRpbPd7.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-4MYWR3UA-B7eMvxAO.js → classDiagram-v2-4MYWR3UA-DWMkK6DS.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-BtB8mbt8.js → cose-bilkent-JH36ORCC-Df0fISlN.js} +1 -1
- package/dist/web/assets/{cynefin-EF2NZ3EQ-CIctqxlE.js → cynefin-EF2NZ3EQ-BzpSmYdw.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-WF24UDRP-qat2GD9P.js → cynefinDiagram-WF24UDRP-rmMtUtwo.js} +1 -1
- package/dist/web/assets/{dagre-NK4GIZVX-OJamzzID.js → dagre-NK4GIZVX-CgCHVbx5.js} +1 -1
- package/dist/web/assets/{diagram-CBK3MWTC-C7cX2tqO.js → diagram-CBK3MWTC-Dj4cXo7W.js} +1 -1
- package/dist/web/assets/{diagram-I5XIIV2D-DsMfKVN7.js → diagram-I5XIIV2D-CKeuZP3y.js} +1 -1
- package/dist/web/assets/{diagram-ODIL2UCW-Cz66FxdJ.js → diagram-ODIL2UCW-BZAfQGN3.js} +1 -1
- package/dist/web/assets/{diagram-PFBEJUXE-CwhPuwKj.js → diagram-PFBEJUXE-BxVXsn4p.js} +1 -1
- package/dist/web/assets/{diagram-RJA3I4VV-C52IGiFJ.js → diagram-RJA3I4VV-CRsbf7dF.js} +1 -1
- package/dist/web/assets/{diagram-TYUNFSNR-C2LZVLKY.js → diagram-TYUNFSNR-DgTwLnuh.js} +1 -1
- package/dist/web/assets/{dist-Bxu8YbZb.js → dist-Doi7ZXfI.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-V4P3TTPT-eQKKlMli.js → ebnfDiagram-V4P3TTPT-DAJybFsQ.js} +1 -1
- package/dist/web/assets/{elk-QONTBCTQ-C5kIOZTA.js → elk-QONTBCTQ-ClmbVmdT.js} +1 -1
- package/dist/web/assets/{erDiagram-KYQIGQAA-CMTowz5P.js → erDiagram-KYQIGQAA-D54WxqQQ.js} +1 -1
- package/dist/web/assets/{eventmodeling-K75KTNOO-C5v-UF8X.js → eventmodeling-K75KTNOO-DawI4hQp.js} +1 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-DdOQFHlQ.js +1 -0
- package/dist/web/assets/{ganttDiagram-R7GPNTJY-B0viiC-b.js → ganttDiagram-R7GPNTJY-cnaBlOXJ.js} +1 -1
- package/dist/web/assets/{gitGraph-VSP46ZUC-tEjFmPhN.js → gitGraph-VSP46ZUC-f5UpyFWQ.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-CsOwt7jz.js → gitGraphDiagram-PDYL7XHY-DHAuB_Wo.js} +1 -1
- package/dist/web/assets/index-CmG4JSXi.js +147 -0
- package/dist/web/assets/index-Crq1cgK9.css +1 -0
- package/dist/web/assets/{info-OHQRW6UA-DnFGu4Ew.js → info-OHQRW6UA-D_9B9AJs.js} +1 -1
- package/dist/web/assets/{infoDiagram-MVDRKAX5-B6WiNaDF.js → infoDiagram-MVDRKAX5-DRBRWeRu.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-Dn70fI1r.js → ishikawaDiagram-HPEHV2GE-CYmQuozY.js} +1 -1
- package/dist/web/assets/{journeyDiagram-BOSHW7O7-BUjYzV2f.js → journeyDiagram-BOSHW7O7-CX1zkmCe.js} +1 -1
- package/dist/web/assets/{kanban-definition-FNSA4HC5-BDMfWbtB.js → kanban-definition-FNSA4HC5-BJPOrsY6.js} +1 -1
- package/dist/web/assets/{line-DNSRZHBK.js → line-7T8ot9Ur.js} +1 -1
- package/dist/web/assets/{linear-CrS49q6J.js → linear-DMmP6WCj.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-DXuyO8Px.js → mermaid-parser.core-Lmja4cot.js} +3 -3
- package/dist/web/assets/{mermaid.core-DUTnbQkq.js → mermaid.core-Dxj_7oC8.js} +4 -4
- package/dist/web/assets/{mindmap-definition-6OY57UG3-CqZTtItJ.js → mindmap-definition-6OY57UG3-C7iJoXRJ.js} +1 -1
- package/dist/web/assets/{packet-JDAUHWVQ-DXEZgY0a.js → packet-JDAUHWVQ-DDIQ5UBn.js} +1 -1
- package/dist/web/assets/{pegDiagram-ECIUJNBX-D6CCPNem.js → pegDiagram-ECIUJNBX-DBAOXG96.js} +1 -1
- package/dist/web/assets/{pie-XZMESJXO-AXRFjZ4G.js → pie-XZMESJXO-AUvt4NWU.js} +1 -1
- package/dist/web/assets/{pieDiagram-GNMPY74T-B9Ss8_5s.js → pieDiagram-GNMPY74T-8JH78W7q.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-D57K4MC3-JrlylCtz.js → quadrantDiagram-D57K4MC3-C45rOnuv.js} +1 -1
- package/dist/web/assets/{radar-ABXABTNO-ChFm4hZg.js → radar-ABXABTNO-CIQZLc1o.js} +1 -1
- package/dist/web/assets/{railroad-I3PHUGI6-DaXXzqhZ.js → railroad-I3PHUGI6-b-hnOwbi.js} +1 -1
- package/dist/web/assets/{railroad-abnf-LNEFI6M7-DGE67q11.js → railroad-abnf-LNEFI6M7-CfSBVDJ_.js} +1 -1
- package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-Cq9S3q72.js → railroad-ebnf-DWYD2UWJ-DtF0pRkV.js} +1 -1
- package/dist/web/assets/{railroad-peg-JR7BVNR7-D2Gth3eY.js → railroad-peg-JR7BVNR7-CclJYQKR.js} +1 -1
- package/dist/web/assets/{railroadDiagram-Y72NRBL7-BpkXX59H.js → railroadDiagram-Y72NRBL7-hvCbqhde.js} +1 -1
- package/dist/web/assets/{requirementDiagram-EQYSW5RA-oNp3DMM4.js → requirementDiagram-EQYSW5RA-D-hxd63Q.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-SY24JHO5-bHfheSKO.js → sankeyDiagram-SY24JHO5-5ewmrlVs.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-BLEHNHQU-CEM2XfNF.js → sequenceDiagram-BLEHNHQU-JOfTl3nj.js} +1 -1
- package/dist/web/assets/{src-KjMctvzy.js → src-BwOfNz4_.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-D_TaR_ix.js → stateDiagram-v2-A6IESKWZ-CzVjFAR7.js} +1 -1
- package/dist/web/assets/{swimlanes-B3ENRKFQ-BUYl2fsg.js → swimlanes-B3ENRKFQ-BGr6XbCx.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-C-s2RzEc.js +8 -0
- package/dist/web/assets/{timeline-definition-JXYKGLGB-CpKsGN6d.js → timeline-definition-JXYKGLGB-DPhFyTu3.js} +1 -1
- package/dist/web/assets/{treeView-D4JQ5SDB-Dioaagqt.js → treeView-D4JQ5SDB-BNJbdzV5.js} +1 -1
- package/dist/web/assets/{treemap-SAJKECNS-B8NLQ14o.js → treemap-SAJKECNS-DPEkYUkN.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-WPOLBNNX-CfwdxcsG.js → usecaseDiagram-WPOLBNNX-Ci781Pvl.js} +1 -1
- package/dist/web/assets/{vennDiagram-Q3Y3IDCW-DQoKGtXo.js → vennDiagram-Q3Y3IDCW-DtUiBDbf.js} +1 -1
- package/dist/web/assets/{wardley-7MLQ67FV-DQHLHmeZ.js → wardley-7MLQ67FV-D50wpEWr.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-IVAIDKWA-DV-lq7zb.js → wardleyDiagram-IVAIDKWA-C2UArT_M.js} +1 -1
- package/dist/web/assets/{xychartDiagram-4URNHDU4-wV4ueoGC.js → xychartDiagram-4URNHDU4-UoX7lJqB.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +6 -6
- package/dist/web/assets/channel-GGfPocHk.js +0 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-C-jE8afx.js +0 -1
- package/dist/web/assets/index-COSho7m2.css +0 -1
- package/dist/web/assets/index-D7GZPtTj.js +0 -147
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-DDLmyR4x.js +0 -8
package/dist/server/http.js
CHANGED
|
@@ -190,6 +190,10 @@ function createApp({
|
|
|
190
190
|
await parse(c, schemas.removeProjectSchema);
|
|
191
191
|
return c.json(service.projectClones.retryRegistration(id(c.req.param("cloneId"))));
|
|
192
192
|
});
|
|
193
|
+
app.post(
|
|
194
|
+
"/api/projects/reorder",
|
|
195
|
+
async (c) => c.json(service.reorderProjects(await parse(c, schemas.reorderProjectsSchema)))
|
|
196
|
+
);
|
|
193
197
|
app.get(
|
|
194
198
|
"/api/projects/:projectId/runtime-settings",
|
|
195
199
|
async (c) => c.json(await service.readRuntimeSettings(id(c.req.param("projectId"))))
|
|
@@ -273,6 +277,12 @@ function createApp({
|
|
|
273
277
|
c.header("Cross-Origin-Resource-Policy", "same-origin");
|
|
274
278
|
c.header("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
275
279
|
const image = await service.getThreadImage(id(c.req.param("threadId")), c.req.query("path"));
|
|
280
|
+
const etag = `"${createHash("sha256").update(image.bytes).digest("hex")}"`;
|
|
281
|
+
c.header("Cache-Control", "private, no-cache");
|
|
282
|
+
c.header("ETag", etag);
|
|
283
|
+
const ifNoneMatch = c.req.header("If-None-Match");
|
|
284
|
+
if (ifNoneMatch === "*" || ifNoneMatch?.split(",").some((tag) => tag.trim().replace(/^W\//, "") === etag))
|
|
285
|
+
return c.body(null, 304);
|
|
276
286
|
return c.body(image.bytes, 200, {
|
|
277
287
|
"Content-Type": image.contentType,
|
|
278
288
|
"Content-Length": String(image.bytes.length)
|
package/dist/server/http.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/http.ts"],
|
|
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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",
|
|
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.post('/api/projects/reorder', async (c) =>\n c.json(service.reorderProjects(await parse(c, schemas.reorderProjectsSchema))),\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 // Hash the validated bytes so same-size overwrites with preserved mtimes also invalidate.\n const etag = `\"${createHash('sha256').update(image.bytes).digest('hex')}\"`;\n c.header('Cache-Control', 'private, no-cache');\n c.header('ETag', etag);\n const ifNoneMatch = c.req.header('If-None-Match');\n if (\n ifNoneMatch === '*' ||\n ifNoneMatch?.split(',').some((tag) => tag.trim().replace(/^W\\//, '') === etag)\n )\n return c.body(null, 304);\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
|
}
|
package/dist/server/projects.js
CHANGED
|
@@ -2,9 +2,13 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
4
4
|
import { basename, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
|
-
import { asc } from "drizzle-orm";
|
|
5
|
+
import { asc, eq } from "drizzle-orm";
|
|
6
6
|
import { AppError } from "../shared/errors.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
createProjectSchema,
|
|
9
|
+
renameProjectSchema,
|
|
10
|
+
reorderProjectsSchema
|
|
11
|
+
} from "../shared/validation.js";
|
|
8
12
|
import { projectRegistrations } from "./db/schema.js";
|
|
9
13
|
function containsPath(root, candidate) {
|
|
10
14
|
const difference = relative(root, candidate);
|
|
@@ -25,7 +29,11 @@ function checkoutRoot(cwd) {
|
|
|
25
29
|
class ProjectRegistry {
|
|
26
30
|
constructor(configs, database) {
|
|
27
31
|
this.database = database;
|
|
28
|
-
for (const row of database?.select().from(projectRegistrations).orderBy(
|
|
32
|
+
for (const row of database?.select().from(projectRegistrations).orderBy(
|
|
33
|
+
asc(projectRegistrations.sortOrder),
|
|
34
|
+
asc(projectRegistrations.createdAt),
|
|
35
|
+
asc(projectRegistrations.id)
|
|
36
|
+
).all() ?? [])
|
|
29
37
|
this.registered.set(row.id, row);
|
|
30
38
|
const seeds = [];
|
|
31
39
|
for (const config of configs) {
|
|
@@ -52,6 +60,7 @@ class ProjectRegistry {
|
|
|
52
60
|
path,
|
|
53
61
|
canonicalRoot,
|
|
54
62
|
removedAt: null,
|
|
63
|
+
sortOrder: this.nextSortOrder(),
|
|
55
64
|
createdAt: now,
|
|
56
65
|
updatedAt: now
|
|
57
66
|
};
|
|
@@ -68,6 +77,12 @@ class ProjectRegistry {
|
|
|
68
77
|
Date.now()
|
|
69
78
|
);
|
|
70
79
|
}
|
|
80
|
+
nextSortOrder() {
|
|
81
|
+
return [...this.registered.values()].reduce(
|
|
82
|
+
(next, row) => Math.max(next, row.sortOrder + 1),
|
|
83
|
+
0
|
|
84
|
+
);
|
|
85
|
+
}
|
|
71
86
|
directory(path) {
|
|
72
87
|
if (!isAbsolute(path) || path.includes("\0"))
|
|
73
88
|
throw new AppError("INVALID_PROJECT_PATH", "\u8BF7\u8F93\u5165\u8FD0\u884C Codex \u7684\u7535\u8111\u4E0A\u7684\u7EDD\u5BF9\u76EE\u5F55\u8DEF\u5F84", 400);
|
|
@@ -130,7 +145,29 @@ class ProjectRegistry {
|
|
|
130
145
|
}
|
|
131
146
|
}
|
|
132
147
|
list() {
|
|
133
|
-
return [...this.registered.values()].filter((project) => project.removedAt === null).
|
|
148
|
+
return [...this.registered.values()].filter((project) => project.removedAt === null).sort(
|
|
149
|
+
(a, b) => a.sortOrder - b.sortOrder || a.createdAt - b.createdAt || a.id.localeCompare(b.id)
|
|
150
|
+
).map((project) => this.inspect(project));
|
|
151
|
+
}
|
|
152
|
+
reorder(input) {
|
|
153
|
+
const { projectIds } = reorderProjectsSchema.parse(input);
|
|
154
|
+
const active = [...this.registered.values()].filter((row) => row.removedAt === null);
|
|
155
|
+
if (projectIds.length !== active.length || projectIds.some(
|
|
156
|
+
(id) => !this.registered.has(id) || this.registered.get(id).removedAt !== null
|
|
157
|
+
))
|
|
158
|
+
throw new AppError("PROJECT_ORDER_CONFLICT", "\u9879\u76EE\u5217\u8868\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u65B0\u8C03\u6574\u987A\u5E8F", 409);
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
const rows = projectIds.map((id, sortOrder) => ({
|
|
161
|
+
...this.registration(id),
|
|
162
|
+
sortOrder,
|
|
163
|
+
updatedAt: now
|
|
164
|
+
}));
|
|
165
|
+
this.database?.transaction((tx) => {
|
|
166
|
+
for (const row of rows)
|
|
167
|
+
tx.update(projectRegistrations).set({ sortOrder: row.sortOrder, updatedAt: now }).where(eq(projectRegistrations.id, row.id)).run();
|
|
168
|
+
});
|
|
169
|
+
for (const row of rows) this.registered.set(row.id, row);
|
|
170
|
+
return this.list();
|
|
134
171
|
}
|
|
135
172
|
/** Also usable when a saved directory is missing, so it can still be managed. */
|
|
136
173
|
describe(id) {
|
|
@@ -153,7 +190,12 @@ class ProjectRegistry {
|
|
|
153
190
|
const removed = matching.find((row2) => row2.removedAt !== null);
|
|
154
191
|
const now = Date.now();
|
|
155
192
|
if (removed) {
|
|
156
|
-
const restored = {
|
|
193
|
+
const restored = {
|
|
194
|
+
...removed,
|
|
195
|
+
removedAt: null,
|
|
196
|
+
sortOrder: this.nextSortOrder(),
|
|
197
|
+
updatedAt: now
|
|
198
|
+
};
|
|
157
199
|
const project = this.inspect(restored);
|
|
158
200
|
if (!project.available)
|
|
159
201
|
throw new AppError("PROJECT_UNAVAILABLE", project.error ?? "\u539F\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528", 409);
|
|
@@ -171,6 +213,7 @@ class ProjectRegistry {
|
|
|
171
213
|
path: canonicalRoot,
|
|
172
214
|
canonicalRoot,
|
|
173
215
|
removedAt: null,
|
|
216
|
+
sortOrder: this.nextSortOrder(),
|
|
174
217
|
createdAt: this.nextCreatedAt(),
|
|
175
218
|
updatedAt: now
|
|
176
219
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/projects.ts"],
|
|
4
|
-
"sourcesContent": ["import { execFileSync } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { accessSync, constants, realpathSync, statSync } from 'node:fs';\nimport { basename, isAbsolute, relative, resolve, sep } from 'node:path';\nimport { asc } from 'drizzle-orm';\nimport { AppError } from '../shared/errors.js';\nimport type { CreateProjectInput, Project, RenameProjectInput } from '../shared/types.js';\nimport { createProjectSchema, renameProjectSchema } from '../shared/validation.js';\nimport type { AppDatabase } from './db/index.js';\nimport { projectRegistrations } from './db/schema.js';\n\nexport interface ProjectConfig {\n id: string;\n name: string;\n path: string;\n}\ntype Registration = typeof projectRegistrations.$inferSelect;\n\nexport function containsPath(root: string, candidate: string): boolean {\n const difference = relative(root, candidate);\n return (\n difference === '' ||\n (difference !== '..' && !difference.startsWith(`..${sep}`) && !isAbsolute(difference))\n );\n}\n\nfunction checkoutRoot(cwd: string): string | undefined {\n try {\n const output = execFileSync('git', ['-C', cwd, 'rev-parse', '--show-toplevel'], {\n encoding: 'utf8',\n timeout: 3000,\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return output ? realpathSync(output) : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport class ProjectRegistry {\n private readonly registered = new Map<string, Registration>();\n\n constructor(\n configs: ProjectConfig[],\n private readonly database?: AppDatabase,\n ) {\n for (const row of database\n ?.select()\n .from(projectRegistrations)\n .orderBy(asc(projectRegistrations.createdAt), asc(projectRegistrations.id))\n .all() ?? [])\n this.registered.set(row.id, row);\n // JSON remains a source of new registrations, while persisted UI decisions win.\n // Keep legacy aliases and IDs intact; only new UI registrations reject aliases.\n const seeds: Registration[] = [];\n for (const config of configs) {\n const path = resolve(config.path);\n const existing = this.registered.get(config.id);\n if (existing) {\n if (existing.path !== path)\n throw new AppError(\n 'PROJECT_ID_CONFLICT',\n `\u9879\u76EE ${config.id} \u5DF2\u7ED1\u5B9A\u5176\u4ED6\u76EE\u5F55\uFF1B\u9879\u76EE ID \u548C\u76EE\u5F55\u4E0D\u53EF\u4FEE\u6539\uFF0C\u8BF7\u4F7F\u7528\u65B0 ID`,\n 409,\n { projectId: config.id },\n );\n continue;\n }\n let canonicalRoot: string | null = null;\n try {\n canonicalRoot = this.directory(path);\n } catch {\n // Existing configurations with temporarily missing directories still start.\n }\n const now = this.nextCreatedAt();\n const row = {\n ...config,\n path,\n canonicalRoot,\n removedAt: null,\n createdAt: now,\n updatedAt: now,\n };\n this.registered.set(config.id, row);\n seeds.push(row);\n }\n if (seeds.length) database?.insert(projectRegistrations).values(seeds).run();\n }\n\n private nextCreatedAt(): number {\n // Preserve seed order for legacy aliases even when imported within one millisecond.\n return [...this.registered.values()].reduce(\n (next, row) => Math.max(next, row.createdAt + 1),\n Date.now(),\n );\n }\n\n private directory(path: string): string {\n if (!isAbsolute(path) || path.includes('\\0'))\n throw new AppError('INVALID_PROJECT_PATH', '\u8BF7\u8F93\u5165\u8FD0\u884C Codex \u7684\u7535\u8111\u4E0A\u7684\u7EDD\u5BF9\u76EE\u5F55\u8DEF\u5F84', 400);\n try {\n const canonicalRoot = realpathSync(path);\n if (!statSync(canonicalRoot).isDirectory())\n throw new AppError('PROJECT_UNAVAILABLE', '\u9879\u76EE\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55', 409);\n accessSync(canonicalRoot, constants.R_OK | constants.X_OK);\n return canonicalRoot;\n } catch (error) {\n if (error instanceof AppError) throw error;\n const code = (error as NodeJS.ErrnoException).code;\n throw new AppError(\n 'PROJECT_UNAVAILABLE',\n code === 'ENOENT' || code === 'ENOTDIR'\n ? '\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1B\u8BF7\u8F93\u5165\u8FD0\u884C Codex \u7684\u7535\u8111\u4E0A\u7684\u76EE\u5F55'\n : code === 'EACCES' || code === 'EPERM'\n ? '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u8BBF\u95EE\uFF0C\u9700\u8981\u8BFB\u53D6\u548C\u8FDB\u5165\u76EE\u5F55\u7684\u6743\u9650'\n : '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u548C\u8BBF\u95EE\u6743\u9650',\n 409,\n );\n }\n }\n\n private save(row: Registration): void {\n this.database\n ?.insert(projectRegistrations)\n .values(row)\n .onConflictDoUpdate({ target: projectRegistrations.id, set: row })\n .run();\n this.registered.set(row.id, row);\n }\n\n private registration(id: string): Registration {\n const row = this.registered.get(id);\n if (!row || row.removedAt !== null)\n throw new AppError('PROJECT_NOT_FOUND', '\u9879\u76EE\u672A\u6CE8\u518C\u6216\u5DF2\u79FB\u9664', 404);\n return row;\n }\n\n private inspect(config: Registration): Project {\n const rootPath = config.path;\n try {\n const canonicalRoot = this.directory(rootPath);\n if (config.canonicalRoot !== null && canonicalRoot !== config.canonicalRoot)\n throw new AppError(\n 'PROJECT_UNAVAILABLE',\n '\u9879\u76EE\u76EE\u5F55\u7684\u771F\u5B9E\u8DEF\u5F84\u5DF2\u6539\u53D8\uFF0C\u4E0D\u80FD\u6CBF\u7528\u539F\u9879\u76EE\u8EAB\u4EFD',\n 409,\n );\n if (config.canonicalRoot === null)\n this.save({ ...config, canonicalRoot, updatedAt: Date.now() });\n return {\n id: config.id,\n name: config.name,\n rootPath,\n canonicalRoot,\n workspaceKey: checkoutRoot(canonicalRoot) ?? canonicalRoot,\n available: true,\n };\n } catch (error) {\n return {\n id: config.id,\n name: config.name,\n rootPath,\n canonicalRoot: config.canonicalRoot ?? rootPath,\n workspaceKey: config.canonicalRoot ?? rootPath,\n available: false,\n error: error instanceof Error ? error.message : '\u9879\u76EE\u4E0D\u53EF\u7528',\n };\n }\n }\n\n list(): Project[] {\n return [...this.registered.values()]\n .filter((project) => project.removedAt === null)\n .map((project) => this.inspect(project));\n }\n\n /** Also usable when a saved directory is missing, so it can still be managed. */\n describe(id: string): Project {\n return this.inspect(this.registration(id));\n }\n\n add(input: CreateProjectInput): Project {\n const parsed = createProjectSchema.parse(input);\n const canonicalRoot = this.directory(parsed.path);\n // Inspect lazily imported paths before checking, including legacy unavailable seeds.\n this.list();\n for (const row of this.registered.values()) {\n if (row.canonicalRoot !== null || row.removedAt === null) continue;\n try {\n this.save({ ...row, canonicalRoot: this.directory(row.path), updatedAt: Date.now() });\n } catch {\n // A tombstone still reserves its ID while its directory remains unavailable.\n }\n }\n const matching = [...this.registered.values()].filter(\n (row) => row.canonicalRoot === canonicalRoot,\n );\n const removed = matching.find((row) => row.removedAt !== null);\n const now = Date.now();\n if (removed) {\n // Restoring a grandfathered alias reuses an existing identity; it does not\n // create a duplicate registration even when another legacy alias is active.\n // A spelling/alias supplied during restoration does not change saved identity.\n const restored = { ...removed, removedAt: null, updatedAt: now };\n const project = this.inspect(restored);\n if (!project.available)\n throw new AppError('PROJECT_UNAVAILABLE', project.error ?? '\u539F\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n this.save({ ...restored, name: parsed.name ?? removed.name });\n return this.get(removed.id);\n }\n const existing = matching[0];\n if (existing)\n throw new AppError('PROJECT_EXISTS', '\u8BE5\u76EE\u5F55\u5DF2\u6DFB\u52A0\uFF0C\u8BF7\u9009\u62E9\u5DF2\u6709\u9879\u76EE', 409, {\n projectId: existing.id,\n });\n const row: Registration = {\n id: randomUUID(),\n name: parsed.name ?? (basename(canonicalRoot) || canonicalRoot),\n path: canonicalRoot,\n canonicalRoot,\n removedAt: null,\n createdAt: this.nextCreatedAt(),\n updatedAt: now,\n };\n this.save(row);\n return this.get(row.id);\n }\n\n rename(id: string, input: RenameProjectInput): Project {\n const { name } = renameProjectSchema.parse(input);\n this.save({ ...this.registration(id), name, updatedAt: Date.now() });\n return this.describe(id);\n }\n\n remove(id: string): void {\n const now = Date.now();\n this.save({ ...this.registration(id), removedAt: now, updatedAt: now });\n }\n\n get(id: string): Project {\n const project = this.describe(id);\n if (!project.available)\n throw new AppError('PROJECT_UNAVAILABLE', '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528', 409, { projectId: id });\n return project;\n }\n\n assertOwnership(\n projectId: string,\n cwd: string,\n ): { project: Project; cwd: string; workspaceKey: string } {\n const project = this.get(projectId);\n let canonicalCwd: string;\n try {\n canonicalCwd = realpathSync(cwd);\n if (!statSync(canonicalCwd).isDirectory()) throw new Error('not a directory');\n } catch {\n throw new AppError('PROJECT_UNAVAILABLE', '\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n }\n if (!containsPath(project.canonicalRoot, canonicalCwd))\n throw new AppError('PROJECT_OWNERSHIP', '\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u6240\u9009\u9879\u76EE\u76EE\u5F55', 403);\n return {\n project,\n cwd: canonicalCwd,\n workspaceKey: checkoutRoot(canonicalCwd) ?? project.canonicalRoot,\n };\n }\n\n findOwner(cwd: string): { project: Project; cwd: string; workspaceKey: string } {\n let canonicalCwd: string;\n try {\n canonicalCwd = realpathSync(cwd);\n } catch {\n throw new AppError('PROJECT_UNAVAILABLE', '\u4F1A\u8BDD\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n }\n // Tombstones reserve automatic ownership as well: a parent must not adopt\n // previously undiscovered history from a removed nested project.\n // An active grandfathered alias at the same root remains eligible; only a\n // deeper tombstone reserves history against a different, shallower directory.\n const project = [...this.registered.values()]\n .map((entry) => ({ project: this.inspect(entry), removed: entry.removedAt !== null }))\n .filter((entry) => containsPath(entry.project.canonicalRoot, canonicalCwd))\n .sort(\n (a, b) =>\n b.project.canonicalRoot.length - a.project.canonicalRoot.length ||\n Number(a.removed) - Number(b.removed),\n )[0]?.project;\n if (!project) throw new AppError('PROJECT_OWNERSHIP', '\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u5DF2\u6CE8\u518C\u9879\u76EE', 403);\n return this.assertOwnership(project.id, canonicalCwd);\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,YAAY,WAAW,cAAc,gBAAgB;AAC9D,SAAS,UAAU,YAAY,UAAU,SAAS,WAAW;AAC7D,SAAS,
|
|
4
|
+
"sourcesContent": ["import { execFileSync } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { accessSync, constants, realpathSync, statSync } from 'node:fs';\nimport { basename, isAbsolute, relative, resolve, sep } from 'node:path';\nimport { asc, eq } from 'drizzle-orm';\nimport { AppError } from '../shared/errors.js';\nimport type {\n CreateProjectInput,\n Project,\n RenameProjectInput,\n ReorderProjectsInput,\n} from '../shared/types.js';\nimport {\n createProjectSchema,\n renameProjectSchema,\n reorderProjectsSchema,\n} from '../shared/validation.js';\nimport type { AppDatabase } from './db/index.js';\nimport { projectRegistrations } from './db/schema.js';\n\nexport interface ProjectConfig {\n id: string;\n name: string;\n path: string;\n}\ntype Registration = typeof projectRegistrations.$inferSelect;\n\nexport function containsPath(root: string, candidate: string): boolean {\n const difference = relative(root, candidate);\n return (\n difference === '' ||\n (difference !== '..' && !difference.startsWith(`..${sep}`) && !isAbsolute(difference))\n );\n}\n\nfunction checkoutRoot(cwd: string): string | undefined {\n try {\n const output = execFileSync('git', ['-C', cwd, 'rev-parse', '--show-toplevel'], {\n encoding: 'utf8',\n timeout: 3000,\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return output ? realpathSync(output) : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport class ProjectRegistry {\n private readonly registered = new Map<string, Registration>();\n\n constructor(\n configs: ProjectConfig[],\n private readonly database?: AppDatabase,\n ) {\n for (const row of database\n ?.select()\n .from(projectRegistrations)\n .orderBy(\n asc(projectRegistrations.sortOrder),\n asc(projectRegistrations.createdAt),\n asc(projectRegistrations.id),\n )\n .all() ?? [])\n this.registered.set(row.id, row);\n // JSON remains a source of new registrations, while persisted UI decisions win.\n // Keep legacy aliases and IDs intact; only new UI registrations reject aliases.\n const seeds: Registration[] = [];\n for (const config of configs) {\n const path = resolve(config.path);\n const existing = this.registered.get(config.id);\n if (existing) {\n if (existing.path !== path)\n throw new AppError(\n 'PROJECT_ID_CONFLICT',\n `\u9879\u76EE ${config.id} \u5DF2\u7ED1\u5B9A\u5176\u4ED6\u76EE\u5F55\uFF1B\u9879\u76EE ID \u548C\u76EE\u5F55\u4E0D\u53EF\u4FEE\u6539\uFF0C\u8BF7\u4F7F\u7528\u65B0 ID`,\n 409,\n { projectId: config.id },\n );\n continue;\n }\n let canonicalRoot: string | null = null;\n try {\n canonicalRoot = this.directory(path);\n } catch {\n // Existing configurations with temporarily missing directories still start.\n }\n const now = this.nextCreatedAt();\n const row = {\n ...config,\n path,\n canonicalRoot,\n removedAt: null,\n sortOrder: this.nextSortOrder(),\n createdAt: now,\n updatedAt: now,\n };\n this.registered.set(config.id, row);\n seeds.push(row);\n }\n if (seeds.length) database?.insert(projectRegistrations).values(seeds).run();\n }\n\n private nextCreatedAt(): number {\n // Preserve seed order for legacy aliases even when imported within one millisecond.\n return [...this.registered.values()].reduce(\n (next, row) => Math.max(next, row.createdAt + 1),\n Date.now(),\n );\n }\n\n private nextSortOrder(): number {\n return [...this.registered.values()].reduce(\n (next, row) => Math.max(next, row.sortOrder + 1),\n 0,\n );\n }\n\n private directory(path: string): string {\n if (!isAbsolute(path) || path.includes('\\0'))\n throw new AppError('INVALID_PROJECT_PATH', '\u8BF7\u8F93\u5165\u8FD0\u884C Codex \u7684\u7535\u8111\u4E0A\u7684\u7EDD\u5BF9\u76EE\u5F55\u8DEF\u5F84', 400);\n try {\n const canonicalRoot = realpathSync(path);\n if (!statSync(canonicalRoot).isDirectory())\n throw new AppError('PROJECT_UNAVAILABLE', '\u9879\u76EE\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55', 409);\n accessSync(canonicalRoot, constants.R_OK | constants.X_OK);\n return canonicalRoot;\n } catch (error) {\n if (error instanceof AppError) throw error;\n const code = (error as NodeJS.ErrnoException).code;\n throw new AppError(\n 'PROJECT_UNAVAILABLE',\n code === 'ENOENT' || code === 'ENOTDIR'\n ? '\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1B\u8BF7\u8F93\u5165\u8FD0\u884C Codex \u7684\u7535\u8111\u4E0A\u7684\u76EE\u5F55'\n : code === 'EACCES' || code === 'EPERM'\n ? '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u8BBF\u95EE\uFF0C\u9700\u8981\u8BFB\u53D6\u548C\u8FDB\u5165\u76EE\u5F55\u7684\u6743\u9650'\n : '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u548C\u8BBF\u95EE\u6743\u9650',\n 409,\n );\n }\n }\n\n private save(row: Registration): void {\n this.database\n ?.insert(projectRegistrations)\n .values(row)\n .onConflictDoUpdate({ target: projectRegistrations.id, set: row })\n .run();\n this.registered.set(row.id, row);\n }\n\n private registration(id: string): Registration {\n const row = this.registered.get(id);\n if (!row || row.removedAt !== null)\n throw new AppError('PROJECT_NOT_FOUND', '\u9879\u76EE\u672A\u6CE8\u518C\u6216\u5DF2\u79FB\u9664', 404);\n return row;\n }\n\n private inspect(config: Registration): Project {\n const rootPath = config.path;\n try {\n const canonicalRoot = this.directory(rootPath);\n if (config.canonicalRoot !== null && canonicalRoot !== config.canonicalRoot)\n throw new AppError(\n 'PROJECT_UNAVAILABLE',\n '\u9879\u76EE\u76EE\u5F55\u7684\u771F\u5B9E\u8DEF\u5F84\u5DF2\u6539\u53D8\uFF0C\u4E0D\u80FD\u6CBF\u7528\u539F\u9879\u76EE\u8EAB\u4EFD',\n 409,\n );\n if (config.canonicalRoot === null)\n this.save({ ...config, canonicalRoot, updatedAt: Date.now() });\n return {\n id: config.id,\n name: config.name,\n rootPath,\n canonicalRoot,\n workspaceKey: checkoutRoot(canonicalRoot) ?? canonicalRoot,\n available: true,\n };\n } catch (error) {\n return {\n id: config.id,\n name: config.name,\n rootPath,\n canonicalRoot: config.canonicalRoot ?? rootPath,\n workspaceKey: config.canonicalRoot ?? rootPath,\n available: false,\n error: error instanceof Error ? error.message : '\u9879\u76EE\u4E0D\u53EF\u7528',\n };\n }\n }\n\n list(): Project[] {\n return [...this.registered.values()]\n .filter((project) => project.removedAt === null)\n .sort(\n (a, b) =>\n a.sortOrder - b.sortOrder || a.createdAt - b.createdAt || a.id.localeCompare(b.id),\n )\n .map((project) => this.inspect(project));\n }\n\n reorder(input: ReorderProjectsInput): Project[] {\n const { projectIds } = reorderProjectsSchema.parse(input);\n const active = [...this.registered.values()].filter((row) => row.removedAt === null);\n if (\n projectIds.length !== active.length ||\n projectIds.some(\n (id) => !this.registered.has(id) || this.registered.get(id)!.removedAt !== null,\n )\n )\n throw new AppError('PROJECT_ORDER_CONFLICT', '\u9879\u76EE\u5217\u8868\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u65B0\u8C03\u6574\u987A\u5E8F', 409);\n const now = Date.now();\n const rows = projectIds.map((id, sortOrder) => ({\n ...this.registration(id),\n sortOrder,\n updatedAt: now,\n }));\n // Commit the complete order atomically, then update memory only after success.\n this.database?.transaction((tx) => {\n for (const row of rows)\n tx.update(projectRegistrations)\n .set({ sortOrder: row.sortOrder, updatedAt: now })\n .where(eq(projectRegistrations.id, row.id))\n .run();\n });\n for (const row of rows) this.registered.set(row.id, row);\n return this.list();\n }\n\n /** Also usable when a saved directory is missing, so it can still be managed. */\n describe(id: string): Project {\n return this.inspect(this.registration(id));\n }\n\n add(input: CreateProjectInput): Project {\n const parsed = createProjectSchema.parse(input);\n const canonicalRoot = this.directory(parsed.path);\n // Inspect lazily imported paths before checking, including legacy unavailable seeds.\n this.list();\n for (const row of this.registered.values()) {\n if (row.canonicalRoot !== null || row.removedAt === null) continue;\n try {\n this.save({ ...row, canonicalRoot: this.directory(row.path), updatedAt: Date.now() });\n } catch {\n // A tombstone still reserves its ID while its directory remains unavailable.\n }\n }\n const matching = [...this.registered.values()].filter(\n (row) => row.canonicalRoot === canonicalRoot,\n );\n const removed = matching.find((row) => row.removedAt !== null);\n const now = Date.now();\n if (removed) {\n // Restoring a grandfathered alias reuses an existing identity; it does not\n // create a duplicate registration even when another legacy alias is active.\n // A spelling/alias supplied during restoration does not change saved identity.\n const restored = {\n ...removed,\n removedAt: null,\n sortOrder: this.nextSortOrder(),\n updatedAt: now,\n };\n const project = this.inspect(restored);\n if (!project.available)\n throw new AppError('PROJECT_UNAVAILABLE', project.error ?? '\u539F\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n this.save({ ...restored, name: parsed.name ?? removed.name });\n return this.get(removed.id);\n }\n const existing = matching[0];\n if (existing)\n throw new AppError('PROJECT_EXISTS', '\u8BE5\u76EE\u5F55\u5DF2\u6DFB\u52A0\uFF0C\u8BF7\u9009\u62E9\u5DF2\u6709\u9879\u76EE', 409, {\n projectId: existing.id,\n });\n const row: Registration = {\n id: randomUUID(),\n name: parsed.name ?? (basename(canonicalRoot) || canonicalRoot),\n path: canonicalRoot,\n canonicalRoot,\n removedAt: null,\n sortOrder: this.nextSortOrder(),\n createdAt: this.nextCreatedAt(),\n updatedAt: now,\n };\n this.save(row);\n return this.get(row.id);\n }\n\n rename(id: string, input: RenameProjectInput): Project {\n const { name } = renameProjectSchema.parse(input);\n this.save({ ...this.registration(id), name, updatedAt: Date.now() });\n return this.describe(id);\n }\n\n remove(id: string): void {\n const now = Date.now();\n this.save({ ...this.registration(id), removedAt: now, updatedAt: now });\n }\n\n get(id: string): Project {\n const project = this.describe(id);\n if (!project.available)\n throw new AppError('PROJECT_UNAVAILABLE', '\u9879\u76EE\u76EE\u5F55\u4E0D\u53EF\u7528', 409, { projectId: id });\n return project;\n }\n\n assertOwnership(\n projectId: string,\n cwd: string,\n ): { project: Project; cwd: string; workspaceKey: string } {\n const project = this.get(projectId);\n let canonicalCwd: string;\n try {\n canonicalCwd = realpathSync(cwd);\n if (!statSync(canonicalCwd).isDirectory()) throw new Error('not a directory');\n } catch {\n throw new AppError('PROJECT_UNAVAILABLE', '\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n }\n if (!containsPath(project.canonicalRoot, canonicalCwd))\n throw new AppError('PROJECT_OWNERSHIP', '\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u6240\u9009\u9879\u76EE\u76EE\u5F55', 403);\n return {\n project,\n cwd: canonicalCwd,\n workspaceKey: checkoutRoot(canonicalCwd) ?? project.canonicalRoot,\n };\n }\n\n findOwner(cwd: string): { project: Project; cwd: string; workspaceKey: string } {\n let canonicalCwd: string;\n try {\n canonicalCwd = realpathSync(cwd);\n } catch {\n throw new AppError('PROJECT_UNAVAILABLE', '\u4F1A\u8BDD\u76EE\u5F55\u4E0D\u53EF\u7528', 409);\n }\n // Tombstones reserve automatic ownership as well: a parent must not adopt\n // previously undiscovered history from a removed nested project.\n // An active grandfathered alias at the same root remains eligible; only a\n // deeper tombstone reserves history against a different, shallower directory.\n const project = [...this.registered.values()]\n .map((entry) => ({ project: this.inspect(entry), removed: entry.removedAt !== null }))\n .filter((entry) => containsPath(entry.project.canonicalRoot, canonicalCwd))\n .sort(\n (a, b) =>\n b.project.canonicalRoot.length - a.project.canonicalRoot.length ||\n Number(a.removed) - Number(b.removed),\n )[0]?.project;\n if (!project) throw new AppError('PROJECT_OWNERSHIP', '\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u5DF2\u6CE8\u518C\u9879\u76EE', 403);\n return this.assertOwnership(project.id, canonicalCwd);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["row"]
|
|
7
7
|
}
|
package/dist/server/service.js
CHANGED
|
@@ -143,6 +143,11 @@ class GatewayService {
|
|
|
143
143
|
this.events.publishProjects(this.projects.list());
|
|
144
144
|
return project;
|
|
145
145
|
}
|
|
146
|
+
reorderProjects(input) {
|
|
147
|
+
const projects = this.projects.reorder(input);
|
|
148
|
+
this.events.publishProjects(projects);
|
|
149
|
+
return { data: projects };
|
|
150
|
+
}
|
|
146
151
|
removeProject(projectId) {
|
|
147
152
|
const project = this.projects.describe(projectId);
|
|
148
153
|
const pending = this.store.pendingProjectOperations(projectId)[0];
|