theokit 0.19.1 → 0.19.2
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-5UMCZYY4.js → agent-UGVJJXRY.js} +2 -2
- package/dist/{build-QGHSA7FT.js → build-KZBSHSKG.js} +2 -2
- package/dist/{chunk-X53XXQCX.js → chunk-2YS3CNO4.js} +9 -6
- package/dist/chunk-2YS3CNO4.js.map +1 -0
- package/dist/{chunk-5VNZ5EG3.js → chunk-7BYQD7IE.js} +5 -3
- package/dist/{chunk-5VNZ5EG3.js.map → chunk-7BYQD7IE.js.map} +1 -1
- package/dist/{chunk-N3WK6MKO.js → chunk-RRJ66UTS.js} +9 -6
- package/dist/chunk-RRJ66UTS.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/{dev-HBXSZSDL.js → dev-RQLE5W72.js} +4 -2
- package/dist/dev-RQLE5W72.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{mcp-VWUOA7T7.js → mcp-H5GWOGD7.js} +2 -2
- package/dist/{start-A5BPZ3KH.js → start-TGNHQ7NZ.js} +2 -2
- package/dist/start-TGNHQ7NZ.js.map +1 -0
- package/dist/vite-plugin/index.d.ts +7 -0
- package/dist/vite-plugin/index.js +1 -1
- package/dist/{vite-plugin-QOCVYPFI.js → vite-plugin-H2SMD2Q4.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-N3WK6MKO.js.map +0 -1
- package/dist/chunk-X53XXQCX.js.map +0 -1
- package/dist/dev-HBXSZSDL.js.map +0 -1
- package/dist/start-A5BPZ3KH.js.map +0 -1
- /package/dist/{agent-5UMCZYY4.js.map → agent-UGVJJXRY.js.map} +0 -0
- /package/dist/{build-QGHSA7FT.js.map → build-KZBSHSKG.js.map} +0 -0
- /package/dist/{mcp-VWUOA7T7.js.map → mcp-H5GWOGD7.js.map} +0 -0
- /package/dist/{vite-plugin-QOCVYPFI.js.map → vite-plugin-H2SMD2Q4.js.map} +0 -0
|
@@ -177,14 +177,16 @@ async function agentCommand(name, message, deps = {}) {
|
|
|
177
177
|
async function createAgentSsrLoader(projectRoot) {
|
|
178
178
|
const { createServer } = await import("vite");
|
|
179
179
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
180
|
-
const { theoPluginAsync } = await import("./vite-plugin-
|
|
180
|
+
const { theoPluginAsync } = await import("./vite-plugin-H2SMD2Q4.js");
|
|
181
181
|
const { loadConfig } = await import("./load-config-JKYO5RFK.js");
|
|
182
182
|
const config = await loadConfig(projectRoot);
|
|
183
183
|
const theoPlugins = await theoPluginAsync({
|
|
184
184
|
root: projectRoot,
|
|
185
185
|
ssr: config.ssr,
|
|
186
186
|
services: config.services,
|
|
187
|
-
viteOptimizeDeps: config.viteOptimizeDeps
|
|
187
|
+
viteOptimizeDeps: config.viteOptimizeDeps,
|
|
188
|
+
// #95 — honor config `serverDir` so the terminal SSR loader transpiles under the same root as dev.
|
|
189
|
+
serverDir: config.serverDir
|
|
188
190
|
});
|
|
189
191
|
const server = await createServer({
|
|
190
192
|
root: projectRoot,
|
|
@@ -207,4 +209,4 @@ export {
|
|
|
207
209
|
agentCommand,
|
|
208
210
|
createAgentSsrLoader
|
|
209
211
|
};
|
|
210
|
-
//# sourceMappingURL=chunk-
|
|
212
|
+
//# sourceMappingURL=chunk-7BYQD7IE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/agent/run-terminal-agent.ts","../src/server/agent/render-terminal.ts","../src/cli/commands/agent.ts"],"sourcesContent":["/**\n * M5 (theokit-ai-first) — run a compiled agent in the terminal, reusing the M4 harness.\n *\n * The web `mountAgent` renders `streamAgentUIMessages` to an HTTP `Response` and resolves HITL\n * approvals via the approve route. This is its terminal sibling: SAME `compileAgentModule` + SAME\n * `streamAgentUIMessages` + SAME in-process approval registry — only the render surface (stdout) and\n * the approval input (a readline prompt) differ (ADR 0039 D2). In a single-process CLI the stream's\n * `awaitApproval` (→ `registry.register`) and the terminal prompt (→ `registry.resolve`) share the one\n * in-process registry — the M4 singleton's exact fit. No new runtime, no LLM call, no tool dispatch.\n */\nimport {\n compileAgentModule,\n streamAgentUIMessages,\n type HumanInTheLoopOptions,\n} from '@theokit/agents'\n\nimport { getApprovalRegistry, type ApprovalRegistry } from './approval-registry.js'\nimport {\n promptTerminalApproval,\n renderAgentStreamToTerminal,\n type TerminalOut,\n} from './render-terminal.js'\n\nexport interface RunTerminalAgentInput {\n message: string\n /** Resume key; a fresh id per run when omitted. */\n sessionId?: string\n /** Injectable sink (defaults to `process.stdout` at the CLI entry). */\n stdout?: TerminalOut\n /** Injectable shared registry (defaults to the process singleton). */\n registry?: ApprovalRegistry\n /** Injectable approval prompt (defaults to the readline prompt over the process streams). */\n promptApproval?: (req: { toolName: string; timeoutMs?: number }) => Promise<boolean>\n /** Labels a fail-fast `AgentDefinitionError` (the file path). */\n source?: string\n}\n\n/**\n * Compile the module (M4, gathers `@Mixin` toolboxes), stream it, and render to the terminal. When the\n * agent has `@HumanInTheLoop`-gated tools, the terminal prompts and resolves the shared registry —\n * approve runs the tool, deny/timeout/non-TTY denies and the run continues.\n */\nexport async function runAgentInTerminal(\n mod: unknown,\n apiKey: string,\n input: RunTerminalAgentInput,\n): Promise<{ sawError: boolean }> {\n const compiled = compileAgentModule(mod, input.source)\n const stdout = input.stdout ?? process.stdout\n const registry = input.registry ?? getApprovalRegistry()\n const sessionId = input.sessionId ?? crypto.randomUUID()\n const promptApproval =\n input.promptApproval ??\n ((req: { toolName: string; timeoutMs?: number }) =>\n promptTerminalApproval(req, { input: process.stdin, output: process.stdout }, req.timeoutMs))\n\n // Mirror mount-agent's HITL wiring; absent ⇒ the non-HITL stream path (M2), unchanged.\n const gated = compiled.hitl\n const hitl =\n gated && gated.size > 0\n ? {\n gated,\n awaitApproval: (approvalId: string, opts: HumanInTheLoopOptions) =>\n registry.register(approvalId, {\n timeoutMs: opts.timeout ?? 300_000,\n onTimeout: opts.onTimeout ?? 'abort',\n }),\n }\n : undefined\n\n const chunks = streamAgentUIMessages(compiled, apiKey, {\n message: input.message,\n sessionId,\n hitl,\n })\n return renderAgentStreamToTerminal(chunks, {\n stdout,\n onApproval: async ({ approvalId, toolName }) => {\n // The renderer paused here (the SDK run is paused in its awaited pre_tool_call hook); prompt,\n // then resolve the SAME registry the stream registered into — the run resumes with the decision.\n // The prompt shares the gated tool's timeout so it can never outlive the registry-settled run.\n const timeoutMs = gated?.get(toolName)?.timeout ?? 300_000\n const approved = await promptApproval({ toolName, timeoutMs })\n registry.resolve(approvalId, approved)\n },\n })\n}\n","/**\n * M5 (theokit-ai-first) — the terminal render surface for the M4 agent harness.\n *\n * Consumes the M4 `UIMessageChunk` stream (`streamAgentUIMessages`) and writes it to the terminal:\n * streaming text, a dim reasoning line, `▸ tool(input)` / result cards, a checkpoint notice, errors.\n * On a HITL `tool-approval-request` it delegates to the injected `onApproval` (the entry wires that to\n * a readline prompt + the approval registry). This is the ONLY new code M5 adds — no runtime, no LLM\n * call, no tool dispatch (ADR 0039 D2). I/O is INJECTED (`stdout`, prompt streams) so the whole\n * surface is deterministically testable without a TTY (ADR 0039 D4 / ADR-M5a).\n */\nimport { createInterface } from 'node:readline'\nimport type { Readable, Writable } from 'node:stream'\n\nimport type { UIMessageChunk } from 'ai'\n\n/** ANSI helpers — applied only on a TTY so a captured (non-TTY) sink stays plain-text for tests. */\nconst ANSI = {\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n green: '\\x1b[32m',\n reset: '\\x1b[0m',\n}\nfunction paint(text: string, color: keyof typeof ANSI, tty: boolean | undefined): string {\n return tty ? `${ANSI[color]}${text}${ANSI.reset}` : text\n}\n\n/** A stdout-like sink; `isTTY` gates color (Node's `process.stdout` carries it, a test sink does not). */\nexport type TerminalOut = Writable & { isTTY?: boolean }\n\nexport interface TerminalRenderOptions {\n stdout: TerminalOut\n /** Resolve a HITL approval (the entry prompts + resolves the registry). */\n onApproval: (req: { approvalId: string; toolName: string }) => Promise<void>\n}\n\n/** Render an `unknown` tool output/input for display (string as-is; other JSON-ish values stringified). */\nfunction display(value: unknown): string {\n return typeof value === 'string' ? value : JSON.stringify(value ?? {})\n}\n\n/**\n * Map a single (non-approval) `UIMessageChunk` to its terminal line(s), or `''` for chunks that render\n * nothing (`start`/`text-start`/`reasoning-start`/…). Pure — the async loop owns approval + I/O.\n * Narrows the `ai` discriminated union directly on `chunk.type` (no cast; G3).\n */\nfunction renderChunkLine(chunk: UIMessageChunk, tty: boolean | undefined): string {\n switch (chunk.type) {\n case 'text-delta':\n return chunk.delta\n case 'text-end':\n case 'finish':\n return '\\n'\n case 'reasoning-delta':\n return paint(chunk.delta, 'dim', tty)\n case 'reasoning-end':\n return '\\n'\n case 'tool-input-available':\n return paint(`\\n▸ ${chunk.toolName}(${display(chunk.input)})\\n`, 'cyan', tty)\n case 'tool-output-available':\n return paint(` ✓ ${display(chunk.output)}\\n`, 'green', tty)\n case 'tool-output-error':\n return paint(` ✗ ${chunk.errorText}\\n`, 'red', tty)\n case 'error':\n return paint(`\\n✗ ${chunk.errorText}\\n`, 'red', tty)\n default:\n // ai-sdk `data-*` transient parts (e.g. the M4 `data-checkpoint` resume handle).\n return chunk.type === 'data-checkpoint'\n ? paint('\\n⎇ checkpoint saved — resume with the same session id\\n', 'dim', tty)\n : ''\n }\n}\n\n/**\n * Render the `UIMessageChunk` stream to `stdout`. Sequential: one chunk → its line(s). The SDK run is\n * already paused inside the awaited `pre_tool_call` hook when a `tool-approval-request` arrives, so a\n * blocking `await onApproval(...)` here is correct — no frame buffer, no concurrency. Returns whether\n * an `error` chunk was seen so the caller can signal a non-zero exit (fail-loud, not silent exit 0).\n */\nexport async function renderAgentStreamToTerminal(\n chunks: AsyncIterable<UIMessageChunk>,\n opts: TerminalRenderOptions,\n): Promise<{ sawError: boolean }> {\n const tty = opts.stdout.isTTY\n const write = (s: string): void => {\n if (s) opts.stdout.write(s)\n }\n // toolCallId → toolName, so the approval prompt (whose chunk carries only ids) can name the tool.\n const toolNames = new Map<string, string>()\n let sawError = false\n\n for await (const chunk of chunks) {\n if (chunk.type === 'tool-approval-request') {\n const toolName = toolNames.get(chunk.toolCallId)\n await opts.onApproval({ approvalId: chunk.approvalId, toolName: toolName ?? 'tool' })\n continue\n }\n if (chunk.type === 'tool-input-available' && chunk.toolCallId) {\n toolNames.set(chunk.toolCallId, chunk.toolName)\n }\n if (chunk.type === 'error') sawError = true\n write(renderChunkLine(chunk, tty))\n }\n return { sawError }\n}\n\n/** Injectable I/O for the approval prompt (defaults to the process streams at the CLI entry). */\nexport interface PromptIO {\n input: Readable & { isTTY?: boolean }\n output: Writable & { isTTY?: boolean }\n}\n\n/**\n * Prompt `Approve <tool>? (y/N)` and resolve to the decision. A non-interactive environment (piped /\n * CI — either stream is not a TTY) AUTO-DENIES without prompting (ADR-M5b fail-safe: a decision that\n * cannot be obtained is a deny, never an auto-approve; mirrors HITL `onTimeout: 'abort'`).\n *\n * `timeoutMs` (the gated tool's `@HumanInTheLoop` timeout) auto-denies + closes the prompt when the\n * human walks away — WITHOUT it the readline question would outlive the SDK run (the registry settles\n * the run at its own timeout but readline has no timer), hanging the CLI on a now-irrelevant prompt.\n */\nexport function promptTerminalApproval(\n req: { toolName: string },\n io: PromptIO,\n timeoutMs?: number,\n): Promise<boolean> {\n if (!io.input.isTTY || !io.output.isTTY) {\n io.output.write(`\\n⚠ Non-interactive terminal — auto-denying approval for '${req.toolName}'.\\n`)\n return Promise.resolve(false)\n }\n return new Promise<boolean>((resolve) => {\n const rl = createInterface({ input: io.input, output: io.output })\n let timer: ReturnType<typeof setTimeout> | undefined\n const settle = (approved: boolean): void => {\n if (timer) clearTimeout(timer)\n rl.close()\n resolve(approved)\n }\n if (timeoutMs !== undefined && timeoutMs > 0) {\n timer = setTimeout(() => {\n io.output.write(`\\n⚠ Approval timed out — denying '${req.toolName}'.\\n`)\n settle(false)\n }, timeoutMs)\n }\n rl.question(`\\n❔ Approve ${req.toolName}? (y/N) `, (answer) => {\n const a = answer.trim().toLowerCase()\n settle(a === 'y' || a === 'yes')\n })\n })\n}\n","/**\n * M5 (theokit-ai-first) — `theokit agent <name> [message]`: run a scanned agent in the terminal.\n *\n * Scans the top-level `agents/` directory (M2), loads the matched `agents/<name>.ts` through the\n * framework's OWN Vite pipeline (the SAME transpile `theokit dev` uses — legacy `@Agent`/`@Tool`\n * decorators need it; Node's native loader can't transpile TS), resolves the provider apiKey, and\n * runs it in the terminal via the M4 harness (`runAgentInTerminal`). A dev-time surface (ADR 0039 D1),\n * not a CLI product. `deps` is injectable so the fail-fast branches are tested without Vite/an LLM.\n */\nimport { loadEnv } from '../../config/load-env.js'\nimport { resolveProvider } from '../../server/agent/provider-resolver.js'\nimport { runAgentInTerminal } from '../../server/agent/run-terminal-agent.js'\nimport { scanAgents } from '../../server/scan/agent-scan.js'\n\nexport interface AgentCommandDeps {\n projectRoot?: string\n /** Load a TS agent module; defaults to a fresh minimal Vite SSR server (framework transpile). */\n loadModule?: (filePath: string) => Promise<Record<string, unknown>>\n runAgent?: typeof runAgentInTerminal\n resolveApiKey?: () => string\n}\n\nexport async function agentCommand(\n name: string,\n message: string | undefined,\n deps: AgentCommandDeps = {},\n): Promise<{ sawError: boolean }> {\n if (!message || message.trim().length === 0) {\n throw new Error('theokit agent: a message is required. Usage: theokit agent <name> \"<message>\"')\n }\n const projectRoot = deps.projectRoot ?? process.cwd()\n const agents = scanAgents(projectRoot)\n const agent = agents.find((a) => a.name === name)\n if (!agent) {\n const names = agents.map((a) => a.name).join(', ') || '(none found in agents/)'\n throw new Error(`theokit agent: '${name}' not found. Available agents: ${names}`)\n }\n\n const runAgent = deps.runAgent ?? runAgentInTerminal\n // Load .env into process.env BEFORE resolving the provider key — parity with `theokit dev`\n // (dev.ts loadEnv), so an app with OPENROUTER_API_KEY in .env works here too (review H1). Skipped\n // when the key is injected (tests) — a temp project has no .env anyway.\n const apiKey =\n deps.resolveApiKey?.() ??\n (() => {\n loadEnv({ cwd: projectRoot, mode: 'development' })\n return resolveProvider().apiKey\n })()\n\n let loadModule = deps.loadModule\n let dispose: (() => Promise<void>) | undefined\n if (!loadModule) {\n const loader = await createAgentSsrLoader(projectRoot)\n loadModule = loader.load\n dispose = loader.dispose\n }\n\n try {\n const mod = await loadModule(agent.filePath)\n return await runAgent(mod, apiKey, { message, source: agent.filePath })\n } finally {\n if (dispose) await dispose()\n }\n}\n\n/**\n * A minimal middleware-mode Vite server built from the SAME `theoPluginAsync` plugin set `theokit dev`\n * uses (`cli/commands/dev.ts`) — so a class-decorated `agents/<name>.ts` transpiles identically. No\n * HTTP listen, no service orchestration, silent — just `ssrLoadModule`. Caller MUST `dispose()`.\n */\nexport async function createAgentSsrLoader(projectRoot: string): Promise<{\n load: (p: string) => Promise<Record<string, unknown>>\n dispose: () => Promise<void>\n}> {\n const { createServer } = await import('vite')\n const react = (await import('@vitejs/plugin-react')).default\n const { theoPluginAsync } = await import('../../vite-plugin/index.js')\n const { loadConfig } = await import('../../config/load-config.js')\n // Pass the project's ssr/services/optimizeDeps config through, exactly as dev.ts does — so an app\n // that customizes ssr.noExternal transpiles here identically to `theokit dev` (review L1).\n const config = await loadConfig(projectRoot)\n const theoPlugins = await theoPluginAsync({\n root: projectRoot,\n ssr: config.ssr,\n services: config.services,\n viteOptimizeDeps: config.viteOptimizeDeps,\n })\n const server = await createServer({\n root: projectRoot,\n plugins: [react(), ...theoPlugins],\n server: { middlewareMode: true },\n appType: 'custom',\n logLevel: 'silent',\n })\n return {\n load: (p) => server.ssrLoadModule(p) as Promise<Record<string, unknown>>,\n dispose: async () => {\n // Surface a cleanup failure instead of swallowing it (error-handling.md) — non-fatal, the run\n // already finished, so warn rather than throw past the CLI boundary.\n await server.close().catch((err: unknown) => {\n console.warn('[theokit agent] Vite server cleanup error:', err)\n })\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAUA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;;;ACJP,SAAS,uBAAuB;AAMhC,IAAM,OAAO;AAAA,EACX,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACT;AACA,SAAS,MAAM,MAAc,OAA0B,KAAkC;AACvF,SAAO,MAAM,GAAG,KAAK,KAAK,CAAC,GAAG,IAAI,GAAG,KAAK,KAAK,KAAK;AACtD;AAYA,SAAS,QAAQ,OAAwB;AACvC,SAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,SAAS,CAAC,CAAC;AACvE;AAOA,SAAS,gBAAgB,OAAuB,KAAkC;AAChF,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,MAAM,MAAM,OAAO,OAAO,GAAG;AAAA,IACtC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,MAAM;AAAA,SAAO,MAAM,QAAQ,IAAI,QAAQ,MAAM,KAAK,CAAC;AAAA,GAAO,QAAQ,GAAG;AAAA,IAC9E,KAAK;AACH,aAAO,MAAM,YAAO,QAAQ,MAAM,MAAM,CAAC;AAAA,GAAM,SAAS,GAAG;AAAA,IAC7D,KAAK;AACH,aAAO,MAAM,YAAO,MAAM,SAAS;AAAA,GAAM,OAAO,GAAG;AAAA,IACrD,KAAK;AACH,aAAO,MAAM;AAAA,SAAO,MAAM,SAAS;AAAA,GAAM,OAAO,GAAG;AAAA,IACrD;AAEE,aAAO,MAAM,SAAS,oBAClB,MAAM,sEAA4D,OAAO,GAAG,IAC5E;AAAA,EACR;AACF;AAQA,eAAsB,4BACpB,QACA,MACgC;AAChC,QAAM,MAAM,KAAK,OAAO;AACxB,QAAM,QAAQ,CAAC,MAAoB;AACjC,QAAI,EAAG,MAAK,OAAO,MAAM,CAAC;AAAA,EAC5B;AAEA,QAAM,YAAY,oBAAI,IAAoB;AAC1C,MAAI,WAAW;AAEf,mBAAiB,SAAS,QAAQ;AAChC,QAAI,MAAM,SAAS,yBAAyB;AAC1C,YAAM,WAAW,UAAU,IAAI,MAAM,UAAU;AAC/C,YAAM,KAAK,WAAW,EAAE,YAAY,MAAM,YAAY,UAAU,YAAY,OAAO,CAAC;AACpF;AAAA,IACF;AACA,QAAI,MAAM,SAAS,0BAA0B,MAAM,YAAY;AAC7D,gBAAU,IAAI,MAAM,YAAY,MAAM,QAAQ;AAAA,IAChD;AACA,QAAI,MAAM,SAAS,QAAS,YAAW;AACvC,UAAM,gBAAgB,OAAO,GAAG,CAAC;AAAA,EACnC;AACA,SAAO,EAAE,SAAS;AACpB;AAiBO,SAAS,uBACd,KACA,IACA,WACkB;AAClB,MAAI,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,OAAO;AACvC,OAAG,OAAO,MAAM;AAAA,oEAA6D,IAAI,QAAQ;AAAA,CAAM;AAC/F,WAAO,QAAQ,QAAQ,KAAK;AAAA,EAC9B;AACA,SAAO,IAAI,QAAiB,CAAC,YAAY;AACvC,UAAM,KAAK,gBAAgB,EAAE,OAAO,GAAG,OAAO,QAAQ,GAAG,OAAO,CAAC;AACjE,QAAI;AACJ,UAAM,SAAS,CAAC,aAA4B;AAC1C,UAAI,MAAO,cAAa,KAAK;AAC7B,SAAG,MAAM;AACT,cAAQ,QAAQ;AAAA,IAClB;AACA,QAAI,cAAc,UAAa,YAAY,GAAG;AAC5C,cAAQ,WAAW,MAAM;AACvB,WAAG,OAAO,MAAM;AAAA,4CAAqC,IAAI,QAAQ;AAAA,CAAM;AACvE,eAAO,KAAK;AAAA,MACd,GAAG,SAAS;AAAA,IACd;AACA,OAAG,SAAS;AAAA,iBAAe,IAAI,QAAQ,YAAY,CAAC,WAAW;AAC7D,YAAM,IAAI,OAAO,KAAK,EAAE,YAAY;AACpC,aAAO,MAAM,OAAO,MAAM,KAAK;AAAA,IACjC,CAAC;AAAA,EACH,CAAC;AACH;;;AD3GA,eAAsB,mBACpB,KACA,QACA,OACgC;AAChC,QAAM,WAAW,mBAAmB,KAAK,MAAM,MAAM;AACrD,QAAM,SAAS,MAAM,UAAU,QAAQ;AACvC,QAAM,WAAW,MAAM,YAAY,oBAAoB;AACvD,QAAM,YAAY,MAAM,aAAa,OAAO,WAAW;AACvD,QAAM,iBACJ,MAAM,mBACL,CAAC,QACA,uBAAuB,KAAK,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,GAAG,IAAI,SAAS;AAG/F,QAAM,QAAQ,SAAS;AACvB,QAAM,OACJ,SAAS,MAAM,OAAO,IAClB;AAAA,IACE;AAAA,IACA,eAAe,CAAC,YAAoB,SAClC,SAAS,SAAS,YAAY;AAAA,MAC5B,WAAW,KAAK,WAAW;AAAA,MAC3B,WAAW,KAAK,aAAa;AAAA,IAC/B,CAAC;AAAA,EACL,IACA;AAEN,QAAM,SAAS,sBAAsB,UAAU,QAAQ;AAAA,IACrD,SAAS,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF,CAAC;AACD,SAAO,4BAA4B,QAAQ;AAAA,IACzC;AAAA,IACA,YAAY,OAAO,EAAE,YAAY,SAAS,MAAM;AAI9C,YAAM,YAAY,OAAO,IAAI,QAAQ,GAAG,WAAW;AACnD,YAAM,WAAW,MAAM,eAAe,EAAE,UAAU,UAAU,CAAC;AAC7D,eAAS,QAAQ,YAAY,QAAQ;AAAA,IACvC;AAAA,EACF,CAAC;AACH;;;AEhEA,eAAsB,aACpB,MACA,SACA,OAAyB,CAAC,GACM;AAChC,MAAI,CAAC,WAAW,QAAQ,KAAK,EAAE,WAAW,GAAG;AAC3C,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AACA,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AACpD,QAAM,SAAS,WAAW,WAAW;AACrC,QAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChD,MAAI,CAAC,OAAO;AACV,UAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK;AACtD,UAAM,IAAI,MAAM,mBAAmB,IAAI,kCAAkC,KAAK,EAAE;AAAA,EAClF;AAEA,QAAM,WAAW,KAAK,YAAY;AAIlC,QAAM,SACJ,KAAK,gBAAgB,MACpB,MAAM;AACL,YAAQ,EAAE,KAAK,aAAa,MAAM,cAAc,CAAC;AACjD,WAAO,gBAAgB,EAAE;AAAA,EAC3B,GAAG;AAEL,MAAI,aAAa,KAAK;AACtB,MAAI;AACJ,MAAI,CAAC,YAAY;AACf,UAAM,SAAS,MAAM,qBAAqB,WAAW;AACrD,iBAAa,OAAO;AACpB,cAAU,OAAO;AAAA,EACnB;AAEA,MAAI;AACF,UAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC3C,WAAO,MAAM,SAAS,KAAK,QAAQ,EAAE,SAAS,QAAQ,MAAM,SAAS,CAAC;AAAA,EACxE,UAAE;AACA,QAAI,QAAS,OAAM,QAAQ;AAAA,EAC7B;AACF;AAOA,eAAsB,qBAAqB,aAGxC;AACD,QAAM,EAAE,aAAa,IAAI,MAAM,OAAO,MAAM;AAC5C,QAAM,SAAS,MAAM,OAAO,sBAAsB,GAAG;AACrD,QAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,2BAA4B;AACrE,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,2BAA6B;AAGjE,QAAM,SAAS,MAAM,WAAW,WAAW;AAC3C,QAAM,cAAc,MAAM,gBAAgB;AAAA,IACxC,MAAM;AAAA,IACN,KAAK,OAAO;AAAA,IACZ,UAAU,OAAO;AAAA,IACjB,kBAAkB,OAAO;AAAA,EAC3B,CAAC;AACD,QAAM,SAAS,MAAM,aAAa;AAAA,IAChC,MAAM;AAAA,IACN,SAAS,CAAC,MAAM,GAAG,GAAG,WAAW;AAAA,IACjC,QAAQ,EAAE,gBAAgB,KAAK;AAAA,IAC/B,SAAS;AAAA,IACT,UAAU;AAAA,EACZ,CAAC;AACD,SAAO;AAAA,IACL,MAAM,CAAC,MAAM,OAAO,cAAc,CAAC;AAAA,IACnC,SAAS,YAAY;AAGnB,YAAM,OAAO,MAAM,EAAE,MAAM,CAAC,QAAiB;AAC3C,gBAAQ,KAAK,8CAA8C,GAAG;AAAA,MAChE,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server/agent/run-terminal-agent.ts","../src/server/agent/render-terminal.ts","../src/cli/commands/agent.ts"],"sourcesContent":["/**\n * M5 (theokit-ai-first) — run a compiled agent in the terminal, reusing the M4 harness.\n *\n * The web `mountAgent` renders `streamAgentUIMessages` to an HTTP `Response` and resolves HITL\n * approvals via the approve route. This is its terminal sibling: SAME `compileAgentModule` + SAME\n * `streamAgentUIMessages` + SAME in-process approval registry — only the render surface (stdout) and\n * the approval input (a readline prompt) differ (ADR 0039 D2). In a single-process CLI the stream's\n * `awaitApproval` (→ `registry.register`) and the terminal prompt (→ `registry.resolve`) share the one\n * in-process registry — the M4 singleton's exact fit. No new runtime, no LLM call, no tool dispatch.\n */\nimport {\n compileAgentModule,\n streamAgentUIMessages,\n type HumanInTheLoopOptions,\n} from '@theokit/agents'\n\nimport { getApprovalRegistry, type ApprovalRegistry } from './approval-registry.js'\nimport {\n promptTerminalApproval,\n renderAgentStreamToTerminal,\n type TerminalOut,\n} from './render-terminal.js'\n\nexport interface RunTerminalAgentInput {\n message: string\n /** Resume key; a fresh id per run when omitted. */\n sessionId?: string\n /** Injectable sink (defaults to `process.stdout` at the CLI entry). */\n stdout?: TerminalOut\n /** Injectable shared registry (defaults to the process singleton). */\n registry?: ApprovalRegistry\n /** Injectable approval prompt (defaults to the readline prompt over the process streams). */\n promptApproval?: (req: { toolName: string; timeoutMs?: number }) => Promise<boolean>\n /** Labels a fail-fast `AgentDefinitionError` (the file path). */\n source?: string\n}\n\n/**\n * Compile the module (M4, gathers `@Mixin` toolboxes), stream it, and render to the terminal. When the\n * agent has `@HumanInTheLoop`-gated tools, the terminal prompts and resolves the shared registry —\n * approve runs the tool, deny/timeout/non-TTY denies and the run continues.\n */\nexport async function runAgentInTerminal(\n mod: unknown,\n apiKey: string,\n input: RunTerminalAgentInput,\n): Promise<{ sawError: boolean }> {\n const compiled = compileAgentModule(mod, input.source)\n const stdout = input.stdout ?? process.stdout\n const registry = input.registry ?? getApprovalRegistry()\n const sessionId = input.sessionId ?? crypto.randomUUID()\n const promptApproval =\n input.promptApproval ??\n ((req: { toolName: string; timeoutMs?: number }) =>\n promptTerminalApproval(req, { input: process.stdin, output: process.stdout }, req.timeoutMs))\n\n // Mirror mount-agent's HITL wiring; absent ⇒ the non-HITL stream path (M2), unchanged.\n const gated = compiled.hitl\n const hitl =\n gated && gated.size > 0\n ? {\n gated,\n awaitApproval: (approvalId: string, opts: HumanInTheLoopOptions) =>\n registry.register(approvalId, {\n timeoutMs: opts.timeout ?? 300_000,\n onTimeout: opts.onTimeout ?? 'abort',\n }),\n }\n : undefined\n\n const chunks = streamAgentUIMessages(compiled, apiKey, {\n message: input.message,\n sessionId,\n hitl,\n })\n return renderAgentStreamToTerminal(chunks, {\n stdout,\n onApproval: async ({ approvalId, toolName }) => {\n // The renderer paused here (the SDK run is paused in its awaited pre_tool_call hook); prompt,\n // then resolve the SAME registry the stream registered into — the run resumes with the decision.\n // The prompt shares the gated tool's timeout so it can never outlive the registry-settled run.\n const timeoutMs = gated?.get(toolName)?.timeout ?? 300_000\n const approved = await promptApproval({ toolName, timeoutMs })\n registry.resolve(approvalId, approved)\n },\n })\n}\n","/**\n * M5 (theokit-ai-first) — the terminal render surface for the M4 agent harness.\n *\n * Consumes the M4 `UIMessageChunk` stream (`streamAgentUIMessages`) and writes it to the terminal:\n * streaming text, a dim reasoning line, `▸ tool(input)` / result cards, a checkpoint notice, errors.\n * On a HITL `tool-approval-request` it delegates to the injected `onApproval` (the entry wires that to\n * a readline prompt + the approval registry). This is the ONLY new code M5 adds — no runtime, no LLM\n * call, no tool dispatch (ADR 0039 D2). I/O is INJECTED (`stdout`, prompt streams) so the whole\n * surface is deterministically testable without a TTY (ADR 0039 D4 / ADR-M5a).\n */\nimport { createInterface } from 'node:readline'\nimport type { Readable, Writable } from 'node:stream'\n\nimport type { UIMessageChunk } from 'ai'\n\n/** ANSI helpers — applied only on a TTY so a captured (non-TTY) sink stays plain-text for tests. */\nconst ANSI = {\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n green: '\\x1b[32m',\n reset: '\\x1b[0m',\n}\nfunction paint(text: string, color: keyof typeof ANSI, tty: boolean | undefined): string {\n return tty ? `${ANSI[color]}${text}${ANSI.reset}` : text\n}\n\n/** A stdout-like sink; `isTTY` gates color (Node's `process.stdout` carries it, a test sink does not). */\nexport type TerminalOut = Writable & { isTTY?: boolean }\n\nexport interface TerminalRenderOptions {\n stdout: TerminalOut\n /** Resolve a HITL approval (the entry prompts + resolves the registry). */\n onApproval: (req: { approvalId: string; toolName: string }) => Promise<void>\n}\n\n/** Render an `unknown` tool output/input for display (string as-is; other JSON-ish values stringified). */\nfunction display(value: unknown): string {\n return typeof value === 'string' ? value : JSON.stringify(value ?? {})\n}\n\n/**\n * Map a single (non-approval) `UIMessageChunk` to its terminal line(s), or `''` for chunks that render\n * nothing (`start`/`text-start`/`reasoning-start`/…). Pure — the async loop owns approval + I/O.\n * Narrows the `ai` discriminated union directly on `chunk.type` (no cast; G3).\n */\nfunction renderChunkLine(chunk: UIMessageChunk, tty: boolean | undefined): string {\n switch (chunk.type) {\n case 'text-delta':\n return chunk.delta\n case 'text-end':\n case 'finish':\n return '\\n'\n case 'reasoning-delta':\n return paint(chunk.delta, 'dim', tty)\n case 'reasoning-end':\n return '\\n'\n case 'tool-input-available':\n return paint(`\\n▸ ${chunk.toolName}(${display(chunk.input)})\\n`, 'cyan', tty)\n case 'tool-output-available':\n return paint(` ✓ ${display(chunk.output)}\\n`, 'green', tty)\n case 'tool-output-error':\n return paint(` ✗ ${chunk.errorText}\\n`, 'red', tty)\n case 'error':\n return paint(`\\n✗ ${chunk.errorText}\\n`, 'red', tty)\n default:\n // ai-sdk `data-*` transient parts (e.g. the M4 `data-checkpoint` resume handle).\n return chunk.type === 'data-checkpoint'\n ? paint('\\n⎇ checkpoint saved — resume with the same session id\\n', 'dim', tty)\n : ''\n }\n}\n\n/**\n * Render the `UIMessageChunk` stream to `stdout`. Sequential: one chunk → its line(s). The SDK run is\n * already paused inside the awaited `pre_tool_call` hook when a `tool-approval-request` arrives, so a\n * blocking `await onApproval(...)` here is correct — no frame buffer, no concurrency. Returns whether\n * an `error` chunk was seen so the caller can signal a non-zero exit (fail-loud, not silent exit 0).\n */\nexport async function renderAgentStreamToTerminal(\n chunks: AsyncIterable<UIMessageChunk>,\n opts: TerminalRenderOptions,\n): Promise<{ sawError: boolean }> {\n const tty = opts.stdout.isTTY\n const write = (s: string): void => {\n if (s) opts.stdout.write(s)\n }\n // toolCallId → toolName, so the approval prompt (whose chunk carries only ids) can name the tool.\n const toolNames = new Map<string, string>()\n let sawError = false\n\n for await (const chunk of chunks) {\n if (chunk.type === 'tool-approval-request') {\n const toolName = toolNames.get(chunk.toolCallId)\n await opts.onApproval({ approvalId: chunk.approvalId, toolName: toolName ?? 'tool' })\n continue\n }\n if (chunk.type === 'tool-input-available' && chunk.toolCallId) {\n toolNames.set(chunk.toolCallId, chunk.toolName)\n }\n if (chunk.type === 'error') sawError = true\n write(renderChunkLine(chunk, tty))\n }\n return { sawError }\n}\n\n/** Injectable I/O for the approval prompt (defaults to the process streams at the CLI entry). */\nexport interface PromptIO {\n input: Readable & { isTTY?: boolean }\n output: Writable & { isTTY?: boolean }\n}\n\n/**\n * Prompt `Approve <tool>? (y/N)` and resolve to the decision. A non-interactive environment (piped /\n * CI — either stream is not a TTY) AUTO-DENIES without prompting (ADR-M5b fail-safe: a decision that\n * cannot be obtained is a deny, never an auto-approve; mirrors HITL `onTimeout: 'abort'`).\n *\n * `timeoutMs` (the gated tool's `@HumanInTheLoop` timeout) auto-denies + closes the prompt when the\n * human walks away — WITHOUT it the readline question would outlive the SDK run (the registry settles\n * the run at its own timeout but readline has no timer), hanging the CLI on a now-irrelevant prompt.\n */\nexport function promptTerminalApproval(\n req: { toolName: string },\n io: PromptIO,\n timeoutMs?: number,\n): Promise<boolean> {\n if (!io.input.isTTY || !io.output.isTTY) {\n io.output.write(`\\n⚠ Non-interactive terminal — auto-denying approval for '${req.toolName}'.\\n`)\n return Promise.resolve(false)\n }\n return new Promise<boolean>((resolve) => {\n const rl = createInterface({ input: io.input, output: io.output })\n let timer: ReturnType<typeof setTimeout> | undefined\n const settle = (approved: boolean): void => {\n if (timer) clearTimeout(timer)\n rl.close()\n resolve(approved)\n }\n if (timeoutMs !== undefined && timeoutMs > 0) {\n timer = setTimeout(() => {\n io.output.write(`\\n⚠ Approval timed out — denying '${req.toolName}'.\\n`)\n settle(false)\n }, timeoutMs)\n }\n rl.question(`\\n❔ Approve ${req.toolName}? (y/N) `, (answer) => {\n const a = answer.trim().toLowerCase()\n settle(a === 'y' || a === 'yes')\n })\n })\n}\n","/**\n * M5 (theokit-ai-first) — `theokit agent <name> [message]`: run a scanned agent in the terminal.\n *\n * Scans the top-level `agents/` directory (M2), loads the matched `agents/<name>.ts` through the\n * framework's OWN Vite pipeline (the SAME transpile `theokit dev` uses — legacy `@Agent`/`@Tool`\n * decorators need it; Node's native loader can't transpile TS), resolves the provider apiKey, and\n * runs it in the terminal via the M4 harness (`runAgentInTerminal`). A dev-time surface (ADR 0039 D1),\n * not a CLI product. `deps` is injectable so the fail-fast branches are tested without Vite/an LLM.\n */\nimport { loadEnv } from '../../config/load-env.js'\nimport { resolveProvider } from '../../server/agent/provider-resolver.js'\nimport { runAgentInTerminal } from '../../server/agent/run-terminal-agent.js'\nimport { scanAgents } from '../../server/scan/agent-scan.js'\n\nexport interface AgentCommandDeps {\n projectRoot?: string\n /** Load a TS agent module; defaults to a fresh minimal Vite SSR server (framework transpile). */\n loadModule?: (filePath: string) => Promise<Record<string, unknown>>\n runAgent?: typeof runAgentInTerminal\n resolveApiKey?: () => string\n}\n\nexport async function agentCommand(\n name: string,\n message: string | undefined,\n deps: AgentCommandDeps = {},\n): Promise<{ sawError: boolean }> {\n if (!message || message.trim().length === 0) {\n throw new Error('theokit agent: a message is required. Usage: theokit agent <name> \"<message>\"')\n }\n const projectRoot = deps.projectRoot ?? process.cwd()\n const agents = scanAgents(projectRoot)\n const agent = agents.find((a) => a.name === name)\n if (!agent) {\n const names = agents.map((a) => a.name).join(', ') || '(none found in agents/)'\n throw new Error(`theokit agent: '${name}' not found. Available agents: ${names}`)\n }\n\n const runAgent = deps.runAgent ?? runAgentInTerminal\n // Load .env into process.env BEFORE resolving the provider key — parity with `theokit dev`\n // (dev.ts loadEnv), so an app with OPENROUTER_API_KEY in .env works here too (review H1). Skipped\n // when the key is injected (tests) — a temp project has no .env anyway.\n const apiKey =\n deps.resolveApiKey?.() ??\n (() => {\n loadEnv({ cwd: projectRoot, mode: 'development' })\n return resolveProvider().apiKey\n })()\n\n let loadModule = deps.loadModule\n let dispose: (() => Promise<void>) | undefined\n if (!loadModule) {\n const loader = await createAgentSsrLoader(projectRoot)\n loadModule = loader.load\n dispose = loader.dispose\n }\n\n try {\n const mod = await loadModule(agent.filePath)\n return await runAgent(mod, apiKey, { message, source: agent.filePath })\n } finally {\n if (dispose) await dispose()\n }\n}\n\n/**\n * A minimal middleware-mode Vite server built from the SAME `theoPluginAsync` plugin set `theokit dev`\n * uses (`cli/commands/dev.ts`) — so a class-decorated `agents/<name>.ts` transpiles identically. No\n * HTTP listen, no service orchestration, silent — just `ssrLoadModule`. Caller MUST `dispose()`.\n */\nexport async function createAgentSsrLoader(projectRoot: string): Promise<{\n load: (p: string) => Promise<Record<string, unknown>>\n dispose: () => Promise<void>\n}> {\n const { createServer } = await import('vite')\n const react = (await import('@vitejs/plugin-react')).default\n const { theoPluginAsync } = await import('../../vite-plugin/index.js')\n const { loadConfig } = await import('../../config/load-config.js')\n // Pass the project's ssr/services/optimizeDeps config through, exactly as dev.ts does — so an app\n // that customizes ssr.noExternal transpiles here identically to `theokit dev` (review L1).\n const config = await loadConfig(projectRoot)\n const theoPlugins = await theoPluginAsync({\n root: projectRoot,\n ssr: config.ssr,\n services: config.services,\n viteOptimizeDeps: config.viteOptimizeDeps,\n // #95 — honor config `serverDir` so the terminal SSR loader transpiles under the same root as dev.\n serverDir: config.serverDir,\n })\n const server = await createServer({\n root: projectRoot,\n plugins: [react(), ...theoPlugins],\n server: { middlewareMode: true },\n appType: 'custom',\n logLevel: 'silent',\n })\n return {\n load: (p) => server.ssrLoadModule(p) as Promise<Record<string, unknown>>,\n dispose: async () => {\n // Surface a cleanup failure instead of swallowing it (error-handling.md) — non-fatal, the run\n // already finished, so warn rather than throw past the CLI boundary.\n await server.close().catch((err: unknown) => {\n console.warn('[theokit agent] Vite server cleanup error:', err)\n })\n },\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -865,7 +865,7 @@ async function runConfigureServer(server, ctx) {
|
|
|
865
865
|
} catch {
|
|
866
866
|
}
|
|
867
867
|
});
|
|
868
|
-
const serverDir =
|
|
868
|
+
const serverDir = ctx.serverDir;
|
|
869
869
|
server.middlewares.use(
|
|
870
870
|
createActionMiddleware(server, serverDir, {
|
|
871
871
|
pluginRunner: ctx.pluginRunner,
|
|
@@ -1889,6 +1889,7 @@ function findConsumerConfig(projectRoot, basename2) {
|
|
|
1889
1889
|
async function theoPluginAsync(rootOrOptions) {
|
|
1890
1890
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
1891
1891
|
const projectRoot = options.root ?? process.cwd();
|
|
1892
|
+
const serverDirAbs = resolve7(projectRoot, options.serverDir ?? "server");
|
|
1892
1893
|
const consumerTailwindConfig = findConsumerConfig(projectRoot, "tailwind.config");
|
|
1893
1894
|
const consumerPostcssConfig = findConsumerConfig(projectRoot, "postcss.config");
|
|
1894
1895
|
const uiPlugins = await integrateUseTheoUI(projectRoot, {
|
|
@@ -1908,12 +1909,12 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
1908
1909
|
const { appTypedClientPlugin } = await import("./app-typed-client-X6WKTFX2.js");
|
|
1909
1910
|
const appClientPlugin = appTypedClientPlugin({
|
|
1910
1911
|
cwd: projectRoot,
|
|
1911
|
-
serverDir:
|
|
1912
|
+
serverDir: serverDirAbs,
|
|
1912
1913
|
distDir: resolve7(projectRoot, ".theokit")
|
|
1913
1914
|
});
|
|
1914
1915
|
const { actionsVirtualModule } = await import("./actions-virtual-module-HD3D75C2.js");
|
|
1915
1916
|
const actionsPlugin = actionsVirtualModule({
|
|
1916
|
-
serverDir:
|
|
1917
|
+
serverDir: serverDirAbs,
|
|
1917
1918
|
distDir: resolve7(projectRoot, ".theokit")
|
|
1918
1919
|
});
|
|
1919
1920
|
const { agentsTypedClientPlugin } = await import("./agents-typed-client-LQ36PCHL.js");
|
|
@@ -1923,11 +1924,11 @@ async function theoPluginAsync(rootOrOptions) {
|
|
|
1923
1924
|
distDir: resolve7(projectRoot, ".theokit"),
|
|
1924
1925
|
// Agents live at <projectRoot>/agents; generateManifest scans them via the server dir's
|
|
1925
1926
|
// parent, which is projectRoot for the canonical layout.
|
|
1926
|
-
scanManifest: () => generateManifest(
|
|
1927
|
+
scanManifest: () => generateManifest(serverDirAbs, projectRoot)
|
|
1927
1928
|
});
|
|
1928
1929
|
const { serverRoutesHmrPlugin } = await import("./server-routes-hmr-VZXOP5YT.js");
|
|
1929
1930
|
const routesHmrPlugin = serverRoutesHmrPlugin({
|
|
1930
|
-
serverDir:
|
|
1931
|
+
serverDir: serverDirAbs
|
|
1931
1932
|
});
|
|
1932
1933
|
return [
|
|
1933
1934
|
theoPlugin(rootOrOptions),
|
|
@@ -1971,6 +1972,7 @@ function theoPlugin(rootOrOptions) {
|
|
|
1971
1972
|
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
1972
1973
|
const projectRoot = options.root ?? process.cwd();
|
|
1973
1974
|
const appDir = resolve7(projectRoot, "app");
|
|
1975
|
+
const serverDir = resolve7(projectRoot, options.serverDir ?? "server");
|
|
1974
1976
|
const ssrEnabled = options.ssr ?? false;
|
|
1975
1977
|
const currentDir = dirname4(fileURLToPath(import.meta.url));
|
|
1976
1978
|
const theoSrcDir = resolveTheoRootDir(currentDir);
|
|
@@ -2057,6 +2059,7 @@ function theoPlugin(rootOrOptions) {
|
|
|
2057
2059
|
await runConfigureServer(server, {
|
|
2058
2060
|
projectRoot,
|
|
2059
2061
|
appDir,
|
|
2062
|
+
serverDir,
|
|
2060
2063
|
resolvedDistDir,
|
|
2061
2064
|
ssrEnabled,
|
|
2062
2065
|
isDevMode: isDevModeRef,
|
|
@@ -2087,4 +2090,4 @@ export {
|
|
|
2087
2090
|
theoPluginAsync,
|
|
2088
2091
|
theoPlugin
|
|
2089
2092
|
};
|
|
2090
|
-
//# sourceMappingURL=chunk-
|
|
2093
|
+
//# sourceMappingURL=chunk-RRJ66UTS.js.map
|