@elevasis/sdk 1.15.1 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/cli.cjs +2325 -124
  2. package/dist/index.d.ts +410 -473
  3. package/dist/index.js +96 -44
  4. package/dist/node/index.d.ts +69 -0
  5. package/dist/node/index.js +273 -0
  6. package/dist/test-utils/index.d.ts +473 -466
  7. package/dist/types/worker/platform.d.ts +2 -9
  8. package/package.json +12 -3
  9. package/reference/_navigation.md +23 -1
  10. package/reference/_reference-manifest.json +98 -0
  11. package/reference/claude-config/rules/agent-start-here.md +13 -0
  12. package/reference/claude-config/rules/organization-model.md +40 -40
  13. package/reference/claude-config/rules/organization-os.md +16 -16
  14. package/reference/claude-config/rules/vibe.md +13 -13
  15. package/reference/claude-config/skills/knowledge/SKILL.md +253 -0
  16. package/reference/claude-config/skills/{configure → knowledge}/operations/codify-level-a.md +100 -100
  17. package/reference/claude-config/skills/{configure → knowledge}/operations/codify-level-b.md +158 -158
  18. package/reference/claude-config/skills/knowledge/operations/customers.md +109 -0
  19. package/reference/claude-config/skills/knowledge/operations/features.md +113 -0
  20. package/reference/claude-config/skills/knowledge/operations/goals.md +118 -0
  21. package/reference/claude-config/skills/knowledge/operations/identity.md +93 -0
  22. package/reference/claude-config/skills/knowledge/operations/labels.md +89 -0
  23. package/reference/claude-config/skills/knowledge/operations/offerings.md +109 -0
  24. package/reference/claude-config/skills/knowledge/operations/roles.md +99 -0
  25. package/reference/claude-config/skills/knowledge/operations/techStack.md +102 -0
  26. package/reference/claude-config/skills/run-ui/SKILL.md +73 -0
  27. package/reference/claude-config/skills/setup/SKILL.md +270 -270
  28. package/reference/claude-config/skills/tutorial/SKILL.md +249 -0
  29. package/reference/claude-config/skills/tutorial/progress-template.md +74 -0
  30. package/reference/claude-config/skills/tutorial/technical.md +1309 -0
  31. package/reference/claude-config/skills/tutorial/vibe-coder.md +890 -0
  32. package/reference/claude-config/sync-notes/2026-05-04-elevasis-workspace.md +71 -0
  33. package/reference/claude-config/sync-notes/2026-05-04-template-skills-run-ui-and-tutorial.md +59 -0
  34. package/reference/deployment/index.mdx +5 -5
  35. package/reference/examples/organization-model.ts +40 -0
  36. package/reference/framework/index.mdx +1 -1
  37. package/reference/framework/tutorial-system.mdx +86 -173
  38. package/reference/packages/core/src/knowledge/README.md +32 -0
  39. package/reference/packages/ui/src/knowledge/README.md +31 -0
  40. package/reference/packages/ui/src/theme/presets/README.md +19 -0
  41. package/reference/scaffold/core/organization-model.mdx +1 -1
  42. package/reference/scaffold/recipes/add-a-feature.md +1 -1
  43. package/reference/scaffold/recipes/customize-crm-actions.md +433 -433
  44. package/reference/scaffold/recipes/customize-organization-model.md +3 -3
  45. package/reference/scaffold/recipes/extend-lead-gen.md +90 -55
  46. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +1 -1
  47. package/reference/scaffold/recipes/index.md +6 -0
  48. package/reference/scaffold/reference/contracts.md +1265 -1154
  49. package/reference/scaffold/reference/feature-registry.md +2 -1
  50. package/reference/scaffold/ui/composition-extensibility.mdx +17 -0
  51. package/reference/claude-config/skills/configure/SKILL.md +0 -98
  52. package/reference/claude-config/skills/configure/operations/customers.md +0 -150
  53. package/reference/claude-config/skills/configure/operations/features.md +0 -162
  54. package/reference/claude-config/skills/configure/operations/goals.md +0 -147
  55. package/reference/claude-config/skills/configure/operations/identity.md +0 -133
  56. package/reference/claude-config/skills/configure/operations/labels.md +0 -128
  57. package/reference/claude-config/skills/configure/operations/offerings.md +0 -159
  58. package/reference/claude-config/skills/configure/operations/roles.md +0 -153
  59. package/reference/claude-config/skills/configure/operations/techStack.md +0 -139
package/dist/index.js CHANGED
@@ -37,11 +37,105 @@ var ToolingError = class extends ExecutionError {
37
37
  this.details = details;
38
38
  }
39
39
  };
40
+ z.string().uuid();
41
+ z.string().trim().min(1).max(1e3);
42
+ z.enum(["agent", "workflow"]);
43
+ z.enum(["agent", "workflow", "scheduler", "api"]);
44
+ z.string().trim().toLowerCase().min(1, "Credential name required").max(100, "Credential name too long (max 100 chars)").regex(
45
+ /^[a-z0-9]+(-[a-z0-9]+)+$/,
46
+ "Credential name must be lowercase letters, numbers, and hyphens in format: service-environment (e.g., gmail-prod, attio-dev)"
47
+ );
48
+ z.enum(["google-sheets", "dropbox"]);
49
+ z.string().min(10, "Authorization code too short").max(1e3, "Authorization code too long");
50
+ z.string().min(10, "State parameter too short").max(2048, "State parameter too long");
51
+ z.string().trim().transform((str) => str.replace(/[<>'"]/g, ""));
52
+ var EmailSchema = z.string().email();
53
+ z.string().url();
54
+ z.object({
55
+ limit: z.coerce.number().int().min(1).max(100).default(20),
56
+ offset: z.coerce.number().int().min(0).default(0)
57
+ });
58
+ z.string().datetime();
59
+ z.object({
60
+ startDate: z.string().datetime(),
61
+ endDate: z.string().datetime()
62
+ });
63
+ var ORGANIZATION_MODEL_ICON_TOKENS = [
64
+ "nav.dashboard",
65
+ "nav.sales",
66
+ "nav.crm",
67
+ "nav.lead-gen",
68
+ "nav.projects",
69
+ "nav.operations",
70
+ "nav.monitoring",
71
+ "nav.knowledge",
72
+ "nav.settings",
73
+ "nav.admin",
74
+ "nav.archive",
75
+ "knowledge.playbook",
76
+ "knowledge.strategy",
77
+ "knowledge.reference",
78
+ "feature.dashboard",
79
+ "feature.sales",
80
+ "feature.crm",
81
+ "feature.finance",
82
+ "feature.lead-gen",
83
+ "feature.platform",
84
+ "feature.projects",
85
+ "feature.operations",
86
+ "feature.knowledge",
87
+ "feature.monitoring",
88
+ "feature.settings",
89
+ "feature.admin",
90
+ "feature.archive",
91
+ "feature.seo",
92
+ "resource.agent",
93
+ "resource.workflow",
94
+ "resource.integration",
95
+ "resource.database",
96
+ "resource.user",
97
+ "resource.team",
98
+ "integration.gmail",
99
+ "integration.google-sheets",
100
+ "integration.attio",
101
+ "surface.dashboard",
102
+ "surface.overview",
103
+ "surface.command-view",
104
+ "surface.command-queue",
105
+ "surface.pipeline",
106
+ "surface.lists",
107
+ "surface.resources",
108
+ "surface.settings",
109
+ "status.success",
110
+ "status.error",
111
+ "status.warning",
112
+ "status.info",
113
+ "status.pending",
114
+ "action.approve",
115
+ "action.reject",
116
+ "action.retry",
117
+ "action.edit",
118
+ "action.view",
119
+ "action.launch",
120
+ "action.message",
121
+ "action.escalate",
122
+ "action.promote",
123
+ "action.submit",
124
+ "action.email"
125
+ ];
126
+ var CustomIconTokenSchema = z.string().trim().max(80).regex(/^custom\.[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "Custom icon tokens must start with custom.");
127
+ var OrganizationModelBuiltinIconTokenSchema = z.enum(ORGANIZATION_MODEL_ICON_TOKENS);
128
+ var OrganizationModelIconTokenSchema = z.union([
129
+ OrganizationModelBuiltinIconTokenSchema,
130
+ CustomIconTokenSchema
131
+ ]);
132
+
133
+ // ../core/src/organization-model/domains/shared.ts
40
134
  var ModelIdSchema = z.string().trim().min(1).max(100).regex(/^[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "IDs must be lowercase and use -, _, or . separators");
41
135
  var LabelSchema = z.string().trim().min(1).max(120);
42
136
  var DescriptionSchema = z.string().trim().min(1).max(2e3);
43
137
  var ColorTokenSchema = z.string().trim().min(1).max(50);
44
- var IconNameSchema = z.string().trim().min(1).max(80);
138
+ var IconNameSchema = OrganizationModelIconTokenSchema;
45
139
  z.string().trim().startsWith("/").max(300);
46
140
  var ReferenceIdsSchema = z.array(ModelIdSchema).default([]);
47
141
  var DisplayMetadataSchema = z.object({
@@ -3694,48 +3788,6 @@ var ResourceRegistry = class {
3694
3788
  }
3695
3789
  return cache.commandView;
3696
3790
  }
3697
- /**
3698
- * List resources that have UI interfaces configured
3699
- * Used by Execution Runner Catalog UI
3700
- *
3701
- * @param organizationName - Organization name
3702
- * @param environment - Optional environment filter ('dev' or 'prod')
3703
- * @returns Array of resources with interfaces
3704
- */
3705
- listExecutable(organizationName, environment) {
3706
- const cache = this.serializedCache.get(organizationName);
3707
- if (!cache) {
3708
- return [];
3709
- }
3710
- const results = [];
3711
- cache.definitions.workflows.forEach((serializedWorkflow, resourceId) => {
3712
- if (!serializedWorkflow.interface) return;
3713
- if (environment && serializedWorkflow.config.status !== environment) return;
3714
- results.push({
3715
- resourceId,
3716
- resourceName: serializedWorkflow.config.name,
3717
- resourceType: "workflow",
3718
- description: serializedWorkflow.config.description,
3719
- status: serializedWorkflow.config.status,
3720
- version: serializedWorkflow.config.version,
3721
- interface: serializedWorkflow.interface
3722
- });
3723
- });
3724
- cache.definitions.agents.forEach((serializedAgent, resourceId) => {
3725
- if (!serializedAgent.interface) return;
3726
- if (environment && serializedAgent.config.status !== environment) return;
3727
- results.push({
3728
- resourceId,
3729
- resourceName: serializedAgent.config.name,
3730
- resourceType: "agent",
3731
- description: serializedAgent.config.description,
3732
- status: serializedAgent.config.status,
3733
- version: serializedAgent.config.version,
3734
- interface: serializedAgent.interface
3735
- });
3736
- });
3737
- return results;
3738
- }
3739
3791
  };
3740
3792
  var StageChangeEventSchema = z.object({
3741
3793
  type: z.literal("stage_change"),
@@ -3942,4 +3994,4 @@ function isOurReplyAction(deal) {
3942
3994
  return (deal.ownership ?? getDealOwnership(deal)) === "us";
3943
3995
  }
3944
3996
 
3945
- export { ActivityEventSchema, DEFAULT_CRM_ACTIONS, ExecutionError, RegistryValidationError, ResourceRegistry, StepType, ToolingError, deriveActions };
3997
+ export { ActivityEventSchema, DEFAULT_CRM_ACTIONS, EmailSchema, ExecutionError, RegistryValidationError, ResourceRegistry, StepType, ToolingError, deriveActions };
@@ -0,0 +1,69 @@
1
+ type KnowledgeKind = 'playbook' | 'strategy' | 'reference';
2
+ interface KnowledgeCodegenNode {
3
+ id: string;
4
+ kind: KnowledgeKind;
5
+ title: string;
6
+ summary: string;
7
+ icon?: string;
8
+ body: string;
9
+ links: {
10
+ nodeId: string;
11
+ }[];
12
+ ownerIds: string[];
13
+ updatedAt: string;
14
+ }
15
+ interface GenerateKnowledgeNodesOptions {
16
+ sourceDir: string;
17
+ outputPath: string;
18
+ typeImportPath?: string;
19
+ exportedName?: string;
20
+ sourceLabel?: string;
21
+ }
22
+ interface GenerateKnowledgeNodesResult {
23
+ nodes: KnowledgeCodegenNode[];
24
+ outputPath: string;
25
+ }
26
+ declare function readKnowledgeNodeMdx(filePath: string): KnowledgeCodegenNode;
27
+ declare function generateKnowledgeNodesTs(options: {
28
+ nodes: KnowledgeCodegenNode[];
29
+ typeImportPath?: string;
30
+ exportedName?: string;
31
+ sourceLabel?: string;
32
+ }): string;
33
+ declare function generateKnowledgeNodes(options: GenerateKnowledgeNodesOptions): GenerateKnowledgeNodesResult;
34
+
35
+ interface KnowledgeNodeInput {
36
+ id: string;
37
+ kind: string;
38
+ title: string;
39
+ summary: string;
40
+ body: string;
41
+ }
42
+ interface KnowledgeSearchEntry {
43
+ id: string;
44
+ title: string;
45
+ summary: string;
46
+ bodyText: string;
47
+ }
48
+ interface CodegenResult {
49
+ bodiesTsx: string;
50
+ searchIndex: KnowledgeSearchEntry[];
51
+ }
52
+ /**
53
+ * Compiles knowledge nodes into generated file contents.
54
+ * Pure function: same input -> same output. No file I/O.
55
+ */
56
+ declare function generateKnowledgeBodies(nodes: KnowledgeNodeInput[]): Promise<CodegenResult>;
57
+
58
+ interface ResolvedKnowledgeLayout {
59
+ mode: 'monorepo' | 'external';
60
+ projectRoot: string;
61
+ omSourcePath: string;
62
+ mdxNodesDir: string;
63
+ generatedDir: string;
64
+ watchPaths: string[];
65
+ }
66
+ declare function runKnowledgeCodegen(layout: ResolvedKnowledgeLayout): Promise<void>;
67
+
68
+ export { generateKnowledgeBodies, generateKnowledgeNodes, generateKnowledgeNodesTs, readKnowledgeNodeMdx, runKnowledgeCodegen };
69
+ export type { CodegenResult, GenerateKnowledgeNodesOptions, GenerateKnowledgeNodesResult, KnowledgeCodegenNode, KnowledgeKind, KnowledgeNodeInput, KnowledgeSearchEntry, ResolvedKnowledgeLayout };
@@ -0,0 +1,273 @@
1
+ import { readFileSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
2
+ import { relative, dirname, resolve, join, extname } from 'path';
3
+ import { compile } from '@mdx-js/mdx';
4
+ import remarkGfm from 'remark-gfm';
5
+
6
+ // src/knowledge-codegen.ts
7
+ function listMdxFiles(directory) {
8
+ return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
9
+ const path = join(directory, entry.name);
10
+ if (entry.isDirectory()) return listMdxFiles(path);
11
+ return entry.isFile() && extname(entry.name) === ".mdx" ? [path] : [];
12
+ });
13
+ }
14
+ function parseScalar(value) {
15
+ const trimmed = value.trim();
16
+ const quoted = trimmed.match(/^['"]([\s\S]*)['"]$/);
17
+ return quoted ? quoted[1] : trimmed;
18
+ }
19
+ function parseFrontmatter(raw, filePath) {
20
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
21
+ if (!match) throw new Error(`[knowledge-node-codegen] Missing frontmatter in ${filePath}`);
22
+ const frontmatter = {};
23
+ const lines = match[1].split(/\r?\n/);
24
+ for (let index = 0; index < lines.length; index += 1) {
25
+ const line = lines[index];
26
+ if (!line.trim()) continue;
27
+ const pair = line.match(/^([A-Za-z][A-Za-z0-9]*):(?:\s*(.*))?$/);
28
+ if (!pair) throw new Error(`[knowledge-node-codegen] Invalid frontmatter line in ${filePath}: ${line}`);
29
+ const key = pair[1];
30
+ const inlineValue = pair[2]?.trim() ?? "";
31
+ if (inlineValue) {
32
+ frontmatter[key] = parseScalar(inlineValue);
33
+ continue;
34
+ }
35
+ const values = [];
36
+ while (index + 1 < lines.length && /^\s+-\s+/.test(lines[index + 1])) {
37
+ index += 1;
38
+ values.push(parseScalar(lines[index].replace(/^\s+-\s+/, "")));
39
+ }
40
+ frontmatter[key] = values;
41
+ }
42
+ return { frontmatter, body: match[2].trim() };
43
+ }
44
+ function assertString(frontmatter, key, filePath) {
45
+ const value = frontmatter[key];
46
+ if (typeof value !== "string" || value.trim().length === 0) {
47
+ throw new Error(`[knowledge-node-codegen] ${filePath} frontmatter requires string "${key}"`);
48
+ }
49
+ return value.trim();
50
+ }
51
+ function optionalString(frontmatter, key, filePath) {
52
+ const value = frontmatter[key];
53
+ if (value === void 0) return void 0;
54
+ if (typeof value !== "string" || value.trim().length === 0) {
55
+ throw new Error(`[knowledge-node-codegen] ${filePath} frontmatter "${key}" must be a nonempty string`);
56
+ }
57
+ return value.trim();
58
+ }
59
+ function assertKind(value, filePath) {
60
+ if (value === "playbook" || value === "strategy" || value === "reference") return value;
61
+ throw new Error(`[knowledge-node-codegen] ${filePath} has invalid kind "${value}"`);
62
+ }
63
+ function optionalStringArray(frontmatter, key, filePath) {
64
+ const value = frontmatter[key];
65
+ if (value === void 0) return [];
66
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
67
+ throw new Error(`[knowledge-node-codegen] ${filePath} frontmatter "${key}" must be a string array`);
68
+ }
69
+ return value.map((entry) => entry.trim()).filter(Boolean);
70
+ }
71
+ function readKnowledgeNodeMdx(filePath) {
72
+ const raw = readFileSync(filePath, "utf8");
73
+ const { frontmatter, body } = parseFrontmatter(raw, filePath);
74
+ return {
75
+ id: assertString(frontmatter, "id", filePath),
76
+ kind: assertKind(assertString(frontmatter, "kind", filePath), filePath),
77
+ title: assertString(frontmatter, "title", filePath),
78
+ summary: assertString(frontmatter, "description", filePath),
79
+ icon: optionalString(frontmatter, "icon", filePath),
80
+ body,
81
+ links: optionalStringArray(frontmatter, "links", filePath).map((nodeId) => ({ nodeId })),
82
+ ownerIds: optionalStringArray(frontmatter, "ownerIds", filePath),
83
+ updatedAt: assertString(frontmatter, "updatedAt", filePath)
84
+ };
85
+ }
86
+ function generateKnowledgeNodesTs(options) {
87
+ const exportedName = options.exportedName ?? "mdxKnowledgeNodes";
88
+ const typeImport = options.typeImportPath ? [`import type { OrgKnowledgeNode } from '${options.typeImportPath}'`, ""] : [];
89
+ const typeSatisfies = options.typeImportPath ? " satisfies OrgKnowledgeNode[]" : "";
90
+ return [
91
+ "// @generated by generate-knowledge-nodes -- DO NOT EDIT",
92
+ "// Regenerate: elevasis-sdk knowledge:generate",
93
+ `// Source: ${options.sourceLabel ?? "knowledge/nodes/**/*.mdx"}`,
94
+ "",
95
+ ...typeImport,
96
+ `export const ${exportedName} = ${JSON.stringify(options.nodes, null, 2)}${typeSatisfies}`,
97
+ ""
98
+ ].join("\n");
99
+ }
100
+ function generateKnowledgeNodes(options) {
101
+ const files = listMdxFiles(options.sourceDir).sort(
102
+ (a, b) => relative(options.sourceDir, a).localeCompare(relative(options.sourceDir, b))
103
+ );
104
+ const nodes = files.map(readKnowledgeNodeMdx);
105
+ const ids = /* @__PURE__ */ new Set();
106
+ for (const node of nodes) {
107
+ if (ids.has(node.id)) throw new Error(`[knowledge-node-codegen] Duplicate knowledge node id: ${node.id}`);
108
+ ids.add(node.id);
109
+ }
110
+ mkdirSync(dirname(options.outputPath), { recursive: true });
111
+ writeFileSync(
112
+ options.outputPath,
113
+ generateKnowledgeNodesTs({
114
+ nodes,
115
+ typeImportPath: options.typeImportPath,
116
+ exportedName: options.exportedName,
117
+ sourceLabel: options.sourceLabel
118
+ }),
119
+ "utf8"
120
+ );
121
+ return { nodes, outputPath: options.outputPath };
122
+ }
123
+ var ALLOWED_COMPONENTS = /* @__PURE__ */ new Set(["Card", "Cards", "Step", "Steps", "Callout", "Tab", "Tabs"]);
124
+ function extractCustomComponents(compiledCode) {
125
+ const found = /* @__PURE__ */ new Set();
126
+ const destructurePattern = /\{([^}]+)\}\s*=\s*_components/g;
127
+ let match;
128
+ while ((match = destructurePattern.exec(compiledCode)) !== null) {
129
+ for (const part of match[1].split(",")) {
130
+ const name = part.trim().split(":")[0].trim();
131
+ if (name && /^[A-Z]/.test(name)) {
132
+ found.add(name);
133
+ }
134
+ }
135
+ }
136
+ return [...found];
137
+ }
138
+ function validateComponents(nodeId, compiledCode) {
139
+ const components = extractCustomComponents(compiledCode);
140
+ const unknown = components.filter((c) => !ALLOWED_COMPONENTS.has(c));
141
+ if (unknown.length > 0) {
142
+ throw new Error(
143
+ `[knowledge-codegen] node "${nodeId}" uses unknown JSX component(s): ${unknown.join(", ")}.
144
+ Allowed components: ${[...ALLOWED_COMPONENTS].join(", ")}.
145
+ To add a component:
146
+ 1. Add it to ALLOWED_COMPONENTS in packages/sdk/src/node/knowledge-bodies-codegen.ts
147
+ 2. Add it to the runtime KnowledgeMDXProvider allowlist (Wave 3d)`
148
+ );
149
+ }
150
+ }
151
+ function stripToPlainText(body) {
152
+ return body.replace(/^(import|export)\s+.+$/gm, "").replace(/<[A-Z][^>]*>/g, "").replace(/<\/[A-Z][^>]*>/g, "").replace(/^#{1,6}\s+/gm, "").replace(/[*_`~]/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\n{3,}/g, "\n\n").trim();
153
+ }
154
+ var BODIES_HEADER = [
155
+ "// @generated by generate-knowledge-bodies -- DO NOT EDIT",
156
+ "// Regenerate: pnpm scaffold:sync",
157
+ "// Source: packages/elevasis-core/src/organization-model.ts",
158
+ "",
159
+ "import { Fragment, jsx, jsxs } from 'react/jsx-runtime'",
160
+ "import type { ComponentType } from 'react'",
161
+ ""
162
+ ].join("\n");
163
+ var FACTORY_BLOCK = [
164
+ "// ---------------------------------------------------------------------------",
165
+ "// Inline compiled MDX component factory",
166
+ "// ---------------------------------------------------------------------------",
167
+ "",
168
+ "type MDXRuntime = {",
169
+ " Fragment: typeof Fragment",
170
+ " jsx: typeof jsx",
171
+ " jsxs: typeof jsxs",
172
+ "}",
173
+ "",
174
+ "type KnowledgeBodyProps = {",
175
+ " components?: Record<string, ComponentType>",
176
+ "}",
177
+ "",
178
+ "/**",
179
+ " * Wraps a compiled MDX function-body string into a React component.",
180
+ " * The function-body format from @mdx-js/mdx expects arguments[0]",
181
+ " * to be { Fragment, jsx, jsxs } from react/jsx-runtime.",
182
+ " */",
183
+ "function makeKnowledgeComponent(fnBody: string): ComponentType<KnowledgeBodyProps> {",
184
+ " // eslint-disable-next-line @typescript-eslint/no-implied-eval",
185
+ " const factory = new Function(fnBody) as (runtime: MDXRuntime) => { default: ComponentType }",
186
+ " return function KnowledgeBody(props: KnowledgeBodyProps) {",
187
+ " const runtime = { Fragment, jsx, jsxs, ...props } as unknown as MDXRuntime",
188
+ " const mod = factory(runtime)",
189
+ " const Content = mod.default",
190
+ " return Content ? jsx(Content as ComponentType<KnowledgeBodyProps>, props) : null",
191
+ " }",
192
+ "}",
193
+ ""
194
+ ].join("\n");
195
+ var MAP_HEADER = [
196
+ "// ---------------------------------------------------------------------------",
197
+ "// Generated map: node id -> compiled React component",
198
+ "// ---------------------------------------------------------------------------",
199
+ ""
200
+ ].join("\n");
201
+ async function generateKnowledgeBodies(nodes) {
202
+ if (nodes.length === 0) {
203
+ const bodiesTsx2 = [
204
+ "// @generated by generate-knowledge-bodies -- DO NOT EDIT",
205
+ "// Regenerate: pnpm scaffold:sync",
206
+ "// Source: packages/elevasis-core/src/organization-model.ts",
207
+ "",
208
+ "import type { ComponentType } from 'react'",
209
+ "",
210
+ "export const KNOWLEDGE_BODIES: Record<",
211
+ " string,",
212
+ " ComponentType<{ components?: Record<string, ComponentType> }>",
213
+ "> = {}",
214
+ ""
215
+ ].join("\n");
216
+ return { bodiesTsx: bodiesTsx2, searchIndex: [] };
217
+ }
218
+ const nodeComments = [];
219
+ const mapEntries = [];
220
+ const searchIndex = [];
221
+ for (const node of nodes) {
222
+ if (/^(import|export)\s+/m.test(node.body)) {
223
+ throw new Error(
224
+ `[knowledge-codegen] node "${node.id}" body contains import/export statements, which are not allowed in Phase 1 MDX bodies.`
225
+ );
226
+ }
227
+ const compiled = await compile(node.body, {
228
+ outputFormat: "function-body",
229
+ jsx: false,
230
+ remarkPlugins: [remarkGfm]
231
+ });
232
+ const fnBodyCode = String(compiled);
233
+ validateComponents(node.id, fnBodyCode);
234
+ const bodyText = stripToPlainText(node.body);
235
+ searchIndex.push({ id: node.id, title: node.title, summary: node.summary, bodyText });
236
+ nodeComments.push(`// Node: ${node.id} (${node.kind})`);
237
+ mapEntries.push(` '${node.id}': makeKnowledgeComponent(${JSON.stringify(fnBodyCode)})`);
238
+ }
239
+ const mapBlock = `export const KNOWLEDGE_BODIES: Record<string, ComponentType<KnowledgeBodyProps>> = {
240
+ ` + mapEntries.join(",\n") + "\n}\n";
241
+ const bodiesTsx = BODIES_HEADER + FACTORY_BLOCK + MAP_HEADER + (nodeComments.length > 0 ? nodeComments.join("\n") + "\n\n" : "") + mapBlock;
242
+ return { bodiesTsx, searchIndex };
243
+ }
244
+ async function runKnowledgeCodegen(layout) {
245
+ let nodes;
246
+ if (layout.mode === "monorepo") {
247
+ const omSpecifier = "@repo/elevasis-core/organization-model";
248
+ const om = await import(
249
+ /* @vite-ignore */
250
+ omSpecifier
251
+ );
252
+ nodes = om.canonicalOrganizationModel.knowledge.nodes;
253
+ } else {
254
+ const outputPath = resolve(layout.generatedDir, "nodes.ts");
255
+ const result = generateKnowledgeNodes({
256
+ sourceDir: layout.mdxNodesDir,
257
+ outputPath,
258
+ typeImportPath: "@elevasis/core/organization-model",
259
+ exportedName: "mdxKnowledgeNodes"
260
+ });
261
+ nodes = result.nodes;
262
+ }
263
+ const { bodiesTsx, searchIndex } = await generateKnowledgeBodies(nodes);
264
+ mkdirSync(layout.generatedDir, { recursive: true });
265
+ writeFileSync(resolve(layout.generatedDir, "knowledge-bodies.tsx"), bodiesTsx, "utf8");
266
+ writeFileSync(
267
+ resolve(layout.generatedDir, "knowledge-search-index.json"),
268
+ JSON.stringify(searchIndex, null, 2) + "\n",
269
+ "utf8"
270
+ );
271
+ }
272
+
273
+ export { generateKnowledgeBodies, generateKnowledgeNodes, generateKnowledgeNodesTs, readKnowledgeNodeMdx, runKnowledgeCodegen };