@happyvertical/smrt-core 0.56.0 → 0.56.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/generators.md +37 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -1
- package/dist/cookbook/engine/commands.d.ts.map +1 -1
- package/dist/cookbook/engine/commands.js +12 -0
- package/dist/cookbook/engine/commands.js.map +1 -1
- package/dist/cookbook/engine/defaults.d.ts.map +1 -1
- package/dist/cookbook/engine/defaults.js +8 -0
- package/dist/cookbook/engine/defaults.js.map +1 -1
- package/dist/cookbook/engine/document.d.ts +4 -0
- package/dist/cookbook/engine/document.d.ts.map +1 -1
- package/dist/cookbook/engine/document.js +11 -3
- package/dist/cookbook/engine/document.js.map +1 -1
- package/dist/cookbook/engine/engine.d.ts.map +1 -1
- package/dist/cookbook/engine/engine.js +3 -1
- package/dist/cookbook/engine/engine.js.map +1 -1
- package/dist/cookbook/engine/schemas.d.ts.map +1 -1
- package/dist/cookbook/engine/schemas.js +8 -0
- package/dist/cookbook/engine/schemas.js.map +1 -1
- package/dist/cookbook/engine/types.d.ts +5 -1
- package/dist/cookbook/engine/types.d.ts.map +1 -1
- package/dist/cookbook/engine/types.js.map +1 -1
- package/dist/generators/index.d.ts +1 -0
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +2 -1
- package/dist/generators/mcp-runtime-template.d.ts +3 -0
- package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
- package/dist/generators/mcp-runtime-template.js +30 -4
- package/dist/generators/mcp-runtime-template.js.map +1 -1
- package/dist/generators/mcp.d.ts +5 -0
- package/dist/generators/mcp.d.ts.map +1 -1
- package/dist/generators/mcp.js +78 -7
- package/dist/generators/mcp.js.map +1 -1
- package/dist/generators.js +2 -1
- package/dist/index.js +2 -1
- package/dist/manifest/browser-capability.generated.js +34 -5
- package/dist/manifest/browser-capability.generated.js.map +1 -1
- package/dist/manifest/index.js +1 -1
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/mcp-serializer.d.ts +38 -0
- package/dist/mcp-serializer.d.ts.map +1 -0
- package/dist/mcp-serializer.js +60 -0
- package/dist/mcp-serializer.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/index.js +34 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/index.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/errors.js +343 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/errors.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/get-format.js +109 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/get-format.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/package-json-reader.js +102 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/package-json-reader.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/resolve.js +673 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/resolve.js.map +1 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/utils.js +32 -0
- package/dist/node_modules/.pnpm/import-meta-resolve@4.2.0/node_modules/import-meta-resolve/lib/utils.js.map +1 -0
- package/dist/registry/types.d.ts +13 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +7 -5
- package/dist/utils/import-project-vite.js +1 -1
- package/dist/utils/import-workspace-module.js +1 -1
- package/dist/vite-plugin/dev-plane-route.js +1 -1
- package/dist/vite-plugin/import-build-aware.js +1 -1
- package/dist/vite-plugin/index.js +1 -1
- package/dist/vite-plugin/resources-route.js +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +1 -1
- package/package.json +16 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","names":[],"sources":["../../../src/cookbook/engine/engine.ts"],"sourcesContent":["import { validateCookbook } from '../validate.js';\nimport {\n adopt,\n execute,\n libraryName,\n type Outcome,\n type PlanState,\n} from './commands.js';\nimport { DEFAULT_APP_NAME, DEFAULT_COLOR_SCHEME } from './defaults.js';\nimport {\n clone,\n describeTheme,\n emptyCookbook,\n readSettings,\n same,\n} from './document.js';\nimport { buildNav } from './nav.js';\nimport {\n buildBatchTool,\n buildCommandTools,\n type CommandSchemas,\n checkSchema,\n commandSchemas,\n} from './schemas.js';\nimport {\n type BatchResult,\n COOKBOOK_COMMANDS_VERSION,\n type CommandBatch,\n type CommandError,\n type CommandName,\n type CommandResult,\n type CommandTool,\n type EngineCatalog,\n type EngineState,\n type JournalEntry,\n type JsonSchema,\n type PlanSnapshot,\n type RunOptions,\n} from './types.js';\n\nexport interface CookbookEngineOptions {\n catalog: EngineCatalog;\n /** Start from this document (strictly checked; the call throws if invalid). */\n cookbook?: unknown;\n /** Resume from a saved {@link EngineState} (wins over `cookbook`). */\n state?: EngineState;\n /** How many command ids are remembered for retries; default 500. */\n maxJournal?: number;\n /** How many undo entries are kept; default 20. */\n maxUndo?: number;\n /** Optional namespace for process-local undo handles; default `undo`. */\n undoPrefix?: string;\n}\n\n/**\n * The cookbook command engine: typed, versioned commands over one cookbook\n * document, held in plain objects. Never throws from `run`/`batch`; every\n * refusal is a typed error and leaves the document untouched.\n */\nexport interface CookbookEngine {\n /**\n * Run one command (`{ name, input, id?, expectedRevision? }`). A repeated\n * `id` returns the first result with `replayed: true` and applies nothing.\n */\n run(command: unknown, options?: RunOptions): CommandResult;\n /**\n * Run several commands all-or-nothing. On any failure the state is exactly\n * as before and the error names the failing command.\n */\n batch(batch: CommandBatch | unknown): BatchResult;\n /** The compact plan state, cheap enough for a model prompt. */\n snapshot(): PlanSnapshot;\n /** The document (a copy). */\n cookbook(): ReturnType<typeof clone<PlanState['doc']>>;\n /** Serializable state to persist and resume from, retries included. */\n state(): EngineState;\n /** Call `listener` with the snapshot now and after every change. */\n subscribe(listener: (snapshot: PlanSnapshot) => void): () => void;\n /** Command tool definitions (JSON Schema inputs), enums narrowed to the catalog. */\n readonly tools: readonly CommandTool[];\n /** The atomic-batch tool definition. */\n readonly batchTool: {\n name: 'run_batch';\n description: string;\n inputSchema: JsonSchema;\n };\n}\n\ninterface UndoEntry {\n before: PlanState;\n /** What the change left; undo is a conflict while the plan differs from it. */\n after: PlanState;\n}\n\nconst err = (\n code: CommandError['code'],\n message: string,\n extra: Pick<CommandError, 'path' | 'details'> = {},\n): CommandError => ({ code, message, ...extra });\n\n/** Key order never changes a payload's identity: `{a, b}` and `{b, a}` match. */\nconst canonical = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(canonical);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [\n key,\n canonical((value as Record<string, unknown>)[key]),\n ]),\n );\n }\n return value;\n};\n\nconst fingerprint = (value: unknown): string => {\n try {\n return JSON.stringify(canonical(value)) ?? 'undefined';\n } catch {\n return 'unserializable';\n }\n};\n\ntype Parsed =\n | { ok: true; name: CommandName; input: Record<string, unknown> }\n | { ok: false; error: CommandError };\n\nfunction readCommand(\n value: unknown,\n schemas: CommandSchemas,\n extraKeys: readonly string[],\n): Parsed {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {\n ok: false,\n error: err('unknown_command', 'A command is an object: { name, input }.'),\n };\n }\n const record = value as Record<string, unknown>;\n const { name, input = {} } = record;\n if (typeof name !== 'string' || !Object.hasOwn(schemas, name)) {\n return {\n ok: false,\n error: err('unknown_command', `Unknown command ${JSON.stringify(name)}.`),\n };\n }\n for (const key of Object.keys(record)) {\n if (key !== 'name' && key !== 'input' && !extraKeys.includes(key)) {\n return {\n ok: false,\n error: err('invalid_input', `${key} is not part of a command.`, {\n path: key,\n }),\n };\n }\n }\n const problem = checkSchema(schemas[name as CommandName], input);\n if (problem) {\n return {\n ok: false,\n error: err('invalid_input', problem.message, { path: problem.path }),\n };\n }\n return {\n ok: true,\n name: name as CommandName,\n input: input as Record<string, unknown>,\n };\n}\n\nconst checkId = (id: unknown): CommandError | null =>\n id === undefined ||\n (typeof id === 'string' && id.length > 0 && id.length <= 200)\n ? null\n : err(\n 'invalid_input',\n 'id must be a non-empty string of at most 200 characters.',\n { path: 'id' },\n );\n\nconst checkRevision = (value: unknown): CommandError | null =>\n value === undefined || (Number.isInteger(value) && (value as number) >= 0)\n ? null\n : err('invalid_input', 'expectedRevision must be a whole number.', {\n path: 'expectedRevision',\n });\n\nexport function createCookbookEngine(\n options: CookbookEngineOptions,\n): CookbookEngine {\n const { catalog } = options;\n const schemas = commandSchemas(catalog);\n const tools = buildCommandTools(catalog);\n const batchTool = buildBatchTool(catalog);\n const maxJournal = options.maxJournal ?? 500;\n const maxUndo = options.maxUndo ?? 20;\n\n let current: PlanState;\n let revision = 0;\n const journal = new Map<string, JournalEntry>();\n\n if (options.state) {\n const saved = options.state;\n const checked = validateCookbook(saved.cookbook);\n if (!checked.ok)\n throw new Error(`Invalid saved cookbook: ${checked.errors.join('; ')}`);\n if (!Number.isInteger(saved.revision) || saved.revision < 0) {\n throw new Error('Invalid saved revision.');\n }\n current = {\n doc: adopt(catalog, checked.cookbook),\n applied: saved.applied ?? null,\n };\n revision = saved.revision;\n for (const entry of saved.journal ?? [])\n journal.set(entry.id, clone(entry));\n } else if (options.cookbook !== undefined) {\n const checked = validateCookbook(options.cookbook);\n if (!checked.ok)\n throw new Error(`Invalid cookbook: ${checked.errors.join('; ')}`);\n current = { doc: adopt(catalog, checked.cookbook), applied: null };\n } else {\n current = { doc: adopt(catalog, emptyCookbook()), applied: null };\n }\n\n const undos = new Map<string, UndoEntry>();\n let undoIds: string[] = [];\n let undoCounter = 0;\n const listeners = new Map<(s: PlanSnapshot) => void, number>();\n\n function snapshotOf(state: PlanState, rev: number): PlanSnapshot {\n const { doc } = state;\n const byId = new Map(catalog.recipes.map((r) => [r.id, r]));\n const settings = readSettings(catalog, doc);\n const exposed = new Set(\n catalog.models.filter((m) => m.exposed !== false).map((m) => m.id),\n );\n return {\n version: COOKBOOK_COMMANDS_VERSION,\n revision: rev,\n app: {\n name:\n doc.name ?? libraryName(catalog, state.applied) ?? DEFAULT_APP_NAME,\n description: doc.description ?? null,\n cookbook: state.applied,\n },\n recipes: doc.recipes.flatMap((id) => {\n const recipe = byId.get(id);\n return recipe ? [{ id, label: recipe.label }] : [];\n }),\n features: doc.features.filter((id) => exposed.has(id)),\n unavailable: [\n ...doc.recipes.filter((id) => !byId.has(id)),\n ...doc.features.filter((id) => !exposed.has(id)),\n ],\n settings: {\n currency: settings.currency,\n taxRate: Number((settings.taxRate * 100).toFixed(4)),\n paymentTerms: settings.paymentTerms,\n },\n theme: {\n text: describeTheme(doc.theme),\n preset: doc.theme?.preset ?? null,\n primary: doc.theme?.custom?.primary ?? null,\n colorScheme: doc.theme?.colorScheme ?? DEFAULT_COLOR_SCHEME,\n borderRadius: doc.theme?.borderRadius ?? null,\n density: doc.theme?.density ?? null,\n contrast: doc.theme?.contrast ?? null,\n },\n sections: buildNav(catalog, doc).map((s) => ({\n id: s.id,\n label: s.label,\n hidden: s.hidden,\n items: s.items.map((i) => ({\n id: i.id,\n label: i.label,\n hidden: i.hidden,\n })),\n })),\n policies: doc.policies.length,\n undo: [...undoIds],\n };\n }\n\n const snapshot = () => snapshotOf(current, revision);\n\n function notify(): void {\n for (const [listener, last] of listeners) {\n if (last === revision) continue;\n listeners.set(listener, revision);\n listener(snapshot());\n }\n }\n\n function remember(\n id: string | undefined,\n print: string,\n result: CommandResult | BatchResult,\n ) {\n if (id === undefined) return;\n journal.set(id, { id, fingerprint: print, result: clone(result) });\n while (journal.size > maxJournal) {\n const oldest = journal.keys().next().value;\n if (oldest === undefined) break;\n journal.delete(oldest);\n }\n }\n\n function replay<R extends CommandResult | BatchResult>(\n id: string | undefined,\n print: string,\n ): R | CommandResult | null {\n if (id === undefined) return null;\n const hit = journal.get(id);\n if (!hit) return null;\n if (hit.fingerprint !== print) {\n return {\n ok: false,\n id,\n error: err(\n 'id_reuse',\n `The id \"${id}\" was already used for a different command.`,\n {\n path: 'id',\n },\n ),\n };\n }\n return { ...(clone(hit.result) as R), replayed: true };\n }\n\n function recordUndo(before: PlanState, after: PlanState): string {\n const undoId = `${options.undoPrefix ?? 'undo'}-${++undoCounter}`;\n undos.set(undoId, { before: clone(before), after: clone(after) });\n undoIds = [...undoIds, undoId].slice(-maxUndo);\n for (const key of [...undos.keys()])\n if (!undoIds.includes(key)) undos.delete(key);\n return undoId;\n }\n\n const changedBetween = (a: PlanState, b: PlanState) =>\n a.applied !== b.applied || !same(a.doc, b.doc);\n\n function toSuccess(\n id: string | undefined,\n name: CommandName,\n outcome: Extract<Outcome, { ok: true }>,\n revisionBefore: number,\n revisionAfter: number,\n snap: PlanSnapshot,\n undoId?: string,\n ): Extract<CommandResult, { ok: true }> {\n return {\n ok: true,\n ...(id !== undefined ? { id } : {}),\n snapshot: snap,\n receipt: {\n name,\n ...(id !== undefined ? { id } : {}),\n summary: revisionAfter !== revisionBefore ? outcome.summary : '',\n changed: revisionAfter !== revisionBefore,\n revisionBefore,\n revisionAfter,\n ...(undoId ? { undoId } : {}),\n ...(outcome.changes ? { changes: outcome.changes } : {}),\n ...(outcome.warnings ? { warnings: outcome.warnings } : {}),\n },\n ...(outcome.data !== undefined ? { data: outcome.data } : {}),\n };\n }\n\n function runUndo(\n id: string | undefined,\n input: { undoId: string; force?: boolean },\n ): CommandResult {\n const entry = undos.get(input.undoId);\n if (!entry) {\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: err('not_found', `Nothing to undo for \"${input.undoId}\".`, {\n path: 'input.undoId',\n }),\n };\n }\n if (!input.force && changedBetween(current, entry.after)) {\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: err(\n 'conflict',\n 'The plan changed since; send force: true to undo anyway.',\n {\n details: { currentRevision: revision },\n },\n ),\n };\n }\n const before = revision;\n const restored = clone(entry.before);\n const changed = changedBetween(current, restored);\n current = restored;\n if (changed) revision += 1;\n undos.delete(input.undoId);\n undoIds = undoIds.filter((u) => u !== input.undoId);\n const result = toSuccess(\n id,\n 'undo',\n { ok: true, state: current, summary: 'Undone.' },\n before,\n revision,\n snapshot(),\n );\n notify();\n return result;\n }\n\n function run(command: unknown, runOptions: RunOptions = {}): CommandResult {\n try {\n const raw =\n command && typeof command === 'object' && !Array.isArray(command)\n ? (command as Record<string, unknown>)\n : undefined;\n const id = raw?.id as string | undefined;\n const idProblem = checkId(id);\n if (idProblem) return { ok: false, error: idProblem };\n const expected = (raw?.expectedRevision ?? runOptions.expectedRevision) as\n | number\n | undefined;\n const revProblem = checkRevision(expected);\n if (revProblem)\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: revProblem,\n };\n\n const print = fingerprint({\n name: raw?.name,\n input: raw?.input ?? {},\n expectedRevision: expected,\n });\n const replayed = replay<CommandResult>(id, print);\n if (replayed) return replayed as CommandResult;\n\n const finish = (result: CommandResult) => {\n remember(id, print, result);\n return result;\n };\n const withId = (error: CommandError): CommandResult => ({\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error,\n });\n\n const parsed = readCommand(command, schemas, ['id', 'expectedRevision']);\n if (!parsed.ok) return finish(withId(parsed.error));\n if (expected !== undefined && expected !== revision) {\n return finish(\n withId(\n err(\n 'conflict',\n `The plan is at revision ${revision}, not ${expected}. Read the snapshot and try again.`,\n {\n details: {\n expectedRevision: expected,\n currentRevision: revision,\n },\n },\n ),\n ),\n );\n }\n if (parsed.name === 'undo') {\n return finish(\n runUndo(id, parsed.input as { undoId: string; force?: boolean }),\n );\n }\n const before = current;\n const outcome = execute(\n catalog,\n before,\n parsed.name,\n parsed.input as never,\n );\n if (!outcome.ok) return finish(withId(outcome.error));\n const revisionBefore = revision;\n const changed = changedBetween(before, outcome.state);\n let undoId: string | undefined;\n if (changed) {\n current = outcome.state;\n revision += 1;\n undoId = recordUndo(before, outcome.state);\n }\n const result = finish(\n toSuccess(\n id,\n parsed.name,\n outcome,\n revisionBefore,\n revision,\n snapshot(),\n undoId,\n ),\n );\n notify();\n return result;\n } catch (cause) {\n return {\n ok: false,\n error: err(\n 'failed',\n cause instanceof Error ? cause.message : String(cause),\n ),\n };\n }\n }\n\n function batch(input: CommandBatch | unknown): BatchResult {\n const unchanged = (error: CommandError, id?: string): BatchResult => ({\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error,\n snapshot: snapshot(),\n });\n try {\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n return unchanged(\n err('invalid_input', 'A batch is an object: { commands }.'),\n );\n }\n const raw = input as Record<string, unknown>;\n const id = raw.id as string | undefined;\n const idProblem = checkId(id);\n if (idProblem) return unchanged(idProblem);\n const revProblem = checkRevision(raw.expectedRevision);\n if (revProblem) return unchanged(revProblem, id);\n const print = fingerprint({\n commands: raw.commands,\n expectedRevision: raw.expectedRevision,\n });\n const replayed = replay<BatchResult>(id, print);\n if (replayed) {\n return 'results' in replayed || 'snapshot' in replayed\n ? (replayed as BatchResult)\n : unchanged(\n (replayed as Extract<CommandResult, { ok: false }>).error,\n id,\n );\n }\n const finish = (result: BatchResult) => {\n remember(id, print, result);\n return result;\n };\n\n const commands = raw.commands;\n if (\n !Array.isArray(commands) ||\n commands.length === 0 ||\n commands.length > 50\n ) {\n return finish(\n unchanged(\n err(\n 'invalid_input',\n 'commands must be a list of 1 to 50 commands.',\n { path: 'commands' },\n ),\n id,\n ),\n );\n }\n const expected = raw.expectedRevision as number | undefined;\n if (expected !== undefined && expected !== revision) {\n return finish(\n unchanged(\n err(\n 'conflict',\n `The plan is at revision ${revision}, not ${expected}. Read the snapshot and try again.`,\n {\n details: {\n expectedRevision: expected,\n currentRevision: revision,\n },\n },\n ),\n id,\n ),\n );\n }\n\n const failAt = (index: number, name: unknown, cause: CommandError) =>\n finish(\n unchanged(\n err(\n 'batch_failed',\n `Command ${index + 1} (${String(name)}) failed: ${cause.message}`,\n {\n path: `commands[${index}]`,\n details: { index, cause },\n },\n ),\n id,\n ),\n );\n\n // Everything runs on a working copy; the live state is replaced once, at the end.\n const base = current;\n const baseRevision = revision;\n let working = base;\n let rev = baseRevision;\n const results: Extract<CommandResult, { ok: true }>[] = [];\n for (const [index, command] of commands.entries()) {\n const parsed = readCommand(command, schemas, []);\n if (!parsed.ok)\n return failAt(\n index,\n (command as { name?: unknown })?.name,\n parsed.error,\n );\n if (parsed.name === 'undo') {\n return failAt(\n index,\n 'undo',\n err('invalid_input', 'undo cannot run inside a batch.'),\n );\n }\n const outcome = execute(\n catalog,\n working,\n parsed.name,\n parsed.input as never,\n );\n if (!outcome.ok) return failAt(index, parsed.name, outcome.error);\n const before = rev;\n if (changedBetween(working, outcome.state)) rev += 1;\n working = outcome.state;\n results.push(\n toSuccess(\n undefined,\n parsed.name,\n outcome,\n before,\n rev,\n snapshotOf(working, rev),\n ),\n );\n }\n const changed = rev !== baseRevision;\n let undoId: string | undefined;\n if (changed) {\n current = working;\n revision = rev;\n undoId = recordUndo(base, working);\n // The batch's one undo restores the state before all of it.\n for (const r of results) if (r.receipt.changed) delete r.receipt.undoId;\n }\n const result = finish({\n ok: true,\n ...(id !== undefined ? { id } : {}),\n snapshot: snapshot(),\n receipt: {\n ...(id !== undefined ? { id } : {}),\n count: results.length,\n changed,\n revisionBefore: baseRevision,\n revisionAfter: rev,\n ...(undoId ? { undoId } : {}),\n },\n results,\n });\n notify();\n return result;\n } catch (cause) {\n return unchanged(\n err('failed', cause instanceof Error ? cause.message : String(cause)),\n );\n }\n }\n\n return {\n run: run as CookbookEngine['run'],\n batch,\n snapshot,\n cookbook: () => clone(current.doc),\n state: () => ({\n version: COOKBOOK_COMMANDS_VERSION,\n revision,\n applied: current.applied,\n cookbook: clone(current.doc),\n journal: [...journal.values()].map((entry) => clone(entry)),\n }),\n subscribe(listener) {\n listeners.set(listener, revision);\n listener(snapshot());\n return () => {\n listeners.delete(listener);\n };\n },\n tools,\n batchTool,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine.js","names":[],"sources":["../../../src/cookbook/engine/engine.ts"],"sourcesContent":["import { validateCookbook } from '../validate.js';\nimport {\n adopt,\n execute,\n libraryName,\n type Outcome,\n type PlanState,\n} from './commands.js';\nimport { DEFAULT_APP_NAME, DEFAULT_COLOR_SCHEME } from './defaults.js';\nimport {\n clone,\n describeTheme,\n emptyCookbook,\n readSettings,\n same,\n} from './document.js';\nimport { buildNav } from './nav.js';\nimport {\n buildBatchTool,\n buildCommandTools,\n type CommandSchemas,\n checkSchema,\n commandSchemas,\n} from './schemas.js';\nimport {\n type BatchResult,\n COOKBOOK_COMMANDS_VERSION,\n type CommandBatch,\n type CommandError,\n type CommandName,\n type CommandResult,\n type CommandTool,\n type EngineCatalog,\n type EngineState,\n type JournalEntry,\n type JsonSchema,\n type PlanSnapshot,\n type RunOptions,\n} from './types.js';\n\nexport interface CookbookEngineOptions {\n catalog: EngineCatalog;\n /** Start from this document (strictly checked; the call throws if invalid). */\n cookbook?: unknown;\n /** Resume from a saved {@link EngineState} (wins over `cookbook`). */\n state?: EngineState;\n /** How many command ids are remembered for retries; default 500. */\n maxJournal?: number;\n /** How many undo entries are kept; default 20. */\n maxUndo?: number;\n /** Optional namespace for process-local undo handles; default `undo`. */\n undoPrefix?: string;\n}\n\n/**\n * The cookbook command engine: typed, versioned commands over one cookbook\n * document, held in plain objects. Never throws from `run`/`batch`; every\n * refusal is a typed error and leaves the document untouched.\n */\nexport interface CookbookEngine {\n /**\n * Run one command (`{ name, input, id?, expectedRevision? }`). A repeated\n * `id` returns the first result with `replayed: true` and applies nothing.\n */\n run(command: unknown, options?: RunOptions): CommandResult;\n /**\n * Run several commands all-or-nothing. On any failure the state is exactly\n * as before and the error names the failing command.\n */\n batch(batch: CommandBatch | unknown): BatchResult;\n /** The compact plan state, cheap enough for a model prompt. */\n snapshot(): PlanSnapshot;\n /** The document (a copy). */\n cookbook(): ReturnType<typeof clone<PlanState['doc']>>;\n /** Serializable state to persist and resume from, retries included. */\n state(): EngineState;\n /** Call `listener` with the snapshot now and after every change. */\n subscribe(listener: (snapshot: PlanSnapshot) => void): () => void;\n /** Command tool definitions (JSON Schema inputs), enums narrowed to the catalog. */\n readonly tools: readonly CommandTool[];\n /** The atomic-batch tool definition. */\n readonly batchTool: {\n name: 'run_batch';\n description: string;\n inputSchema: JsonSchema;\n };\n}\n\ninterface UndoEntry {\n before: PlanState;\n /** What the change left; undo is a conflict while the plan differs from it. */\n after: PlanState;\n}\n\nconst err = (\n code: CommandError['code'],\n message: string,\n extra: Pick<CommandError, 'path' | 'details'> = {},\n): CommandError => ({ code, message, ...extra });\n\n/** Key order never changes a payload's identity: `{a, b}` and `{b, a}` match. */\nconst canonical = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(canonical);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [\n key,\n canonical((value as Record<string, unknown>)[key]),\n ]),\n );\n }\n return value;\n};\n\nconst fingerprint = (value: unknown): string => {\n try {\n return JSON.stringify(canonical(value)) ?? 'undefined';\n } catch {\n return 'unserializable';\n }\n};\n\ntype Parsed =\n | { ok: true; name: CommandName; input: Record<string, unknown> }\n | { ok: false; error: CommandError };\n\nfunction readCommand(\n value: unknown,\n schemas: CommandSchemas,\n extraKeys: readonly string[],\n): Parsed {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return {\n ok: false,\n error: err('unknown_command', 'A command is an object: { name, input }.'),\n };\n }\n const record = value as Record<string, unknown>;\n const { name, input = {} } = record;\n if (typeof name !== 'string' || !Object.hasOwn(schemas, name)) {\n return {\n ok: false,\n error: err('unknown_command', `Unknown command ${JSON.stringify(name)}.`),\n };\n }\n for (const key of Object.keys(record)) {\n if (key !== 'name' && key !== 'input' && !extraKeys.includes(key)) {\n return {\n ok: false,\n error: err('invalid_input', `${key} is not part of a command.`, {\n path: key,\n }),\n };\n }\n }\n const problem = checkSchema(schemas[name as CommandName], input);\n if (problem) {\n return {\n ok: false,\n error: err('invalid_input', problem.message, { path: problem.path }),\n };\n }\n return {\n ok: true,\n name: name as CommandName,\n input: input as Record<string, unknown>,\n };\n}\n\nconst checkId = (id: unknown): CommandError | null =>\n id === undefined ||\n (typeof id === 'string' && id.length > 0 && id.length <= 200)\n ? null\n : err(\n 'invalid_input',\n 'id must be a non-empty string of at most 200 characters.',\n { path: 'id' },\n );\n\nconst checkRevision = (value: unknown): CommandError | null =>\n value === undefined || (Number.isInteger(value) && (value as number) >= 0)\n ? null\n : err('invalid_input', 'expectedRevision must be a whole number.', {\n path: 'expectedRevision',\n });\n\nexport function createCookbookEngine(\n options: CookbookEngineOptions,\n): CookbookEngine {\n const { catalog } = options;\n const schemas = commandSchemas(catalog);\n const tools = buildCommandTools(catalog);\n const batchTool = buildBatchTool(catalog);\n const maxJournal = options.maxJournal ?? 500;\n const maxUndo = options.maxUndo ?? 20;\n\n let current: PlanState;\n let revision = 0;\n const journal = new Map<string, JournalEntry>();\n\n if (options.state) {\n const saved = options.state;\n const checked = validateCookbook(saved.cookbook);\n if (!checked.ok)\n throw new Error(`Invalid saved cookbook: ${checked.errors.join('; ')}`);\n if (!Number.isInteger(saved.revision) || saved.revision < 0) {\n throw new Error('Invalid saved revision.');\n }\n current = {\n doc: adopt(catalog, checked.cookbook),\n applied: saved.applied ?? null,\n };\n revision = saved.revision;\n for (const entry of saved.journal ?? [])\n journal.set(entry.id, clone(entry));\n } else if (options.cookbook !== undefined) {\n const checked = validateCookbook(options.cookbook);\n if (!checked.ok)\n throw new Error(`Invalid cookbook: ${checked.errors.join('; ')}`);\n current = { doc: adopt(catalog, checked.cookbook), applied: null };\n } else {\n current = { doc: adopt(catalog, emptyCookbook()), applied: null };\n }\n\n const undos = new Map<string, UndoEntry>();\n let undoIds: string[] = [];\n let undoCounter = 0;\n const listeners = new Map<(s: PlanSnapshot) => void, number>();\n\n function snapshotOf(state: PlanState, rev: number): PlanSnapshot {\n const { doc } = state;\n const byId = new Map(catalog.recipes.map((r) => [r.id, r]));\n const settings = readSettings(catalog, doc);\n const exposed = new Set(\n catalog.models.filter((m) => m.exposed !== false).map((m) => m.id),\n );\n return {\n version: COOKBOOK_COMMANDS_VERSION,\n revision: rev,\n app: {\n name:\n doc.name ?? libraryName(catalog, state.applied) ?? DEFAULT_APP_NAME,\n description: doc.description ?? null,\n cookbook: state.applied,\n },\n recipes: doc.recipes.flatMap((id) => {\n const recipe = byId.get(id);\n return recipe ? [{ id, label: recipe.label }] : [];\n }),\n features: doc.features.filter((id) => exposed.has(id)),\n unavailable: [\n ...doc.recipes.filter((id) => !byId.has(id)),\n ...doc.features.filter((id) => !exposed.has(id)),\n ],\n settings: {\n currency: settings.currency,\n taxRate: Number((settings.taxRate * 100).toFixed(4)),\n paymentTerms: settings.paymentTerms,\n pricesIncludeTax: settings.pricesIncludeTax,\n taxRounding: settings.taxRounding,\n },\n theme: {\n text: describeTheme(doc.theme),\n preset: doc.theme?.preset ?? null,\n primary: doc.theme?.custom?.primary ?? null,\n colorScheme: doc.theme?.colorScheme ?? DEFAULT_COLOR_SCHEME,\n borderRadius: doc.theme?.borderRadius ?? null,\n density: doc.theme?.density ?? null,\n contrast: doc.theme?.contrast ?? null,\n },\n sections: buildNav(catalog, doc).map((s) => ({\n id: s.id,\n label: s.label,\n hidden: s.hidden,\n items: s.items.map((i) => ({\n id: i.id,\n label: i.label,\n hidden: i.hidden,\n })),\n })),\n policies: doc.policies.length,\n undo: [...undoIds],\n };\n }\n\n const snapshot = () => snapshotOf(current, revision);\n\n function notify(): void {\n for (const [listener, last] of listeners) {\n if (last === revision) continue;\n listeners.set(listener, revision);\n listener(snapshot());\n }\n }\n\n function remember(\n id: string | undefined,\n print: string,\n result: CommandResult | BatchResult,\n ) {\n if (id === undefined) return;\n journal.set(id, { id, fingerprint: print, result: clone(result) });\n while (journal.size > maxJournal) {\n const oldest = journal.keys().next().value;\n if (oldest === undefined) break;\n journal.delete(oldest);\n }\n }\n\n function replay<R extends CommandResult | BatchResult>(\n id: string | undefined,\n print: string,\n ): R | CommandResult | null {\n if (id === undefined) return null;\n const hit = journal.get(id);\n if (!hit) return null;\n if (hit.fingerprint !== print) {\n return {\n ok: false,\n id,\n error: err(\n 'id_reuse',\n `The id \"${id}\" was already used for a different command.`,\n {\n path: 'id',\n },\n ),\n };\n }\n return { ...(clone(hit.result) as R), replayed: true };\n }\n\n function recordUndo(before: PlanState, after: PlanState): string {\n const undoId = `${options.undoPrefix ?? 'undo'}-${++undoCounter}`;\n undos.set(undoId, { before: clone(before), after: clone(after) });\n undoIds = [...undoIds, undoId].slice(-maxUndo);\n for (const key of [...undos.keys()])\n if (!undoIds.includes(key)) undos.delete(key);\n return undoId;\n }\n\n const changedBetween = (a: PlanState, b: PlanState) =>\n a.applied !== b.applied || !same(a.doc, b.doc);\n\n function toSuccess(\n id: string | undefined,\n name: CommandName,\n outcome: Extract<Outcome, { ok: true }>,\n revisionBefore: number,\n revisionAfter: number,\n snap: PlanSnapshot,\n undoId?: string,\n ): Extract<CommandResult, { ok: true }> {\n return {\n ok: true,\n ...(id !== undefined ? { id } : {}),\n snapshot: snap,\n receipt: {\n name,\n ...(id !== undefined ? { id } : {}),\n summary: revisionAfter !== revisionBefore ? outcome.summary : '',\n changed: revisionAfter !== revisionBefore,\n revisionBefore,\n revisionAfter,\n ...(undoId ? { undoId } : {}),\n ...(outcome.changes ? { changes: outcome.changes } : {}),\n ...(outcome.warnings ? { warnings: outcome.warnings } : {}),\n },\n ...(outcome.data !== undefined ? { data: outcome.data } : {}),\n };\n }\n\n function runUndo(\n id: string | undefined,\n input: { undoId: string; force?: boolean },\n ): CommandResult {\n const entry = undos.get(input.undoId);\n if (!entry) {\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: err('not_found', `Nothing to undo for \"${input.undoId}\".`, {\n path: 'input.undoId',\n }),\n };\n }\n if (!input.force && changedBetween(current, entry.after)) {\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: err(\n 'conflict',\n 'The plan changed since; send force: true to undo anyway.',\n {\n details: { currentRevision: revision },\n },\n ),\n };\n }\n const before = revision;\n const restored = clone(entry.before);\n const changed = changedBetween(current, restored);\n current = restored;\n if (changed) revision += 1;\n undos.delete(input.undoId);\n undoIds = undoIds.filter((u) => u !== input.undoId);\n const result = toSuccess(\n id,\n 'undo',\n { ok: true, state: current, summary: 'Undone.' },\n before,\n revision,\n snapshot(),\n );\n notify();\n return result;\n }\n\n function run(command: unknown, runOptions: RunOptions = {}): CommandResult {\n try {\n const raw =\n command && typeof command === 'object' && !Array.isArray(command)\n ? (command as Record<string, unknown>)\n : undefined;\n const id = raw?.id as string | undefined;\n const idProblem = checkId(id);\n if (idProblem) return { ok: false, error: idProblem };\n const expected = (raw?.expectedRevision ?? runOptions.expectedRevision) as\n | number\n | undefined;\n const revProblem = checkRevision(expected);\n if (revProblem)\n return {\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error: revProblem,\n };\n\n const print = fingerprint({\n name: raw?.name,\n input: raw?.input ?? {},\n expectedRevision: expected,\n });\n const replayed = replay<CommandResult>(id, print);\n if (replayed) return replayed as CommandResult;\n\n const finish = (result: CommandResult) => {\n remember(id, print, result);\n return result;\n };\n const withId = (error: CommandError): CommandResult => ({\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error,\n });\n\n const parsed = readCommand(command, schemas, ['id', 'expectedRevision']);\n if (!parsed.ok) return finish(withId(parsed.error));\n if (expected !== undefined && expected !== revision) {\n return finish(\n withId(\n err(\n 'conflict',\n `The plan is at revision ${revision}, not ${expected}. Read the snapshot and try again.`,\n {\n details: {\n expectedRevision: expected,\n currentRevision: revision,\n },\n },\n ),\n ),\n );\n }\n if (parsed.name === 'undo') {\n return finish(\n runUndo(id, parsed.input as { undoId: string; force?: boolean }),\n );\n }\n const before = current;\n const outcome = execute(\n catalog,\n before,\n parsed.name,\n parsed.input as never,\n );\n if (!outcome.ok) return finish(withId(outcome.error));\n const revisionBefore = revision;\n const changed = changedBetween(before, outcome.state);\n let undoId: string | undefined;\n if (changed) {\n current = outcome.state;\n revision += 1;\n undoId = recordUndo(before, outcome.state);\n }\n const result = finish(\n toSuccess(\n id,\n parsed.name,\n outcome,\n revisionBefore,\n revision,\n snapshot(),\n undoId,\n ),\n );\n notify();\n return result;\n } catch (cause) {\n return {\n ok: false,\n error: err(\n 'failed',\n cause instanceof Error ? cause.message : String(cause),\n ),\n };\n }\n }\n\n function batch(input: CommandBatch | unknown): BatchResult {\n const unchanged = (error: CommandError, id?: string): BatchResult => ({\n ok: false,\n ...(id !== undefined ? { id } : {}),\n error,\n snapshot: snapshot(),\n });\n try {\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n return unchanged(\n err('invalid_input', 'A batch is an object: { commands }.'),\n );\n }\n const raw = input as Record<string, unknown>;\n const id = raw.id as string | undefined;\n const idProblem = checkId(id);\n if (idProblem) return unchanged(idProblem);\n const revProblem = checkRevision(raw.expectedRevision);\n if (revProblem) return unchanged(revProblem, id);\n const print = fingerprint({\n commands: raw.commands,\n expectedRevision: raw.expectedRevision,\n });\n const replayed = replay<BatchResult>(id, print);\n if (replayed) {\n return 'results' in replayed || 'snapshot' in replayed\n ? (replayed as BatchResult)\n : unchanged(\n (replayed as Extract<CommandResult, { ok: false }>).error,\n id,\n );\n }\n const finish = (result: BatchResult) => {\n remember(id, print, result);\n return result;\n };\n\n const commands = raw.commands;\n if (\n !Array.isArray(commands) ||\n commands.length === 0 ||\n commands.length > 50\n ) {\n return finish(\n unchanged(\n err(\n 'invalid_input',\n 'commands must be a list of 1 to 50 commands.',\n { path: 'commands' },\n ),\n id,\n ),\n );\n }\n const expected = raw.expectedRevision as number | undefined;\n if (expected !== undefined && expected !== revision) {\n return finish(\n unchanged(\n err(\n 'conflict',\n `The plan is at revision ${revision}, not ${expected}. Read the snapshot and try again.`,\n {\n details: {\n expectedRevision: expected,\n currentRevision: revision,\n },\n },\n ),\n id,\n ),\n );\n }\n\n const failAt = (index: number, name: unknown, cause: CommandError) =>\n finish(\n unchanged(\n err(\n 'batch_failed',\n `Command ${index + 1} (${String(name)}) failed: ${cause.message}`,\n {\n path: `commands[${index}]`,\n details: { index, cause },\n },\n ),\n id,\n ),\n );\n\n // Everything runs on a working copy; the live state is replaced once, at the end.\n const base = current;\n const baseRevision = revision;\n let working = base;\n let rev = baseRevision;\n const results: Extract<CommandResult, { ok: true }>[] = [];\n for (const [index, command] of commands.entries()) {\n const parsed = readCommand(command, schemas, []);\n if (!parsed.ok)\n return failAt(\n index,\n (command as { name?: unknown })?.name,\n parsed.error,\n );\n if (parsed.name === 'undo') {\n return failAt(\n index,\n 'undo',\n err('invalid_input', 'undo cannot run inside a batch.'),\n );\n }\n const outcome = execute(\n catalog,\n working,\n parsed.name,\n parsed.input as never,\n );\n if (!outcome.ok) return failAt(index, parsed.name, outcome.error);\n const before = rev;\n if (changedBetween(working, outcome.state)) rev += 1;\n working = outcome.state;\n results.push(\n toSuccess(\n undefined,\n parsed.name,\n outcome,\n before,\n rev,\n snapshotOf(working, rev),\n ),\n );\n }\n const changed = rev !== baseRevision;\n let undoId: string | undefined;\n if (changed) {\n current = working;\n revision = rev;\n undoId = recordUndo(base, working);\n // The batch's one undo restores the state before all of it.\n for (const r of results) if (r.receipt.changed) delete r.receipt.undoId;\n }\n const result = finish({\n ok: true,\n ...(id !== undefined ? { id } : {}),\n snapshot: snapshot(),\n receipt: {\n ...(id !== undefined ? { id } : {}),\n count: results.length,\n changed,\n revisionBefore: baseRevision,\n revisionAfter: rev,\n ...(undoId ? { undoId } : {}),\n },\n results,\n });\n notify();\n return result;\n } catch (cause) {\n return unchanged(\n err('failed', cause instanceof Error ? cause.message : String(cause)),\n );\n }\n }\n\n return {\n run: run as CookbookEngine['run'],\n batch,\n snapshot,\n cookbook: () => clone(current.doc),\n state: () => ({\n version: COOKBOOK_COMMANDS_VERSION,\n revision,\n applied: current.applied,\n cookbook: clone(current.doc),\n journal: [...journal.values()].map((entry) => clone(entry)),\n }),\n subscribe(listener) {\n listeners.set(listener, revision);\n listener(snapshot());\n return () => {\n listeners.delete(listener);\n };\n },\n tools,\n batchTool,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/schemas.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,UAAU,EACX,MAAM,YAAY,CAAC;AA8BpB;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/schemas.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,UAAU,EACX,MAAM,YAAY,CAAC;AA8BpB;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW,EAAE,CA6QvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG;IACtD,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;CACzB,CA+BA;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,EACd,IAAI,SAAU,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiG1C;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC;AAEvE,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,cAAc,CAIrE"}
|
|
@@ -119,6 +119,14 @@ function buildCommandTools(catalog) {
|
|
|
119
119
|
description: "Default payment terms, e.g. \"Net 30\".",
|
|
120
120
|
minLength: 1,
|
|
121
121
|
maxLength: 40
|
|
122
|
+
},
|
|
123
|
+
pricesIncludeTax: {
|
|
124
|
+
type: "boolean",
|
|
125
|
+
description: "Whether new document prices include tax."
|
|
126
|
+
},
|
|
127
|
+
taxRounding: {
|
|
128
|
+
enum: ["line", "document"],
|
|
129
|
+
description: "Whether tax rounds per line or per document."
|
|
122
130
|
}
|
|
123
131
|
})
|
|
124
132
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":[],"sources":["../../../src/cookbook/engine/schemas.ts"],"sourcesContent":["import { DEFAULT_THEME_PRESETS, MAX_TERMS_LENGTH } from './defaults.js';\nimport type {\n CommandName,\n CommandTool,\n EngineCatalog,\n JsonSchema,\n} from './types.js';\n\nconst ids = (description: string, values?: readonly string[]): JsonSchema => ({\n type: 'array',\n description,\n minItems: 1,\n maxItems: 50,\n items: values?.length\n ? { type: 'string', enum: [...values] }\n : { type: 'string', minLength: 1 },\n});\n\nconst text = (description: string, extra: JsonSchema = {}): JsonSchema => ({\n type: 'string',\n description,\n minLength: 1,\n maxLength: 200,\n ...extra,\n});\n\nconst object = (\n properties: Record<string, JsonSchema>,\n required: string[] = [],\n): JsonSchema => ({\n type: 'object',\n properties,\n ...(required.length ? { required } : {}),\n additionalProperties: false,\n});\n\n/**\n * Every command as an MCP/LLM tool definition (`inputSchema` is JSON Schema\n * 2020-12). Recipe and cookbook ids become enums from the catalog, so\n * grammar-constrained decoding cannot name one that does not exist.\n */\nexport function buildCommandTools(catalog: EngineCatalog): CommandTool[] {\n const recipeIds = catalog.recipes.map((r) => r.id);\n const cookbookIds = (catalog.cookbooks ?? []).map((c) => c.id);\n const presets = catalog.themePresets ?? DEFAULT_THEME_PRESETS;\n const cookbookId = (description: string): JsonSchema => ({\n type: 'string',\n description,\n ...(cookbookIds.length ? { enum: [...cookbookIds] } : { minLength: 1 }),\n });\n const entryId = (what: string): JsonSchema =>\n text(`The id of ${what}, as the plan snapshot's \"sections\" lists it.`);\n const replace: JsonSchema = {\n type: 'boolean',\n description: 'Confirm replacing what is there.',\n };\n return [\n {\n name: 'add_recipes',\n description:\n 'Switch recipes on. Recipes they require come along. Returns what was added.',\n inputSchema: object({ ids: ids('Recipe ids to add.', recipeIds) }, [\n 'ids',\n ]),\n },\n {\n name: 'remove_recipes',\n description:\n 'Switch recipes off. A recipe another one needs is kept and reported.',\n inputSchema: object({ ids: ids('Recipe ids to remove.', recipeIds) }, [\n 'ids',\n ]),\n },\n {\n name: 'add_features',\n description:\n 'Add single models no recipe covers, by qualified name (`@scope/pkg:Class`).',\n inputSchema: object({ ids: ids('Qualified model names to add.') }, [\n 'ids',\n ]),\n },\n {\n name: 'remove_features',\n description: 'Remove single models added with add_features.',\n inputSchema: object({ ids: ids('Qualified model names to remove.') }, [\n 'ids',\n ]),\n },\n {\n name: 'add_cookbook',\n description:\n 'Add the recipes and features of a ready-made cookbook to the current app. Nothing is replaced.',\n inputSchema: object({ id: cookbookId('The cookbook to add.') }, ['id']),\n },\n {\n name: 'remove_cookbook',\n description:\n 'Remove the recipes and features a ready-made cookbook adds. Ones another recipe needs are kept.',\n inputSchema: object({ id: cookbookId('The cookbook to remove.') }, [\n 'id',\n ]),\n },\n {\n name: 'apply_cookbook',\n description:\n 'Select a ready-made cookbook: replace the whole app (recipes, options, menu, theme) with it. When the app has anything in it, replace must be true.',\n inputSchema: object(\n { id: cookbookId('The cookbook to set up.'), replace },\n ['id'],\n ),\n },\n {\n name: 'import_cookbook',\n description:\n 'Replace the whole app with a cookbook document (version 1). Checked strictly; nothing is applied if it is invalid. When the app has anything in it, replace must be true.',\n inputSchema: object(\n {\n document: {\n type: 'object',\n description: 'A cookbook document, version 1.',\n },\n replace,\n },\n ['document'],\n ),\n },\n {\n name: 'set_settings',\n description:\n 'Change app settings: currency, default tax rate (percent), default payment terms. Applies to new records only.',\n inputSchema: object({\n currency: catalog.currencies?.length\n ? {\n type: 'string',\n description: 'ISO 4217 code, e.g. CAD.',\n enum: [...catalog.currencies],\n }\n : {\n type: 'string',\n description: 'ISO 4217 code, e.g. CAD.',\n pattern: '^[A-Z]{3}$',\n },\n taxRate: {\n type: 'number',\n description: 'Default tax rate in percent, 0 to 100.',\n minimum: 0,\n maximum: 100,\n },\n paymentTerms: {\n type: 'string',\n description: 'Default payment terms, e.g. \"Net 30\".',\n minLength: 1,\n maxLength: MAX_TERMS_LENGTH,\n },\n }),\n },\n {\n name: 'set_policy',\n description:\n \"Set one field's policy: default value, visibility, label or help. The model must be covered by a recipe or feature that is on. null clears a part.\",\n inputSchema: object(\n {\n model: text(\n 'Qualified model name, e.g. @happyvertical/smrt-commerce:Order.',\n ),\n field: text('The model field name.'),\n defaultValue: {\n description:\n 'The default as a JSON value (a string, number or boolean). null clears it.',\n },\n visibility: {\n enum: ['basic', 'advanced', 'hidden', null],\n description: 'Whether the field shows in forms and lists.',\n },\n label: {\n type: ['string', 'null'],\n description: 'A different label.',\n maxLength: 120,\n },\n help: {\n type: ['string', 'null'],\n description: 'Help text under the field.',\n maxLength: 400,\n },\n },\n ['model', 'field'],\n ),\n },\n {\n name: 'set_theme',\n description:\n 'Change the look: a preset, a brand colour, light or dark. A preset replaces a brand colour.',\n inputSchema: object({\n preset: { enum: [...presets], description: 'A built-in theme.' },\n primary: {\n type: 'string',\n description: 'Brand colour as #rrggbb.',\n pattern: '^#[0-9a-fA-F]{6}$',\n },\n colorScheme: {\n enum: ['light', 'dark', 'system'],\n description: 'Light, dark or follow the device.',\n },\n fontFamily: {\n type: ['string', 'null'],\n minLength: 1,\n description: 'Font key. Null restores the preset font.',\n },\n borderRadius: {\n enum: ['none', 'sm', 'md', 'lg', 'xl', 'full'],\n description: 'Corner roundness.',\n },\n density: {\n enum: ['comfortable', 'touch'],\n description: 'Control size: comfortable, or larger touch targets.',\n },\n contrast: {\n enum: ['auto', 'standard', 'more'],\n description:\n 'Contrast: auto follows the device, or force standard or more.',\n },\n }),\n },\n {\n name: 'reset_theme',\n description: 'Go back to the default look.',\n inputSchema: object({}),\n },\n {\n name: 'set_name',\n description: 'Name and describe the app. null clears a part.',\n inputSchema: object({\n name: { type: ['string', 'null'], minLength: 1, maxLength: 60 },\n description: {\n type: ['string', 'null'],\n minLength: 1,\n maxLength: 400,\n },\n }),\n },\n {\n name: 'rename_section',\n description: 'Rename a menu section.',\n inputSchema: object(\n {\n id: entryId('the section'),\n label: text('The new name.', { maxLength: 60 }),\n },\n ['id', 'label'],\n ),\n },\n {\n name: 'rename_item',\n description: 'Rename a menu entry. A null label restores its own name.',\n inputSchema: object(\n {\n id: entryId('the entry'),\n label: { type: ['string', 'null'], minLength: 1, maxLength: 60 },\n },\n ['id', 'label'],\n ),\n },\n {\n name: 'hide',\n description: 'Hide a menu section or entry. Nothing is deleted.',\n inputSchema: object({ id: entryId('the section or entry') }, ['id']),\n },\n {\n name: 'show',\n description: 'Show a hidden menu section or entry again.',\n inputSchema: object({ id: entryId('the section or entry') }, ['id']),\n },\n {\n name: 'validate',\n description:\n 'Check the current cookbook against the catalog and report typed diagnostics. Changes nothing.',\n inputSchema: object({}),\n },\n {\n name: 'export_cookbook',\n description:\n 'The cookbook as a <name>.cookbook.json file (text in the result). Changes nothing.',\n inputSchema: object({\n name: text('A name for the file.', { maxLength: 60 }),\n }),\n },\n {\n name: 'undo',\n description:\n 'Undo an earlier change by the undoId its receipt carried. Refused with a conflict when the plan changed since, unless force is true.',\n inputSchema: object(\n {\n undoId: text('The undoId from a receipt.'),\n force: {\n type: 'boolean',\n description: 'Undo even after later edits.',\n },\n },\n ['undoId'],\n ),\n },\n ];\n}\n\n/**\n * The batch envelope as a tool definition: several commands, applied\n * all-or-nothing. Commands inside are validated against their own schemas.\n */\nexport function buildBatchTool(catalog: EngineCatalog): {\n name: 'run_batch';\n description: string;\n inputSchema: JsonSchema;\n} {\n return {\n name: 'run_batch',\n description:\n 'Run several commands as one atomic batch: all apply or none does. A failure names the command and leaves the plan unchanged.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1, maxLength: 200 },\n expectedRevision: { type: 'integer', minimum: 0 },\n commands: {\n type: 'array',\n minItems: 1,\n maxItems: 50,\n items: {\n oneOf: buildCommandTools(catalog).map((tool) => ({\n type: 'object',\n properties: {\n name: { const: tool.name },\n input: tool.inputSchema,\n },\n required: ['name'],\n additionalProperties: false,\n })),\n },\n },\n },\n required: ['commands'],\n additionalProperties: false,\n },\n };\n}\n\nconst typeOf = (value: unknown): string =>\n value === null\n ? 'null'\n : Array.isArray(value)\n ? 'array'\n : Number.isInteger(value)\n ? 'integer'\n : typeof value;\n\nfunction typeMatches(wanted: string, value: unknown): boolean {\n const actual = typeOf(value);\n return actual === wanted || (wanted === 'number' && actual === 'integer');\n}\n\n/**\n * Check a value against a command schema (the subset the commands use). One\n * validator for runtime and exported schemas, so they cannot drift. Returns\n * the first problem as `{ path, message }`, or null.\n */\nexport function checkSchema(\n schema: JsonSchema,\n value: unknown,\n path = 'input',\n): { path: string; message: string } | null {\n const bad = (message: string) => ({ path, message: `${path} ${message}` });\n const type = schema.type as string | string[] | undefined;\n if (type) {\n const wanted = Array.isArray(type) ? type : [type];\n if (!wanted.some((t) => typeMatches(t, value))) {\n return bad(`must be ${wanted.join(' or ')}`);\n }\n }\n const choices = schema.enum as unknown[] | undefined;\n if (choices && !choices.includes(value)) {\n return bad(\n choices.length > 12\n ? 'is not a known value'\n : `must be one of ${choices.map((c) => JSON.stringify(c)).join(', ')}`,\n );\n }\n if (typeof value === 'string') {\n const { minLength, maxLength, pattern } = schema as {\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n };\n if (minLength !== undefined && value.length < minLength) {\n return bad('must not be empty');\n }\n if (maxLength !== undefined && value.length > maxLength) {\n return bad(`must be at most ${maxLength} characters`);\n }\n if (pattern && !new RegExp(pattern).test(value)) {\n return bad('has the wrong format');\n }\n }\n if (typeof value === 'number') {\n const { minimum, maximum } = schema as {\n minimum?: number;\n maximum?: number;\n };\n if (!Number.isFinite(value)) return bad('must be a finite number');\n if (minimum !== undefined && value < minimum) {\n return bad(`must be at least ${minimum}`);\n }\n if (maximum !== undefined && value > maximum) {\n return bad(`must be at most ${maximum}`);\n }\n }\n if (Array.isArray(value)) {\n const { minItems, maxItems, items } = schema as {\n minItems?: number;\n maxItems?: number;\n items?: JsonSchema;\n };\n if (minItems !== undefined && value.length < minItems) {\n return bad(`needs at least ${minItems} item${minItems === 1 ? '' : 's'}`);\n }\n if (maxItems !== undefined && value.length > maxItems) {\n return bad(`takes at most ${maxItems} items`);\n }\n if (items) {\n for (const [index, item] of value.entries()) {\n const problem = checkSchema(items, item, `${path}[${index}]`);\n if (problem) return problem;\n }\n }\n }\n if (typeOf(value) === 'object') {\n const object = value as Record<string, unknown>;\n const { properties, required, additionalProperties } = schema as {\n properties?: Record<string, JsonSchema>;\n required?: string[];\n additionalProperties?: boolean;\n };\n for (const key of required ?? []) {\n if (object[key] === undefined) {\n return {\n path: `${path}.${key}`,\n message: `${path}.${key} is required`,\n };\n }\n }\n for (const [key, entry] of Object.entries(object)) {\n const child = properties?.[key];\n if (!child) {\n if (additionalProperties === false) {\n return {\n path: `${path}.${key}`,\n message: `${path}.${key} is not an option of this command`,\n };\n }\n continue;\n }\n if (entry === undefined) continue;\n const problem = checkSchema(child, entry, `${path}.${key}`);\n if (problem) return problem;\n }\n }\n return null;\n}\n\nexport type CommandSchemas = Readonly<Record<CommandName, JsonSchema>>;\n\n/** The input schemas by command name. */\nexport function commandSchemas(catalog: EngineCatalog): CommandSchemas {\n return Object.fromEntries(\n buildCommandTools(catalog).map((tool) => [tool.name, tool.inputSchema]),\n ) as CommandSchemas;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schemas.js","names":[],"sources":["../../../src/cookbook/engine/schemas.ts"],"sourcesContent":["import { DEFAULT_THEME_PRESETS, MAX_TERMS_LENGTH } from './defaults.js';\nimport type {\n CommandName,\n CommandTool,\n EngineCatalog,\n JsonSchema,\n} from './types.js';\n\nconst ids = (description: string, values?: readonly string[]): JsonSchema => ({\n type: 'array',\n description,\n minItems: 1,\n maxItems: 50,\n items: values?.length\n ? { type: 'string', enum: [...values] }\n : { type: 'string', minLength: 1 },\n});\n\nconst text = (description: string, extra: JsonSchema = {}): JsonSchema => ({\n type: 'string',\n description,\n minLength: 1,\n maxLength: 200,\n ...extra,\n});\n\nconst object = (\n properties: Record<string, JsonSchema>,\n required: string[] = [],\n): JsonSchema => ({\n type: 'object',\n properties,\n ...(required.length ? { required } : {}),\n additionalProperties: false,\n});\n\n/**\n * Every command as an MCP/LLM tool definition (`inputSchema` is JSON Schema\n * 2020-12). Recipe and cookbook ids become enums from the catalog, so\n * grammar-constrained decoding cannot name one that does not exist.\n */\nexport function buildCommandTools(catalog: EngineCatalog): CommandTool[] {\n const recipeIds = catalog.recipes.map((r) => r.id);\n const cookbookIds = (catalog.cookbooks ?? []).map((c) => c.id);\n const presets = catalog.themePresets ?? DEFAULT_THEME_PRESETS;\n const cookbookId = (description: string): JsonSchema => ({\n type: 'string',\n description,\n ...(cookbookIds.length ? { enum: [...cookbookIds] } : { minLength: 1 }),\n });\n const entryId = (what: string): JsonSchema =>\n text(`The id of ${what}, as the plan snapshot's \"sections\" lists it.`);\n const replace: JsonSchema = {\n type: 'boolean',\n description: 'Confirm replacing what is there.',\n };\n return [\n {\n name: 'add_recipes',\n description:\n 'Switch recipes on. Recipes they require come along. Returns what was added.',\n inputSchema: object({ ids: ids('Recipe ids to add.', recipeIds) }, [\n 'ids',\n ]),\n },\n {\n name: 'remove_recipes',\n description:\n 'Switch recipes off. A recipe another one needs is kept and reported.',\n inputSchema: object({ ids: ids('Recipe ids to remove.', recipeIds) }, [\n 'ids',\n ]),\n },\n {\n name: 'add_features',\n description:\n 'Add single models no recipe covers, by qualified name (`@scope/pkg:Class`).',\n inputSchema: object({ ids: ids('Qualified model names to add.') }, [\n 'ids',\n ]),\n },\n {\n name: 'remove_features',\n description: 'Remove single models added with add_features.',\n inputSchema: object({ ids: ids('Qualified model names to remove.') }, [\n 'ids',\n ]),\n },\n {\n name: 'add_cookbook',\n description:\n 'Add the recipes and features of a ready-made cookbook to the current app. Nothing is replaced.',\n inputSchema: object({ id: cookbookId('The cookbook to add.') }, ['id']),\n },\n {\n name: 'remove_cookbook',\n description:\n 'Remove the recipes and features a ready-made cookbook adds. Ones another recipe needs are kept.',\n inputSchema: object({ id: cookbookId('The cookbook to remove.') }, [\n 'id',\n ]),\n },\n {\n name: 'apply_cookbook',\n description:\n 'Select a ready-made cookbook: replace the whole app (recipes, options, menu, theme) with it. When the app has anything in it, replace must be true.',\n inputSchema: object(\n { id: cookbookId('The cookbook to set up.'), replace },\n ['id'],\n ),\n },\n {\n name: 'import_cookbook',\n description:\n 'Replace the whole app with a cookbook document (version 1). Checked strictly; nothing is applied if it is invalid. When the app has anything in it, replace must be true.',\n inputSchema: object(\n {\n document: {\n type: 'object',\n description: 'A cookbook document, version 1.',\n },\n replace,\n },\n ['document'],\n ),\n },\n {\n name: 'set_settings',\n description:\n 'Change app settings: currency, default tax rate (percent), default payment terms. Applies to new records only.',\n inputSchema: object({\n currency: catalog.currencies?.length\n ? {\n type: 'string',\n description: 'ISO 4217 code, e.g. CAD.',\n enum: [...catalog.currencies],\n }\n : {\n type: 'string',\n description: 'ISO 4217 code, e.g. CAD.',\n pattern: '^[A-Z]{3}$',\n },\n taxRate: {\n type: 'number',\n description: 'Default tax rate in percent, 0 to 100.',\n minimum: 0,\n maximum: 100,\n },\n paymentTerms: {\n type: 'string',\n description: 'Default payment terms, e.g. \"Net 30\".',\n minLength: 1,\n maxLength: MAX_TERMS_LENGTH,\n },\n pricesIncludeTax: {\n type: 'boolean',\n description: 'Whether new document prices include tax.',\n },\n taxRounding: {\n enum: ['line', 'document'],\n description: 'Whether tax rounds per line or per document.',\n },\n }),\n },\n {\n name: 'set_policy',\n description:\n \"Set one field's policy: default value, visibility, label or help. The model must be covered by a recipe or feature that is on. null clears a part.\",\n inputSchema: object(\n {\n model: text(\n 'Qualified model name, e.g. @happyvertical/smrt-commerce:Order.',\n ),\n field: text('The model field name.'),\n defaultValue: {\n description:\n 'The default as a JSON value (a string, number or boolean). null clears it.',\n },\n visibility: {\n enum: ['basic', 'advanced', 'hidden', null],\n description: 'Whether the field shows in forms and lists.',\n },\n label: {\n type: ['string', 'null'],\n description: 'A different label.',\n maxLength: 120,\n },\n help: {\n type: ['string', 'null'],\n description: 'Help text under the field.',\n maxLength: 400,\n },\n },\n ['model', 'field'],\n ),\n },\n {\n name: 'set_theme',\n description:\n 'Change the look: a preset, a brand colour, light or dark. A preset replaces a brand colour.',\n inputSchema: object({\n preset: { enum: [...presets], description: 'A built-in theme.' },\n primary: {\n type: 'string',\n description: 'Brand colour as #rrggbb.',\n pattern: '^#[0-9a-fA-F]{6}$',\n },\n colorScheme: {\n enum: ['light', 'dark', 'system'],\n description: 'Light, dark or follow the device.',\n },\n fontFamily: {\n type: ['string', 'null'],\n minLength: 1,\n description: 'Font key. Null restores the preset font.',\n },\n borderRadius: {\n enum: ['none', 'sm', 'md', 'lg', 'xl', 'full'],\n description: 'Corner roundness.',\n },\n density: {\n enum: ['comfortable', 'touch'],\n description: 'Control size: comfortable, or larger touch targets.',\n },\n contrast: {\n enum: ['auto', 'standard', 'more'],\n description:\n 'Contrast: auto follows the device, or force standard or more.',\n },\n }),\n },\n {\n name: 'reset_theme',\n description: 'Go back to the default look.',\n inputSchema: object({}),\n },\n {\n name: 'set_name',\n description: 'Name and describe the app. null clears a part.',\n inputSchema: object({\n name: { type: ['string', 'null'], minLength: 1, maxLength: 60 },\n description: {\n type: ['string', 'null'],\n minLength: 1,\n maxLength: 400,\n },\n }),\n },\n {\n name: 'rename_section',\n description: 'Rename a menu section.',\n inputSchema: object(\n {\n id: entryId('the section'),\n label: text('The new name.', { maxLength: 60 }),\n },\n ['id', 'label'],\n ),\n },\n {\n name: 'rename_item',\n description: 'Rename a menu entry. A null label restores its own name.',\n inputSchema: object(\n {\n id: entryId('the entry'),\n label: { type: ['string', 'null'], minLength: 1, maxLength: 60 },\n },\n ['id', 'label'],\n ),\n },\n {\n name: 'hide',\n description: 'Hide a menu section or entry. Nothing is deleted.',\n inputSchema: object({ id: entryId('the section or entry') }, ['id']),\n },\n {\n name: 'show',\n description: 'Show a hidden menu section or entry again.',\n inputSchema: object({ id: entryId('the section or entry') }, ['id']),\n },\n {\n name: 'validate',\n description:\n 'Check the current cookbook against the catalog and report typed diagnostics. Changes nothing.',\n inputSchema: object({}),\n },\n {\n name: 'export_cookbook',\n description:\n 'The cookbook as a <name>.cookbook.json file (text in the result). Changes nothing.',\n inputSchema: object({\n name: text('A name for the file.', { maxLength: 60 }),\n }),\n },\n {\n name: 'undo',\n description:\n 'Undo an earlier change by the undoId its receipt carried. Refused with a conflict when the plan changed since, unless force is true.',\n inputSchema: object(\n {\n undoId: text('The undoId from a receipt.'),\n force: {\n type: 'boolean',\n description: 'Undo even after later edits.',\n },\n },\n ['undoId'],\n ),\n },\n ];\n}\n\n/**\n * The batch envelope as a tool definition: several commands, applied\n * all-or-nothing. Commands inside are validated against their own schemas.\n */\nexport function buildBatchTool(catalog: EngineCatalog): {\n name: 'run_batch';\n description: string;\n inputSchema: JsonSchema;\n} {\n return {\n name: 'run_batch',\n description:\n 'Run several commands as one atomic batch: all apply or none does. A failure names the command and leaves the plan unchanged.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', minLength: 1, maxLength: 200 },\n expectedRevision: { type: 'integer', minimum: 0 },\n commands: {\n type: 'array',\n minItems: 1,\n maxItems: 50,\n items: {\n oneOf: buildCommandTools(catalog).map((tool) => ({\n type: 'object',\n properties: {\n name: { const: tool.name },\n input: tool.inputSchema,\n },\n required: ['name'],\n additionalProperties: false,\n })),\n },\n },\n },\n required: ['commands'],\n additionalProperties: false,\n },\n };\n}\n\nconst typeOf = (value: unknown): string =>\n value === null\n ? 'null'\n : Array.isArray(value)\n ? 'array'\n : Number.isInteger(value)\n ? 'integer'\n : typeof value;\n\nfunction typeMatches(wanted: string, value: unknown): boolean {\n const actual = typeOf(value);\n return actual === wanted || (wanted === 'number' && actual === 'integer');\n}\n\n/**\n * Check a value against a command schema (the subset the commands use). One\n * validator for runtime and exported schemas, so they cannot drift. Returns\n * the first problem as `{ path, message }`, or null.\n */\nexport function checkSchema(\n schema: JsonSchema,\n value: unknown,\n path = 'input',\n): { path: string; message: string } | null {\n const bad = (message: string) => ({ path, message: `${path} ${message}` });\n const type = schema.type as string | string[] | undefined;\n if (type) {\n const wanted = Array.isArray(type) ? type : [type];\n if (!wanted.some((t) => typeMatches(t, value))) {\n return bad(`must be ${wanted.join(' or ')}`);\n }\n }\n const choices = schema.enum as unknown[] | undefined;\n if (choices && !choices.includes(value)) {\n return bad(\n choices.length > 12\n ? 'is not a known value'\n : `must be one of ${choices.map((c) => JSON.stringify(c)).join(', ')}`,\n );\n }\n if (typeof value === 'string') {\n const { minLength, maxLength, pattern } = schema as {\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n };\n if (minLength !== undefined && value.length < minLength) {\n return bad('must not be empty');\n }\n if (maxLength !== undefined && value.length > maxLength) {\n return bad(`must be at most ${maxLength} characters`);\n }\n if (pattern && !new RegExp(pattern).test(value)) {\n return bad('has the wrong format');\n }\n }\n if (typeof value === 'number') {\n const { minimum, maximum } = schema as {\n minimum?: number;\n maximum?: number;\n };\n if (!Number.isFinite(value)) return bad('must be a finite number');\n if (minimum !== undefined && value < minimum) {\n return bad(`must be at least ${minimum}`);\n }\n if (maximum !== undefined && value > maximum) {\n return bad(`must be at most ${maximum}`);\n }\n }\n if (Array.isArray(value)) {\n const { minItems, maxItems, items } = schema as {\n minItems?: number;\n maxItems?: number;\n items?: JsonSchema;\n };\n if (minItems !== undefined && value.length < minItems) {\n return bad(`needs at least ${minItems} item${minItems === 1 ? '' : 's'}`);\n }\n if (maxItems !== undefined && value.length > maxItems) {\n return bad(`takes at most ${maxItems} items`);\n }\n if (items) {\n for (const [index, item] of value.entries()) {\n const problem = checkSchema(items, item, `${path}[${index}]`);\n if (problem) return problem;\n }\n }\n }\n if (typeOf(value) === 'object') {\n const object = value as Record<string, unknown>;\n const { properties, required, additionalProperties } = schema as {\n properties?: Record<string, JsonSchema>;\n required?: string[];\n additionalProperties?: boolean;\n };\n for (const key of required ?? []) {\n if (object[key] === undefined) {\n return {\n path: `${path}.${key}`,\n message: `${path}.${key} is required`,\n };\n }\n }\n for (const [key, entry] of Object.entries(object)) {\n const child = properties?.[key];\n if (!child) {\n if (additionalProperties === false) {\n return {\n path: `${path}.${key}`,\n message: `${path}.${key} is not an option of this command`,\n };\n }\n continue;\n }\n if (entry === undefined) continue;\n const problem = checkSchema(child, entry, `${path}.${key}`);\n if (problem) return problem;\n }\n }\n return null;\n}\n\nexport type CommandSchemas = Readonly<Record<CommandName, JsonSchema>>;\n\n/** The input schemas by command name. */\nexport function commandSchemas(catalog: EngineCatalog): CommandSchemas {\n return Object.fromEntries(\n buildCommandTools(catalog).map((tool) => [tool.name, tool.inputSchema]),\n ) as CommandSchemas;\n}\n"],"mappings":"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"}
|
|
@@ -42,7 +42,7 @@ export interface EngineLibraryCookbook {
|
|
|
42
42
|
document: Cookbook;
|
|
43
43
|
}
|
|
44
44
|
/** Which model fields each app setting is the default of. */
|
|
45
|
-
export type SettingTargets = Record<'currency' | 'taxRate' | 'paymentTerms', readonly {
|
|
45
|
+
export type SettingTargets = Record<'currency' | 'taxRate' | 'paymentTerms' | 'pricesIncludeTax' | 'taxRounding', readonly {
|
|
46
46
|
model: string;
|
|
47
47
|
field: string;
|
|
48
48
|
}[]>;
|
|
@@ -104,6 +104,8 @@ export interface CommandInputs {
|
|
|
104
104
|
currency?: string;
|
|
105
105
|
taxRate?: number;
|
|
106
106
|
paymentTerms?: string;
|
|
107
|
+
pricesIncludeTax?: boolean;
|
|
108
|
+
taxRounding?: 'line' | 'document';
|
|
107
109
|
};
|
|
108
110
|
/** Set (or clear with null) one field's policy row. App scope. */
|
|
109
111
|
set_policy: {
|
|
@@ -212,6 +214,8 @@ export interface PlanSnapshot {
|
|
|
212
214
|
currency: string;
|
|
213
215
|
taxRate: number;
|
|
214
216
|
paymentTerms: string;
|
|
217
|
+
pricesIncludeTax: boolean;
|
|
218
|
+
taxRounding: 'line' | 'document';
|
|
215
219
|
};
|
|
216
220
|
theme: {
|
|
217
221
|
text: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,gBAAgB,EAChB,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,CAC/C,GACC,OAAO,CACL,IAAI,CAAC,gBAAgB,EAAE,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,CACxE,CAAC;AAEJ,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACjC;AAED,kEAAkE;AAClE,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG,MAAM,CACjC,UAAU,GAAG,SAAS,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/cookbook/engine/types.ts"],"sourcesContent":["/**\n * Cookbook command engine, contract v1 (#3753).\n *\n * Plain data in, plain data out: no SvelteKit, browser storage, planner\n * singleton or inference dependency, and no Node imports, so the same engine\n * runs in a browser planner, a CLI, an MCP server or a website. Adapters own\n * navigation/focus, persistence and transport; the engine owns the document.\n */\nimport type { Cookbook, RecipeDefinition } from '@happyvertical/smrt-types';\n\n/**\n * The command set version. A change an older client could not send or read\n * bumps it; adding a command or an optional field does not.\n */\nexport const COOKBOOK_COMMANDS_VERSION = 1;\n\n/** The part of a manifest recipe the engine reads (a `RecipeDefinition` fits). */\nexport type EngineRecipe = Pick<\n RecipeDefinition,\n 'id' | 'label' | 'models' | 'nav' | 'requires'\n> &\n Partial<\n Pick<RecipeDefinition, 'requiresAny' | 'group' | 'section' | 'options'>\n >;\n\n/** One field of a catalog model, for `set_policy` and settings defaults. */\nexport interface EngineField {\n name: string;\n /** System fields (id, timestamps) cannot be given a policy. */\n system?: boolean;\n /** The field's own starting value, so a setting equal to it writes no row. */\n default?: unknown;\n}\n\n/** One catalog model. Same shape as smrt-svelte's `CookbookModelInfo`, plus fields. */\nexport interface EngineModel {\n /** Qualified name, `@scope/pkg:Class`. */\n id: string;\n name: string;\n /** Package id used in item ids: `commerce` for `@happyvertical/smrt-commerce`. */\n packageId: string;\n description?: string;\n /** Has an API, MCP or CLI surface; only exposed models can be added as features. */\n exposed?: boolean;\n /** When given, `set_policy` rejects a field not listed. */\n fields?: readonly EngineField[];\n}\n\n/** A ready-made cookbook the catalog offers (a library entry). */\nexport interface EngineLibraryCookbook {\n id: string;\n name: string;\n document: Cookbook;\n}\n\n/** Which model fields each app setting is the default of. */\nexport type SettingTargets = Record<\n 'currency' | 'taxRate' | 'paymentTerms',\n readonly { model: string; field: string }[]\n>;\n\n/**\n * Everything the engine resolves ids against, as data: recipes and models from\n * published manifests, optionally a library of cookbooks. Nothing here is\n * bundled with the engine.\n */\nexport interface EngineCatalog {\n recipes: readonly EngineRecipe[];\n models: readonly EngineModel[];\n cookbooks?: readonly EngineLibraryCookbook[];\n /** Movable shell item ids resolved by the host (`dock:`, `slot:`, recipe, or host ids). */\n placementItems?: readonly string[];\n /** Theme preset names; default {@link DEFAULT_THEME_PRESETS}. */\n themePresets?: readonly string[];\n /** ISO 4217 codes; default any three capital letters. */\n currencies?: readonly string[];\n /** Default {@link COMMERCE_SETTING_TARGETS}. */\n settingTargets?: SettingTargets;\n}\n\n/** Input of each command, keyed by the command's (tool) name. */\nexport interface CommandInputs {\n /** Switch recipes on, with everything they `require`. */\n add_recipes: { ids: string[] };\n /** Switch recipes off; ones another recipe needs are kept (and reported). */\n remove_recipes: { ids: string[] };\n /** Add models no recipe covers, by qualified name. */\n add_features: { ids: string[] };\n remove_features: { ids: string[] };\n /** Add the recipes and features of a library cookbook to what is there. */\n add_cookbook: { id: string };\n /** Remove what a library cookbook added (recipes others need are kept). */\n remove_cookbook: { id: string };\n /** Select a library cookbook, replacing the app (needs `replace` if non-empty). */\n apply_cookbook: { id: string; replace?: boolean };\n /** Import a cookbook document, replacing the app (needs `replace` if non-empty). */\n import_cookbook: { document: unknown; replace?: boolean };\n /** App settings; tax rate in percent, 0 to 100. */\n set_settings: { currency?: string; taxRate?: number; paymentTerms?: string };\n /** Set (or clear with null) one field's policy row. App scope. */\n set_policy: {\n model: string;\n field: string;\n defaultValue?: unknown;\n visibility?: 'basic' | 'advanced' | 'hidden' | null;\n label?: string | null;\n help?: string | null;\n };\n set_theme: {\n preset?: string;\n primary?: string;\n colorScheme?: 'light' | 'dark' | 'system';\n fontFamily?: string | null;\n borderRadius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n density?: 'comfortable' | 'touch';\n contrast?: 'auto' | 'standard' | 'more';\n };\n reset_theme: Record<string, never>;\n /** Name (and describe) the app; null clears. */\n set_name: { name?: string | null; description?: string | null };\n rename_section: { id: string; label: string };\n /** `null` restores the entry's own name. */\n rename_item: { id: string; label: string | null };\n hide: { id: string };\n show: { id: string };\n /** Check the current document and report typed diagnostics. Changes nothing. */\n validate: Record<string, never>;\n /** The cookbook as `<name>.cookbook.json` text. Changes nothing. */\n export_cookbook: { name?: string };\n /** Undo an earlier change by the `undoId` its receipt carried. */\n undo: { undoId: string; force?: boolean };\n}\n\nexport type CommandName = keyof CommandInputs;\n\n/** A command as a client sends it. */\nexport type CookbookCommand = {\n [N in CommandName]: {\n name: N;\n input: CommandInputs[N];\n /** Retry key: a repeated id returns the first receipt and applies nothing. */\n id?: string;\n /** Refuse with `conflict` unless the plan is still at this revision. */\n expectedRevision?: number;\n };\n}[CommandName];\n\n/** Stable strings a client can switch on. */\nexport type CommandErrorCode =\n | 'unknown_command'\n | 'invalid_input'\n | 'not_found'\n /** A destructive command needs `replace: true` (or `force: true`). */\n | 'confirmation_required'\n /** The plan moved on since the caller looked (`expectedRevision`, undo). */\n | 'conflict'\n /** A command id was reused with a different command. */\n | 'id_reuse'\n /** An atomic batch failed; `details.index` names the command, nothing applied. */\n | 'batch_failed'\n | 'failed';\n\nexport interface CommandError {\n code: CommandErrorCode;\n message: string;\n /** Where the problem is, as a path into the input (`input.ids[1]`). */\n path?: string;\n details?: Record<string, unknown>;\n}\n\n/** What a recipe/feature command did, after `requires` ran. */\nexport interface RecipeChanges {\n added: string[];\n removed: string[];\n /** Asked to remove, but another recipe still needs them. */\n kept: string[];\n}\n\nexport interface PlanSnapshot {\n version: typeof COOKBOOK_COMMANDS_VERSION;\n /** Counts applied changes; equal histories give equal revisions. */\n revision: number;\n app: { name: string; description: string | null; cookbook: string | null };\n recipes: { id: string; label: string }[];\n features: string[];\n /** Recipe and feature ids this catalog lacks; kept on export. */\n unavailable: string[];\n settings: { currency: string; taxRate: number; paymentTerms: string };\n theme: {\n text: string;\n preset: string | null;\n primary: string | null;\n colorScheme: string;\n borderRadius: string | null;\n density: string | null;\n contrast: string | null;\n };\n sections: {\n id: string;\n label: string;\n hidden: boolean;\n items: { id: string; label: string; hidden: boolean }[];\n }[];\n policies: number;\n /** Undo ids still available, newest last. */\n undo: string[];\n}\n\nexport interface CommandReceipt {\n name: CommandName;\n /** The command id, when one was sent. */\n id?: string;\n summary: string;\n changed: boolean;\n revisionBefore: number;\n revisionAfter: number;\n undoId?: string;\n changes?: RecipeChanges;\n /** Non-fatal notes (an import's legacy `$schema` migration). */\n warnings?: string[];\n}\n\nexport type CommandResult =\n | {\n ok: true;\n id?: string;\n /** True when this is the stored result of an earlier run of the same id. */\n replayed?: boolean;\n snapshot: PlanSnapshot;\n receipt: CommandReceipt;\n data?: unknown;\n }\n | { ok: false; id?: string; replayed?: boolean; error: CommandError };\n\nexport interface RunOptions {\n expectedRevision?: number;\n}\n\n/** Several commands applied all-or-nothing. */\nexport interface CommandBatch {\n id?: string;\n commands: readonly unknown[];\n expectedRevision?: number;\n}\n\nexport type BatchResult =\n | {\n ok: true;\n id?: string;\n replayed?: boolean;\n snapshot: PlanSnapshot;\n receipt: {\n id?: string;\n count: number;\n changed: boolean;\n revisionBefore: number;\n revisionAfter: number;\n undoId?: string;\n };\n /** One result per command, in order. */\n results: Extract<CommandResult, { ok: true }>[];\n }\n | {\n ok: false;\n id?: string;\n replayed?: boolean;\n error: CommandError;\n /** The state is exactly as before the batch. */\n snapshot: PlanSnapshot;\n };\n\n/** One diagnostic from `validate`. */\nexport interface Diagnostic {\n severity: 'error' | 'warning';\n code: string;\n path: string;\n message: string;\n}\n\nexport interface ValidateData {\n ok: boolean;\n diagnostics: Diagnostic[];\n}\n\nexport interface ExportData {\n fileName: string;\n text: string;\n cookbook: Cookbook;\n}\n\n/** A journal row: enough to answer a retry of `id` after a restart. */\nexport interface JournalEntry {\n id: string;\n fingerprint: string;\n result: CommandResult | BatchResult;\n}\n\n/** The engine's whole state as plain JSON, to persist and resume from. */\nexport interface EngineState {\n version: typeof COOKBOOK_COMMANDS_VERSION;\n revision: number;\n /** The library cookbook the plan was last set up from, if any. */\n applied: string | null;\n cookbook: Cookbook;\n journal: JournalEntry[];\n}\n\nexport interface JsonSchema {\n [key: string]: unknown;\n}\n\n/** One command as an LLM or MCP tool definition. */\nexport interface CommandTool {\n name: CommandName;\n description: string;\n inputSchema: JsonSchema;\n}\n"],"mappings":";;;;;AAcA,IAAa,4BAA4B"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/cookbook/engine/types.ts"],"sourcesContent":["/**\n * Cookbook command engine, contract v1 (#3753).\n *\n * Plain data in, plain data out: no SvelteKit, browser storage, planner\n * singleton or inference dependency, and no Node imports, so the same engine\n * runs in a browser planner, a CLI, an MCP server or a website. Adapters own\n * navigation/focus, persistence and transport; the engine owns the document.\n */\nimport type { Cookbook, RecipeDefinition } from '@happyvertical/smrt-types';\n\n/**\n * The command set version. A change an older client could not send or read\n * bumps it; adding a command or an optional field does not.\n */\nexport const COOKBOOK_COMMANDS_VERSION = 1;\n\n/** The part of a manifest recipe the engine reads (a `RecipeDefinition` fits). */\nexport type EngineRecipe = Pick<\n RecipeDefinition,\n 'id' | 'label' | 'models' | 'nav' | 'requires'\n> &\n Partial<\n Pick<RecipeDefinition, 'requiresAny' | 'group' | 'section' | 'options'>\n >;\n\n/** One field of a catalog model, for `set_policy` and settings defaults. */\nexport interface EngineField {\n name: string;\n /** System fields (id, timestamps) cannot be given a policy. */\n system?: boolean;\n /** The field's own starting value, so a setting equal to it writes no row. */\n default?: unknown;\n}\n\n/** One catalog model. Same shape as smrt-svelte's `CookbookModelInfo`, plus fields. */\nexport interface EngineModel {\n /** Qualified name, `@scope/pkg:Class`. */\n id: string;\n name: string;\n /** Package id used in item ids: `commerce` for `@happyvertical/smrt-commerce`. */\n packageId: string;\n description?: string;\n /** Has an API, MCP or CLI surface; only exposed models can be added as features. */\n exposed?: boolean;\n /** When given, `set_policy` rejects a field not listed. */\n fields?: readonly EngineField[];\n}\n\n/** A ready-made cookbook the catalog offers (a library entry). */\nexport interface EngineLibraryCookbook {\n id: string;\n name: string;\n document: Cookbook;\n}\n\n/** Which model fields each app setting is the default of. */\nexport type SettingTargets = Record<\n 'currency' | 'taxRate' | 'paymentTerms' | 'pricesIncludeTax' | 'taxRounding',\n readonly { model: string; field: string }[]\n>;\n\n/**\n * Everything the engine resolves ids against, as data: recipes and models from\n * published manifests, optionally a library of cookbooks. Nothing here is\n * bundled with the engine.\n */\nexport interface EngineCatalog {\n recipes: readonly EngineRecipe[];\n models: readonly EngineModel[];\n cookbooks?: readonly EngineLibraryCookbook[];\n /** Movable shell item ids resolved by the host (`dock:`, `slot:`, recipe, or host ids). */\n placementItems?: readonly string[];\n /** Theme preset names; default {@link DEFAULT_THEME_PRESETS}. */\n themePresets?: readonly string[];\n /** ISO 4217 codes; default any three capital letters. */\n currencies?: readonly string[];\n /** Default {@link COMMERCE_SETTING_TARGETS}. */\n settingTargets?: SettingTargets;\n}\n\n/** Input of each command, keyed by the command's (tool) name. */\nexport interface CommandInputs {\n /** Switch recipes on, with everything they `require`. */\n add_recipes: { ids: string[] };\n /** Switch recipes off; ones another recipe needs are kept (and reported). */\n remove_recipes: { ids: string[] };\n /** Add models no recipe covers, by qualified name. */\n add_features: { ids: string[] };\n remove_features: { ids: string[] };\n /** Add the recipes and features of a library cookbook to what is there. */\n add_cookbook: { id: string };\n /** Remove what a library cookbook added (recipes others need are kept). */\n remove_cookbook: { id: string };\n /** Select a library cookbook, replacing the app (needs `replace` if non-empty). */\n apply_cookbook: { id: string; replace?: boolean };\n /** Import a cookbook document, replacing the app (needs `replace` if non-empty). */\n import_cookbook: { document: unknown; replace?: boolean };\n /** App settings; tax rate in percent, 0 to 100. */\n set_settings: {\n currency?: string;\n taxRate?: number;\n paymentTerms?: string;\n pricesIncludeTax?: boolean;\n taxRounding?: 'line' | 'document';\n };\n /** Set (or clear with null) one field's policy row. App scope. */\n set_policy: {\n model: string;\n field: string;\n defaultValue?: unknown;\n visibility?: 'basic' | 'advanced' | 'hidden' | null;\n label?: string | null;\n help?: string | null;\n };\n set_theme: {\n preset?: string;\n primary?: string;\n colorScheme?: 'light' | 'dark' | 'system';\n fontFamily?: string | null;\n borderRadius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n density?: 'comfortable' | 'touch';\n contrast?: 'auto' | 'standard' | 'more';\n };\n reset_theme: Record<string, never>;\n /** Name (and describe) the app; null clears. */\n set_name: { name?: string | null; description?: string | null };\n rename_section: { id: string; label: string };\n /** `null` restores the entry's own name. */\n rename_item: { id: string; label: string | null };\n hide: { id: string };\n show: { id: string };\n /** Check the current document and report typed diagnostics. Changes nothing. */\n validate: Record<string, never>;\n /** The cookbook as `<name>.cookbook.json` text. Changes nothing. */\n export_cookbook: { name?: string };\n /** Undo an earlier change by the `undoId` its receipt carried. */\n undo: { undoId: string; force?: boolean };\n}\n\nexport type CommandName = keyof CommandInputs;\n\n/** A command as a client sends it. */\nexport type CookbookCommand = {\n [N in CommandName]: {\n name: N;\n input: CommandInputs[N];\n /** Retry key: a repeated id returns the first receipt and applies nothing. */\n id?: string;\n /** Refuse with `conflict` unless the plan is still at this revision. */\n expectedRevision?: number;\n };\n}[CommandName];\n\n/** Stable strings a client can switch on. */\nexport type CommandErrorCode =\n | 'unknown_command'\n | 'invalid_input'\n | 'not_found'\n /** A destructive command needs `replace: true` (or `force: true`). */\n | 'confirmation_required'\n /** The plan moved on since the caller looked (`expectedRevision`, undo). */\n | 'conflict'\n /** A command id was reused with a different command. */\n | 'id_reuse'\n /** An atomic batch failed; `details.index` names the command, nothing applied. */\n | 'batch_failed'\n | 'failed';\n\nexport interface CommandError {\n code: CommandErrorCode;\n message: string;\n /** Where the problem is, as a path into the input (`input.ids[1]`). */\n path?: string;\n details?: Record<string, unknown>;\n}\n\n/** What a recipe/feature command did, after `requires` ran. */\nexport interface RecipeChanges {\n added: string[];\n removed: string[];\n /** Asked to remove, but another recipe still needs them. */\n kept: string[];\n}\n\nexport interface PlanSnapshot {\n version: typeof COOKBOOK_COMMANDS_VERSION;\n /** Counts applied changes; equal histories give equal revisions. */\n revision: number;\n app: { name: string; description: string | null; cookbook: string | null };\n recipes: { id: string; label: string }[];\n features: string[];\n /** Recipe and feature ids this catalog lacks; kept on export. */\n unavailable: string[];\n settings: {\n currency: string;\n taxRate: number;\n paymentTerms: string;\n pricesIncludeTax: boolean;\n taxRounding: 'line' | 'document';\n };\n theme: {\n text: string;\n preset: string | null;\n primary: string | null;\n colorScheme: string;\n borderRadius: string | null;\n density: string | null;\n contrast: string | null;\n };\n sections: {\n id: string;\n label: string;\n hidden: boolean;\n items: { id: string; label: string; hidden: boolean }[];\n }[];\n policies: number;\n /** Undo ids still available, newest last. */\n undo: string[];\n}\n\nexport interface CommandReceipt {\n name: CommandName;\n /** The command id, when one was sent. */\n id?: string;\n summary: string;\n changed: boolean;\n revisionBefore: number;\n revisionAfter: number;\n undoId?: string;\n changes?: RecipeChanges;\n /** Non-fatal notes (an import's legacy `$schema` migration). */\n warnings?: string[];\n}\n\nexport type CommandResult =\n | {\n ok: true;\n id?: string;\n /** True when this is the stored result of an earlier run of the same id. */\n replayed?: boolean;\n snapshot: PlanSnapshot;\n receipt: CommandReceipt;\n data?: unknown;\n }\n | { ok: false; id?: string; replayed?: boolean; error: CommandError };\n\nexport interface RunOptions {\n expectedRevision?: number;\n}\n\n/** Several commands applied all-or-nothing. */\nexport interface CommandBatch {\n id?: string;\n commands: readonly unknown[];\n expectedRevision?: number;\n}\n\nexport type BatchResult =\n | {\n ok: true;\n id?: string;\n replayed?: boolean;\n snapshot: PlanSnapshot;\n receipt: {\n id?: string;\n count: number;\n changed: boolean;\n revisionBefore: number;\n revisionAfter: number;\n undoId?: string;\n };\n /** One result per command, in order. */\n results: Extract<CommandResult, { ok: true }>[];\n }\n | {\n ok: false;\n id?: string;\n replayed?: boolean;\n error: CommandError;\n /** The state is exactly as before the batch. */\n snapshot: PlanSnapshot;\n };\n\n/** One diagnostic from `validate`. */\nexport interface Diagnostic {\n severity: 'error' | 'warning';\n code: string;\n path: string;\n message: string;\n}\n\nexport interface ValidateData {\n ok: boolean;\n diagnostics: Diagnostic[];\n}\n\nexport interface ExportData {\n fileName: string;\n text: string;\n cookbook: Cookbook;\n}\n\n/** A journal row: enough to answer a retry of `id` after a restart. */\nexport interface JournalEntry {\n id: string;\n fingerprint: string;\n result: CommandResult | BatchResult;\n}\n\n/** The engine's whole state as plain JSON, to persist and resume from. */\nexport interface EngineState {\n version: typeof COOKBOOK_COMMANDS_VERSION;\n revision: number;\n /** The library cookbook the plan was last set up from, if any. */\n applied: string | null;\n cookbook: Cookbook;\n journal: JournalEntry[];\n}\n\nexport interface JsonSchema {\n [key: string]: unknown;\n}\n\n/** One command as an LLM or MCP tool definition. */\nexport interface CommandTool {\n name: CommandName;\n description: string;\n inputSchema: JsonSchema;\n}\n"],"mappings":";;;;;AAcA,IAAa,4BAA4B"}
|
|
@@ -12,5 +12,6 @@ export { APIGenerator, computeRuntimeWebManifestHash, createRestServer, startRes
|
|
|
12
12
|
export type { OpenAPIConfig } from "./swagger.js";
|
|
13
13
|
export { generateOpenAPISpec, setupSwaggerUI, } from "./swagger.js";
|
|
14
14
|
export { runWithTenantGate, setTenantEntryPointRunner, type TenantEntryPointRunner, type TenantGateOptions, } from "./tenant-gate.js";
|
|
15
|
+
export { fieldTypeToJsonSchema, type ToolFieldMeta, type ToolJsonSchema, } from "./tool-schema.js";
|
|
15
16
|
export { normalizeTypedHttpError, type TypedHttpFailure, } from "./typed-http-error.js";
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,2BAA2B,EAC3B,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,EAC3B,oBAAoB,EACpB,0BAA0B,EAC1B,KAAK,uBAAuB,EAC5B,uBAAuB,EACvB,8BAA8B,EAC9B,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,sBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,yBAAyB,EACzB,4BAA4B,EAC5B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,eAAe,EACf,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,KAAK,+BAA+B,EACpC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,EAC5B,8BAA8B,EAC9B,qCAAqC,EACrC,KAAK,UAAU,EACf,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,oBAAiB,CAAC;AAKzB,OAAO,EACL,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,8BAA8B,EAC9B,kCAAkC,EAClC,mCAAmC,EACnC,6BAA6B,EAC7B,qBAAqB,EACrB,mCAAmC,GACpC,MAAM,mBAAgB,CAAC;AACxB,YAAY,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,UAAO,CAAC;AAEf,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,2BAA2B,EAC3B,YAAY,GACb,MAAM,UAAO,CAAC;AAIf,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,6BAA6B,EAC7B,gCAAgC,EAChC,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,EAClC,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,sBAAmB,CAAC;AAC3B,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAQ,CAAC;AAEtE,OAAO,EACL,YAAY,EACZ,6BAA6B,EAC7B,gBAAgB,EAChB,eAAe,GAChB,MAAM,WAAQ,CAAC;AAChB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAW,CAAC;AAE/C,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,cAAW,CAAC;AAEnB,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,kBAAe,CAAC;AAEvB,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,GACtB,MAAM,uBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,2BAA2B,EAC3B,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,EAC3B,oBAAoB,EACpB,0BAA0B,EAC1B,KAAK,uBAAuB,EAC5B,uBAAuB,EACvB,8BAA8B,EAC9B,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,sBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,yBAAyB,EACzB,4BAA4B,EAC5B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,eAAe,EACf,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,KAAK,+BAA+B,EACpC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,EAC5B,8BAA8B,EAC9B,qCAAqC,EACrC,KAAK,UAAU,EACf,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,oBAAiB,CAAC;AAKzB,OAAO,EACL,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,8BAA8B,EAC9B,kCAAkC,EAClC,mCAAmC,EACnC,6BAA6B,EAC7B,qBAAqB,EACrB,mCAAmC,GACpC,MAAM,mBAAgB,CAAC;AACxB,YAAY,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,UAAO,CAAC;AAEf,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,2BAA2B,EAC3B,YAAY,GACb,MAAM,UAAO,CAAC;AAIf,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,6BAA6B,EAC7B,gCAAgC,EAChC,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,EAClC,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,sBAAmB,CAAC;AAC3B,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAQ,CAAC;AAEtE,OAAO,EACL,YAAY,EACZ,6BAA6B,EAC7B,gBAAgB,EAChB,eAAe,GAChB,MAAM,WAAQ,CAAC;AAChB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAW,CAAC;AAE/C,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,cAAW,CAAC;AAEnB,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,kBAAe,CAAC;AAIvB,OAAO,EACL,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,kBAAe,CAAC;AAEvB,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,GACtB,MAAM,uBAAoB,CAAC"}
|
package/dist/generators/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { PRIVATE_READ_CACHE_CONTROL, canonicalReadRepresentation, computeBodyEta
|
|
|
2
2
|
import { CRUD_OPERATIONS, SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY, buildCustomActionInputSchema, buildCustomActionInvocationArgs, classifyMethodWireability, classifyParameterWireability, coerceCustomActionArgument, createClassNamePredicate, createManifestClassNamePredicate, customActionParameterInputName, declaredTypeAcceptsDate, declaresRuntimeRestRoute, declaresRuntimeRestRouteShape, isCrudOperation, isCrudToolAction, normalizeCustomActionFailure, queryStringDecoderFor, readMethodDecoratorConfig, resolveApiMethodExposure, resolveCustomActionMetadata, resolveDeclaredScopeMismatch, resolveEffectiveActionMetadata, toCustomActionBoolean, toCustomActionDate, toCustomActionNumber } from "./custom-action.js";
|
|
3
3
|
import { DEFAULT_EVENTS_HEARTBEAT_MS, DEFAULT_EVENTS_MAX_SUBSCRIBERS, DEFAULT_EVENTS_RETRY_AFTER_SECONDS, buildChangeEventStream, changeEventSubscribersAtCapacity, eventStreamCapacityExceededResponse, normalizeEventsMaxSubscribers, signalVisibleToTenant, tryReserveChangeEventSubscriberSlot } from "./events-route.js";
|
|
4
4
|
import { runWithTenantGate, setTenantEntryPointRunner } from "./tenant-gate.js";
|
|
5
|
+
import { fieldTypeToJsonSchema } from "./tool-schema.js";
|
|
5
6
|
import { MCPGenerator, MCP_STABLE_CATALOG_TTL_MS, resolveMCPToolListCacheHint, sortMCPTools } from "./mcp.js";
|
|
6
7
|
import { PLAYBOOK_PREFLIGHT_CAPABILITY, PLAYBOOK_PREFLIGHT_ROUTE_SEGMENT, handlePlaybookPreflightRoute, isApiActionEnabledForObject, isRestActionRoutable, isRestRoutePublic, resolveRegisteredObjectName, restFieldReadPermissions, restMethodForApiAction } from "./preflight-route.js";
|
|
7
8
|
import { normalizeTypedHttpError } from "./typed-http-error.js";
|
|
8
9
|
import { APIGenerator, computeRuntimeWebManifestHash, createRestServer, startRestServer } from "./rest.js";
|
|
9
10
|
import { generateOpenAPISpec, setupSwaggerUI } from "./swagger.js";
|
|
10
|
-
export { APIGenerator, CRUD_OPERATIONS, DEFAULT_EVENTS_HEARTBEAT_MS, DEFAULT_EVENTS_MAX_SUBSCRIBERS, DEFAULT_EVENTS_RETRY_AFTER_SECONDS, MCPGenerator, MCP_STABLE_CATALOG_TTL_MS, PLAYBOOK_PREFLIGHT_CAPABILITY, PLAYBOOK_PREFLIGHT_ROUTE_SEGMENT, PRIVATE_READ_CACHE_CONTROL, SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY, buildChangeEventStream, buildCustomActionInputSchema, buildCustomActionInvocationArgs, canonicalReadRepresentation, changeEventSubscribersAtCapacity, classifyMethodWireability, classifyParameterWireability, coerceCustomActionArgument, computeBodyEtag, computeRuntimeWebManifestHash, computeTableVersionEtag, conditionalJsonResponse, createClassNamePredicate, createManifestClassNamePredicate, createRestServer, customActionParameterInputName, declaredTypeAcceptsDate, declaresRuntimeRestRoute, declaresRuntimeRestRouteShape, eventStreamCapacityExceededResponse, generateOpenAPISpec, handlePlaybookPreflightRoute, ifNoneMatchHasConcreteMatch, ifNoneMatchSatisfied, isApiActionEnabledForObject, isCrudOperation, isCrudToolAction, isRestActionRoutable, isRestRoutePublic, normalizeCustomActionFailure, normalizeEventsMaxSubscribers, normalizeTypedHttpError, queryStringDecoderFor, readMethodDecoratorConfig, resolveApiMethodExposure, resolveCustomActionMetadata, resolveDeclaredScopeMismatch, resolveEffectiveActionMetadata, resolveMCPToolListCacheHint, resolveReadCacheControl, resolveRegisteredObjectName, resolveTenantEtagDiscriminator, restFieldReadPermissions, restMethodForApiAction, runWithTenantGate, setTenantEntryPointRunner, setupSwaggerUI, signalVisibleToTenant, sortMCPTools, startRestServer, toCustomActionBoolean, toCustomActionDate, toCustomActionNumber, tryReserveChangeEventSubscriberSlot, versionConditionalResponse, warnIfSharedCacheNeutralized };
|
|
11
|
+
export { APIGenerator, CRUD_OPERATIONS, DEFAULT_EVENTS_HEARTBEAT_MS, DEFAULT_EVENTS_MAX_SUBSCRIBERS, DEFAULT_EVENTS_RETRY_AFTER_SECONDS, MCPGenerator, MCP_STABLE_CATALOG_TTL_MS, PLAYBOOK_PREFLIGHT_CAPABILITY, PLAYBOOK_PREFLIGHT_ROUTE_SEGMENT, PRIVATE_READ_CACHE_CONTROL, SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY, buildChangeEventStream, buildCustomActionInputSchema, buildCustomActionInvocationArgs, canonicalReadRepresentation, changeEventSubscribersAtCapacity, classifyMethodWireability, classifyParameterWireability, coerceCustomActionArgument, computeBodyEtag, computeRuntimeWebManifestHash, computeTableVersionEtag, conditionalJsonResponse, createClassNamePredicate, createManifestClassNamePredicate, createRestServer, customActionParameterInputName, declaredTypeAcceptsDate, declaresRuntimeRestRoute, declaresRuntimeRestRouteShape, eventStreamCapacityExceededResponse, fieldTypeToJsonSchema, generateOpenAPISpec, handlePlaybookPreflightRoute, ifNoneMatchHasConcreteMatch, ifNoneMatchSatisfied, isApiActionEnabledForObject, isCrudOperation, isCrudToolAction, isRestActionRoutable, isRestRoutePublic, normalizeCustomActionFailure, normalizeEventsMaxSubscribers, normalizeTypedHttpError, queryStringDecoderFor, readMethodDecoratorConfig, resolveApiMethodExposure, resolveCustomActionMetadata, resolveDeclaredScopeMismatch, resolveEffectiveActionMetadata, resolveMCPToolListCacheHint, resolveReadCacheControl, resolveRegisteredObjectName, resolveTenantEtagDiscriminator, restFieldReadPermissions, restMethodForApiAction, runWithTenantGate, setTenantEntryPointRunner, setupSwaggerUI, signalVisibleToTenant, sortMCPTools, startRestServer, toCustomActionBoolean, toCustomActionDate, toCustomActionNumber, tryReserveChangeEventSubscriberSlot, versionConditionalResponse, warnIfSharedCacheNeutralized };
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - Error handling and logging
|
|
10
10
|
* - Graceful shutdown
|
|
11
11
|
*/
|
|
12
|
+
import type { ApiSerializerReference } from '../registry/types.js';
|
|
12
13
|
import type { CustomActionScope } from './custom-action.js';
|
|
13
14
|
import type { MCPConfig, MCPContext } from './mcp.js';
|
|
14
15
|
import type { McpToolTarget } from './mcp-tool-name.js';
|
|
@@ -48,6 +49,8 @@ export interface RuntimeOptions {
|
|
|
48
49
|
}>;
|
|
49
50
|
/** Explicit original execution targets for generated protocol aliases. */
|
|
50
51
|
toolTargets?: Record<string, McpToolTarget>;
|
|
52
|
+
/** Async serializers for standard get tools, keyed by emitted tool name. */
|
|
53
|
+
getSerializers?: Record<string, ApiSerializerReference>;
|
|
51
54
|
/** Cache hint emitted for deploy-static tools/list results. */
|
|
52
55
|
toolListCacheHint?: {
|
|
53
56
|
ttlMs: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-runtime-template.d.ts","sourceRoot":"","sources":["../../src/generators/mcp-runtime-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AASxD,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,kCAAkC;IAClC,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,UAAU,CAAC;IAErB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,wDAAwD;IACxD,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvC,WAAW,CAAC,EAAE;YACZ,YAAY,EAAE,OAAO,CAAC;YACtB,eAAe,EAAE,OAAO,CAAC;YACzB,cAAc,EAAE,OAAO,CAAC;YACxB,aAAa,EAAE,OAAO,CAAC;SACxB,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,KAAK,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC;YACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;SAC1B,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,CAAC,CAAC;IACH,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC5C,+DAA+D;IAC/D,iBAAiB,CAAC,EAAE;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC;KAClC,CAAC;IACF,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CACpB,MAAM,EACN;QACE,KAAK,EAAE,iBAAiB,CAAC;QACzB,QAAQ,EAAE,OAAO,CAAC;QAClB,sEAAsE;QACtE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,OAAO,CAAC;KACxB,CACF,CAAC;IACF,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACN;QACE,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,qDAAqD;QACrD,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CACF,CAAC;IAEF;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEpD;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CACjD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"mcp-runtime-template.d.ts","sourceRoot":"","sources":["../../src/generators/mcp-runtime-template.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ function capitalize(str) {
|
|
|
24
24
|
* @returns TypeScript code for server entry point
|
|
25
25
|
*/
|
|
26
26
|
function generateRuntimeBootstrap(options = {}) {
|
|
27
|
-
const { name = "smrt-mcp-server", version = "1.0.0", description = "Auto-generated MCP server from SMRT objects", debug = false, tools = [], toolTargets: explicitToolTargets, customActions = {}, taskActions = {}, tenantScopedObjects = [], stiTargets = {}, listOrderBy = {}, toolListCacheHint = {
|
|
27
|
+
const { name = "smrt-mcp-server", version = "1.0.0", description = "Auto-generated MCP server from SMRT objects", debug = false, tools = [], toolTargets: explicitToolTargets, getSerializers = {}, customActions = {}, taskActions = {}, tenantScopedObjects = [], stiTargets = {}, listOrderBy = {}, toolListCacheHint = {
|
|
28
28
|
ttlMs: 864e5,
|
|
29
29
|
cacheScope: "private"
|
|
30
30
|
} } = options;
|
|
@@ -85,7 +85,7 @@ ${indent} if (!item) {
|
|
|
85
85
|
${indent} throw new Error('Object not found');
|
|
86
86
|
${indent} }
|
|
87
87
|
|
|
88
|
-
${indent} return successResult(
|
|
88
|
+
${indent} return successResult(await serializeGetResult(${JSON.stringify(tool.name)}, item));
|
|
89
89
|
${indent}}`;
|
|
90
90
|
case "create": return `${indent}case '${tool.name}': {
|
|
91
91
|
${indent} const { collection, objectName: targetObjectName } = await resolveCreateTarget(${JSON.stringify(objectName)}, ${JSON.stringify(lookup)}, args, aiConfig);
|
|
@@ -248,6 +248,20 @@ const PUBLIC_JSON_OPTIONS = {
|
|
|
248
248
|
.map((permission) => permission.trim())
|
|
249
249
|
.filter(Boolean),
|
|
250
250
|
};
|
|
251
|
+
const GET_SERIALIZERS: Record<string, { importPath: string; exportName: string }> = ${JSON.stringify(getSerializers)};
|
|
252
|
+
|
|
253
|
+
async function serializeGetResult(toolName: string, item: any): Promise<any> {
|
|
254
|
+
const reference = GET_SERIALIZERS[toolName];
|
|
255
|
+
if (!reference) return item.toPublicJSON(PUBLIC_JSON_OPTIONS);
|
|
256
|
+
const serializerModule = await import(reference.importPath);
|
|
257
|
+
const serializer = serializerModule[reference.exportName];
|
|
258
|
+
if (typeof serializer !== 'function') {
|
|
259
|
+
throw new Error(
|
|
260
|
+
\`MCP get serializer '\${reference.exportName}' was not exported by '\${reference.importPath}'\`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return toPublicResult(await serializer(item, PUBLIC_JSON_OPTIONS));
|
|
264
|
+
}
|
|
251
265
|
|
|
252
266
|
/**
|
|
253
267
|
* Page-bound guard (#2367). MCP tool arguments are untyped JSON, so \`limit\`
|
|
@@ -357,6 +371,17 @@ function errorResult(structuredContent: any, text: string, _meta?: Record<string
|
|
|
357
371
|
};
|
|
358
372
|
}
|
|
359
373
|
|
|
374
|
+
function normalizePublicToolError(error: any): { code: string; message: string } | undefined {
|
|
375
|
+
if (!error || typeof error !== 'object') return undefined;
|
|
376
|
+
if (
|
|
377
|
+
typeof error.code !== 'string' ||
|
|
378
|
+
!/^[A-Za-z][A-Za-z0-9_.:-]{0,127}$/.test(error.code) ||
|
|
379
|
+
typeof error.publicMessage !== 'string' ||
|
|
380
|
+
error.publicMessage.length === 0
|
|
381
|
+
) return undefined;
|
|
382
|
+
return { code: error.code, message: error.publicMessage };
|
|
383
|
+
}
|
|
384
|
+
|
|
360
385
|
${hasTaskActions ? `
|
|
361
386
|
// The bundled SDK validates tools/call responses against its older result
|
|
362
387
|
// codec, which does not yet know CreateTaskResult. Intercept the extension at
|
|
@@ -678,11 +703,12 @@ ${hasTenantScoped ? `
|
|
|
678
703
|
|
|
679
704
|
return result;
|
|
680
705
|
} catch (error) {
|
|
681
|
-
const
|
|
706
|
+
const publicError = normalizePublicToolError(error);
|
|
707
|
+
const errorMessage = publicError?.message ?? (error instanceof Error ? error.message : 'Unknown error');
|
|
682
708
|
console.error(\`[MCP] Tool execution failed: \${toolName}\`, error);
|
|
683
709
|
|
|
684
710
|
return errorResult(
|
|
685
|
-
{ error: { message: errorMessage } },
|
|
711
|
+
{ error: publicError ?? { message: errorMessage } },
|
|
686
712
|
\`Error executing tool \${toolName}: \${errorMessage}\`,
|
|
687
713
|
);
|
|
688
714
|
}
|