theokit 0.19.3 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-LFS3MXL7.js → agent-76WK2CZJ.js} +2 -2
- package/dist/{agents-typed-client-DPFVM2OY.js → agents-typed-client-DCPSXUU5.js} +5 -2
- package/dist/{agents-typed-client-DPFVM2OY.js.map → agents-typed-client-DCPSXUU5.js.map} +1 -1
- package/dist/{agents-typed-client-2K3UAOUF.js → agents-typed-client-RIJVHSX4.js} +5 -2
- package/dist/{agents-typed-client-2K3UAOUF.js.map → agents-typed-client-RIJVHSX4.js.map} +1 -1
- package/dist/{build-B675HLFR.js → build-6UDZJIHD.js} +16 -6
- package/dist/build-6UDZJIHD.js.map +1 -0
- package/dist/{chunk-5YBUPJC2.js → chunk-23T4CO4M.js} +2 -2
- package/dist/{chunk-UGK6KR4D.js → chunk-3WOODHXK.js} +7 -5
- package/dist/chunk-3WOODHXK.js.map +1 -0
- package/dist/{chunk-QSLNS5EZ.js → chunk-7PFHQ56Q.js} +7 -5
- package/dist/chunk-7PFHQ56Q.js.map +1 -0
- package/dist/{chunk-JQSFBJR5.js → chunk-GEQJAFSV.js} +6 -9
- package/dist/chunk-GEQJAFSV.js.map +1 -0
- package/dist/chunk-WLKFWVOM.js +278 -0
- package/dist/chunk-WLKFWVOM.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/{dev-ORWXOTNX.js → dev-NHHTXOA4.js} +6 -4
- package/dist/dev-NHHTXOA4.js.map +1 -0
- package/dist/index.d.ts +30 -2
- package/dist/index.js +29 -11
- package/dist/index.js.map +1 -1
- package/dist/{mcp-MQTG6IS4.js → mcp-HP5RVOOZ.js} +2 -2
- package/dist/{registry-XJUYD2OU.js → registry-XSRSTH33.js} +2 -2
- package/dist/{routes-TJQIXCOS.js → routes-XNS3UM3B.js} +3 -3
- package/dist/routes-XNS3UM3B.js.map +1 -0
- package/dist/server/define/index.d.ts +269 -4
- package/dist/server/define/index.js +15 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +22 -14
- package/dist/server/index.js.map +1 -1
- package/dist/{static-7ARBVDJF.js → static-CYG2WGYP.js} +2 -2
- package/dist/static-CYG2WGYP.js.map +1 -0
- package/dist/vite-plugin/index.d.ts +6 -0
- package/dist/vite-plugin/index.js +1 -1
- package/dist/{vite-plugin-WIJ5RMQQ.js → vite-plugin-3UDOJGO5.js} +2 -2
- package/package.json +1 -1
- package/dist/build-B675HLFR.js.map +0 -1
- package/dist/chunk-CWVBDUDC.js +0 -108
- package/dist/chunk-CWVBDUDC.js.map +0 -1
- package/dist/chunk-JQSFBJR5.js.map +0 -1
- package/dist/chunk-QSLNS5EZ.js.map +0 -1
- package/dist/chunk-UGK6KR4D.js.map +0 -1
- package/dist/dev-ORWXOTNX.js.map +0 -1
- package/dist/routes-TJQIXCOS.js.map +0 -1
- package/dist/static-7ARBVDJF.js.map +0 -1
- /package/dist/{agent-LFS3MXL7.js.map → agent-76WK2CZJ.js.map} +0 -0
- /package/dist/{chunk-5YBUPJC2.js.map → chunk-23T4CO4M.js.map} +0 -0
- /package/dist/{mcp-MQTG6IS4.js.map → mcp-HP5RVOOZ.js.map} +0 -0
- /package/dist/{registry-XJUYD2OU.js.map → registry-XSRSTH33.js.map} +0 -0
- /package/dist/{vite-plugin-WIJ5RMQQ.js.map → vite-plugin-3UDOJGO5.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/static.ts","../src/adapters/static-paths.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * All filesystem inputs in this file are derived from:\n * - `process.cwd()` resolved at build time, OR\n * - directory tree walks rooted in `serverDir`/`appDir` (themselves\n * resolved from cwd), OR\n * - file paths produced by `collectStaticPaths` (a controlled router\n * scanner).\n * No path here originates from HTTP input, environment variables, or\n * deserialized user data. The path-traversal vector the rule guards\n * against does not apply — this is a build-time tool, not a request\n * handler.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve, relative } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { scanRoutes } from '../router/scan.js'\nimport type { RouteNode } from '../router/types.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport {\n collectStaticPaths,\n type CollectOptions,\n type LoadStaticPaths,\n type ResolvedPath,\n} from './static-paths.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport class StaticApiRoutesDetectedError extends Error {\n constructor(routes: string[]) {\n super(\n `Static adapter cannot build a project with API routes. Found: ${routes.join(\n ', ',\n )}. Use 'node', 'vercel', 'cloudflare' or another runtime adapter.`,\n )\n this.name = 'StaticApiRoutesDetectedError'\n }\n}\n\nexport class StaticRenderError extends Error {\n constructor(url: string, cause: unknown) {\n const causeMsg = cause instanceof Error ? cause.message : String(cause)\n super(`SSR render failed for ${url}: ${causeMsg}`)\n this.name = 'StaticRenderError'\n if (cause instanceof Error) {\n this.cause = cause\n }\n }\n}\n\nexport interface StaticBuildDeps {\n detectApiRoutes?: (serverDir: string) => string[]\n scanAppRoutes?: (appDir: string) => RouteNode\n collectPaths?: (tree: RouteNode, options: CollectOptions) => Promise<ResolvedPath[]>\n loadStaticPaths?: LoadStaticPaths\n renderHtml?: (url: string, cwd: string) => Promise<string>\n ensureDir?: (path: string) => Promise<void>\n writeFile?: (path: string, content: string) => Promise<void>\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n}\n\nexport function detectApiRoutes(serverDir: string): string[] {\n const routesDir = resolve(serverDir, 'routes')\n if (!existsSync(routesDir)) return []\n if (!statSync(routesDir).isDirectory()) return []\n\n const out: string[] = []\n walkRoutes(routesDir, routesDir, out)\n return out\n}\n\nfunction walkRoutes(root: string, dir: string, out: string[]): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue\n const full = resolve(dir, entry.name)\n if (entry.isDirectory()) {\n walkRoutes(root, full, out)\n } else if (entry.isFile() && /\\.(ts|tsx|js|jsx|mjs)$/.test(entry.name)) {\n const rel = relative(root, full).split(/[\\\\/]/).join('/')\n out.push(rel)\n }\n }\n}\n\n/* eslint-disable @typescript-eslint/require-await -- DI contract is async; default impl uses sync fs */\n\n// The DI surface exposes async helpers (so consumers can override with\n// real async IO — e.g. S3 uploads). The defaults use sync fs because\n// every caller awaits the result anyway.\nconst defaultEnsureDir = async (path: string): Promise<void> => {\n mkdirSync(path, { recursive: true })\n}\n\nconst defaultWriteFile = async (path: string, content: string): Promise<void> => {\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n}\n\n/* eslint-enable @typescript-eslint/require-await */\n\n/**\n * Default loader: dynamic-imports the file at `paramsFilePath` and invokes\n * its default export. Returns null if the file does not exist (the caller\n * will throw StaticPathsRequiredError with a clear message in that case).\n */\nconst defaultLoadStaticPaths: LoadStaticPaths = async (paramsFilePath) => {\n if (!existsSync(paramsFilePath)) return null\n try {\n const mod = (await import(pathToFileURL(paramsFilePath).href)) as {\n default?: LoadStaticPaths | (() => Awaited<ReturnType<LoadStaticPaths>>)\n }\n if (typeof mod.default !== 'function') return null\n // The user's `static-paths.ts` may export `default` as either sync or\n // async — `await` accepts both, but ESLint's `await-thenable` cannot\n // see through the union.\n const value = mod.default(paramsFilePath)\n const result = value instanceof Promise ? await value : value\n return result ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Default renderer: loads the built SSR entry (`.theokit/server/entry-server.js`)\n * and calls its `render(url)` export, wrapping the result in the client\n * `index.html` template. Falls back to a minimal HTML shell when no SSR build\n * is present (so the static adapter still emits something usable even without\n * SSR enabled).\n */\nfunction createDefaultRenderHtml(cwd: string): (url: string) => Promise<string> {\n return async (url: string): Promise<string> => {\n const clientDir = resolve(cwd, '.theokit/client')\n const indexPath = resolve(clientDir, 'index.html')\n const ssrEntryPath = resolve(cwd, '.theokit/server/entry-server.js')\n\n let baseHtml = '<!doctype html><html><body><div id=\"root\"></div></body></html>'\n if (existsSync(indexPath)) {\n baseHtml = readFileSync(indexPath, 'utf-8')\n }\n\n if (!existsSync(ssrEntryPath)) {\n // No SSR build — emit the client shell. Hydration on the client will\n // render the route once JS loads. Acceptable degradation when the user\n // chose static + ssr: false.\n return baseHtml\n }\n\n try {\n const mod = (await import(pathToFileURL(ssrEntryPath).href)) as {\n render?: (u: string) => Promise<string | { redirect: Response }>\n }\n if (typeof mod.render !== 'function') return baseHtml\n const result = await mod.render(url)\n if (typeof result === 'string') {\n const rootMatch = /<div id=[\"']root[\"'][^>]*>/.exec(baseHtml)\n if (rootMatch) {\n const splitIdx = baseHtml.indexOf(rootMatch[0]) + rootMatch[0].length\n return baseHtml.slice(0, splitIdx) + result + baseHtml.slice(splitIdx)\n }\n return baseHtml.replace('</body>', result + '</body>')\n }\n // redirect — emit a meta refresh fallback for static export\n return `<!doctype html><meta http-equiv=\"refresh\" content=\"0; url=/\" />`\n } catch (err) {\n throw new StaticRenderError(url, err)\n }\n }\n}\n\nexport async function buildStatic(\n config: TheoConfig,\n cwd: string,\n deps: StaticBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('static', readManifest(cwd))\n\n const detect = deps.detectApiRoutes ?? detectApiRoutes\n const apiRoutes = detect(resolve(cwd, 'server'))\n if (apiRoutes.length > 0) {\n throw new StaticApiRoutesDetectedError(apiRoutes)\n }\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const scan = deps.scanAppRoutes ?? scanRoutes\n // #95 — honor config `appDir` (default \"app\") so `--target static` prerenders a custom frontend dir.\n const appDir = resolve(cwd, config.appDir)\n const tree = scan(appDir)\n\n const loadStaticPaths = deps.loadStaticPaths ?? defaultLoadStaticPaths\n const collect = deps.collectPaths ?? collectStaticPaths\n const paths = await collect(tree, { appDir, loadStaticPaths })\n\n if (paths.length === 0) return\n\n const renderHtml = deps.renderHtml ?? createDefaultRenderHtml(cwd)\n const ensureDir = deps.ensureDir ?? defaultEnsureDir\n const writeFile = deps.writeFile ?? defaultWriteFile\n\n const outDir = resolve(cwd, '.theokit/static')\n await ensureDir(outDir)\n\n for (const path of paths) {\n let html: string\n try {\n html = await renderHtml(path.url, cwd)\n } catch (err) {\n throw new StaticRenderError(path.url, err)\n }\n const outPath = resolve(outDir, path.filename)\n await writeFile(outPath, html)\n }\n}\n\nexport const staticAdapter: DeployAdapter = {\n name: 'static',\n build(config, cwd, ctx) {\n return buildStatic(config, cwd, {}, ctx)\n },\n}\n","import type { RouteNode } from '../router/types.js'\n\nexport interface ResolvedPath {\n /** URL path to render, e.g. '/blog/123' */\n url: string\n /** Output file path relative to .theokit/static/, e.g. 'blog/123.html' */\n filename: string\n}\n\nexport type StaticPathParams = Record<string, string | string[]>\n\nexport type LoadStaticPaths = (paramsFilePath: string) => Promise<StaticPathParams[] | null>\n\nexport class StaticPathsRequiredError extends Error {\n constructor(routePath: string, paramsFile: string) {\n super(\n `Route ${routePath} has dynamic segments and requires ${paramsFile}. ` +\n `Export default function returning Array<{ <param>: string | string[] }>.`,\n )\n this.name = 'StaticPathsRequiredError'\n }\n}\n\nexport interface CollectOptions {\n appDir: string\n loadStaticPaths: LoadStaticPaths\n}\n\nexport type ParsedSegment =\n | { kind: 'static' }\n | { kind: 'param'; name: string }\n | { kind: 'catch-all'; name: string }\n\nconst CATCH_ALL = /^\\[\\.\\.\\.(.+)\\]$/\nconst PARAM = /^\\[(.+)\\]$/\n\nexport function parseSegment(segment: string): ParsedSegment {\n const catchAll = CATCH_ALL.exec(segment)\n if (catchAll) return { kind: 'catch-all', name: catchAll[1] }\n const param = PARAM.exec(segment)\n if (param) return { kind: 'param', name: param[1] }\n return { kind: 'static' }\n}\n\nexport async function collectStaticPaths(\n tree: RouteNode,\n options: CollectOptions,\n): Promise<ResolvedPath[]> {\n const out: ResolvedPath[] = []\n await walk(tree, [], out, options)\n return out\n}\n\nasync function walk(\n node: RouteNode,\n parentSegments: string[],\n out: ResolvedPath[],\n options: CollectOptions,\n): Promise<void> {\n const segments = node.segment === '' ? parentSegments : [...parentSegments, node.segment]\n\n if (node.page) {\n const resolved = await resolveNodePaths(segments, options)\n out.push(...resolved)\n }\n\n for (const child of node.children) {\n await walk(child, segments, out, options)\n }\n}\n\nasync function resolveNodePaths(\n segments: string[],\n options: CollectOptions,\n): Promise<ResolvedPath[]> {\n if (segments.length === 0) {\n return [{ url: '/', filename: 'index.html' }]\n }\n\n const parsed = segments.map(parseSegment)\n const hasDynamic = parsed.some((p) => p.kind !== 'static')\n\n if (!hasDynamic) {\n const joined = segments.join('/')\n return [{ url: '/' + joined, filename: joined + '.html' }]\n }\n\n let lastDynamicIdx = 0\n for (let i = 0; i < parsed.length; i++) {\n if (parsed[i].kind !== 'static') lastDynamicIdx = i\n }\n\n const dirSegments = segments.slice(0, lastDynamicIdx + 1)\n const paramsFile = `${options.appDir}/${dirSegments.join('/')}/static-paths.ts`\n const params = await options.loadStaticPaths(paramsFile)\n\n if (!params) {\n const routePath = '/' + segments.join('/')\n throw new StaticPathsRequiredError(routePath, paramsFile)\n }\n\n return params.map((paramSet) => {\n const filled: string[] = []\n for (let i = 0; i < segments.length; i++) {\n const p = parsed[i]\n if (p.kind === 'static') {\n filled.push(segments[i])\n } else {\n const value = paramSet[p.name]\n if (Array.isArray(value)) {\n filled.push(...value)\n } else {\n filled.push(value)\n }\n }\n }\n const joined = filled.join('/')\n return { url: '/' + joined, filename: joined + '.html' }\n })\n}\n"],"mappings":"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","names":[]}
|
|
@@ -106,6 +106,12 @@ interface TheoPluginOptions {
|
|
|
106
106
|
* `"agents"`. Set to e.g. `"core/agents"` to co-locate agents with the domain root (#95 follow-up).
|
|
107
107
|
*/
|
|
108
108
|
agentsDir?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Frontend dir (config `appDir`, default "app") holding the file-based router (`page.tsx`,
|
|
111
|
+
* `layout.tsx`, …), relative to the project root. Set to e.g. `"apps/web"` to group the web UI
|
|
112
|
+
* under an `apps/` root alongside other frontends (#95 follow-up).
|
|
113
|
+
*/
|
|
114
|
+
appDir?: string;
|
|
109
115
|
}
|
|
110
116
|
/**
|
|
111
117
|
* Async factory companion. Returns `[theoPlugin, ...autoChainedPlugins]`.
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
defineTheoIntegration,
|
|
8
8
|
theoPlugin,
|
|
9
9
|
theoPluginAsync
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3WOODHXK.js";
|
|
11
11
|
import "./chunk-DXF64KS5.js";
|
|
12
12
|
import "./chunk-DMC6HYUR.js";
|
|
13
13
|
import "./chunk-M6NMS5LR.js";
|
|
@@ -32,4 +32,4 @@ export {
|
|
|
32
32
|
theoPlugin,
|
|
33
33
|
theoPluginAsync
|
|
34
34
|
};
|
|
35
|
-
//# sourceMappingURL=vite-plugin-
|
|
35
|
+
//# sourceMappingURL=vite-plugin-3UDOJGO5.js.map
|
package/package.json
CHANGED
|
@@ -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 { scanCrons } 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\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 validateProjectStructure(cwd)\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, distDir, target })\n\n // T1.2 — job scan + manifest (no per-target translation needed)\n await emitJobArtifacts({ cwd, serverDir, distDir })\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 makeVitePlugins: async (opts) => [react(), ...(await theoPluginAsync(opts))].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 distDir: string\n target: BuildTarget\n}): Promise<void> {\n const cronsDir = resolve(opts.serverDir, 'crons')\n\n const cronNodes = existsSync(cronsDir) ? await scanCrons(cronsDir) : []\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/.',\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 if (!existsSync(cronsDir)) return []\n\n const filePaths: string[] = []\n walkSourceFiles(cronsDir, { 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 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\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","/* eslint-disable security/detect-non-literal-fs-filename --\n * Cleanup helpers. Paths are caller-controlled (CLI/config); EC-3 path-safety\n * guard rejects absolute paths outside cwd to prevent catastrophic data loss.\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","existsSync","relativize"]}
|
package/dist/chunk-CWVBDUDC.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// src/server/define/define-route.ts
|
|
2
|
-
function defineRoute(config) {
|
|
3
|
-
return config;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
// src/server/define/define-action.ts
|
|
7
|
-
function defineAction(config) {
|
|
8
|
-
return config;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// src/server/define/define-middleware.ts
|
|
12
|
-
function defineMiddleware(handler) {
|
|
13
|
-
return handler;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// src/server/define/define-agent-tool.ts
|
|
17
|
-
import { z } from "zod";
|
|
18
|
-
var TOOL_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
|
|
19
|
-
function isZodObject(schema) {
|
|
20
|
-
let current = schema;
|
|
21
|
-
for (let depth = 0; depth < 10; depth++) {
|
|
22
|
-
if (current instanceof z.ZodObject) return true;
|
|
23
|
-
const z4 = current.def;
|
|
24
|
-
if (z4?.type === "object") return true;
|
|
25
|
-
const z3 = current._def;
|
|
26
|
-
if (z3?.typeName === "ZodObject") return true;
|
|
27
|
-
const next = z4?.innerType ?? z4?.in ?? z3?.schema ?? z3?.innerType;
|
|
28
|
-
if (next !== void 0) {
|
|
29
|
-
current = next;
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
function defineAgentTool(spec) {
|
|
37
|
-
if (!TOOL_NAME_REGEX.test(spec.name)) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`defineAgentTool: name must match ${TOOL_NAME_REGEX.source}. Got: ${JSON.stringify(spec.name)}`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (!isZodObject(spec.inputSchema)) {
|
|
43
|
-
throw new Error("defineAgentTool: inputSchema must be a ZodObject (z.object({...}))");
|
|
44
|
-
}
|
|
45
|
-
if (spec.description.length === 0) {
|
|
46
|
-
console.warn(
|
|
47
|
-
`defineAgentTool(${JSON.stringify(spec.name)}): empty description degrades LLM tool selection \u2014 provide a one-sentence summary.`
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
const { $schema: _$schema, ...inputSchema } = z.toJSONSchema(spec.inputSchema);
|
|
51
|
-
return {
|
|
52
|
-
name: spec.name,
|
|
53
|
-
description: spec.description,
|
|
54
|
-
inputSchema,
|
|
55
|
-
handler: async (input, ctx) => {
|
|
56
|
-
const parsed = spec.inputSchema.parse(input);
|
|
57
|
-
const result = await spec.handler(parsed, ctx);
|
|
58
|
-
if (spec.toModelOutput) return spec.toModelOutput(result);
|
|
59
|
-
if (typeof result !== "string") {
|
|
60
|
-
throw new Error(
|
|
61
|
-
`defineAgentTool(${JSON.stringify(spec.name)}): handler returned a non-string; provide toModelOutput to map it to a string for the model.`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
return result;
|
|
65
|
-
},
|
|
66
|
-
// M18 — carry the per-target formatters for the app (ignored by the SDK wire).
|
|
67
|
-
...spec.transform !== void 0 ? { transform: spec.transform } : {}
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function applyTransform(tool, result, target) {
|
|
71
|
-
const fn = tool.transform?.[target];
|
|
72
|
-
return fn ? fn(result) : result;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// src/server/define/define-websocket.ts
|
|
76
|
-
function defineWebSocket(handler) {
|
|
77
|
-
return handler;
|
|
78
|
-
}
|
|
79
|
-
function defineWebSocketWeb(handler) {
|
|
80
|
-
return handler;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/server/define/define-channel.ts
|
|
84
|
-
function defineChannel(handler) {
|
|
85
|
-
return handler;
|
|
86
|
-
}
|
|
87
|
-
function defineWebChannel(handler) {
|
|
88
|
-
return handler;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// src/server/define/define-plugin.ts
|
|
92
|
-
function defineTheoPlugin(plugin) {
|
|
93
|
-
return plugin;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export {
|
|
97
|
-
defineRoute,
|
|
98
|
-
defineAction,
|
|
99
|
-
defineMiddleware,
|
|
100
|
-
defineAgentTool,
|
|
101
|
-
applyTransform,
|
|
102
|
-
defineWebSocket,
|
|
103
|
-
defineWebSocketWeb,
|
|
104
|
-
defineChannel,
|
|
105
|
-
defineWebChannel,
|
|
106
|
-
defineTheoPlugin
|
|
107
|
-
};
|
|
108
|
-
//# sourceMappingURL=chunk-CWVBDUDC.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/define/define-route.ts","../src/server/define/define-action.ts","../src/server/define/define-middleware.ts","../src/server/define/define-agent-tool.ts","../src/server/define/define-websocket.ts","../src/server/define/define-channel.ts","../src/server/define/define-plugin.ts"],"sourcesContent":["import type { z } from 'zod'\n\n// T2.2 (architecture-cleanup) — RouteConfig type moved to core/contracts/\n// (canonical home per ADR-0001 v3). Re-export preserves the public path\n// `import { type RouteConfig } from 'theokit/server'`.\nexport type { RouteConfig } from '../../core/contracts/route-config.js'\n\nimport type { RouteConfig } from '../../core/contracts/route-config.js'\n\n/**\n * Define a typed HTTP route.\n * Identity function — provides type inference for route handlers.\n */\nexport function defineRoute<\n TQuery extends z.ZodType = z.ZodUndefined,\n TBody extends z.ZodType = z.ZodUndefined,\n TParams extends z.ZodType = z.ZodUndefined,\n TCtx = unknown,\n TResponse = unknown,\n>(\n config: RouteConfig<TQuery, TBody, TParams, TCtx, TResponse>,\n): RouteConfig<TQuery, TBody, TParams, TCtx, TResponse> {\n return config\n}\n","import type { z } from 'zod'\n\n/**\n * Action wire-protocol accept mode per plan g3-server-actions-and-useaction\n * v1.2 ADR D1. Default behavior (when omitted) is `'json'`. `'form'` opts the\n * action into FormData multipart parsing for progressive-enhancement forms;\n * the runtime in `server/http/action-execute.ts` will coerce FormData entries\n * against the `input` schema via `formDataToObject` (Astro pattern).\n */\nexport type ActionAccept = 'form' | 'json'\n\nexport interface ActionConfig<TInput extends z.ZodType, TCtx = unknown> {\n /**\n * Zod input schema. Required: every action declares its input contract via\n * Zod (architecture rule: zod-is-SSOT). The shape becomes the handler's\n * typed `input` parameter via `z.infer<TInput>`.\n */\n input: TInput\n /**\n * Wire-protocol accept mode. Defaults to `'json'` when omitted. Setting\n * `'form'` switches the runtime to FormData multipart parsing — the input\n * schema MUST be `z.object(...)` so field-by-field coercion can drive\n * boolean string / number / array coercion (Astro pattern).\n */\n accept?: ActionAccept\n /**\n * Opt OUT of CSRF enforcement for this action. Default (omitted) keeps the\n * multi-header CSRF gate active. Set `false` for endpoints intentionally\n * callable without the `X-Theo-Action` header (e.g. public webhooks). The\n * runtime in `server/http/action-execute.ts` reads this flag.\n */\n csrf?: false\n handler: (ctx: { input: z.infer<TInput>; ctx: TCtx }) => unknown\n}\n\n/**\n * Define a typed server action.\n *\n * Identity function — provides type inference for action handlers. The\n * runtime that consumes the config (validation + invocation + serialization)\n * lives in `server/http/action-execute.ts`.\n *\n * Per plan g3-server-actions-and-useaction v1.2 § Phase 1 / T1.2: the new\n * `accept?: 'form' | 'json'` field is the only contract change vs the\n * pre-G3 identity. Existing callsites (`defineAction({input, handler})`)\n * continue to compile — `accept` is opt-in.\n */\nexport function defineAction<TInput extends z.ZodType, TCtx = unknown>(\n config: ActionConfig<TInput, TCtx>,\n): ActionConfig<TInput, TCtx> {\n return config\n}\n","export type MiddlewareHandler = (\n request: Request,\n next: (request: Request) => Promise<Response>,\n) => Response | Promise<Response>\n\n/**\n * Define a middleware handler.\n * Identity function — provides type annotation for middleware.\n */\nexport function defineMiddleware(handler: MiddlewareHandler): MiddlewareHandler {\n return handler\n}\n","import { z } from 'zod'\n\n/**\n * Item #4 — `defineAgentTool`\n *\n * Sugar over the `@theokit/sdk` `CustomTool` contract. Takes a Zod schema +\n * handler and produces a structurally-compatible `CustomTool` that\n * `Agent.create({ tools: [...] })` accepts.\n *\n * Uses Zod v4's native `z.toJSONSchema()` to convert the input schema to\n * JSON Schema for LLM providers.\n *\n * Handler error propagation:\n * `defineAgentTool` parses the input via the Zod schema BEFORE calling the\n * user handler. Invalid input throws a `ZodError`, which the SDK's tool-\n * dispatcher treats as a tool failure and surfaces to the model as a tool\n * error (the SDK owns the wire; ADR D3).\n */\n\n/**\n * Local mirror of the SDK's `CustomTool` interface. We don't `import type`\n * from `@theokit/sdk` because the SDK is an optional peer (consumers who\n * never call `defineAgentTool` shouldn't need it installed). The shape is\n * the wire contract; any structurally-matching object is accepted by\n * `Agent.create({ tools })`.\n *\n * @public\n */\nexport interface CustomTool {\n name: string\n description: string\n inputSchema: Record<string, unknown>\n handler: (\n input: Record<string, unknown>,\n ctx?: { signal?: AbortSignal; context?: unknown },\n ) => string | Promise<string>\n /** M18 — optional per-target formatters for the app's UI/transcript (ignored by the SDK wire). */\n transform?: ToolTransform\n}\n\n/**\n * M18 — per-target formatters. `display` shapes the rich handler result for the UI; `transcript`\n * shapes it for a saved transcript. Applied by {@link applyTransform}, never by the model wire.\n */\nexport interface ToolTransform<R = unknown> {\n display?: (result: R) => unknown\n transcript?: (result: R) => unknown\n}\n\n/**\n * Spec accepted by {@link defineAgentTool}. `inputSchema` is a Zod 3 schema\n * rooted in `z.object(...)`. The `handler` argument type is inferred via\n * `z.infer<T>`.\n *\n * @public\n */\nexport interface DefineAgentToolSpec<T extends z.ZodType, R = string> {\n /** Tool name surfaced to the LLM. Must match `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$`. */\n name: string\n /** Description surfaced to the LLM. Required — drives tool-selection accuracy. */\n description: string\n /** Zod schema describing the input. Must be `z.object(...)` at the root. */\n inputSchema: T\n /**\n * Handler invoked with the parsed input and, optionally, the run `ctx` (M7). `ctx.context`\n * is the object supplied once at the agent level (`defineAgent({ context })`) or per-run —\n * read it for shared config like `projectRoot` instead of baking it into the factory.\n * `ctx.signal` is the abort signal. Optional so existing one-arg handlers keep working.\n *\n * M18 — the handler may return RICH data `R` (not just a string) when `toModelOutput` is\n * provided to map it to the model-visible string.\n */\n handler: (\n input: z.infer<T>,\n ctx?: { signal?: AbortSignal; context?: unknown },\n ) => R | Promise<R>\n /**\n * M18 — map the rich handler result `R` to the string the model sees. Required (in practice)\n * when `handler` returns a non-string; absent ⇒ the handler must return a string.\n */\n toModelOutput?: (result: R) => string\n /** M18 — per-target formatters (`display` / `transcript`) for the app, applied by {@link applyTransform}. */\n transform?: ToolTransform<R>\n}\n\nconst TOOL_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/\n\nfunction isZodObject(schema: z.ZodType): boolean {\n // Refinements (`.refine`), transforms (`.transform`), and defaults wrap the\n // underlying schema — walk the chain until we hit a ZodObject (or give up).\n // Supports both zod 4 (`instanceof z.ZodObject`, `def.type === 'object'`,\n // wrappers via `def.innerType` / pipe via `def.in`) and zod 3\n // (`_def.typeName === 'ZodObject'`, wrappers via `_def.schema`/`_def.innerType`).\n let current: unknown = schema\n for (let depth = 0; depth < 10; depth++) {\n if (current instanceof z.ZodObject) return true\n const z4 = (current as { def?: { type?: string; innerType?: unknown; in?: unknown } }).def\n if (z4?.type === 'object') return true\n const z3 = (current as { _def?: { typeName?: string; schema?: unknown; innerType?: unknown } })\n ._def\n if (z3?.typeName === 'ZodObject') return true\n const next = z4?.innerType ?? z4?.in ?? z3?.schema ?? z3?.innerType\n if (next !== undefined) {\n current = next\n continue\n }\n return false\n }\n return false\n}\n\n/**\n * Build a {@link CustomTool} from a Zod 3 schema + handler.\n *\n * Behavior:\n * - Validates `name` matches the LLM tool-name regex.\n * - Requires `inputSchema` to be a `ZodObject` (Anthropic + SDK contract).\n * - Warns (not throws) if `description` is empty — empty descriptions\n * degrade LLM tool selection.\n * - Converts the Zod schema to JSON Schema 7 inline (no `$ref`s — LLMs handle\n * inline schemas more reliably).\n * - Strips the top-level `$schema` field (Anthropic rejects schemas with\n * `$schema` at root in some provider modes).\n * - Wraps the handler to parse the input via the Zod schema BEFORE invoking\n * the user code — bad LLM-supplied input throws `ZodError`, which the SDK\n * converts to `tool_result(isError)`.\n *\n * @public\n */\nexport function defineAgentTool<T extends z.ZodType, R = string>(\n spec: DefineAgentToolSpec<T, R>,\n): CustomTool {\n if (!TOOL_NAME_REGEX.test(spec.name)) {\n throw new Error(\n `defineAgentTool: name must match ${TOOL_NAME_REGEX.source}. Got: ${JSON.stringify(spec.name)}`,\n )\n }\n if (!isZodObject(spec.inputSchema)) {\n throw new Error('defineAgentTool: inputSchema must be a ZodObject (z.object({...}))')\n }\n if (spec.description.length === 0) {\n console.warn(\n `defineAgentTool(${JSON.stringify(spec.name)}): empty description degrades LLM tool selection — provide a one-sentence summary.`,\n )\n }\n\n // Zod v4 native JSON Schema conversion — replaces zod-to-json-schema dep.\n // Strip $schema (Anthropic + some providers reject it).\n const { $schema: _$schema, ...inputSchema } = z.toJSONSchema(spec.inputSchema) as Record<\n string,\n unknown\n > & {\n $schema?: unknown\n }\n\n return {\n name: spec.name,\n description: spec.description,\n inputSchema,\n handler: async (\n input: Record<string, unknown>,\n ctx?: { signal?: AbortSignal; context?: unknown },\n ): Promise<string> => {\n const parsed = spec.inputSchema.parse(input)\n // M7 — forward the run ctx so the handler can read `ctx.context` (e.g. projectRoot).\n const result = await spec.handler(parsed, ctx)\n // M18 — shape the (possibly rich) result into the model-visible string.\n if (spec.toModelOutput) return spec.toModelOutput(result)\n if (typeof result !== 'string') {\n throw new Error(\n `defineAgentTool(${JSON.stringify(spec.name)}): handler returned a non-string; provide toModelOutput to map it to a string for the model.`,\n )\n }\n return result\n },\n // M18 — carry the per-target formatters for the app (ignored by the SDK wire).\n ...(spec.transform !== undefined ? { transform: spec.transform as ToolTransform } : {}),\n }\n}\n\n/**\n * M18 — apply a tool's `transform` for a target (`display` / `transcript`). Returns the formatted\n * value, or the raw `result` when the tool declares no transform for that target.\n */\nexport function applyTransform(\n tool: CustomTool,\n result: unknown,\n target: 'display' | 'transcript',\n): unknown {\n const fn = tool.transform?.[target]\n return fn ? fn(result) : result\n}\n","import type { IncomingMessage } from 'node:http'\n\nexport interface WebSocketLike {\n send(data: string | Buffer): void\n close(code?: number, reason?: string): void\n}\n\nexport interface WebSocketHandler {\n onOpen?: (ws: WebSocketLike, req: IncomingMessage) => void\n onMessage?: (ws: WebSocketLike, data: string | Buffer) => void\n onClose?: (ws: WebSocketLike, code: number, reason: Buffer) => void\n onError?: (ws: WebSocketLike, error: Error) => void\n}\n\n/**\n * Define a WebSocket endpoint handler.\n * Identity function — provides type inference for WebSocket handlers.\n */\nexport function defineWebSocket(handler: WebSocketHandler): WebSocketHandler {\n return handler\n}\n\n/**\n * T5a.2 Phase F slice 3/3 — Web-Standards WebSocket endpoint handler.\n *\n * Mirror of `WebSocketHandler` for the Web `Request` shape. `onOpen`\n * receives `request: Request` instead of `req: IncomingMessage`. The\n * rest of the lifecycle (onMessage, onClose, onError) is shape-agnostic\n * (`WebSocketLike` is already Web-standards-compatible per the existing\n * design — `send(string | Buffer)` works on both Node `ws` and Web\n * `WebSocket` instances; CF Workers / Bun / Deno coerce as needed at\n * the adapter boundary).\n *\n * Per `docs/plans/t5a2-incoming-message-to-request-shape-refactor-plan.md`\n * v1.0 § Phase F (closes Phase F).\n *\n * **Architectural note — WebSocket upgrade semantics differ across runtimes:**\n * - Node + `ws`: `WebSocketServer.handleUpgrade(req, socket, head, cb)` —\n * `req` is `IncomingMessage`. Use `WebSocketHandler`.\n * - CF Workers: `new WebSocketPair()` + `request.headers` (the upgrade\n * handshake IS a Web Request). Use `WebSocketHandlerWeb`.\n * - Bun: `server.upgrade(request, { data })` — same Web Request shape.\n * - Deno: `Deno.upgradeWebSocket(request)` — same Web Request shape.\n *\n * Cross-runtime WebSocket endpoints ship BOTH `WebSocketHandler` +\n * `WebSocketHandlerWeb` exports; the runtime adapter picks the matching\n * one. This is the canonical Hono / Nitric pattern.\n */\nexport interface WebSocketHandlerWeb {\n onOpen?: (ws: WebSocketLike, request: Request) => void\n onMessage?: (ws: WebSocketLike, data: string | Uint8Array) => void\n onClose?: (ws: WebSocketLike, code: number, reason: string) => void\n onError?: (ws: WebSocketLike, error: Error) => void\n}\n\n/**\n * Web-Standards `defineWebSocket` sibling. Identity function — provides\n * type inference for Web WebSocket handlers.\n *\n * **Type difference note vs Node path:**\n * - `onMessage` data is `string | Uint8Array` instead of `string | Buffer`\n * (Web standards have no `Buffer`; Node's Buffer is a Uint8Array\n * subclass so the Node path's Buffer values flow through unchanged\n * when adapters wrap them).\n * - `onClose` reason is `string` instead of `Buffer` (Web `CloseEvent`\n * exposes the reason as a UTF-8 string natively).\n */\nexport function defineWebSocketWeb(handler: WebSocketHandlerWeb): WebSocketHandlerWeb {\n return handler\n}\n","import type { IncomingMessage } from 'node:http'\n\nimport type { WebSocketLike } from './define-websocket.js'\n\nexport interface ChannelHandler<TMessage = unknown> {\n onSubscribe?: (ws: WebSocketLike, room: string, req: IncomingMessage) => void\n onMessage?: (ws: WebSocketLike, room: string, data: TMessage) => void\n onUnsubscribe?: (ws: WebSocketLike, room: string) => void\n}\n\n/**\n * Define a channel handler for WebSocket rooms.\n * Identity function — provides type inference for channel handlers.\n */\nexport function defineChannel<TMessage = unknown>(\n handler: ChannelHandler<TMessage>,\n): ChannelHandler<TMessage> {\n return handler\n}\n\n/**\n * T5a.2 Phase F slice 2/3 — Web-Standards channel handler.\n *\n * Mirror of `ChannelHandler<TMessage>` for the Web `Request` shape.\n * `onSubscribe` receives `request: Request` instead of `req: IncomingMessage`\n * — the rest of the surface (onMessage, onUnsubscribe) is shape-agnostic\n * (WebSocketLike is already Web-standards-compatible per `define-websocket.ts`).\n *\n * Per `docs/plans/t5a2-incoming-message-to-request-shape-refactor-plan.md`\n * v1.0 § Phase F.\n *\n * **Architectural note:** WebSocket upgrade semantics differ across\n * runtimes:\n * - Node: `WebSocketServer.handleUpgrade(req, socket, head, cb)` —\n * hands you `req: IncomingMessage` at the upgrade handshake.\n * - CF Workers: `new WebSocketPair()` + `request.headers` (the upgrade\n * handshake IS a Web Request) — hands you `request: Request`.\n * - Bun: `server.upgrade(request, { data })` — same Web Request shape.\n * - Deno: `Deno.upgradeWebSocket(request)` — same Web Request shape.\n *\n * Channel handlers targeting CF/Bun/Deno use `WebChannelHandler`; legacy\n * Node consumers stay on `ChannelHandler`. Cross-runtime channels ship\n * both shapes.\n */\nexport interface WebChannelHandler<TMessage = unknown> {\n onSubscribe?: (ws: WebSocketLike, room: string, request: Request) => void\n onMessage?: (ws: WebSocketLike, room: string, data: TMessage) => void\n onUnsubscribe?: (ws: WebSocketLike, room: string) => void\n}\n\n/**\n * Web-Standards `defineChannel` sibling. Identity function — provides\n * type inference for Web channel handlers.\n */\nexport function defineWebChannel<TMessage = unknown>(\n handler: WebChannelHandler<TMessage>,\n): WebChannelHandler<TMessage> {\n return handler\n}\n","import type { TheoPlugin } from '../plugin-types.js'\n\n/**\n * Identity function for defining a Theo plugin.\n *\n * **Note:** Prefer `definePlugin` (shorter, canonical name per ADR-0008 D6).\n * Both functions are identical — `defineTheoPlugin` is kept as an alias for\n * existing in-tree consumers without forcing a migration sweep.\n */\nexport function defineTheoPlugin(plugin: TheoPlugin): TheoPlugin {\n return plugin\n}\n"],"mappings":";AAaO,SAAS,YAOd,QACsD;AACtD,SAAO;AACT;;;ACwBO,SAAS,aACd,QAC4B;AAC5B,SAAO;AACT;;;AC1CO,SAAS,iBAAiB,SAA+C;AAC9E,SAAO;AACT;;;ACXA,SAAS,SAAS;AAqFlB,IAAM,kBAAkB;AAExB,SAAS,YAAY,QAA4B;AAM/C,MAAI,UAAmB;AACvB,WAAS,QAAQ,GAAG,QAAQ,IAAI,SAAS;AACvC,QAAI,mBAAmB,EAAE,UAAW,QAAO;AAC3C,UAAM,KAAM,QAA2E;AACvF,QAAI,IAAI,SAAS,SAAU,QAAO;AAClC,UAAM,KAAM,QACT;AACH,QAAI,IAAI,aAAa,YAAa,QAAO;AACzC,UAAM,OAAO,IAAI,aAAa,IAAI,MAAM,IAAI,UAAU,IAAI;AAC1D,QAAI,SAAS,QAAW;AACtB,gBAAU;AACV;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAoBO,SAAS,gBACd,MACY;AACZ,MAAI,CAAC,gBAAgB,KAAK,KAAK,IAAI,GAAG;AACpC,UAAM,IAAI;AAAA,MACR,oCAAoC,gBAAgB,MAAM,UAAU,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA,IAC/F;AAAA,EACF;AACA,MAAI,CAAC,YAAY,KAAK,WAAW,GAAG;AAClC,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AACA,MAAI,KAAK,YAAY,WAAW,GAAG;AACjC,YAAQ;AAAA,MACN,mBAAmB,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA,IAC9C;AAAA,EACF;AAIA,QAAM,EAAE,SAAS,UAAU,GAAG,YAAY,IAAI,EAAE,aAAa,KAAK,WAAW;AAO7E,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB;AAAA,IACA,SAAS,OACP,OACA,QACoB;AACpB,YAAM,SAAS,KAAK,YAAY,MAAM,KAAK;AAE3C,YAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAE7C,UAAI,KAAK,cAAe,QAAO,KAAK,cAAc,MAAM;AACxD,UAAI,OAAO,WAAW,UAAU;AAC9B,cAAM,IAAI;AAAA,UACR,mBAAmB,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA;AAAA,IAEA,GAAI,KAAK,cAAc,SAAY,EAAE,WAAW,KAAK,UAA2B,IAAI,CAAC;AAAA,EACvF;AACF;AAMO,SAAS,eACd,MACA,QACA,QACS;AACT,QAAM,KAAK,KAAK,YAAY,MAAM;AAClC,SAAO,KAAK,GAAG,MAAM,IAAI;AAC3B;;;AC7KO,SAAS,gBAAgB,SAA6C;AAC3E,SAAO;AACT;AA+CO,SAAS,mBAAmB,SAAmD;AACpF,SAAO;AACT;;;ACvDO,SAAS,cACd,SAC0B;AAC1B,SAAO;AACT;AAoCO,SAAS,iBACd,SAC6B;AAC7B,SAAO;AACT;;;ACjDO,SAAS,iBAAiB,QAAgC;AAC/D,SAAO;AACT;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/validate-structure.ts","../src/core/errors.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Project-structure validator. Reads paths joined onto `projectRoot`,\n * with names from a fixed `ValidationRule[]` table. No HTTP input.\n */\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { TheoProjectError } from '../core/errors.js'\n\ninterface ValidationRule {\n path: string\n errorMessage: string\n}\n\nconst REQUIRED_DIRS: ValidationRule[] = [\n {\n path: 'app',\n errorMessage: 'Missing required directory: app/',\n },\n]\n\nconst REQUIRED_FILES: ValidationRule[] = [\n {\n path: 'theo.config.ts',\n errorMessage: 'Missing required file: theo.config.ts',\n },\n {\n path: 'package.json',\n errorMessage: 'Missing required file: package.json',\n },\n]\n\nexport function validateProjectStructure(rootDir: string): void {\n if (!existsSync(rootDir)) {\n throw new TheoProjectError([`Project directory does not exist: ${rootDir}`], rootDir)\n }\n\n const errors: string[] = []\n\n for (const rule of REQUIRED_DIRS) {\n if (!existsSync(join(rootDir, rule.path))) {\n errors.push(rule.errorMessage)\n }\n }\n\n for (const rule of REQUIRED_FILES) {\n if (!existsSync(join(rootDir, rule.path))) {\n errors.push(rule.errorMessage)\n }\n }\n\n if (errors.length > 0) {\n throw new TheoProjectError(errors, rootDir)\n }\n}\n","export class TheoProjectError extends Error {\n public readonly errors: string[]\n public readonly rootDir: string\n\n constructor(errors: string[], rootDir: string) {\n const errorLines = errors.map((e) => ` - ${e}`).join('\\n')\n\n super(\n `Invalid Theo project structure\\n\\n` +\n ` Root: ${rootDir}\\n\\n` +\n (errorLines ? ` Errors:\\n${errorLines}\\n` : ''),\n )\n\n this.name = 'TheoProjectError'\n this.errors = errors\n this.rootDir = rootDir\n }\n}\n"],"mappings":";;;;AAIA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;;;ACLd,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1B;AAAA,EACA;AAAA,EAEhB,YAAY,QAAkB,SAAiB;AAC7C,UAAM,aAAa,OAAO,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI;AAE1D;AAAA,MACE;AAAA;AAAA,UACa,OAAO;AAAA;AAAA,KACjB,aAAa;AAAA,EAAc,UAAU;AAAA,IAAO;AAAA,IACjD;AAEA,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AAAA,EACjB;AACF;;;ADHA,IAAM,gBAAkC;AAAA,EACtC;AAAA,IACE,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AACF;AAEA,IAAM,iBAAmC;AAAA,EACvC;AAAA,IACE,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AACF;AAEO,SAAS,yBAAyB,SAAuB;AAC9D,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,UAAM,IAAI,iBAAiB,CAAC,qCAAqC,OAAO,EAAE,GAAG,OAAO;AAAA,EACtF;AAEA,QAAM,SAAmB,CAAC;AAE1B,aAAW,QAAQ,eAAe;AAChC,QAAI,CAAC,WAAW,KAAK,SAAS,KAAK,IAAI,CAAC,GAAG;AACzC,aAAO,KAAK,KAAK,YAAY;AAAA,IAC/B;AAAA,EACF;AAEA,aAAW,QAAQ,gBAAgB;AACjC,QAAI,CAAC,WAAW,KAAK,SAAS,KAAK,IAAI,CAAC,GAAG;AACzC,aAAO,KAAK,KAAK,YAAY;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,IAAI,iBAAiB,QAAQ,OAAO;AAAA,EAC5C;AACF;","names":[]}
|