theokit 0.48.2 → 0.48.4
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/LICENSE +2 -2
- package/dist/{actions-virtual-module-2VVLVXHY.js → actions-virtual-module-GB5FWUPS.js} +6 -6
- package/dist/{actions-virtual-module-Z5LXAX7E.js → actions-virtual-module-YQXRSSMW.js} +2 -2
- package/dist/add-3VLFUPF4.js +0 -0
- package/dist/{agent-Y3JKRROD.js → agent-OAFIXOR5.js} +2 -2
- package/dist/{agents-typed-client-X56CQ6FX.js → agents-typed-client-D4OA2TXB.js} +12 -4
- package/dist/agents-typed-client-D4OA2TXB.js.map +1 -0
- package/dist/{agents-typed-client-TNHCUU7Q.js → agents-typed-client-INR2E7B3.js} +12 -4
- package/dist/agents-typed-client-INR2E7B3.js.map +1 -0
- package/dist/{app-typed-client-N4I4RBLT.js → app-typed-client-5QDNHANF.js} +6 -6
- package/dist/{app-typed-client-NI3CM2FA.js → app-typed-client-GHO3EWZK.js} +2 -2
- package/dist/{aws-lambda-7SUTORXM.js → aws-lambda-CYNDGU5O.js} +3 -3
- package/dist/body-parser-web-TIOTXPDW.js +0 -0
- package/dist/broadcast-LUMOJIJT.js +0 -0
- package/dist/{build-SJQDRD2B.js → build-QYEU5OOZ.js} +13 -12
- package/dist/build-QYEU5OOZ.js.map +1 -0
- package/dist/build-request-body-preview-XPZ2GYMG.js +0 -0
- package/dist/{bun-TLYZCEGE.js → bun-33RD6K7O.js} +3 -3
- package/dist/check-45NKUVSQ.js +0 -0
- package/dist/chunk-2CVV6CNN.js +0 -0
- package/dist/{chunk-ORKNVORZ.js → chunk-47CINLWF.js} +2 -2
- package/dist/chunk-47VNWTL4.js +0 -0
- package/dist/chunk-5ODOE6EF.js +0 -0
- package/dist/chunk-6GGWS7J3.js +0 -0
- package/dist/{chunk-O5W7XSUX.js → chunk-6PWNTTPI.js} +4 -4
- package/dist/{chunk-GEHX6CAE.js → chunk-6RJSGTMN.js} +3 -3
- package/dist/{chunk-GEHX6CAE.js.map → chunk-6RJSGTMN.js.map} +1 -1
- package/dist/{chunk-HRCNHWLP.js → chunk-7CQ6DEWZ.js} +2 -2
- package/dist/{chunk-YRRWQDKK.js → chunk-7QAYC757.js} +89 -14
- package/dist/chunk-7QAYC757.js.map +1 -0
- package/dist/{chunk-CUYEA62B.js → chunk-7VPQHEAJ.js} +2 -4
- package/dist/chunk-7VPQHEAJ.js.map +1 -0
- package/dist/{chunk-5JJCNEUS.js → chunk-A4ZEP3FE.js} +17 -8
- package/dist/chunk-A4ZEP3FE.js.map +1 -0
- package/dist/chunk-A7JBF5FO.js +0 -0
- package/dist/{chunk-MNIQ5F3Y.js → chunk-BMHS4WAN.js} +1 -1
- package/dist/{chunk-MNIQ5F3Y.js.map → chunk-BMHS4WAN.js.map} +1 -1
- package/dist/{chunk-DGQO372T.js → chunk-E576KYYT.js} +3 -3
- package/dist/chunk-E576KYYT.js.map +1 -0
- package/dist/{chunk-L5Z6IY5U.js → chunk-FNTLKHZ7.js} +1 -1
- package/dist/{chunk-L5Z6IY5U.js.map → chunk-FNTLKHZ7.js.map} +1 -1
- package/dist/chunk-GEQJAFSV.js +0 -0
- package/dist/{chunk-AOGYAXPY.js → chunk-GH32R55S.js} +2 -2
- package/dist/{chunk-Y2KHTD2W.js → chunk-GQNBZDYK.js} +1 -1
- package/dist/{chunk-Y2KHTD2W.js.map → chunk-GQNBZDYK.js.map} +1 -1
- package/dist/{chunk-VTJMND23.js → chunk-H6YBKIUN.js} +2 -2
- package/dist/chunk-HBU2GIMZ.js +0 -0
- package/dist/chunk-IEES3CHD.js +0 -0
- package/dist/{chunk-62EU2BVZ.js → chunk-J5MXCGKA.js} +1 -1
- package/dist/{chunk-62EU2BVZ.js.map → chunk-J5MXCGKA.js.map} +1 -1
- package/dist/{chunk-HNBWZKIQ.js → chunk-KTMQUYED.js} +1 -1
- package/dist/{chunk-HNBWZKIQ.js.map → chunk-KTMQUYED.js.map} +1 -1
- package/dist/chunk-LNVMHQ2Z.js +0 -0
- package/dist/{chunk-2ADKT37V.js → chunk-LXAESF4Y.js} +2 -2
- package/dist/{chunk-2ADKT37V.js.map → chunk-LXAESF4Y.js.map} +1 -1
- package/dist/{chunk-FXZZS7YW.js → chunk-T5C46IIU.js} +1 -1
- package/dist/chunk-T5C46IIU.js.map +1 -0
- package/dist/{chunk-ZALJIZH2.js → chunk-VQ62FIQW.js} +80 -16
- package/dist/chunk-VQ62FIQW.js.map +1 -0
- package/dist/chunk-VQIUTCK2.js +0 -0
- package/dist/{chunk-FO55VGMQ.js → chunk-XR74JD4M.js} +1 -1
- package/dist/{chunk-FO55VGMQ.js.map → chunk-XR74JD4M.js.map} +1 -1
- package/dist/{chunk-KSZGBUTI.js → chunk-YGAXV5HR.js} +1 -1
- package/dist/{chunk-KSZGBUTI.js.map → chunk-YGAXV5HR.js.map} +1 -1
- package/dist/{chunk-D3425YDV.js → chunk-ZB7D62OA.js} +2 -2
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/{cloudflare-JTBKOX3F.js → cloudflare-KYUWCEPL.js} +3 -3
- package/dist/configure-agent-registry-ZOBVU3MV.js +0 -0
- package/dist/controller-swc-transform-LUJ4VAZJ.js +0 -0
- package/dist/db-IVVCQE5Z.js +0 -0
- package/dist/{define-websocket-CPQcQK9h.d.ts → define-websocket-DzPn1sR6.d.ts} +0 -1
- package/dist/{deno-deploy-3ESNGYZU.js → deno-deploy-CCTB7HGS.js} +3 -3
- package/dist/{dev-6TWDBX6G.js → dev-5BKIKJYI.js} +12 -12
- package/dist/{dev-emit-7ZZRTYF3.js → dev-emit-GWD6IXV7.js} +3 -3
- package/dist/{dev-emit-E5Z26AMV.js → dev-emit-NBT6JD7R.js} +2 -2
- package/dist/dispatcher-KMZBGMM5.js +0 -0
- package/dist/docker-LZZB4D5E.js +0 -0
- package/dist/doctor-Y53QTUSP.js +0 -0
- package/dist/{generate-WQSNW4F6.js → generate-Y3GWM57K.js} +2 -2
- package/dist/generate-Y3GWM57K.js.map +1 -0
- package/dist/index.d.ts +36 -8
- package/dist/index.js +3 -3
- package/dist/{info-QB7Q3SHP.js → info-MSBQ72EM.js} +4 -4
- package/dist/{internal-api-XQA2L663.js → internal-api-ICU7ITJD.js} +6 -6
- package/dist/{internal-api-REGN3WMX.js → internal-api-WEOSTMSN.js} +2 -2
- package/dist/{load-config-JKJ73TOD.js → load-config-2LP2OEKD.js} +4 -4
- package/dist/{mcp-CO4AGAXV.js → mcp-4FNNCFPM.js} +3 -3
- package/dist/{netlify-OFJUYXTZ.js → netlify-AFMDNKT4.js} +3 -3
- package/dist/node-ZJQEJSP3.js +10 -0
- package/dist/{openapi-5CZCL7YP.js → openapi-FWNYHB6T.js} +10 -10
- package/dist/{openapi-5CZCL7YP.js.map → openapi-FWNYHB6T.js.map} +1 -1
- package/dist/registry-UJ6KNQPJ.js +23 -0
- package/dist/{router-6MAACS25.js → router-V64GKAS6.js} +1 -1
- package/dist/router-V64GKAS6.js.map +1 -0
- package/dist/{routes-GWAWUVVQ.js → routes-6AMNVFMI.js} +5 -5
- package/dist/scan-7MJC6PYU.js +0 -0
- package/dist/{schema-BpH6ivDY.d.ts → schema-BdakLtuC.d.ts} +1 -1
- package/dist/{schema-2JEG6TTU.js → schema-Z3Y7SFLE.js} +3 -7
- package/dist/server/agent/index.d.ts +1 -1
- package/dist/server/cost/index.d.ts +0 -3
- package/dist/server/cost/index.js +1 -1
- package/dist/server/cron/index.d.ts +0 -4
- package/dist/server/cron/index.js +1 -1
- package/dist/server/define/index.d.ts +2 -3
- package/dist/server/define/index.js +1 -1
- package/dist/server/index.d.ts +4 -6
- package/dist/server/index.js +6 -6
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.d.ts +1 -4
- package/dist/server/jobs/index.js +1 -1
- package/dist/server/realtime/index.d.ts +1 -1
- package/dist/server/scan/index.js +1 -1
- package/dist/server/storage/index.d.ts +1 -1
- package/dist/server/webhook/index.d.ts +2 -2
- package/dist/server-error-to-envelope-4TGCDQ2S.js +0 -0
- package/dist/{server-routes-hmr-4W5L2MKN.js → server-routes-hmr-5D2ZPL74.js} +1 -1
- package/dist/server-routes-hmr-5D2ZPL74.js.map +1 -0
- package/dist/{server-routes-hmr-6CRNSEWF.js → server-routes-hmr-BWN3WIGR.js} +1 -1
- package/dist/{server-routes-hmr-6CRNSEWF.js.map → server-routes-hmr-BWN3WIGR.js.map} +1 -1
- package/dist/services-json-7ZXJ4CIS.js +0 -0
- package/dist/{services-typed-client-II7LKXKO.js → services-typed-client-PSAGRPFF.js} +2 -2
- package/dist/{sessions-gc-H4WC4IXB.js → sessions-gc-VAZR654G.js} +3 -3
- package/dist/sessions-gc-VAZR654G.js.map +1 -0
- package/dist/{start-IO3ZYGEX.js → start-QDPYXPW2.js} +14 -14
- package/dist/start-QDPYXPW2.js.map +1 -0
- package/dist/{static-HTT2WNIT.js → static-R25HSXEF.js} +3 -3
- package/dist/{storage-manager-ZSQFLEYT.js → storage-manager-3O5PDO6O.js} +1 -1
- package/dist/storage-manager-3O5PDO6O.js.map +1 -0
- package/dist/{storage-manager-C4jsO0Tp.d.ts → storage-manager-C6hmsaer.d.ts} +1 -1
- package/dist/{theo-cloud-ZTQLXGPS.js → theo-cloud-XAHWOUFK.js} +2 -2
- package/dist/{upgrade-readiness-77P6VNB4.js → upgrade-readiness-OILJRFOV.js} +1 -1
- package/dist/{upgrade-readiness-77P6VNB4.js.map → upgrade-readiness-OILJRFOV.js.map} +1 -1
- package/dist/{vercel-72HFEMJ3.js → vercel-SRS2DH6O.js} +3 -3
- package/dist/vite-plugin/index.d.ts +1 -1
- package/dist/vite-plugin/index.js +3 -3
- package/dist/{vite-plugin-NQ6F7FGV.js → vite-plugin-YOCPU4C6.js} +11 -11
- package/dist/{webhook-types-CNUZY7o1.d.ts → webhook-types-DGIjjcaI.d.ts} +0 -2
- package/package.json +11 -10
- package/dist/agents-typed-client-TNHCUU7Q.js.map +0 -1
- package/dist/agents-typed-client-X56CQ6FX.js.map +0 -1
- package/dist/build-SJQDRD2B.js.map +0 -1
- package/dist/chunk-5JJCNEUS.js.map +0 -1
- package/dist/chunk-CUYEA62B.js.map +0 -1
- package/dist/chunk-DGQO372T.js.map +0 -1
- package/dist/chunk-FXZZS7YW.js.map +0 -1
- package/dist/chunk-YRRWQDKK.js.map +0 -1
- package/dist/chunk-ZALJIZH2.js.map +0 -1
- package/dist/generate-WQSNW4F6.js.map +0 -1
- package/dist/node-ND4MJU3Z.js +0 -10
- package/dist/registry-QTSMLOVG.js +0 -23
- package/dist/router-6MAACS25.js.map +0 -1
- package/dist/server-routes-hmr-4W5L2MKN.js.map +0 -1
- package/dist/sessions-gc-H4WC4IXB.js.map +0 -1
- package/dist/start-IO3ZYGEX.js.map +0 -1
- package/dist/storage-manager-ZSQFLEYT.js.map +0 -1
- /package/dist/{actions-virtual-module-2VVLVXHY.js.map → actions-virtual-module-GB5FWUPS.js.map} +0 -0
- /package/dist/{actions-virtual-module-Z5LXAX7E.js.map → actions-virtual-module-YQXRSSMW.js.map} +0 -0
- /package/dist/{agent-Y3JKRROD.js.map → agent-OAFIXOR5.js.map} +0 -0
- /package/dist/{app-typed-client-N4I4RBLT.js.map → app-typed-client-5QDNHANF.js.map} +0 -0
- /package/dist/{app-typed-client-NI3CM2FA.js.map → app-typed-client-GHO3EWZK.js.map} +0 -0
- /package/dist/{aws-lambda-7SUTORXM.js.map → aws-lambda-CYNDGU5O.js.map} +0 -0
- /package/dist/{bun-TLYZCEGE.js.map → bun-33RD6K7O.js.map} +0 -0
- /package/dist/{chunk-ORKNVORZ.js.map → chunk-47CINLWF.js.map} +0 -0
- /package/dist/{chunk-O5W7XSUX.js.map → chunk-6PWNTTPI.js.map} +0 -0
- /package/dist/{chunk-HRCNHWLP.js.map → chunk-7CQ6DEWZ.js.map} +0 -0
- /package/dist/{chunk-AOGYAXPY.js.map → chunk-GH32R55S.js.map} +0 -0
- /package/dist/{chunk-VTJMND23.js.map → chunk-H6YBKIUN.js.map} +0 -0
- /package/dist/{chunk-D3425YDV.js.map → chunk-ZB7D62OA.js.map} +0 -0
- /package/dist/{cloudflare-JTBKOX3F.js.map → cloudflare-KYUWCEPL.js.map} +0 -0
- /package/dist/{deno-deploy-3ESNGYZU.js.map → deno-deploy-CCTB7HGS.js.map} +0 -0
- /package/dist/{dev-6TWDBX6G.js.map → dev-5BKIKJYI.js.map} +0 -0
- /package/dist/{dev-emit-7ZZRTYF3.js.map → dev-emit-GWD6IXV7.js.map} +0 -0
- /package/dist/{dev-emit-E5Z26AMV.js.map → dev-emit-NBT6JD7R.js.map} +0 -0
- /package/dist/{info-QB7Q3SHP.js.map → info-MSBQ72EM.js.map} +0 -0
- /package/dist/{internal-api-XQA2L663.js.map → internal-api-ICU7ITJD.js.map} +0 -0
- /package/dist/{internal-api-REGN3WMX.js.map → internal-api-WEOSTMSN.js.map} +0 -0
- /package/dist/{load-config-JKJ73TOD.js.map → load-config-2LP2OEKD.js.map} +0 -0
- /package/dist/{mcp-CO4AGAXV.js.map → mcp-4FNNCFPM.js.map} +0 -0
- /package/dist/{netlify-OFJUYXTZ.js.map → netlify-AFMDNKT4.js.map} +0 -0
- /package/dist/{node-ND4MJU3Z.js.map → node-ZJQEJSP3.js.map} +0 -0
- /package/dist/{registry-QTSMLOVG.js.map → registry-UJ6KNQPJ.js.map} +0 -0
- /package/dist/{routes-GWAWUVVQ.js.map → routes-6AMNVFMI.js.map} +0 -0
- /package/dist/{schema-2JEG6TTU.js.map → schema-Z3Y7SFLE.js.map} +0 -0
- /package/dist/{services-typed-client-II7LKXKO.js.map → services-typed-client-PSAGRPFF.js.map} +0 -0
- /package/dist/{static-HTT2WNIT.js.map → static-R25HSXEF.js.map} +0 -0
- /package/dist/{theo-cloud-ZTQLXGPS.js.map → theo-cloud-XAHWOUFK.js.map} +0 -0
- /package/dist/{vercel-72HFEMJ3.js.map → vercel-SRS2DH6O.js.map} +0 -0
- /package/dist/{vite-plugin-NQ6F7FGV.js.map → vite-plugin-YOCPU4C6.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import "tsx/esm";
|
|
|
3
3
|
import {
|
|
4
4
|
prepareTheoCloudArtifacts,
|
|
5
5
|
readManifest
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7VPQHEAJ.js";
|
|
7
7
|
|
|
8
8
|
// src/adapters/theo-cloud.ts
|
|
9
9
|
var theoCloudAdapter = {
|
|
@@ -21,4 +21,4 @@ var theoCloudAdapter = {
|
|
|
21
21
|
export {
|
|
22
22
|
theoCloudAdapter
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=theo-cloud-
|
|
24
|
+
//# sourceMappingURL=theo-cloud-XAHWOUFK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/upgrade-readiness.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'\nimport { resolve, relative, sep } from 'node:path'\n\n/**\n * T2.3 — Upgrade-readiness scanner for the 0.2 → 0.3 cutover.\n *\n * LINT-only. Reads user source, reports anticipated 0.3.0 violations with\n * file:line + suggested fix. NEVER writes user files (ADR D1).\n *\n * Three rules:\n * 1. csrf-missing-header — raw fetch POST/PUT/PATCH/DELETE missing the\n * X-Theo-Action: '1' header → 403 under strict CSRF.\n * 2. inline-script — <script>...</script> in .html files without\n * `src=` attribute → blocked under enforce CSP without unsafe-inline.\n * 3. dangerously-set-inline-script — React `dangerouslySetInnerHTML`\n * payload that contains <script>.\n *\n * EC-7: occurrences inside line comments (// ...) or wrapped in quoted\n * strings are best-effort skipped. The scanner is not a parser — it\n * filters obvious false-positive lines before running the violation\n * regex.\n * EC-8: scanning a directory with no `app/` and no `server/` returns a\n * 'no-project-detected' report with exitCode 0 (no crash).\n */\n\ntype ViolationRule =\n | 'csrf-missing-header'\n | 'inline-script'\n | 'dangerously-set-inline-script'\n | 'zero-config-tailwind-suggest'\n | 'handrolled-dotenv-suggest'\n\nexport interface Violation {\n file: string\n line: number\n rule: ViolationRule\n message: string\n fix: string\n}\n\nexport type ReadinessStatus =\n | 'ready'\n | 'has-violations'\n | 'no-project-detected'\n | 'not-a-theokit-project'\n\nexport interface UpgradeReadinessReport {\n status: ReadinessStatus\n exitCode: 0 | 1\n violations: Violation[]\n}\n\ninterface ScanOptions {\n cwd: string\n /** When true, exitCode is forced to 0 even when violations exist. */\n allowWarnings?: boolean\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.theokit', '.cache'])\nconst SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'])\nconst HTML_EXTS = new Set(['.html', '.htm'])\n\nfunction walkFiles(dir: string, root: string, out: string[]): void {\n let entries: string[]\n try {\n entries = readdirSync(dir)\n } catch {\n return\n }\n for (const name of entries) {\n if (SKIP_DIRS.has(name)) continue\n const full = resolve(dir, name)\n let s\n try {\n s = statSync(full)\n } catch {\n continue\n }\n if (s.isDirectory()) {\n walkFiles(full, root, out)\n } else if (s.isFile()) {\n const dot = name.lastIndexOf('.')\n if (dot < 0) continue\n const ext = name.slice(dot)\n if (SOURCE_EXTS.has(ext) || HTML_EXTS.has(ext)) out.push(full)\n }\n }\n}\n\nfunction isLikelyCommentOrString(rawLine: string, matchIndex: number): boolean {\n // Comment: line-comment marker (//) appears before the match position.\n const lineCommentIdx = rawLine.indexOf('//')\n if (lineCommentIdx !== -1 && lineCommentIdx < matchIndex) {\n // Make sure // is not inside a string (best-effort: count unescaped\n // quote chars before the //)\n const before = rawLine.slice(0, lineCommentIdx)\n const quoteCount = (before.match(/(?<!\\\\)[\"']/g) ?? []).length\n if (quoteCount % 2 === 0) return true\n }\n // String literal: scan quote characters around match. If the match is\n // surrounded by an odd number of unescaped quotes on either side, it\n // sits inside a string. Best-effort — does not parse template literals\n // or multiline strings.\n const before = rawLine.slice(0, matchIndex)\n const doubleQuotes = (before.match(/(?<!\\\\)\"/g) ?? []).length\n const singleQuotes = (before.match(/(?<!\\\\)'/g) ?? []).length\n return doubleQuotes % 2 === 1 || singleQuotes % 2 === 1\n}\n\n// `fetch(` followed (within ~200 chars, same call site) by a method:\n// 'POST' | 'PUT' | 'PATCH' | 'DELETE'. We scan per-line to keep regex\n// state simple; multi-line fetch calls match on the line that carries\n// the `method:` literal.\nconst METHOD_PATTERN = /method\\s*:\\s*['\"`](POST|PUT|PATCH|DELETE)['\"`]/gi\n\nfunction scanSourceFile(file: string, rel: string, content: string, out: Violation[]): void {\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n METHOD_PATTERN.lastIndex = 0\n const match = METHOD_PATTERN.exec(line)\n if (!match) continue\n if (isLikelyCommentOrString(line, match.index)) continue\n\n // Look 8 lines back AND forward for the enclosing `fetch(` and for an\n // X-Theo-Action header in the same call-site block.\n const blockStart = Math.max(0, i - 8)\n const blockEnd = Math.min(lines.length - 1, i + 8)\n const block = lines.slice(blockStart, blockEnd + 1).join('\\n')\n if (!/\\bfetch\\s*\\(/.test(block)) continue\n if (/\\btheoFetch\\s*\\(/.test(block)) continue\n if (/['\"`]X-Theo-Action['\"`]\\s*:/i.test(block)) continue\n\n out.push({\n file: rel,\n line: i + 1,\n rule: 'csrf-missing-header',\n message:\n 'fetch(' +\n match[1] +\n ') without X-Theo-Action header — will return 403 under 0.3.0 strict CSRF',\n fix: \"Use theoFetch(path, { method, body }) OR add headers: { 'X-Theo-Action': '1' }\",\n })\n }\n\n // dangerouslySetInnerHTML with <script> in the payload.\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (!/dangerouslySetInnerHTML/i.test(line)) continue\n // The script may live on the same line or in __html on a following\n // line; check a small window.\n const window = lines.slice(i, Math.min(lines.length, i + 6)).join('\\n')\n if (!/__html\\s*:\\s*['\"`][^'\"`]*<script\\b/i.test(window)) continue\n out.push({\n file: rel,\n line: i + 1,\n rule: 'dangerously-set-inline-script',\n message:\n 'dangerouslySetInnerHTML payload contains <script> — blocked under 0.3.0 enforce CSP',\n fix: 'Move the script into a real module loaded via <script src=\"...\">, or thread ctx.nonce',\n })\n }\n}\n\nconst INLINE_SCRIPT_PATTERN = /<script\\b(?![^>]*\\bsrc\\s*=)[^>]*>[\\s\\S]*?<\\/script>/gi\n\nfunction scanHtmlFile(file: string, rel: string, content: string, out: Violation[]): void {\n INLINE_SCRIPT_PATTERN.lastIndex = 0\n let match: RegExpExecArray | null\n while ((match = INLINE_SCRIPT_PATTERN.exec(content)) !== null) {\n // Compute 1-based line number from match index.\n const before = content.slice(0, match.index)\n const line = (before.match(/\\n/g) ?? []).length + 1\n out.push({\n file: rel,\n line,\n rule: 'inline-script',\n message:\n 'Inline <script> without src — blocked under 0.3.0 enforce CSP without unsafe-inline',\n fix: \"Move into a real script file (e.g. /main.js) and load with <script src='/main.js'>, or thread ctx.nonce\",\n })\n }\n}\n\n/**\n * T4.1 — Zero-config hint: consumer has @theokit/ui in deps AND a manual\n * tailwind.config.* that does NOT import the @theokit/ui preset. Suggest\n * extending via `import preset from '@theokit/ui/preset'`.\n */\nfunction scanZeroConfigTailwindHint(cwd: string, out: Violation[]): void {\n const pkgPath = resolve(cwd, 'package.json')\n if (!existsSync(pkgPath)) return\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }\n try {\n pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as typeof pkg\n } catch {\n return\n }\n const hasUi =\n Boolean(pkg.dependencies?.['@theokit/ui']) || Boolean(pkg.devDependencies?.['@theokit/ui'])\n if (!hasUi) return\n\n for (const ext of ['.ts', '.js', '.mjs', '.cjs']) {\n const cfgPath = resolve(cwd, `tailwind.config${ext}`)\n if (!existsSync(cfgPath)) continue\n let content: string\n try {\n content = readFileSync(cfgPath, 'utf8')\n } catch {\n continue\n }\n if (content.includes('@theokit/ui/preset')) return // already using preset\n out.push({\n file: `tailwind.config${ext}`,\n line: 1,\n rule: 'zero-config-tailwind-suggest',\n message:\n '@theokit/ui detected with a manual tailwind.config — extend with the UI preset to keep theme tokens in sync.',\n fix: \"import preset from '@theokit/ui/preset'; export default { presets: [preset], content: [...] }\",\n })\n return\n }\n}\n\n/**\n * T4.1 — Zero-config hint: consumer has hand-rolled dotenv loading in\n * server/ (import 'dotenv/config', dotenv.config(), readFile('.env'), etc.).\n * Suggest the framework's loadEnv (auto-invoked by CLI commands; importable\n * from theokit/server for standalone scripts).\n */\nfunction scanHandRolledDotenvHint(\n file: string,\n rel: string,\n content: string,\n out: Violation[],\n): void {\n // Only flag server/ files\n if (!rel.startsWith('server/')) return\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? ''\n // import 'dotenv/config' or import * as dotenv from 'dotenv'\n if (/from\\s+['\"]dotenv['\"]/.test(line) || /import\\s+['\"]dotenv\\/config['\"]/.test(line)) {\n out.push({\n file: rel,\n line: i + 1,\n rule: 'handrolled-dotenv-suggest',\n message:\n 'Manual dotenv import detected — TheoKit auto-loads .env in CLI commands. For standalone scripts, import { loadEnv } from \"theokit/server\".',\n fix: \"Remove this import. CLI commands (dev/build/start) auto-load .env. For standalone scripts: import { loadEnv } from 'theokit/server'; loadEnv()\",\n })\n return // one hint per file\n }\n }\n}\n\n/**\n * EC-3: a directory may have an `app/` directory (Next.js, Remix, etc.) but\n * not actually be a TheoKit project. Run our 3 rules against such a project\n * would generate many false positives. The strict guard checks for `theokit`\n * in dependencies OR devDependencies of the cwd's package.json. Returns\n * `null` when the project IS a TheoKit project, or a non-TheoKit report\n * otherwise.\n */\nfunction detectNonTheokitProject(cwd: string): UpgradeReadinessReport | null {\n const pkgPath = resolve(cwd, 'package.json')\n if (!existsSync(pkgPath)) {\n // No package.json — let the existing app/server detection handle it.\n return null\n }\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }\n try {\n pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as typeof pkg\n } catch {\n // Malformed package.json — treat as \"not a TheoKit project we can verify\".\n return { status: 'not-a-theokit-project', exitCode: 1, violations: [] }\n }\n const deps = pkg.dependencies ?? {}\n const devDeps = pkg.devDependencies ?? {}\n if (!Object.hasOwn(deps, 'theokit') && !Object.hasOwn(devDeps, 'theokit')) {\n return { status: 'not-a-theokit-project', exitCode: 1, violations: [] }\n }\n return null\n}\n\n// eslint-disable-next-line @typescript-eslint/require-await -- async surface for future fs.promises migration\nexport async function scanUpgradeReadiness(options: ScanOptions): Promise<UpgradeReadinessReport> {\n const cwd = options.cwd\n const allowWarnings = options.allowWarnings === true\n\n const appDir = resolve(cwd, 'app')\n const serverDir = resolve(cwd, 'server')\n const publicDir = resolve(cwd, 'public')\n\n const hasApp = existsSync(appDir)\n const hasServer = existsSync(serverDir)\n\n if (!hasApp && !hasServer) {\n return { status: 'no-project-detected', exitCode: 0, violations: [] }\n }\n\n // EC-3: refuse to scan non-TheoKit projects (avoid FP avalanche).\n const nonTheokit = detectNonTheokitProject(cwd)\n if (nonTheokit) return nonTheokit\n\n const files: string[] = []\n if (hasApp) walkFiles(appDir, cwd, files)\n if (hasServer) walkFiles(serverDir, cwd, files)\n if (existsSync(publicDir)) walkFiles(publicDir, cwd, files)\n\n const violations: Violation[] = []\n for (const file of files) {\n let content: string\n try {\n content = readFileSync(file, 'utf8')\n } catch {\n continue\n }\n const rel = relative(cwd, file).split(sep).join('/')\n const dot = file.lastIndexOf('.')\n const ext = dot >= 0 ? file.slice(dot) : ''\n if (HTML_EXTS.has(ext)) {\n scanHtmlFile(file, rel, content, violations)\n } else if (SOURCE_EXTS.has(ext)) {\n scanSourceFile(file, rel, content, violations)\n scanHandRolledDotenvHint(file, rel, content, violations)\n }\n }\n\n // T4.1 — Project-level hint (not per-file): does the consumer have a\n // manual tailwind.config without the UI preset?\n scanZeroConfigTailwindHint(cwd, violations)\n\n const hasHigh = violations.length > 0\n const status: ReadinessStatus = hasHigh ? 'has-violations' : 'ready'\n const exitCode: 0 | 1 = hasHigh && !allowWarnings ? 1 : 0\n return { status, exitCode, violations }\n}\n\n/**\n * CLI wrapper. Prints a human-readable or JSON report and exits with the\n * computed exit code. Imported lazily from `cli/index.ts`.\n */\nexport async function upgradeReadinessCommand(opts: {\n json?: boolean\n allowWarnings?: boolean\n}): Promise<void> {\n const report = await scanUpgradeReadiness({\n cwd: process.cwd(),\n allowWarnings: opts.allowWarnings,\n })\n\n if (opts.json) {\n console.log(JSON.stringify(report, null, 2))\n process.exit(report.exitCode)\n }\n\n console.log('')\n if (report.status === 'no-project-detected') {\n console.log(\" · No theokit project detected here (no 'app/' or 'server/' dir).\")\n console.log('')\n process.exit(report.exitCode)\n }\n if (report.status === 'not-a-theokit-project') {\n console.log(' ✗ Not a TheoKit project (theokit not in package.json).')\n console.log(' Run this command from a TheoKit project root.')\n console.log('')\n process.exit(report.exitCode)\n }\n if (report.violations.length === 0) {\n console.log(' ✓ Upgrade-readiness 0.3: no violations detected.')\n console.log('')\n // T1.3 — friendly post-success URL (blueprint R4; Next.js next-codemod precedent).\n // Anchor canon: #rollback (existing in docs/migration/0.2-to-0.3.md per T1.1).\n console.log(' Migration guide: https://theokit.dev/migration/0.2-to-0.3')\n console.log(' Need to roll back temporarily? See #rollback')\n console.log('')\n process.exit(report.exitCode)\n }\n console.log(` ✗ Upgrade-readiness 0.3: ${report.violations.length} violation(s)`)\n console.log('')\n for (const v of report.violations) {\n console.log(` ${v.file}:${v.line} [${v.rule}]`)\n console.log(` ${v.message}`)\n console.log(` fix: ${v.fix}`)\n console.log('')\n }\n // T1.3 — print migration-guide URL on violations branch too (one canonical link\n // regardless of verdict, per blueprint Q5 Astro CHANGELOG URL pattern).\n console.log(' Migration guide: https://theokit.dev/migration/0.2-to-0.3#rollback')\n console.log('')\n process.exit(report.exitCode)\n}\n"],"mappings":"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","names":["before"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/upgrade-readiness.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'\nimport { resolve, relative, sep } from 'node:path'\n\n/**\n * T2.3 — Upgrade-readiness scanner for the 0.2 → 0.3 cutover.\n *\n * LINT-only. Reads user source, reports anticipated 0.3.0 violations with\n * file:line + suggested fix. NEVER writes user files (ADR D1).\n *\n * Three rules:\n * 1. csrf-missing-header — raw fetch POST/PUT/PATCH/DELETE missing the\n * X-Theo-Action: '1' header → 403 under strict CSRF.\n * 2. inline-script — <script>...</script> in .html files without\n * `src=` attribute → blocked under enforce CSP without unsafe-inline.\n * 3. dangerously-set-inline-script — React `dangerouslySetInnerHTML`\n * payload that contains <script>.\n *\n * EC-7: occurrences inside line comments (// ...) or wrapped in quoted\n * strings are best-effort skipped. The scanner is not a parser — it\n * filters obvious false-positive lines before running the violation\n * regex.\n * EC-8: scanning a directory with no `app/` and no `server/` returns a\n * 'no-project-detected' report with exitCode 0 (no crash).\n */\n\ntype ViolationRule =\n | 'csrf-missing-header'\n | 'inline-script'\n | 'dangerously-set-inline-script'\n | 'zero-config-tailwind-suggest'\n | 'handrolled-dotenv-suggest'\n\nexport interface Violation {\n file: string\n line: number\n rule: ViolationRule\n message: string\n fix: string\n}\n\nexport type ReadinessStatus =\n | 'ready'\n | 'has-violations'\n | 'no-project-detected'\n | 'not-a-theokit-project'\n\nexport interface UpgradeReadinessReport {\n status: ReadinessStatus\n exitCode: 0 | 1\n violations: Violation[]\n}\n\ninterface ScanOptions {\n cwd: string\n /** When true, exitCode is forced to 0 even when violations exist. */\n allowWarnings?: boolean\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.theokit', '.cache'])\nconst SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'])\nconst HTML_EXTS = new Set(['.html', '.htm'])\n\nfunction walkFiles(dir: string, root: string, out: string[]): void {\n let entries: string[]\n try {\n entries = readdirSync(dir)\n } catch {\n return\n }\n for (const name of entries) {\n if (SKIP_DIRS.has(name)) continue\n const full = resolve(dir, name)\n let s\n try {\n s = statSync(full)\n } catch {\n continue\n }\n if (s.isDirectory()) {\n walkFiles(full, root, out)\n } else if (s.isFile()) {\n const dot = name.lastIndexOf('.')\n if (dot < 0) continue\n const ext = name.slice(dot)\n if (SOURCE_EXTS.has(ext) || HTML_EXTS.has(ext)) out.push(full)\n }\n }\n}\n\nfunction isLikelyCommentOrString(rawLine: string, matchIndex: number): boolean {\n // Comment: line-comment marker (//) appears before the match position.\n const lineCommentIdx = rawLine.indexOf('//')\n if (lineCommentIdx !== -1 && lineCommentIdx < matchIndex) {\n // Make sure // is not inside a string (best-effort: count unescaped\n // quote chars before the //)\n const before = rawLine.slice(0, lineCommentIdx)\n const quoteCount = (before.match(/(?<!\\\\)[\"']/g) ?? []).length\n if (quoteCount % 2 === 0) return true\n }\n // String literal: scan quote characters around match. If the match is\n // surrounded by an odd number of unescaped quotes on either side, it\n // sits inside a string. Best-effort — does not parse template literals\n // or multiline strings.\n const before = rawLine.slice(0, matchIndex)\n const doubleQuotes = (before.match(/(?<!\\\\)\"/g) ?? []).length\n const singleQuotes = (before.match(/(?<!\\\\)'/g) ?? []).length\n return doubleQuotes % 2 === 1 || singleQuotes % 2 === 1\n}\n\n// `fetch(` followed (within ~200 chars, same call site) by a method:\n// 'POST' | 'PUT' | 'PATCH' | 'DELETE'. We scan per-line to keep regex\n// state simple; multi-line fetch calls match on the line that carries\n// the `method:` literal.\nconst METHOD_PATTERN = /method\\s*:\\s*['\"`](POST|PUT|PATCH|DELETE)['\"`]/gi\n\nfunction scanSourceFile(file: string, rel: string, content: string, out: Violation[]): void {\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n METHOD_PATTERN.lastIndex = 0\n const match = METHOD_PATTERN.exec(line)\n if (!match) continue\n if (isLikelyCommentOrString(line, match.index)) continue\n\n // Look 8 lines back AND forward for the enclosing `fetch(` and for an\n // X-Theo-Action header in the same call-site block.\n const blockStart = Math.max(0, i - 8)\n const blockEnd = Math.min(lines.length - 1, i + 8)\n const block = lines.slice(blockStart, blockEnd + 1).join('\\n')\n if (!/\\bfetch\\s*\\(/.test(block)) continue\n if (/\\btheoFetch\\s*\\(/.test(block)) continue\n if (/['\"`]X-Theo-Action['\"`]\\s*:/i.test(block)) continue\n\n out.push({\n file: rel,\n line: i + 1,\n rule: 'csrf-missing-header',\n message:\n 'fetch(' +\n match[1] +\n ') without X-Theo-Action header — will return 403 under 0.3.0 strict CSRF',\n fix: \"Use theoFetch(path, { method, body }) OR add headers: { 'X-Theo-Action': '1' }\",\n })\n }\n\n // dangerouslySetInnerHTML with <script> in the payload.\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (!/dangerouslySetInnerHTML/i.test(line)) continue\n // The script may live on the same line or in __html on a following\n // line; check a small window.\n const window = lines.slice(i, Math.min(lines.length, i + 6)).join('\\n')\n if (!/__html\\s*:\\s*['\"`][^'\"`]*<script\\b/i.test(window)) continue\n out.push({\n file: rel,\n line: i + 1,\n rule: 'dangerously-set-inline-script',\n message:\n 'dangerouslySetInnerHTML payload contains <script> — blocked under 0.3.0 enforce CSP',\n fix: 'Move the script into a real module loaded via <script src=\"...\">, or thread ctx.nonce',\n })\n }\n}\n\nconst INLINE_SCRIPT_PATTERN = /<script\\b(?![^>]*\\bsrc\\s*=)[^>]*>[\\s\\S]*?<\\/script>/gi\n\nfunction scanHtmlFile(file: string, rel: string, content: string, out: Violation[]): void {\n INLINE_SCRIPT_PATTERN.lastIndex = 0\n let match: RegExpExecArray | null\n while ((match = INLINE_SCRIPT_PATTERN.exec(content)) !== null) {\n // Compute 1-based line number from match index.\n const before = content.slice(0, match.index)\n const line = (before.match(/\\n/g) ?? []).length + 1\n out.push({\n file: rel,\n line,\n rule: 'inline-script',\n message:\n 'Inline <script> without src — blocked under 0.3.0 enforce CSP without unsafe-inline',\n fix: \"Move into a real script file (e.g. /main.js) and load with <script src='/main.js'>, or thread ctx.nonce\",\n })\n }\n}\n\n/**\n * T4.1 — Zero-config hint: consumer has @theokit/ui in deps AND a manual\n * tailwind.config.* that does NOT import the @theokit/ui preset. Suggest\n * extending via `import preset from '@theokit/ui/preset'`.\n */\nfunction scanZeroConfigTailwindHint(cwd: string, out: Violation[]): void {\n const pkgPath = resolve(cwd, 'package.json')\n if (!existsSync(pkgPath)) return\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }\n try {\n pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as typeof pkg\n } catch {\n return\n }\n const hasUi =\n Boolean(pkg.dependencies?.['@theokit/ui']) || Boolean(pkg.devDependencies?.['@theokit/ui'])\n if (!hasUi) return\n\n for (const ext of ['.ts', '.js', '.mjs', '.cjs']) {\n const cfgPath = resolve(cwd, `tailwind.config${ext}`)\n if (!existsSync(cfgPath)) continue\n let content: string\n try {\n content = readFileSync(cfgPath, 'utf8')\n } catch {\n continue\n }\n if (content.includes('@theokit/ui/preset')) return // already using preset\n out.push({\n file: `tailwind.config${ext}`,\n line: 1,\n rule: 'zero-config-tailwind-suggest',\n message:\n '@theokit/ui detected with a manual tailwind.config — extend with the UI preset to keep theme tokens in sync.',\n fix: \"import preset from '@theokit/ui/preset'; export default { presets: [preset], content: [...] }\",\n })\n return\n }\n}\n\n/**\n * T4.1 — Zero-config hint: consumer has hand-rolled dotenv loading in\n * server/ (import 'dotenv/config', dotenv.config(), readFile('.env'), etc.).\n * Suggest the framework's loadEnv (auto-invoked by CLI commands; importable\n * from theokit/server for standalone scripts).\n */\nfunction scanHandRolledDotenvHint(\n file: string,\n rel: string,\n content: string,\n out: Violation[],\n): void {\n // Only flag server/ files\n if (!rel.startsWith('server/')) return\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? ''\n // import 'dotenv/config' or import * as dotenv from 'dotenv'\n if (/from\\s+['\"]dotenv['\"]/.test(line) || /import\\s+['\"]dotenv\\/config['\"]/.test(line)) {\n out.push({\n file: rel,\n line: i + 1,\n rule: 'handrolled-dotenv-suggest',\n message:\n 'Manual dotenv import detected — TheoKit auto-loads .env in CLI commands. For standalone scripts, import { loadEnv } from \"theokit/server\".',\n fix: \"Remove this import. CLI commands (dev/build/start) auto-load .env. For standalone scripts: import { loadEnv } from 'theokit/server'; loadEnv()\",\n })\n return // one hint per file\n }\n }\n}\n\n/**\n * EC-3: a directory may have an `app/` directory (Next.js, Remix, etc.) but\n * not actually be a TheoKit project. Run our 3 rules against such a project\n * would generate many false positives. The strict guard checks for `theokit`\n * in dependencies OR devDependencies of the cwd's package.json. Returns\n * `null` when the project IS a TheoKit project, or a non-TheoKit report\n * otherwise.\n */\nfunction detectNonTheokitProject(cwd: string): UpgradeReadinessReport | null {\n const pkgPath = resolve(cwd, 'package.json')\n if (!existsSync(pkgPath)) {\n // No package.json — let the existing app/server detection handle it.\n return null\n }\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }\n try {\n pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as typeof pkg\n } catch {\n // Malformed package.json — treat as \"not a TheoKit project we can verify\".\n return { status: 'not-a-theokit-project', exitCode: 1, violations: [] }\n }\n const deps = pkg.dependencies ?? {}\n const devDeps = pkg.devDependencies ?? {}\n if (!Object.hasOwn(deps, 'theokit') && !Object.hasOwn(devDeps, 'theokit')) {\n return { status: 'not-a-theokit-project', exitCode: 1, violations: [] }\n }\n return null\n}\n\n// eslint-disable-next-line @typescript-eslint/require-await -- async surface for future fs.promises migration\nexport async function scanUpgradeReadiness(options: ScanOptions): Promise<UpgradeReadinessReport> {\n const cwd = options.cwd\n const allowWarnings = options.allowWarnings === true\n\n const appDir = resolve(cwd, 'app')\n const serverDir = resolve(cwd, 'server')\n const publicDir = resolve(cwd, 'public')\n\n const hasApp = existsSync(appDir)\n const hasServer = existsSync(serverDir)\n\n if (!hasApp && !hasServer) {\n return { status: 'no-project-detected', exitCode: 0, violations: [] }\n }\n\n // EC-3: refuse to scan non-TheoKit projects (avoid FP avalanche).\n const nonTheokit = detectNonTheokitProject(cwd)\n if (nonTheokit) return nonTheokit\n\n const files: string[] = []\n if (hasApp) walkFiles(appDir, cwd, files)\n if (hasServer) walkFiles(serverDir, cwd, files)\n if (existsSync(publicDir)) walkFiles(publicDir, cwd, files)\n\n const violations: Violation[] = []\n for (const file of files) {\n let content: string\n try {\n content = readFileSync(file, 'utf8')\n } catch {\n continue\n }\n const rel = relative(cwd, file).split(sep).join('/')\n const dot = file.lastIndexOf('.')\n const ext = dot >= 0 ? file.slice(dot) : ''\n if (HTML_EXTS.has(ext)) {\n scanHtmlFile(file, rel, content, violations)\n } else if (SOURCE_EXTS.has(ext)) {\n scanSourceFile(file, rel, content, violations)\n scanHandRolledDotenvHint(file, rel, content, violations)\n }\n }\n\n // T4.1 — Project-level hint (not per-file): does the consumer have a\n // manual tailwind.config without the UI preset?\n scanZeroConfigTailwindHint(cwd, violations)\n\n const hasHigh = violations.length > 0\n const status: ReadinessStatus = hasHigh ? 'has-violations' : 'ready'\n const exitCode: 0 | 1 = hasHigh && !allowWarnings ? 1 : 0\n return { status, exitCode, violations }\n}\n\n/**\n * CLI wrapper. Prints a human-readable or JSON report and exits with the\n * computed exit code. Imported lazily from `cli/index.ts`.\n */\nexport async function upgradeReadinessCommand(opts: {\n json?: boolean\n allowWarnings?: boolean\n}): Promise<void> {\n const report = await scanUpgradeReadiness({\n cwd: process.cwd(),\n allowWarnings: opts.allowWarnings,\n })\n\n if (opts.json) {\n console.log(JSON.stringify(report, null, 2))\n process.exit(report.exitCode)\n }\n\n console.log('')\n if (report.status === 'no-project-detected') {\n console.log(\" · No theokit project detected here (no 'app/' or 'server/' dir).\")\n console.log('')\n process.exit(report.exitCode)\n }\n if (report.status === 'not-a-theokit-project') {\n console.log(' ✗ Not a TheoKit project (theokit not in package.json).')\n console.log(' Run this command from a TheoKit project root.')\n console.log('')\n process.exit(report.exitCode)\n }\n if (report.violations.length === 0) {\n console.log(' ✓ Upgrade-readiness 0.3: no violations detected.')\n console.log('')\n // T1.3 — friendly post-success URL (blueprint R4; Next.js next-codemod precedent).\n // Anchor canon: #rollback (existing in per T1.1).\n console.log(' Migration guide: https://theokit.dev/migration/0.2-to-0.3')\n console.log(' Need to roll back temporarily? See #rollback')\n console.log('')\n process.exit(report.exitCode)\n }\n console.log(` ✗ Upgrade-readiness 0.3: ${report.violations.length} violation(s)`)\n console.log('')\n for (const v of report.violations) {\n console.log(` ${v.file}:${v.line} [${v.rule}]`)\n console.log(` ${v.message}`)\n console.log(` fix: ${v.fix}`)\n console.log('')\n }\n // T1.3 — print migration-guide URL on violations branch too (one canonical link\n // regardless of verdict, per blueprint Q5 Astro CHANGELOG URL pattern).\n console.log(' Migration guide: https://theokit.dev/migration/0.2-to-0.3#rollback')\n console.log('')\n process.exit(report.exitCode)\n}\n"],"mappings":"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","names":["before"]}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import "tsx/esm";
|
|
3
3
|
import {
|
|
4
4
|
nodeAdapter
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-E576KYYT.js";
|
|
6
6
|
import {
|
|
7
7
|
assertServicesUnsupported,
|
|
8
8
|
readManifest
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7VPQHEAJ.js";
|
|
10
10
|
|
|
11
11
|
// src/adapters/vercel.ts
|
|
12
12
|
import { existsSync, mkdirSync, writeFileSync, cpSync } from "fs";
|
|
@@ -130,4 +130,4 @@ export {
|
|
|
130
130
|
renderVercelVcConfigJson,
|
|
131
131
|
vercelAdapter
|
|
132
132
|
};
|
|
133
|
-
//# sourceMappingURL=vercel-
|
|
133
|
+
//# sourceMappingURL=vercel-SRS2DH6O.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
import { R as RateLimitConfig } from '../rate-limit-BdNDZ3vt.js';
|
|
3
3
|
import { C as CsrfReadinessStore } from '../csrf-readiness-store-CjIoub3U.js';
|
|
4
|
-
import { S as ServicesConfig } from '../schema-
|
|
4
|
+
import { S as ServicesConfig } from '../schema-BdakLtuC.js';
|
|
5
5
|
import 'node:http';
|
|
6
6
|
import '../rate-limit-store-BEJnhWdw.js';
|
|
7
7
|
import 'zod';
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
defineTheoIntegration,
|
|
6
6
|
theoPlugin,
|
|
7
7
|
theoPluginAsync
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-7QAYC757.js";
|
|
9
9
|
import "../chunk-SSYDEKWF.js";
|
|
10
10
|
import "../chunk-OIGJOYX6.js";
|
|
11
11
|
import "../chunk-OJLL4YD6.js";
|
|
12
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-XR74JD4M.js";
|
|
13
13
|
import "../chunk-XALU5LCU.js";
|
|
14
14
|
import "../chunk-47FFT43U.js";
|
|
15
15
|
import "../chunk-NTDN54XO.js";
|
|
@@ -17,7 +17,7 @@ import "../chunk-KD5G3YXI.js";
|
|
|
17
17
|
import "../chunk-VSLTKX5L.js";
|
|
18
18
|
import "../chunk-TNI4MARH.js";
|
|
19
19
|
import "../chunk-7LVM22VG.js";
|
|
20
|
-
import "../chunk-
|
|
20
|
+
import "../chunk-YGAXV5HR.js";
|
|
21
21
|
import "../chunk-DV34VG3N.js";
|
|
22
22
|
import "../chunk-FB2HBNIC.js";
|
|
23
23
|
import "../chunk-MTEWLGVY.js";
|
|
@@ -7,22 +7,22 @@ import {
|
|
|
7
7
|
defineTheoIntegration,
|
|
8
8
|
theoPlugin,
|
|
9
9
|
theoPluginAsync
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-VQ62FIQW.js";
|
|
11
|
+
import "./chunk-6RJSGTMN.js";
|
|
12
12
|
import "./chunk-2CVV6CNN.js";
|
|
13
13
|
import "./chunk-IEES3CHD.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-GH32R55S.js";
|
|
15
15
|
import "./chunk-HBU2GIMZ.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-A4ZEP3FE.js";
|
|
17
|
+
import "./chunk-7VPQHEAJ.js";
|
|
18
18
|
import "./chunk-5ODOE6EF.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-7CQ6DEWZ.js";
|
|
20
|
+
import "./chunk-H6YBKIUN.js";
|
|
21
21
|
import "./chunk-6GGWS7J3.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-T5C46IIU.js";
|
|
23
|
+
import "./chunk-ZB7D62OA.js";
|
|
24
24
|
import "./chunk-LNVMHQ2Z.js";
|
|
25
|
-
import "./chunk-
|
|
25
|
+
import "./chunk-BMHS4WAN.js";
|
|
26
26
|
import "./chunk-A7JBF5FO.js";
|
|
27
27
|
import "./chunk-VQIUTCK2.js";
|
|
28
28
|
export {
|
|
@@ -33,4 +33,4 @@ export {
|
|
|
33
33
|
theoPlugin,
|
|
34
34
|
theoPluginAsync
|
|
35
35
|
};
|
|
36
|
-
//# sourceMappingURL=vite-plugin-
|
|
36
|
+
//# sourceMappingURL=vite-plugin-YOCPU4C6.js.map
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theokit",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsup",
|
|
9
|
+
"test": "echo 'theokit tests run from root: pnpm test'",
|
|
10
|
+
"prepublishOnly": "node ../../scripts/check-pack-no-workspace.mjs ."
|
|
11
|
+
},
|
|
7
12
|
"bin": {
|
|
8
13
|
"theokit": "./dist/cli/index.js"
|
|
9
14
|
},
|
|
@@ -109,6 +114,9 @@
|
|
|
109
114
|
"dist"
|
|
110
115
|
],
|
|
111
116
|
"dependencies": {
|
|
117
|
+
"@theokit/agents": "workspace:^",
|
|
118
|
+
"@theokit/http": "workspace:^",
|
|
119
|
+
"@theokit/presenter": "workspace:^",
|
|
112
120
|
"@vitejs/plugin-react": "^4.7.0",
|
|
113
121
|
"busboy": "^1.6.0",
|
|
114
122
|
"cac": "^6.7.14",
|
|
@@ -122,10 +130,7 @@
|
|
|
122
130
|
"superjson": "^2.2.6",
|
|
123
131
|
"tsx": "^4.22.4",
|
|
124
132
|
"typescript": "^5.9.3",
|
|
125
|
-
"vite": "^6.4.3"
|
|
126
|
-
"@theokit/agents": "^9.4.0",
|
|
127
|
-
"@theokit/http": "^1.1.0",
|
|
128
|
-
"@theokit/presenter": "^0.7.0"
|
|
133
|
+
"vite": "^6.4.3"
|
|
129
134
|
},
|
|
130
135
|
"peerDependencies": {
|
|
131
136
|
"@theokit/sdk": "^4.52.1",
|
|
@@ -172,9 +177,5 @@
|
|
|
172
177
|
},
|
|
173
178
|
"engines": {
|
|
174
179
|
"node": ">=22.12.0"
|
|
175
|
-
},
|
|
176
|
-
"scripts": {
|
|
177
|
-
"build": "tsup",
|
|
178
|
-
"test": "echo 'theokit tests run from root: pnpm test'"
|
|
179
180
|
}
|
|
180
|
-
}
|
|
181
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vite-plugin/agents-typed-client.ts"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vite-plugin/agents-typed-client.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Codegen-time fs ops: all paths derive from `opts.projectRoot` / `opts.distDir`\n * (vite plugin opts — trusted, set by the framework's CLI). Never serves HTTP input.\n */\n/**\n * M2 (theokit-ai-first) — end-to-end typed binding for the `agents/*.ts` convention.\n *\n * Sibling of `app-typed-client.ts` (kept separate so the `@theo/client` output stays\n * byte-unchanged). Two parts:\n *\n * 1. `generateAgentsDts({ manifest, dtsOutPath, projectRoot })` — pure function emitting\n * `.theokit/agents.d.ts` (the virtual `@theo/agents` module) with `AppAgents` mapping\n * each scanned agent to `InferAgentInput` of its `defineAgent({ input })` schema, plus a\n * typed `useAgent` signature — so the client binds to `/api/agents/<name>` with the right\n * request type and ZERO manual wiring (DoD line 2).\n * 2. `agentsTypedClientPlugin(opts)` — Vite plugin that emits (1), rewrites on `agents/*`\n * changes, and serves the virtual `@theo/agents` runtime (`useAgent` from `theokit/client`).\n */\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, posix } from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nimport type { TheoManifest } from '../server/internal-api.js'\n\nconst FILE_HEADER = `// AUTO-GENERATED by theokit — do not edit.\n// Source: theokit/packages/theo/src/vite-plugin/agents-typed-client.ts (M2).\n// To refresh: \\`pnpm dev\\` or \\`pnpm build\\` regenerates this on every agents/ change.\n\n/* eslint-disable */\n`\n\n/** A safe TS identifier alias for an agent (name may contain path separators). */\nfunction aliasFor(name: string): string {\n return `_agent_${name.replace(/[^\\w$]/g, '_')}`\n}\n\n/** Relative `import type` path from the .d.ts dir to the agent source (extension stripped). */\nfunction importPath(dtsOutPath: string, projectRoot: string, filePath: string): string {\n const fromDir = dirname(dtsOutPath).replace(/\\\\/g, '/')\n const abs = posix.join(projectRoot.replace(/\\\\/g, '/'), filePath.replace(/\\\\/g, '/'))\n const noExt = abs.replace(/\\.[jt]sx?$/, '')\n let rel = posix.relative(fromDir, noExt)\n if (!rel.startsWith('.')) rel = `./${rel}`\n return rel\n}\n\ninterface GenerateAgentsDtsOptions {\n manifest: TheoManifest\n /** Absolute path to the .d.ts that will be emitted (drives the import paths). */\n dtsOutPath: string\n /** Absolute project root — agents live at `<projectRoot>/agents`. */\n projectRoot: string\n}\n\nexport function generateAgentsDts({\n manifest,\n dtsOutPath,\n projectRoot,\n}: GenerateAgentsDtsOptions): string {\n const agents = manifest.agents ?? []\n const imports: string[] = []\n const entries: string[] = []\n const handles: string[] = []\n for (const agent of agents) {\n const alias = aliasFor(agent.name)\n imports.push(\n ` import type ${alias} from '${importPath(dtsOutPath, projectRoot, agent.filePath)}'`,\n )\n entries.push(\n ` '${agent.name}': { input: InferAgentInput<${alias}>; tools: InferAgentToolNames<${alias}> }`,\n )\n // M47 — a named, client-safe handle per agent: `import { chat } from '@theo/agents'; useAgent(chat)`.\n // cmd-click on the generated const hops to the agent source via the type-only import above.\n handles.push(\n ` export const ${agent.name}: AgentHandle<InferAgentInput<${alias}>, InferAgentToolNames<${alias}>>`,\n )\n }\n const handleBlock = handles.length > 0 ? `\\n${handles.join('\\n')}\\n` : ''\n\n const body =\n entries.length > 0\n ? `{\\n${entries.join('\\n')}\\n }`\n : `{\\n // No agents detected — add \\`agents/*.ts\\` to populate this binding.\\n }`\n\n const importBlock = imports.length > 0 ? `${imports.join('\\n')}\\n` : ''\n\n return `${FILE_HEADER}\ndeclare module '@theo/agents' {\n import type { InferAgentInput, InferAgentToolNames } from '@theokit/agents'\n import type { UseAgentReturn, AgentTransport, AgentHandle } from 'theokit/client'\n${importBlock}\n export interface AppAgents ${body}\n\n // Web (and any HTTP surface): bind by agent name — \\`send\\` is typed to the agent's \\`input\\` schema.\n export function useAgent<K extends keyof AppAgents>(\n name: K,\n ): UseAgentReturn<AppAgents[K]['input'], AppAgents[K]['tools']>\n // M47 — bind by a typed handle: \\`import { chat } from '@theo/agents'; useAgent(chat)\\`. No magic\n // string (the path lives on the handle) and no duplicated input type (inferred from the handle).\n export function useAgent<TInput, TTools extends string>(\n handle: AgentHandle<TInput, TTools>,\n ): UseAgentReturn<TInput, TTools>\n // M41 (ADR-0050) — terminal/desktop (and advanced): bind by an explicit AgentTransport\n // (e.g. InProcessTransport). The SAME hook, one consumption shape across every surface.\n export function useAgent<TInput = unknown>(\n transport: AgentTransport,\n ): UseAgentReturn<TInput>\n\n // M47 — one client-safe handle per agent (runtime value = { path }; types are phantom).\n${handleBlock}}\n`\n}\n\n/**\n * M47 — the RUNTIME body of the virtual `@theo/agents` module: it re-exports `useAgent` and emits one\n * handle value per agent (`export const chat = agentHandle('/api/agents/chat')`), so\n * `import { chat } from '@theo/agents'` resolves at runtime.\n *\n * `agentHandle` MUST be `import`ed (a local binding), NOT re-exported — `export { agentHandle } from '…'`\n * re-exports the name but does NOT bind it locally, so `agentHandle(…)` below would throw\n * `ReferenceError: agentHandle is not defined` in the browser (caught by the real-browser dogfood, missed\n * by curl + the .d.ts-only unit test).\n */\nexport function generateAgentsRuntimeModule(agentNames: string[]): string {\n const handleLines = agentNames.map(\n (name) => `export const ${name} = agentHandle('/api/agents/${name}')`,\n )\n return (\n `import { agentHandle } from 'theokit/client'\\n` +\n `export { useAgent } from 'theokit/client'\\n` +\n (handleLines.length > 0 ? handleLines.join('\\n') + '\\n' : '')\n )\n}\n\n// ─── Vite plugin ─────────────────────────────────────────────────────────────\n\nconst VIRTUAL_AGENTS_ID = '@theo/agents'\nconst RESOLVED_AGENTS_ID = '\\0@theo/agents'\n\ninterface AgentsTypedClientPluginOptions {\n /** Absolute project root (agents live at `<projectRoot>/<agentsDir>`). */\n projectRoot: string\n /** Agents dir name (config `agentsDir`, default \"agents\"), relative to projectRoot — the watch glob. */\n agentsDir?: string\n /** Absolute `.theokit/` output dir (where `agents.d.ts` lands). */\n distDir: string\n /** Injects the scanned agents; returns the current manifest-shaped agent list. */\n scanManifest: (projectRoot: string) => TheoManifest\n}\n\n/** Atomic write via tmp + rename; skips when content is unchanged. */\nfunction writeIfChanged(filePath: string, content: string): void {\n if (existsSync(filePath)) {\n try {\n if (readFileSync(filePath, 'utf-8') === content) return\n } catch {\n /* fall through to write */\n }\n }\n mkdirSync(dirname(filePath), { recursive: true })\n const tmp = `${filePath}.${process.pid}.tmp`\n writeFileSync(tmp, content)\n renameSync(tmp, filePath)\n}\n\nfunction emitAgentsDts(opts: AgentsTypedClientPluginOptions): string {\n const dtsOutPath = posix.join(opts.distDir.replace(/\\\\/g, '/'), 'agents.d.ts')\n const content = generateAgentsDts({\n manifest: opts.scanManifest(opts.projectRoot),\n dtsOutPath,\n projectRoot: opts.projectRoot,\n })\n writeIfChanged(dtsOutPath, content)\n return dtsOutPath\n}\n\nexport function agentsTypedClientPlugin(opts: AgentsTypedClientPluginOptions): Plugin {\n let debounce: NodeJS.Timeout | undefined\n let viteServer: ViteDevServer | undefined\n\n const scheduleEmit = (): void => {\n if (debounce) clearTimeout(debounce)\n debounce = setTimeout(() => {\n try {\n emitAgentsDts(opts)\n if (viteServer) {\n const mod = viteServer.moduleGraph.getModuleById(RESOLVED_AGENTS_ID)\n if (mod) viteServer.moduleGraph.invalidateModule(mod)\n }\n } catch (err) {\n console.error('[theokit:agents-typed-client] codegen error:', err)\n }\n }, 100)\n }\n\n return {\n name: 'theokit:agents-typed-client',\n enforce: 'post',\n configResolved() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] initial codegen error:', err)\n }\n },\n buildEnd() {\n try {\n emitAgentsDts(opts)\n } catch (err) {\n console.error('[theokit:agents-typed-client] buildEnd codegen error:', err)\n }\n },\n configureServer(server) {\n viteServer = server\n const agentsGlob = posix.join(\n opts.projectRoot.replace(/\\\\/g, '/'),\n opts.agentsDir ?? 'agents',\n )\n const onFile = (file: string): void => {\n if (file.replace(/\\\\/g, '/').startsWith(agentsGlob)) scheduleEmit()\n }\n server.watcher.on('add', onFile)\n server.watcher.on('change', onFile)\n server.watcher.on('unlink', onFile)\n },\n resolveId(id) {\n return id === VIRTUAL_AGENTS_ID ? RESOLVED_AGENTS_ID : null\n },\n load(id) {\n if (id === RESOLVED_AGENTS_ID) {\n const agents = opts.scanManifest(opts.projectRoot).agents ?? []\n return generateAgentsRuntimeModule(agents.map((a) => a.name))\n }\n return null\n },\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/build.ts","../src/adapters/types.ts","../src/server/cron/adapter-translators.ts","../src/server/_internal/atomic-write.ts","../src/server/cron/cron-manifest.ts","../src/server/cron/cron-scan.ts","../src/server/jobs/job-manifest.ts","../src/server/jobs/job-scan.ts","../src/cli/cleanup/cleanup.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\n// T1.1 (architecture-medium-deferrals) — nodeAdapter no longer static-imported.\n// All adapters dispatch via `adapterRegistry` (lazy-imported within runAdapterBuild).\nimport { VALID_TARGETS, type BuildTarget, type AdapterBuildContext } from '../../adapters/types.js'\nimport { loadConfig } from '../../config/load-config.js'\nimport { loadEnv } from '../../config/load-env.js'\nimport { validateProjectStructure } from '../../config/validate-structure.js'\nimport {\n ExistingConfigUnparseableError,\n translateCronToAws,\n translateCronToCloudflare,\n translateCronToDeno,\n translateCronToVercel,\n} from '../../server/cron/adapter-translators.js'\nimport { writeCronManifest } from '../../server/cron/cron-manifest.js'\nimport { scanCronDirs } from '../../server/cron/cron-scan.js'\nimport { writeJobManifest } from '../../server/jobs/job-manifest.js'\nimport { scanJobs } from '../../server/jobs/job-scan.js'\nimport { generateManifest, writeManifest } from '../../server/scan/manifest.js'\nimport {\n buildManifest as buildServicesManifest,\n writeManifest as writeServicesManifest,\n} from '../../services/index.js'\n// G2 T2.2 — OpenAPI emit. Opt-in via `config.openapi`. Dual output:\n// 1. <distDir>/openapi.json (pre-Vite, dev surface + manifests sibling)\n// 2. dist/openapi.json (post-Vite, build artifact)\n// The dist emit awaits runAdapterBuild — if Vite fails, the second emit\n// never runs (EC-2 absorbed: no stale dist artifact).\nimport { emitOpenApi } from '../../vite-plugin/openapi-emit/emit.js'\nimport { loadRoutesForOpenApi } from '../../vite-plugin/openapi-emit/load-routes.js'\nimport { cleanOutDir } from '../cleanup/cleanup.js'\nimport { preflightNodeAndBindings } from '../preflight-node-version.js'\n\nimport { describeControllerArtifacts, emitControllerArtifacts } from './build/emit-controllers.js'\n\n// Adapters that do NOT support cron triggers natively. Build still\n// succeeds with crons declared, but emits a warning + skip note.\nconst CRON_NA_TARGETS = new Set<BuildTarget>(['bun', 'netlify', 'static'])\n\nexport async function buildCommand(options?: { target?: string }): Promise<void> {\n const cwd = process.cwd()\n // Preflight (FIRST — BEFORE anything that touches native bindings).\n preflightNodeAndBindings(cwd)\n // Phase 1 (T1.2) — Load .env BEFORE config load.\n loadEnv({ cwd, mode: 'production' })\n\n const config = await loadConfig(cwd)\n // #95 — honor config.appDir so a custom frontend dir (e.g. apps/web) passes the structure gate.\n validateProjectStructure(cwd, config.appDir)\n\n // T2.2 — Clean .theokit/ at build start (Astro pattern). Skip .git*.\n const distDirAbs = resolve(cwd, config.distDir)\n await cleanOutDir({ dir: distDirAbs })\n\n const target = (options?.target ?? 'node') as BuildTarget\n\n if (!VALID_TARGETS.includes(target)) {\n throw new Error(\n `Invalid build target \"${target}\". Available targets: ${VALID_TARGETS.join(', ')}`,\n )\n }\n\n // EC-201 — cross-reference note when config.adapters[] diverges from\n // the --target flag. --target is authoritative per ADR D2.\n const configAdapters = (config as { adapters?: readonly string[] }).adapters\n if (configAdapters && configAdapters.length > 0) {\n const otherAdapters = configAdapters.filter((a) => a !== target)\n if (otherAdapters.length > 0) {\n console.log(\n `\\n Note: theo.config.ts.adapters lists [${otherAdapters.join(', ')}]; ` +\n `this build translates for ${target} only. ` +\n `Run \\`theokit build --target=<adapter>\\` separately for each (cross-reference).`,\n )\n }\n }\n\n console.log(`\\n Building for ${target}...\\n`)\n\n // Manifests emit BEFORE adapter bundling (Vite). Why: manifests are\n // fast + deterministic + don't depend on Vite. If Vite fails (missing\n // dep, malformed entry), the user still gets manifests for diagnostics.\n const serverDir = resolve(cwd, config.serverDir)\n const distDir = distDirAbs\n // #95 follow-up — pass projectRoot (cwd) + config.agentsDir so agents scan honors a custom dir.\n const manifest = generateManifest(serverDir, cwd, config.agentsDir)\n writeManifest(manifest, distDir)\n\n const totalEndpoints =\n manifest.routes.length + manifest.actions.length + manifest.websockets.length\n console.log(\n ` ✓ Manifest: ${manifest.routes.length} routes, ${manifest.actions.length} actions, ${manifest.websockets.length} ws (${totalEndpoints} total)`,\n )\n\n // T1.1 — cron scan + manifest + per-target adapter translation\n await emitCronArtifacts({ cwd, serverDir, agentsDir: config.agentsDir, distDir, target })\n\n // T1.2 — job scan + manifest (no per-target translation needed)\n await emitJobArtifacts({ cwd, serverDir, distDir })\n\n // theokit#123 — compile `server/controllers/**` so `theokit start` can serve them.\n //\n // #122 made controllers first-class in dev, where Vite's swc transform compiles them on the fly.\n // Production has neither, so an uncompiled `.controller.ts` cannot load and its routes 404'd —\n // working in dev and failing in prod, which is the worst place for a gap to live.\n //\n // Deliberately NOT folded into `generateManifest` (ADR-5): the manifest is the deploy-adapter\n // contract, and a parallel route source in it would ripple through every adapter. This writes a\n // separate artifact only the Node start path reads. No controllers ⇒ no artifact at all.\n const controllerManifest = await emitControllerArtifacts({ serverDir, distDir })\n if (controllerManifest !== null) {\n console.log(` ${describeControllerArtifacts(controllerManifest)}`)\n }\n\n // Wave 2 (T1.2) — services manifest at <cwd>/.theokit/services.json. Always\n // emit (empty array when services: {} is empty) so adapters can rely on\n // the file existing. Topological order preserved by buildServicesManifest.\n //\n // Plan v1.2 T2.1 — when theo.config.ts declares `name`, emit services.json\n // v2 with that project identifier. Falling back to v1 (no project field)\n // keeps TheoCloud's deprecation warning path intact (services-bundle).\n const projectName = config.name\n const servicesManifest = buildServicesManifest(config.services, projectName)\n writeServicesManifest(cwd, servicesManifest)\n if (servicesManifest.services.length > 0) {\n const versionLabel = `v${String(servicesManifest.version)}`\n const projectLabel =\n servicesManifest.version === 2 ? ` project=\"${servicesManifest.project}\"` : ''\n console.log(\n ` ✓ Services manifest (${versionLabel}${projectLabel}): ${String(servicesManifest.services.length)} service(s) ` +\n `(${servicesManifest.services.map((s) => s.name).join(', ')})`,\n )\n } else if (servicesManifest.version === 1) {\n console.log(\n ' ⚠ services.json emitted as v1 (no `name` in theo.config.ts). ' +\n 'TheoCloud will accept this with a deprecation warning; sunset in theokit 0.6.0. ' +\n 'Run `theokit migrate services-json-v1-to-v2` to upgrade.',\n )\n }\n\n // G2 T2.2 — OpenAPI dev-surface emit (pre-Vite, sibling of manifests).\n // Opt-in: only when config.openapi is defined. Best-effort: a route load\n // failure produces a warning, not a build abort.\n if (config.openapi !== undefined) {\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const devResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distDir },\n })\n console.log(` ✓ OpenAPI: ${String(hydrated.length)} ops → ${devResult.path}`)\n }\n\n // Now run the adapter-specific bundling (Vite + adapter-specific work).\n await runAdapterBuild(target, config, cwd)\n\n // G2 T2.2 — OpenAPI build-artifact emit (post-Vite, EC-2 gated on success).\n // If runAdapterBuild threw, execution never reaches this point — no stale\n // dist/openapi.json is written.\n if (config.openapi !== undefined) {\n const distOut = resolve(cwd, 'dist')\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const distResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distOut },\n })\n console.log(` ✓ OpenAPI (dist): ${distResult.path}`)\n }\n\n const ssrNote = config.ssr ? ' (SSR)' : ''\n console.log(`\\n ✓ Build complete → ${target}${ssrNote}\\n`)\n}\n\nasync function runAdapterBuild(\n target: BuildTarget,\n config: Awaited<ReturnType<typeof loadConfig>>,\n cwd: string,\n): Promise<void> {\n // T1.1 (architecture-cleanup) — CLI composes the Vite Plugin[] and INJECTS it into\n // the adapter via ctx.makeVitePlugins. This inverts the previous `adapters → vite-plugin`\n // edge — adapters no longer import from vite-plugin/ directly.\n //\n // theoPlugin AND `@vitejs/plugin-react` are dynamically imported so the deps are\n // materialized only when needed (adapter is `node`). This keeps the CLI's startup\n // path independent of optional build-time deps (so e.g. `theokit build --target=static`\n // does not need react installed). dep-cruiser's per-module rule allows `cli → vite-plugin`.\n //\n // 0.2.2 regression fix: switched sync `theoPlugin()` → `theoPluginAsync()` so the\n // returned Plugin[] includes the @theo/actions virtual module + typed-client +\n // services + @theokit/ui auto-chain. Without async, build-time Rollup couldn't\n // resolve `@theo/actions` even though dev-time Vite (which already used async)\n // could. See https://github.com/usetheo/theokit/commits — 0.2.2 changelog.\n const { theoPluginAsync } = await import('../../vite-plugin/index.js')\n const { default: react } = await import('@vitejs/plugin-react')\n const ctx: AdapterBuildContext = {\n // `react()` may return Plugin or Plugin[] depending on version; spread the\n // async chain so the contract returns a flat Plugin[] (AdapterBuildContext\n // type updated to `Plugin[] | Promise<Plugin[]>`).\n // #95 — inject the config dirs so the client build's router/entry + typed-client codegen honor\n // custom appDir/serverDir/agentsDir (e.g. \"apps/web\" / \"core\" / \"core/agents\").\n makeVitePlugins: async (opts) =>\n [\n react(),\n ...(await theoPluginAsync({\n ...opts,\n appDir: config.appDir,\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })),\n ].flat(),\n }\n\n // T1.1 (architecture-medium-deferrals, ADR D1) — Adapter Registry replaces\n // the previous 9-case switch. New adapters add 1 line in `adapters/registry.ts`;\n // CLI is closed for modification (OCP).\n const { resolveAdapter } = await import('../../adapters/registry.js')\n const adapter = await resolveAdapter(target)\n await adapter.build(config, cwd, ctx)\n}\n\nasync function emitCronArtifacts(opts: {\n cwd: string\n serverDir: string\n agentsDir: string\n distDir: string\n target: BuildTarget\n}): Promise<void> {\n // Crons live in two conventional homes: `server/crons/` (a backend trigger) and\n // `agents/schedules/` (a scheduled agent run, kept in the agent domain). Both feed one manifest.\n const cronsDir = resolve(opts.serverDir, 'crons')\n const agentsSchedulesDir = resolve(opts.cwd, opts.agentsDir, 'schedules')\n\n const cronNodes = await scanCronDirs([cronsDir, agentsSchedulesDir])\n const manifestPath = resolve(opts.distDir, 'crons.json')\n writeCronManifest(manifestPath, cronNodes, opts.cwd)\n\n console.log(` ✓ Crons: ${cronNodes.length} declared`)\n\n if (cronNodes.length === 0) return\n\n // EC-201: target-specific translation. N/A targets emit a warning + skip.\n if (CRON_NA_TARGETS.has(opts.target)) {\n console.log(\n ` ⚠ Cron not supported by target \"${opts.target}\" — declared crons skipped. ` +\n `See docs/concepts/crons.md for supported targets.`,\n )\n return\n }\n\n const manifestEntries = cronNodes.map((n) => ({\n name: n.name,\n filePath: relativize(n.filePath, opts.cwd),\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n\n try {\n switch (opts.target) {\n case 'vercel':\n translateCronToVercel(resolve(opts.cwd, 'vercel.json'), manifestEntries)\n console.log(` ✓ Cron → vercel.json crons[] (${cronNodes.length} entries)`)\n break\n case 'cloudflare':\n translateCronToCloudflare(resolve(opts.cwd, 'wrangler.toml'), manifestEntries)\n console.log(` ✓ Cron → wrangler.toml [triggers] (${cronNodes.length})`)\n break\n case 'aws-lambda':\n translateCronToAws(resolve(opts.cwd, 'serverless.yml'), manifestEntries)\n console.log(` ✓ Cron → serverless.yml functions (${cronNodes.length})`)\n break\n case 'deno-deploy':\n translateCronToDeno(resolve(opts.distDir, 'crons-entry.ts'), manifestEntries)\n console.log(` ✓ Cron → ${opts.distDir}/crons-entry.ts (Deno.cron)`)\n break\n case 'node':\n console.log(` ✓ Cron → in-process scheduler (theokit start)`)\n break\n }\n } catch (err) {\n if (err instanceof ExistingConfigUnparseableError) throw err\n throw err\n }\n}\n\nasync function emitJobArtifacts(opts: {\n cwd: string\n serverDir: string\n distDir: string\n}): Promise<void> {\n const jobsDir = resolve(opts.serverDir, 'jobs')\n\n const jobNodes = existsSync(jobsDir) ? await scanJobs(jobsDir) : []\n const manifestPath = resolve(opts.distDir, 'jobs.json')\n writeJobManifest(manifestPath, jobNodes, opts.cwd)\n console.log(` ✓ Jobs: ${jobNodes.length} declared`)\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","import type { Plugin } from 'vite'\n\nimport type { TheoConfig } from '../config/schema.js'\n\n/**\n * Build context injected by the CLI into adapter.build.\n *\n * - `makeVitePlugins` — optional factory provided by CLI for adapters\n * that drive `viteBuild()` directly (currently: `nodeAdapter`).\n * When omitted, adapters that need Vite must fail with an actionable\n * error. This inverts the previous direct edge `adapters → vite-plugin`\n * per ADR-0001 v3 (T1.1 of the architecture-cleanup plan).\n *\n * The factory MAY return a Promise — `theokit build` uses\n * `theoPluginAsync` to wire the full Plugin[] chain (actions virtual\n * module + typed client + services + @theokit/ui auto-chain) so adapters\n * MUST `await` the result. See `cli/commands/build.ts` for the canonical\n * invocation.\n */\nexport interface AdapterBuildContext {\n makeVitePlugins?: (opts: { root: string; ssr?: boolean }) => Plugin[] | Promise<Plugin[]>\n}\n\nexport interface DeployAdapter {\n name: string\n build(config: TheoConfig, cwd: string, ctx?: AdapterBuildContext): Promise<void>\n}\n\nexport type BuildTarget =\n | 'node'\n | 'vercel'\n | 'cloudflare'\n | 'static'\n | 'bun'\n | 'deno-deploy'\n | 'netlify'\n | 'aws-lambda'\n | 'theo-cloud'\n\nexport const VALID_TARGETS: BuildTarget[] = [\n 'node',\n 'vercel',\n 'cloudflare',\n 'static',\n 'bun',\n 'deno-deploy',\n 'netlify',\n 'aws-lambda',\n 'theo-cloud',\n]\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time adapter translators: caller-controlled paths only.\n */\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronManifestEntry } from './cron-manifest.js'\n\n/**\n * Thrown when an existing platform-config file (vercel.json, wrangler.toml,\n * serverless.yml) cannot be parsed. Caller must fix the file before\n * re-running `theokit build`. We NEVER silently overwrite a user's config.\n */\nexport class ExistingConfigUnparseableError extends Error {\n readonly code = 'EXISTING_CONFIG_UNPARSEABLE'\n constructor(\n public readonly filePath: string,\n public readonly parseError: string,\n ) {\n super(\n `Existing config \"${filePath}\" could not be parsed: ${parseError}. ` +\n 'Fix or remove the file before re-running build — TheoKit never silently overwrites user configuration.',\n )\n this.name = 'ExistingConfigUnparseableError'\n }\n}\n\n// ──────────────────────────────────────────────────────────\n// Vercel — vercel.json crons[]\n// ──────────────────────────────────────────────────────────\n\ninterface VercelJson {\n crons?: { path: string; schedule: string }[]\n [key: string]: unknown\n}\n\n/**\n * Translate a TheoKit cron manifest into `vercel.json crons[]`.\n *\n * EC-105: existing fields (functions, headers, redirects, rewrites, env,\n * etc.) are preserved verbatim — ONLY the `crons[]` slice is replaced.\n */\nexport function translateCronToVercel(\n vercelJsonPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n let existing: VercelJson = {}\n if (existsSync(vercelJsonPath)) {\n const raw = readFileSync(vercelJsonPath, 'utf8')\n try {\n existing = JSON.parse(raw) as VercelJson\n } catch (err) {\n throw new ExistingConfigUnparseableError(\n vercelJsonPath,\n err instanceof Error ? err.message : String(err),\n )\n }\n }\n const merged: VercelJson = {\n ...existing,\n crons: crons.map((c) => ({\n path: `/api/__crons/${c.name}`,\n schedule: c.schedule,\n })),\n }\n writeAtomic(vercelJsonPath, JSON.stringify(merged, null, 2))\n}\n\n// ──────────────────────────────────────────────────────────\n// Cloudflare — wrangler.toml [triggers] crons\n// ──────────────────────────────────────────────────────────\n\n/**\n * Translate a TheoKit cron manifest into `wrangler.toml [triggers] crons`.\n *\n * EC-105: regex-based mutation that preserves comments + other sections\n * verbatim. Replaces only the `[triggers]` block (or appends if absent).\n */\nexport function translateCronToCloudflare(\n wranglerTomlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const schedules = crons.map((c) => `\"${c.schedule}\"`).join(', ')\n const triggersBlock = `[triggers]\\ncrons = [${schedules}]\\n`\n\n if (!existsSync(wranglerTomlPath)) {\n writeAtomic(wranglerTomlPath, triggersBlock)\n return\n }\n\n const existing = readFileSync(wranglerTomlPath, 'utf8')\n\n // Replace existing [triggers] section if present. Strategy: split into\n // line array, find the [triggers] header line, drop subsequent lines\n // until the next section header (line starting with `[`) or EOF.\n const lines = existing.split('\\n')\n const triggersIdx = lines.findIndex((l) => l.trim() === '[triggers]')\n\n let next: string\n if (triggersIdx !== -1) {\n let endIdx = lines.length\n for (let i = triggersIdx + 1; i < lines.length; i++) {\n if (lines[i].trim().startsWith('[')) {\n endIdx = i\n break\n }\n }\n const before = lines.slice(0, triggersIdx).join('\\n')\n const after = lines.slice(endIdx).join('\\n')\n next = `${before}\\n${triggersBlock.trimEnd()}\\n${after}`.replace(/\\n{3,}/g, '\\n\\n')\n } else {\n next = existing.endsWith('\\n')\n ? `${existing}\\n${triggersBlock}`\n : `${existing}\\n\\n${triggersBlock}`\n }\n writeAtomic(wranglerTomlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// AWS Lambda — serverless.yml functions.<fn>.events: schedule\n// ──────────────────────────────────────────────────────────\n\n/**\n * Convert TheoKit's 5-field UTC cron to AWS EventBridge's 6-field format.\n * EventBridge requires `?` in EITHER day-of-month OR day-of-week (not both `*`).\n *\n * Algorithm:\n * - If DOM is \"*\" and DOW is \"*\" → insert ? in DOW (default)\n * - If DOM is \"*\" and DOW is specific → insert ? in DOM\n * - If DOM is specific and DOW is \"*\" → insert ? in DOW\n * - Append \"*\" year field at end.\n */\nexport function convertToAwsCron(schedule: string): string {\n const parts = schedule.trim().split(/\\s+/)\n if (parts.length !== 5) {\n throw new Error(`Invalid 5-field schedule for AWS conversion: \"${schedule}\"`)\n }\n const [minute, hour, dom, month, dow] = parts\n let awsDom = dom\n let awsDow = dow\n if (dom === '*' && dow === '*') {\n awsDow = '?'\n } else if (dom === '*') {\n awsDom = '?'\n } else if (dow === '*') {\n awsDow = '?'\n }\n return `cron(${minute} ${hour} ${awsDom} ${month} ${awsDow} *)`\n}\n\n/**\n * Translate a TheoKit cron manifest into a `serverless.yml` functions\n * map with `events: - schedule: cron(...)` entries.\n *\n * EC-105: appends to `functions:` block, preserving all existing\n * functions/sections. Cron functions are named `cron_<name>` to avoid\n * collision with user-declared functions.\n */\nexport function translateCronToAws(\n serverlessYmlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const cronFunctionsYaml = crons\n .map(\n (c) => ` cron_${c.name}:\n handler: .theokit/server/crons/${c.name}.handler\n events:\n - schedule: ${convertToAwsCron(c.schedule)}`,\n )\n .join('\\n')\n\n const block = `\\nfunctions:\\n${cronFunctionsYaml}\\n`\n\n if (!existsSync(serverlessYmlPath)) {\n // Minimal serverless.yml scaffold\n writeAtomic(\n serverlessYmlPath,\n `service: theokit-app\\nprovider:\\n name: aws\\n runtime: nodejs22.x\\n${block}`,\n )\n return\n }\n\n const existing = readFileSync(serverlessYmlPath, 'utf8')\n\n // Look for an existing top-level `functions:` block; if present, append our\n // cron entries under it (don't replace user-declared functions).\n const functionsRe = /^functions:\\s*\\n/m\n let next: string\n if (functionsRe.test(existing)) {\n next = existing.replace(functionsRe, (match) => `${match}${cronFunctionsYaml}\\n`)\n } else {\n next = existing.endsWith('\\n') ? `${existing}${block}` : `${existing}\\n${block}`\n }\n writeAtomic(serverlessYmlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// Deno Deploy — Deno.cron registrations\n// ──────────────────────────────────────────────────────────\n\n/**\n * Emit a Deno entry file that registers each cron via `Deno.cron`.\n *\n * Unlike Vercel/CF/AWS, Deno.cron is an in-process runtime API — the\n * entry file is a managed artifact (overwritten each build), not a user\n * config (so EC-105 doesn't apply here).\n */\nexport function translateCronToDeno(entryPath: string, crons: readonly CronManifestEntry[]): void {\n const lines = crons.map(\n (c) =>\n `Deno.cron(\"${c.name}\", \"${c.schedule}\", async () => {\n const mod = await import(\"../${c.filePath}\");\n const def = mod.default;\n await def.handler({\n traceId: crypto.randomUUID().replace(/-/g, \"\"),\n scheduledAt: new Date(),\n signal: AbortSignal.timeout(60_000),\n });\n});`,\n )\n const content = `// AUTOGENERATED by TheoKit cron build — DO NOT EDIT.\n// Source: server/crons/*.ts → .theokit/crons.json → this file.\n${lines.join('\\n\\n')}\n`\n writeAtomic(entryPath, content)\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time atomic write: caller-controlled paths only. No HTTP input\n * reaches these fs calls.\n */\n// T5a.1b — Web Crypto migration. Build-time only; node:fs + node:path stay\n// because this is a manifest-write leaf (e.g. .theokit/jobs.json) and per\n// ADR-0028 the runtime-portable boundary is the request handler, not the\n// scanner. Only node:crypto is swapped out — Web Crypto's\n// getRandomValues works in every supported runtime.\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\n/**\n * Write `content` to `path` atomically via the tmp + rename pattern.\n *\n * Two concurrent calls to `writeAtomic(path, ...)` are guaranteed to\n * leave `path` containing valid content from ONE of the calls (never\n * truncated, never interleaved). POSIX rename is atomic on the same\n * filesystem.\n *\n * EC-106 (jobs-crons-webhooks-cost-tracking-plan) — shared helper for\n * `.theokit/crons.json` and `.theokit/jobs.json` manifest writes so a\n * concurrent dev-server scan + build manifest emit never produces\n * partial JSON.\n *\n * @param path destination path\n * @param content bytes (UTF-8 string) to write\n */\nexport function writeAtomic(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true })\n // Include a random suffix so two concurrent writes don't trample each\n // other's tmp file. Web Crypto getRandomValues is non-blocking +\n // collision-safe for the tiny entropy we need (8 hex chars = 32 bits).\n // Hex-encoded manually to avoid Buffer (runtime-agnostic per ADR-0028).\n const randBuf = new Uint8Array(4)\n globalThis.crypto.getRandomValues(randBuf)\n let suffix = ''\n for (const b of randBuf) suffix += b.toString(16).padStart(2, '0')\n const tmp = `${path}.tmp-${process.pid}-${suffix}`\n writeFileSync(tmp, content, 'utf8')\n renameSync(tmp, path)\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronNode } from './cron-scan.js'\n\nexport const CRON_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface CronManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: 'forbid' | 'allow'\n}\n\nexport interface CronManifest {\n readonly schemaVersion: typeof CRON_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly crons: readonly CronManifestEntry[]\n}\n\n/**\n * Build a `CronManifest` from scanned `CronNode[]`. Filepaths are kept\n * relative to the caller's project root for portability.\n */\nexport function buildCronManifest(nodes: readonly CronNode[], projectRoot?: string): CronManifest {\n const crons: CronManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n return {\n schemaVersion: CRON_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n crons,\n }\n}\n\n/**\n * Write the cron manifest to `path` atomically (EC-106).\n *\n * Accepts either a pre-built `CronManifest` OR an array of `CronNode[]`\n * (which gets converted via `buildCronManifest`). The atomic-write\n * helper guarantees `path` always contains valid JSON, even under\n * concurrent writes (e.g., dev-server rescan + build).\n */\nexport function writeCronManifest(\n path: string,\n input: readonly CronNode[] | CronManifest,\n projectRoot?: string,\n): void {\n const manifest: CronManifest = isManifest(input) ? input : buildCronManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is CronManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'crons' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only. No HTTP\n * input ever reaches these fs calls.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { CronConcurrencyPolicy, CronDefinition } from './cron-types.js'\n\n/**\n * One discovered cron from build-time scan. The handler is intentionally\n * NOT included — manifest is platform-neutral and consumed by adapters\n * that emit static config. Runtime dispatch loads the handler at fire time.\n */\nexport interface CronNode {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: CronConcurrencyPolicy\n}\n\nexport class DuplicateCronNameError extends Error {\n readonly code = 'DUPLICATE_CRON_NAME'\n constructor(\n public readonly cronName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate cron name \"${cronName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Cron names must be unique across server/crons/ and agents/schedules/.',\n )\n this.name = 'DuplicateCronNameError'\n }\n}\n\nconst CRON_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface CronModule {\n default?: unknown\n}\n\nfunction isCronDefinition(value: unknown): value is CronDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.schedule === 'string' &&\n typeof def.handler === 'function' &&\n (def.concurrency === 'forbid' || def.concurrency === 'allow')\n )\n}\n\n/**\n * Scan a directory for cron definition files and return the discovered\n * `CronNode[]` sorted by name. Throws `DuplicateCronNameError` on name\n * collision and `Error` on missing default export.\n *\n * Sequential by design — module imports are awaited one-by-one to keep\n * error messages anchored to the file that failed.\n */\nexport async function scanCrons(cronsDir: string): Promise<CronNode[]> {\n return scanCronDirs([cronsDir])\n}\n\n/**\n * Scan MULTIPLE cron directories and merge the results with a UNIFIED\n * duplicate-name guard across all of them. The framework discovers crons in\n * two conventional homes: `server/crons/` (a backend trigger) and\n * `agents/schedules/` (a scheduled agent run — kept in the agent domain). Both\n * feed the same manifest + deploy translation; a name may not collide across\n * the two dirs. Missing dirs are skipped (no error). Nodes are returned sorted\n * by name for a stable manifest.\n */\nexport async function scanCronDirs(dirs: readonly string[]): Promise<CronNode[]> {\n const filePaths: string[] = []\n for (const dir of dirs) {\n if (!existsSync(dir)) continue\n walkSourceFiles(dir, { extensions: CRON_EXTENSIONS }, (p) => {\n const base = basename(p)\n // Skip private helpers (`_helper.ts`) and OS junk (`.DS_Store`).\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n }\n\n const nodes: CronNode[] = []\n for (const filePath of filePaths) {\n let mod: CronModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import cron file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isCronDefinition(exported)) {\n throw new Error(\n `Cron file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineCron(name, { schedule, handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n schedule: exported.schedule,\n concurrency: exported.concurrency,\n })\n }\n\n // Dup-name detection (unified across every scanned dir).\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateCronNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => a.name.localeCompare(b.name))\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { JobNode } from './job-scan.js'\n\nexport const JOB_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface JobManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport interface JobManifest {\n readonly schemaVersion: typeof JOB_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly jobs: readonly JobManifestEntry[]\n}\n\nexport function buildJobManifest(nodes: readonly JobNode[], projectRoot?: string): JobManifest {\n const jobs: JobManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n maxAttempts: n.maxAttempts,\n hasInputSchema: n.hasInputSchema,\n }))\n return {\n schemaVersion: JOB_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n jobs,\n }\n}\n\nexport function writeJobManifest(\n path: string,\n input: readonly JobNode[] | JobManifest,\n projectRoot?: string,\n): void {\n const manifest: JobManifest = isManifest(input) ? input : buildJobManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is JobManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'jobs' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { JobDefinition } from './job-types.js'\n\nexport interface JobNode {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport class DuplicateJobNameError extends Error {\n readonly code = 'DUPLICATE_JOB_NAME'\n constructor(\n public readonly jobName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate job name \"${jobName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Job names must be unique across server/jobs/.',\n )\n this.name = 'DuplicateJobNameError'\n }\n}\n\nconst JOB_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface JobModule {\n default?: unknown\n}\n\nfunction isJobDefinition(value: unknown): value is JobDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.handler === 'function' &&\n typeof def.maxAttempts === 'number' &&\n typeof def.hasInputSchema === 'boolean'\n )\n}\n\nexport async function scanJobs(jobsDir: string): Promise<JobNode[]> {\n if (!existsSync(jobsDir)) return []\n\n const filePaths: string[] = []\n walkSourceFiles(jobsDir, { extensions: JOB_EXTENSIONS }, (p) => {\n const base = basename(p)\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n\n const nodes: JobNode[] = []\n for (const filePath of filePaths) {\n let mod: JobModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import job file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isJobDefinition(exported)) {\n throw new Error(\n `Job file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineJob(name, { handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n maxAttempts: exported.maxAttempts,\n hasInputSchema: exported.hasInputSchema,\n })\n }\n\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateJobNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => a.name.localeCompare(b.name))\n}\n","/**\n * State cleanup utilities (Phase 2 of\n * docs/plans/framework-zero-config-polish-plan.md).\n *\n * - `cleanOutDir` — Astro pattern: empty a directory except a skip list,\n * used at `theokit build` start.\n * - `gcAgentRegistry` — Nuxt LRU pattern: delete oldest agent dirs when\n * count exceeds cap, used at `theokit dev` startup.\n *\n * EC-3 (MUST FIX, CRITICAL): cleanOutDir refuses to wipe anything outside\n * the current cwd. Prevents catastrophic `distDir: '/'` data loss.\n * EC-9 (SHOULD TEST): gcAgentRegistry handles dirs with mtime=0 (Docker overlay).\n * EC-11 (SHOULD TEST): cleanOutDir normalizes trailing-slash in skip basenames.\n * EC-12 (SHOULD TEST): cleanOutDir catches EROFS and continues.\n */\n\nimport { promises as fs } from 'node:fs'\nimport { basename, resolve as resolvePath, sep } from 'node:path'\n\nimport type {\n CleanOutDirOptions,\n CleanOutDirResult,\n GcAgentRegistryOptions,\n GcAgentRegistryResult,\n} from './cleanup-types.js'\n\nconst DEFAULT_SKIP = ['.git', '.gitkeep', '.gitignore']\n// DEFAULT_MAX_AGENTS removed in Phase 7 — gcAgentRegistry is a tombstone.\n\nfunction normalizeSkipName(name: string): string {\n // EC-11 — strip trailing slash + leading `./`\n return basename(name.replace(/\\/$/, ''))\n}\n\n/**\n * Empty a directory, preserving entries in the skip list.\n *\n * Throws if `opts.dir` is not inside `process.cwd()` (EC-3 path safety).\n * Returns `{deleted:0, kept:0}` when the directory does not exist.\n */\nexport async function cleanOutDir(opts: CleanOutDirOptions): Promise<CleanOutDirResult> {\n const resolvedDir = resolvePath(opts.dir)\n const resolvedCwd = resolvePath(process.cwd())\n\n // EC-3 — path safety guard. CRITICAL.\n if (resolvedDir === resolvedCwd) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be a child of cwd, not cwd itself`,\n )\n }\n if (!resolvedDir.startsWith(resolvedCwd + sep)) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be inside cwd (${resolvedCwd})`,\n )\n }\n\n const skip = new Set((opts.skip ?? DEFAULT_SKIP).map(normalizeSkipName))\n\n let entries: { name: string }[]\n try {\n entries = await fs.readdir(resolvedDir, { withFileTypes: true })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') return { deleted: 0, kept: 0 }\n throw err\n }\n\n let deleted = 0\n let kept = 0\n for (const entry of entries) {\n const name = entry.name\n if (skip.has(name)) {\n kept++\n continue\n }\n const fullPath = resolvePath(resolvedDir, name)\n try {\n await fs.rm(fullPath, { recursive: true, force: true, maxRetries: 3 })\n deleted++\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') {\n deleted++ // already gone\n continue\n }\n // EC-12 — EROFS or other rm failure: warn + continue, don't crash.\n console.warn(\n `[theokit] cleanOutDir could not remove ${fullPath} (${code ?? 'unknown'}); skipping`,\n )\n kept++\n }\n }\n\n return { deleted, kept }\n}\n\n/**\n * Phase 7 — TOMBSTONE for backward-compat. The SDK v1.1.0's `Agent.registry`\n * handles GC natively; this function is a no-op + emits a deprecation warning\n * ONCE per process (EC-10).\n *\n * Will be deleted entirely in TheoKit 0.4.0. Marked deprecated via runtime\n * warning rather than `@deprecated` JSDoc tag to avoid the eslint\n * sonarjs/deprecation flagging our own internal symbols.\n */\nlet warnedOnce = false\nexport async function gcAgentRegistry(\n _opts: GcAgentRegistryOptions,\n): Promise<GcAgentRegistryResult> {\n if (!warnedOnce) {\n warnedOnce = true\n console.warn(\n '[theokit] gcAgentRegistry is deprecated; SDK Agent.registry handles GC natively (configure via theo.config.ts > agents.registry)',\n )\n }\n return Promise.resolve({ deleted: 0, kept: 0 })\n}\n\n/**\n * @internal — testing helper. Resets the module-scoped warnedOnce flag.\n */\nexport function __resetGcDeprecationWarnedForTests(): void {\n warnedOnce = false\n}\n"],"mappings":"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","names":["existsSync","existsSync","existsSync","relativize","isManifest","existsSync","basename","existsSync","basename","basename","writeManifest","relativize","existsSync"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/schema.ts","../src/config/schemas/rate-limit.ts","../src/config/schemas/upload.ts","../src/config/schemas/logging.ts","../src/config/schemas/cache.ts","../src/config/schemas/security.ts","../src/config/schemas/header-safe.ts","../src/config/schemas/storage.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { servicesConfigSchema } from '../services/index.js'\n\nimport {\n cacheSchema,\n loggingSchema,\n rateLimitSchema,\n securitySchema,\n storageSchema,\n uploadSchema,\n type FormatErrorContext,\n type FormatErrorHook,\n} from './schemas/index.js'\n\n// Re-export per-concern schemas + types so downstream consumers\n// (`adapters/*`, vite-plugin, generators, tests) keep their existing\n// imports valid. Per plan T2.3 — pure structural split; zero behavior\n// change at the call site.\nexport {\n cacheSchema,\n corsSchema,\n rateLimitSchema,\n securityHeadersSchema,\n securitySchema,\n storageSchema,\n} from './schemas/index.js'\n\nexport type { StorageConfig } from './schemas/index.js'\n\n/**\n * Root `theo.config.ts` schema — composer assembled from the per-concern\n * primitives re-exported above.\n *\n * Embedded blocks that exist ONLY as part of the root config (`agents`,\n * `ui`, `devtools`, `jobs`, `openapi`) stay inline below. They have no\n * external consumers; splitting them would create lonely files (M5\n * smell) without comprehension benefit.\n */\nexport const theoConfigSchema = z\n .object({\n /**\n * Plan v1.2 T2.1 — project identifier propagated into\n * `.theokit/services.json` v2 `project` field. DNS-1123 compatible (drives\n * Gitea repo + ArgoCD App naming on TheoCloud). When omitted, the build\n * emits services.json v1 with the legacy `services-bundle` fallback\n * (ADR D10) and logs a deprecation warning.\n */\n name: z\n .string()\n .max(63)\n .refine(\n // DNS-1123 equivalent expressed as explicit single-char anchors so\n // security/detect-unsafe-regex stays clean (no backtracking).\n (value) =>\n value.length > 0 &&\n /^[a-z0-9-]+$/u.test(value) &&\n !value.startsWith('-') &&\n !value.endsWith('-'),\n 'name must match DNS-1123 (lowercase alphanumeric+hyphens, 1-63 chars, no leading/trailing hyphen)',\n )\n .optional(),\n appDir: z.string().default('app'),\n serverDir: z.string().default('server'),\n /**\n * Directory (relative to the project root) holding `agents/<name>.ts` definitions, scanned by\n * dev/build/terminal/mcp. Defaults to `\"agents\"` — apps that keep the canonical layout are\n * unaffected. Set to e.g. `\"core/agents\"` to organize agents under a domain root (#95 follow-up).\n */\n agentsDir: z.string().default('agents'),\n /**\n * T2.2 / EC-4 — Build output directory. Must be a relative path inside\n * the project root. Refused absolute or parent-relative paths to prevent\n * `cleanOutDir` from wiping arbitrary locations (defense-in-depth on\n * top of cleanOutDir's runtime EC-3 guard).\n */\n distDir: z\n .string()\n .default('.theokit')\n .refine(\n (d) => !/^([A-Za-z]:)?[/\\\\]/.test(d) && !d.startsWith('..'),\n 'distDir must be a relative path inside the project root (e.g., \".theokit\")',\n ),\n /**\n * Agent runtime configuration.\n *\n * - `maxRegistries` (T2.3, legacy): dev-mode cleanup of stale\n * `.theokit/agents/<id>/` dirs by mtime. Now superseded by SDK's\n * native registry GC but kept for backward-compat.\n * - `registry` (Phase 6, Production-Readiness #2): forwarded to\n * `Agent.registry.configure()` lazily on first request.\n * * `maxAgents` — LRU cap. MUST be ≥ max-concurrent-active-conversations\n * (EC-17 DOCUMENT): with maxAgents:1 and 2 concurrent chats, LRU evicts\n * mid-stream → SDK aborts with code:'aborted'. Default 100 covers\n * indie/small-team; tune up for high-traffic.\n * * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables\n * idle eviction (LRU only).\n */\n agents: z\n .object({\n maxRegistries: z.number().int().positive().default(100),\n registry: z\n .object({\n /** LRU cap — MUST be ≥ max-concurrent-active-conversations. */\n maxAgents: z.number().int().positive().max(10_000).default(100),\n /** Idle eviction window in ms. 0 disables idle eviction (LRU only). */\n idleTimeoutMs: z\n .number()\n .int()\n .nonnegative()\n .default(30 * 60_000),\n })\n .optional(),\n })\n .optional(),\n port: z.number().int().min(1).max(65535).default(3000),\n /** Listen on all addresses (0.0.0.0) for LAN/mobile testing. */\n host: z.union([z.string(), z.boolean()]).default('localhost'),\n /** Automatically open browser on `theokit dev`. */\n open: z.union([z.boolean(), z.string()]).default(false),\n /** Exit if port is already in use instead of trying next available. */\n strictPort: z.boolean().default(false),\n /** Forward browser console/errors to terminal — useful for AI agent dev. */\n forwardConsole: z\n .union([\n z.boolean(),\n z.object({\n unhandledErrors: z.boolean().optional(),\n logLevels: z.array(z.enum(['error', 'warn', 'info', 'log', 'debug'])).optional(),\n }),\n ])\n .default(false),\n /** Pre-transform files on startup for faster first page load. */\n warmup: z\n .object({\n clientFiles: z.array(z.string()).optional(),\n ssrFiles: z.array(z.string()).optional(),\n })\n .optional(),\n ssr: z.boolean().default(false),\n /** When true (and ssr === true), use renderToPipeableStream with progressive\n * shell flush instead of single-shot renderToString. Opt-in for streaming\n * SSR; default false preserves the current behavior. */\n ssrStreaming: z.boolean().default(false),\n rateLimit: rateLimitSchema.optional(),\n upload: uploadSchema.optional(),\n logging: loggingSchema.optional(),\n security: securitySchema.optional(),\n serialization: z.enum(['json', 'superjson']).default('json'),\n // Plugins are validated structurally at runtime by createPluginRunnerFromConfig.\n // Zod only checks the shape minimally (must be array). Type-level safety is\n // provided through defineConfig at the user surface.\n plugins: z.array(z.unknown()).optional(),\n /** Enable client-side batching of theoFetch calls and the\n * /api/__theo_batch__ server endpoint. */\n batching: z\n .union([z.boolean(), z.object({ max: z.number().int().positive().optional() })])\n .optional(),\n /** T4.1 — Audit log. When `logger` is provided, framework events\n * (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are\n * emitted to it. Default: noop. */\n audit: z\n .object({\n logger: z.unknown().optional(),\n })\n .optional(),\n /** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;\n * undefined = enabled when @theokit/ui is detected in node_modules. */\n ui: z\n .union([\n z.literal(false),\n z.object({\n theme: z.enum(['violet-forge', 'noir', 'paper']).optional(),\n fonts: z.enum(['bundled', 'cdn']).optional(),\n }),\n ])\n .optional(),\n /**\n * Cache subsystem (caching-and-revalidation-plan).\n * Default `undefined` keeps caching disabled (backward compatible).\n * Pass `cache: {}` to opt in with defaults.\n */\n cache: cacheSchema.optional(),\n /**\n * Devtools overlay (Phase 0.4.0+ — see docs/plans/devtools-plan.md).\n *\n * - `undefined` (default): devtools auto-injects in `pnpm dev`, NEVER in `vite build`.\n * - `false`: devtools disabled entirely (Vite plugin skips injection even in dev).\n * - `{ ... }`: devtools enabled with explicit defaults (position, theme).\n *\n * Tree-shaken to noop in prod via the dual-export pattern in\n * `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).\n */\n devtools: z\n .union([\n z.literal(false),\n z.object({\n position: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).optional(),\n theme: z.enum(['light', 'dark', 'system']).optional(),\n }),\n ])\n .optional(),\n /**\n * Informative list of deploy adapters the app supports. Does NOT\n * trigger per-build translations — only the `--target` CLI flag does\n * (EC-201 / ADR D2). If `config.adapters` includes a target NOT\n * matching `--target`, `theokit build` emits a cross-reference note.\n */\n adapters: z.array(z.string()).optional(),\n /**\n * Extra package names to pre-bundle via Vite's `optimizeDeps.include`.\n *\n * Framework auto-includes `@theokit/ui` and `lucide-react` when present.\n * Apps adding plugin peer-deps that rely on a runtime `import('<pkg>')`\n * (dynamic specifier) — e.g. `@theokit/plugin-canvas` consumers\n * installing `mermaid` for Mermaid SVG rendering — must declare those\n * here so Vite can resolve the literal in dev mode without\n * \"Failed to resolve module specifier\" errors. Production builds use\n * tsup/esbuild bundling and are not affected.\n *\n * Example:\n * viteOptimizeDeps: ['mermaid']\n */\n viteOptimizeDeps: z.array(z.string()).optional(),\n /**\n * Jobs backend (ADR D3 + T2.1). When configured, every request gets\n * `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a\n * `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).\n */\n jobs: z\n .object({\n backend: z.custom<unknown>((v) => typeof v === 'object' && v !== null),\n })\n .optional(),\n /**\n * StorageManager configuration (T1.1 / ADR-0007).\n *\n * Declares Postgres servers + databases + Redis servers. Consumed by\n * `getStorageManager().configure()` at boot via `start.ts`.\n *\n * Default `undefined` means manager exists but is not configured — adapters\n * relying on the manager (PostgresJobBackend.fromStorageManager, etc.) will\n * throw with an actionable error on first use.\n */\n storage: storageSchema.optional(),\n /**\n * Wave 2 — Polyglot services orchestration (T1.1 / ADR-0012/0013/0014/0015).\n *\n * Declarative external sidecar processes (Python FastAPI / Node Hono)\n * that boot alongside the TheoKit TS app. Empty `services: {}` is the\n * default and preserves Wave 1 behavior.\n */\n services: servicesConfigSchema,\n /**\n * G2 — OpenAPI emit (build-time only).\n *\n * When present, `theokit build` writes a generated `openapi.json` from\n * every `defineRoute()` body/query/params Zod schema. `undefined` keeps\n * the framework backward-compatible (no emit). Pass `openapi: {}` to\n * opt in with defaults.\n *\n * Defaults: spec 3.1.0 · servers `http://localhost:3000` · title\n * \"TheoKit App\" · version \"0.0.0\" · outDir \".theokit\" (next to dist).\n *\n * The env var `THEOKIT_OPENAPI_SERVERS` (CSV of URLs) overrides\n * `servers[].url` at emit time without rebuilding the config.\n */\n openapi: z\n .object({\n servers: z\n .array(\n z.object({\n url: z.url(),\n description: z.string().optional(),\n }),\n )\n .default([{ url: 'http://localhost:3000', description: 'Local development' }]),\n specVersion: z.enum(['3.1.0', '3.0.3']).default('3.1.0'),\n title: z.string().default('TheoKit App'),\n version: z.string().default('0.0.0'),\n outDir: z.string().default('.theokit'),\n })\n .optional(),\n /**\n * G5 T1.3 — error envelope transformer hook (blueprint ADR D3).\n *\n * When present, runs at framework error-boundary time to enrich the\n * envelope with consumer-defined extensions (`hint`, custom telemetry\n * tags, etc.) BEFORE the envelope is serialized to the client. The\n * function signature is preserved via the explicit `FormatErrorHook`\n * type — TS inference flows from `theo.config.ts` into `@theo/client`\n * codegen and `@theokit/ui` AgentErrorCard consumers.\n *\n * Use `z.custom<FormatErrorHook>(...)` because Zod's built-in\n * `z.function()` discards its TS signature after parse; `z.custom`\n * with a function-typed runtime guard preserves the call-site type\n * without trading off Zod runtime validation.\n */\n formatError: z\n .custom<FormatErrorHook>((val) => typeof val === 'function', {\n message: 'formatError must be a function',\n })\n .optional(),\n })\n // EC-2 fix: cross-config refine — no service may share TheoKit's web port.\n .refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {\n message: 'service.port collides with TheoKit web port — change one of them',\n path: ['services'],\n })\n\nexport type TheoConfig = z.infer<typeof theoConfigSchema>\n\n// Silence unused-import warnings for type-only re-exports — TS strips at compile,\n// but exports above re-introduce them for downstream consumers.\ntype _FormatErrorContext = FormatErrorContext\n","import { z } from 'zod'\n\n/**\n * Base bucket config — legacy shape preserved for backwards compatibility.\n */\nconst baseRateLimitSchema = z.object({\n windowMs: z.number().min(1),\n max: z.number().int().min(1),\n})\n\n/**\n * T2.2 — Per-route + per-user rate limit. The new shape adds `routes`\n * (path map), `keyBy`, and `cookieName`. The legacy flat shape is still\n * accepted via the union — see `createRouteRateLimiter` for normalization.\n */\nexport const rateLimitSchema = z.union([\n baseRateLimitSchema,\n z.object({\n default: baseRateLimitSchema.optional(),\n routes: z.record(z.string(), baseRateLimitSchema).optional(),\n keyBy: z\n .union([\n z.enum(['ip', 'session', 'user']),\n z.function({ input: z.tuple([z.unknown()]), output: z.string() }),\n ])\n .optional(),\n cookieName: z.string().min(1).optional(),\n }),\n])\n","import { z } from 'zod'\n\nexport const uploadSchema = z.object({\n maxFileSize: z\n .number()\n .min(1)\n .default(10 * 1024 * 1024), // 10MB\n maxFiles: z.number().int().min(1).default(10),\n maxFieldSize: z\n .number()\n .min(1)\n .default(1 * 1024 * 1024), // 1MB\n})\n","import { z } from 'zod'\n\nexport const loggingSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default('info'),\n})\n","import { z } from 'zod'\n\n// `.finite()` was removed from the 4 numeric schemas below (agent-builder#319): in zod 4 it is a\n// no-op — `z.number()` already rejects `Infinity`, `-Infinity` and `NaN` by default. Measured before\n// removing, against the installed zod 4.4.3, and not assumed from the deprecation message: all five\n// cases (`Infinity`, `-Infinity`, `NaN`, `1.5`, `0`) give the SAME verdict with and without it.\n\n/**\n * Cache subsystem config (caching-and-revalidation-plan).\n * Default `cache: undefined` keeps the framework backward-compatible\n * (no engine initialized → no cache primitives available).\n *\n * Setting `cache: {}` opts in with all defaults.\n */\nconst routeRuleSchema = z.object({\n maxAge: z.number().nonnegative().optional(),\n swr: z.number().nonnegative().optional(),\n tags: z.array(z.string()).optional(),\n})\n\nexport const cacheSchema = z.object({\n enabled: z.boolean().default(true),\n /** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */\n storage: z.union([z.literal('memory'), z.custom<unknown>()]).default('memory'),\n maxEntries: z.number().int().positive().default(1000),\n defaults: z\n .object({\n maxAge: z.number().nonnegative().default(1),\n swr: z.number().nonnegative().optional(),\n cacheErrors: z.boolean().default(false),\n })\n .default({ maxAge: 1, cacheErrors: false }),\n keyDerivation: z\n .object({\n excludeQuery: z.array(z.string()).optional(),\n sortQuery: z.boolean().default(true),\n lowercaseHost: z.boolean().default(true),\n })\n .default({ sortQuery: true, lowercaseHost: true }),\n routeRules: z.record(z.string(), routeRuleSchema).optional(),\n})\n","import { z } from 'zod'\n\nimport { headerSafeString } from './header-safe.js'\n\n/**\n * Phase 5 — CSRF warn-first (EC-1).\n *\n * 0.2.0 default: `warn`. Existing apps keep working but get structured\n * warnings about every state-mutating request that does not carry the\n * `X-Theo-Action: 1` header. 0.3.0 will flip the default to `strict`.\n *\n * Set explicitly to `strict` to opt into the future default early,\n * or `off` to disable CSRF entirely (only valid when you have another\n * defense — bearer auth, no session cookies, etc).\n */\n\n/**\n * Phase 6 — Default security headers (D4 / EC-2).\n *\n * 0.2.0 defaults:\n * - CSP in `report-only` mode (EC-2: don't break existing apps)\n * - X-Frame-Options: DENY · X-Content-Type-Options: nosniff\n * - Referrer-Policy: strict-origin-when-cross-origin\n * - HSTS in production only (no TLS on localhost)\n *\n * Users override individual headers, swap CSP to `enforce`, or disable\n * CSP entirely (`csp: false` / `cspMode: 'off'`).\n */\nexport const securityHeadersSchema = z.object({\n csp: z.union([headerSafeString, z.literal(false)]).optional(),\n // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.\n // Users who want the old behaviour set `cspMode: 'report-only'`\n // explicitly. See docs/migrating/0.2-to-0.3.md.\n cspMode: z.enum(['enforce', 'report-only', 'off']).default('enforce'),\n hsts: z.union([headerSafeString, z.literal(false)]).optional(),\n frameOptions: z.enum(['DENY', 'SAMEORIGIN']).default('DENY'),\n contentTypeOptions: z.literal('nosniff').default('nosniff'),\n referrerPolicy: headerSafeString.default('strict-origin-when-cross-origin'),\n /**\n * T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.\n * Pass `false` to suppress the header.\n */\n permissionsPolicy: z.union([headerSafeString, z.literal(false)]).optional(),\n})\n\n/**\n * T5.1 — Disallowed-routes escalation pattern (Rails-inspired).\n *\n * `routes` accepts string (exact match — trailing slash matters) or\n * RegExp entries. Matched routes that would otherwise emit `csrf.warn`\n * dispatch through `disallowedBehavior` instead:\n * - `'warn'` : no-op vs the default warn-mode behavior\n * - `'raise'` : escalate to 403, even when global `csrf` mode is 'warn'\n *\n * Use to roll out strict mode per-route (e.g., flip /api/auth/* first)\n * without committing the entire surface to strict at once.\n */\nconst disallowedConfigSchema = z.object({\n routes: z.array(z.union([z.string(), z.instanceof(RegExp)])),\n behavior: z.enum(['warn', 'raise']).default('raise'),\n})\n\n/**\n * T1.2 — CORS configuration.\n *\n * `origins` accepts a single value (`'*'`, string, RegExp, callback) OR an\n * array of (string | RegExp). The spec-violating `origins: '*'` +\n * `credentials: true` combination is rejected at parse time (browsers\n * ignore wildcards when credentials are sent).\n *\n * EC-3 — `allowedHeaders` and `exposedHeaders` entries go through the\n * header-safe refinement (CR/LF rejected — CWE-113 mitigation).\n */\nexport const corsSchema = z\n .object({\n origins: z.union([\n z.literal('*'),\n headerSafeString,\n z.instanceof(RegExp),\n z.array(z.union([headerSafeString, z.instanceof(RegExp)])),\n z.function({ input: z.tuple([z.string()]), output: z.boolean() }),\n ]),\n methods: z\n .array(z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']))\n .optional(),\n allowedHeaders: z.array(headerSafeString).optional(),\n exposedHeaders: z.array(headerSafeString).optional(),\n credentials: z.boolean().default(false),\n maxAge: z.number().int().min(0).max(86400).default(600),\n })\n .refine((c) => !(c.origins === '*' && c.credentials), {\n message: 'CORS spec forbids origins:\"*\" with credentials:true — browsers ignore the wildcard',\n })\n\nexport const securitySchema = z.object({\n // T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that\n // grep their warn-mode logs from 0.2.x already know which endpoints\n // break; opt back into 'warn' globally OR use disallowedRoutes for\n // surgical migration. See docs/migrating/0.2-to-0.3.md.\n csrf: z.enum(['off', 'warn', 'strict']).default('strict'),\n headers: securityHeadersSchema.optional(),\n /** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */\n disallowed: disallowedConfigSchema.optional(),\n /** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */\n cors: corsSchema.optional(),\n})\n","import { z } from 'zod'\n\n/**\n * EC-3 — CWE-113 HTTP Response Splitting mitigation.\n *\n * Every string that becomes a header value must reject CR/LF. Apps that\n * derive header values from untrusted input (feature flags, tenant config,\n * URL params) would otherwise let attackers inject Set-Cookie / Location\n * headers via `\\r\\n`. Apply this refinement to every header-bound string\n * field: permissionsPolicy, csp, hsts, referrerPolicy, CORS allow/expose.\n */\nexport const headerSafeString = z\n .string()\n .refine((s) => !/[\\r\\n]/.test(s), { message: 'Header value must not contain CR/LF' })\n","import { z } from 'zod'\n\n/**\n * StorageManager schemas (T1.1 / ADR-0007 D4).\n *\n * `theo.config.ts > storage` declares Postgres servers (credentials), the\n * databases on each server (TheoCloud / managed PG / self-host), and Redis\n * servers. The runtime `StorageManager` consumes this block; adapters\n * (PostgresJobBackend, PostgresConversationStorage, etc.) request pools by\n * database name and never see raw credentials at the call site.\n *\n * EC-1 (DOCUMENT in concept doc T4.1): Zod default strip-unknown mode\n * silently drops typo keys (`databasees` instead of `databases`). The\n * concept doc warns users to use exact names; runtime errors are still\n * actionable (`Database \"X\" not configured`).\n *\n * EC-2 (DEFERRED to use-time): `databases.X.server` references a key in\n * `servers`. Cross-field validation is intentionally NOT enforced at parse\n * time — `StorageManager.usePostgres()` throws an actionable error on the\n * first call with the dangling reference, matching Rails / Nitro behavior.\n */\nconst tlsConfigSchema = z.object({\n rejectUnauthorized: z.boolean().optional(),\n caCert: z.string().optional(),\n clientCert: z.string().optional(),\n clientKey: z.string().optional(),\n})\n\nconst serverConfigSchema = z.object({\n host: z.string().min(1),\n port: z.number().int().positive().max(65535).optional(),\n user: z.string().min(1),\n /** Password may be the empty string (some providers permit it). */\n password: z.string(),\n tls: tlsConfigSchema.optional(),\n})\n\nconst postgresPoolConfigSchema = z.object({\n min: z.number().int().nonnegative().optional(),\n max: z.number().int().positive().optional(),\n connectionTimeoutMillis: z.number().int().positive().optional(),\n idleTimeoutMillis: z.number().int().nonnegative().optional(),\n})\n\nconst postgresDatabaseConfigSchema = z.object({\n /** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */\n server: z.string().min(1),\n database: z.string().min(1),\n pool: postgresPoolConfigSchema.optional(),\n})\n\nconst redisServerConfigSchema = serverConfigSchema.extend({\n db: z.number().int().nonnegative().optional(),\n maxRetriesPerRequest: z.number().int().nonnegative().optional(),\n})\n\nexport const storageSchema = z.object({\n servers: z.record(z.string(), serverConfigSchema).optional(),\n databases: z.record(z.string(), postgresDatabaseConfigSchema).optional(),\n redis: z.record(z.string(), redisServerConfigSchema).optional(),\n})\n\nexport type StorageConfig = z.infer<typeof storageSchema>\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z"]}
|