@ekanos/cli 0.22.0 → 0.23.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 (77) hide show
  1. package/README.md +18 -4
  2. package/dist/commands/add.js +21 -10
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/contract.js +12 -2
  5. package/dist/commands/contract.js.map +1 -1
  6. package/dist/commands/dev.js +33 -2
  7. package/dist/commands/dev.js.map +1 -1
  8. package/dist/commands/publish.d.ts +6 -0
  9. package/dist/commands/publish.js +80 -4
  10. package/dist/commands/publish.js.map +1 -1
  11. package/dist/commands/status.d.ts +44 -0
  12. package/dist/commands/status.js +79 -18
  13. package/dist/commands/status.js.map +1 -1
  14. package/dist/commands/upgrade.js +287 -144
  15. package/dist/commands/upgrade.js.map +1 -1
  16. package/dist/docs-links.js +5 -1
  17. package/dist/docs-links.js.map +1 -1
  18. package/dist/errors.d.ts +2 -0
  19. package/dist/errors.js +9 -0
  20. package/dist/errors.js.map +1 -1
  21. package/dist/exit-codes.d.ts +3 -0
  22. package/dist/exit-codes.js +3 -0
  23. package/dist/exit-codes.js.map +1 -1
  24. package/dist/experience/checks.js +2 -1
  25. package/dist/experience/checks.js.map +1 -1
  26. package/dist/experience/definition-checks.d.ts +7 -0
  27. package/dist/experience/definition-checks.js +36 -4
  28. package/dist/experience/definition-checks.js.map +1 -1
  29. package/dist/experience/init.js +10 -0
  30. package/dist/experience/init.js.map +1 -1
  31. package/dist/experience/load-experience.js +33 -2
  32. package/dist/experience/load-experience.js.map +1 -1
  33. package/dist/experience/pins.d.ts +10 -0
  34. package/dist/experience/pins.js +19 -1
  35. package/dist/experience/pins.js.map +1 -1
  36. package/dist/generated/phosphor-names.d.ts +3 -0
  37. package/dist/generated/phosphor-names.js +1541 -0
  38. package/dist/generated/phosphor-names.js.map +1 -0
  39. package/dist/harness-scaffold.d.ts +13 -0
  40. package/dist/harness-scaffold.js +19 -3
  41. package/dist/harness-scaffold.js.map +1 -1
  42. package/dist/icon-findings.d.ts +12 -17
  43. package/dist/icon-findings.js +49 -74
  44. package/dist/icon-findings.js.map +1 -1
  45. package/dist/index.js +28 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/lockfile-instances.d.ts +60 -0
  48. package/dist/lockfile-instances.js +177 -0
  49. package/dist/lockfile-instances.js.map +1 -0
  50. package/dist/pack-hygiene.d.ts +8 -0
  51. package/dist/pack-hygiene.js +57 -0
  52. package/dist/pack-hygiene.js.map +1 -0
  53. package/dist/package-manager.d.ts +34 -6
  54. package/dist/package-manager.js +130 -20
  55. package/dist/package-manager.js.map +1 -1
  56. package/dist/project.js +11 -0
  57. package/dist/project.js.map +1 -1
  58. package/dist/repo/scaffold.js +4 -0
  59. package/dist/repo/scaffold.js.map +1 -1
  60. package/dist/schema-skew.js.map +1 -1
  61. package/dist/validate-findings.js +10 -1
  62. package/dist/validate-findings.js.map +1 -1
  63. package/dist/workspace-root.d.ts +16 -0
  64. package/dist/workspace-root.js +50 -0
  65. package/dist/workspace-root.js.map +1 -0
  66. package/package.json +4 -4
  67. package/templates/AGENTS.md.tmpl +11 -15
  68. package/templates/experience/package.json.tmpl +8 -6
  69. package/templates/experience/src/widgets/hello-widget.test.tsx.tmpl +49 -0
  70. package/templates/experience/vitest.config.ts.tmpl +21 -0
  71. package/templates/harness/next.config.mjs.tmpl +7 -4
  72. package/templates/package.json.tmpl +5 -5
  73. package/templates/skills/build-integration/references/widget-design.md +2 -3
  74. package/templates/skills/polish-widgets/references/patterns.md +5 -5
  75. package/dist/generated/fa-free-names.d.ts +0 -9
  76. package/dist/generated/fa-free-names.js +0 -2599
  77. package/dist/generated/fa-free-names.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { ExperienceSurfacesSchema, WorkflowTemplateSchema, EKANOS_CHECK_STAGE_IDS, buildExperienceSurfaces, canonicalJson, sha256Hex, validateAgainstSchema, workflowTemplateProblems, } from '@ekanos/integration-schema';
1
+ import { ExperienceSurfacesSchema, WorkflowTemplateSchema, EKANOS_CHECK_STAGE_IDS, buildExperienceSurfaces, canonicalJson, interpretErrorFixture, sha256Hex, validateAgainstSchema, workflowTemplateProblems, } from '@ekanos/integration-schema';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import { declaredOperationKeys } from './integrations-codegen.js';
@@ -49,6 +49,7 @@ export function analyzeDefinition(project, loaded, pinned) {
49
49
  checkIntegration(integration, `page "${page.id}"`);
50
50
  }
51
51
  findings.push(...checkSurfaces(project, definition));
52
+ findings.push(...checkWidgetLayouts(project, definition));
52
53
  for (const section of (_g = (_a = definition.reviewQueue) === null || _a === void 0 ? void 0 : _a.sections) !== null && _g !== void 0 ? _g : []) {
53
54
  if (!checkIntegration(section.integration, `review section "${section.id}"`))
54
55
  continue;
@@ -147,6 +148,22 @@ export function checkSurfaces(project, definition) {
147
148
  file: project.entry,
148
149
  }));
149
150
  }
151
+ /**
152
+ * The dashboard reads a widget's `size`, `layouts.lg.w` and `layouts.lg.maxHeight`
153
+ * and nothing else. `x`, `y` and `h` are required by the layout type, so their
154
+ * presence says nothing; a `md` or `sm` box is optional and is never read, so
155
+ * declaring one is a finding.
156
+ */
157
+ export function checkWidgetLayouts(project, definition) {
158
+ return definition.widgets.flatMap((widget) => {
159
+ const unused = ['md', 'sm'].filter((breakpoint) => { var _a; return ((_a = widget.layouts) === null || _a === void 0 ? void 0 : _a[breakpoint]) !== undefined; });
160
+ if (unused.length === 0)
161
+ return [];
162
+ return [
163
+ warn(`widget "${widget.id}" declares layouts.${unused.join(' and layouts.')}, which the dashboard does not read.`, 'Only size, layouts.lg.w and layouts.lg.maxHeight take effect. Delete the unused box, or keep it knowing it changes nothing.', project.entry),
164
+ ];
165
+ });
166
+ }
150
167
  /** `dist/surfaces.json`: the surfaces and suggested layout as data, no code. */
151
168
  export function buildSurfaces(project, definition) {
152
169
  return buildExperienceSurfaces(project.slug, definition);
@@ -171,20 +188,35 @@ export function checkFixtures(project, pinned) {
171
188
  continue;
172
189
  }
173
190
  const [, kind, op, variant] = match;
174
- if (variant === 'error')
175
- continue;
176
191
  const operation = contract.operations.find((o) => o.kind === kind && o.name === op);
177
192
  if (!operation) {
178
193
  findings.push(err(`${rel}: ${use.name}@${use.version} has no ${kind}/${op}.`, 'Delete the fixture or fix its name.', rel));
179
194
  continue;
180
195
  }
196
+ if (variant === 'error') {
197
+ // An error variant is a refusal, not output: it is never held to the
198
+ // output schema, only to the refusal reasons the executor can give.
199
+ let authored;
200
+ try {
201
+ authored = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));
202
+ }
203
+ catch (_a) {
204
+ findings.push(err(`${rel} is not valid JSON.`, 'Fix the syntax.', rel));
205
+ continue;
206
+ }
207
+ const error = interpretErrorFixture(authored);
208
+ if (error.kind === 'invalid') {
209
+ findings.push(err(`${rel}: ${error.problem}`, 'An error fixture is { "reason": "<refusal reason>", "message": "<optional detail>" }.', rel));
210
+ }
211
+ continue;
212
+ }
181
213
  if (operation.opaque.output)
182
214
  continue;
183
215
  let value;
184
216
  try {
185
217
  value = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));
186
218
  }
187
- catch (_a) {
219
+ catch (_b) {
188
220
  findings.push(err(`${rel} is not valid JSON.`, 'Fix the syntax.', rel));
189
221
  continue;
190
222
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definition-checks.js","sourceRoot":"","sources":["../../src/experience/definition-checks.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ExperienceManifest,\n type ExperienceSurfaces,\n ExperienceSurfacesSchema,\n type Finding,\n type WorkflowTemplate,\n WorkflowTemplateSchema,\n EKANOS_CHECK_STAGE_IDS,\n buildExperienceSurfaces,\n canonicalJson,\n sha256Hex,\n validateAgainstSchema,\n workflowTemplateProblems,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type {\n LoadedExperienceDefinition,\n LoadedExperienceModule,\n} from './definition-shape';\nimport { declaredOperationKeys } from './integrations-codegen';\nimport { type PinnedIntegration, effectLookup } from './pins';\nimport type { ExperienceProject } from './project';\n\nexport const DEFINITION_CHECK = 'checks/experience-definition';\nexport const SURFACES_CHECK = EKANOS_CHECK_STAGE_IDS.experienceSurfaces;\n\nconst err = (message: string, hint: string, file?: string): Finding => ({\n check: DEFINITION_CHECK,\n severity: 'error',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\nconst warn = (message: string, hint: string, file?: string): Finding => ({\n check: DEFINITION_CHECK,\n severity: 'warn',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\nexport interface DefinitionAnalysis {\n findings: Finding[];\n workflows: WorkflowTemplate[];\n}\n\n/**\n * Cross-check the loaded definition against `ekanos.json` and the pinned\n * contracts: every integration a widget, page, review section or workflow step names\n * must be declared, every operation must be in that integration's allowlist, the\n * review queue reads only, and each template serializes to the engine's DSL.\n */\nexport function analyzeDefinition(\n project: ExperienceProject,\n loaded: LoadedExperienceModule,\n pinned: readonly PinnedIntegration[],\n): DefinitionAnalysis {\n const { definition } = loaded;\n const findings: Finding[] = [];\n const workflows: WorkflowTemplate[] = [];\n const declaredIntegrations = new Map(\n project.integrations.map((u) => [u.name, u]),\n );\n const declared = new Map(\n project.integrations.map((u) => [\n u.name,\n new Set(declaredOperationKeys(u)),\n ]),\n );\n const contractOps = new Map(\n pinned.map(({ use, contract }) => [\n use.name,\n new Map(contract.operations.map((op) => [`${op.kind}/${op.name}`, op])),\n ]),\n );\n\n if (definition.slug !== project.slug) {\n findings.push(\n err(\n `the definition's slug \"${definition.slug}\" differs from ekanos.json \"${project.slug}\".`,\n 'Make them equal.',\n project.entry,\n ),\n );\n }\n\n const checkIntegration = (integration: string, owner: string) => {\n if (!declaredIntegrations.has(integration)) {\n findings.push(\n err(\n `${owner} uses integration \"${integration}\", which ekanos.json \"integrations\" does not declare.`,\n `Add it with \"ekanos add ${integration}@<version>\".`,\n project.entry,\n ),\n );\n\n return false;\n }\n\n return true;\n };\n\n for (const widget of definition.widgets) {\n for (const integration of widget.integrations)\n checkIntegration(integration, `widget \"${widget.id}\"`);\n }\n for (const page of definition.pages) {\n for (const integration of page.integrations ?? [])\n checkIntegration(integration, `page \"${page.id}\"`);\n }\n\n findings.push(...checkSurfaces(project, definition));\n\n for (const section of definition.reviewQueue?.sections ?? []) {\n if (\n !checkIntegration(section.integration, `review section \"${section.id}\"`)\n )\n continue;\n if (!declared.get(section.integration)?.has(section.read)) {\n findings.push(\n err(\n `review section \"${section.id}\" reads ${section.read}, which integration \"${section.integration}\" does not declare.`,\n 'Add the operation to the integration in ekanos.json, or read another one.',\n project.entry,\n ),\n );\n } else if (\n contractOps.get(section.integration)?.get(section.read)?.effect !== 'read'\n ) {\n findings.push(\n err(\n `review section \"${section.id}\" reads ${section.read}, which is not a read operation.`,\n 'The review queue is reads-only; writes belong behind a workflow approval.',\n project.entry,\n ),\n );\n }\n }\n\n const effectOf = effectLookup(pinned);\n for (const template of definition.workflows) {\n const where = `workflow \"${template.id}\"`;\n let steps: ReturnType<typeof template.build>;\n try {\n steps = template.build();\n } catch (error) {\n findings.push(\n err(\n `${where}: build() threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the template.',\n project.entry,\n ),\n );\n continue;\n }\n\n let stepsOk = true;\n for (const step of steps) {\n if (step.type !== 'tool' || !step.integration || !step.op) continue;\n if (!checkIntegration(step.integration, `${where} step \"${step.id}\"`)) {\n stepsOk = false;\n } else if (!declared.get(step.integration)?.has(step.op)) {\n stepsOk = false;\n findings.push(\n err(\n `${where} step \"${step.id}\" calls ${step.integration} ${step.op}, which the integration does not declare.`,\n 'Add the operation to the integration\\'s \"operations\" in ekanos.json (ekanos add --ops).',\n project.entry,\n ),\n );\n }\n }\n if (!stepsOk) continue;\n\n let dsl: unknown;\n try {\n dsl = loaded.serializeWorkflowTemplate(template, {\n effectOf,\n experience: project.slug,\n });\n } catch (error) {\n findings.push(\n err(\n `${where}: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the template.',\n project.entry,\n ),\n );\n continue;\n }\n const parsed = WorkflowTemplateSchema.safeParse(dsl);\n if (!parsed.success) {\n findings.push(\n err(\n `${where} does not serialize to a valid workflow: ${parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ')}`,\n 'Fix the step definitions.',\n project.entry,\n ),\n );\n continue;\n }\n for (const problem of workflowTemplateProblems(parsed.data)) {\n findings.push(\n err(`${where}: ${problem}.`, 'Fix the template.', project.entry),\n );\n }\n\n const gated = new Set<string>();\n const preds = new Map<string, string[]>();\n for (const e of parsed.data.edges)\n preds.set(e.to, [...(preds.get(e.to) ?? []), e.from]);\n const hasGate = (id: string, seen = new Set<string>()): boolean => {\n if (seen.has(id)) return false;\n seen.add(id);\n\n return (preds.get(id) ?? []).some(\n (p) =>\n parsed.data.steps.find((s) => s.id === p)?.type === 'approval_gate' ||\n hasGate(p, seen),\n );\n };\n for (const s of parsed.data.steps) {\n if (s.type === 'fusion_tool' && s.effect === 'write' && !hasGate(s.id)) {\n gated.add(s.id);\n }\n }\n for (const id of gated) {\n findings.push(\n warn(\n `${where}: write step \"${id}\" has no approval gate upstream.`,\n 'Put step.approval(...) before a write so a person confirms it.',\n project.entry,\n ),\n );\n }\n\n workflows.push(parsed.data);\n }\n\n return { findings, workflows };\n}\n\n// ─── surfaces ───────────────────────────────────────────────────────────────\n\n/**\n * The surfaces contract: page kinds, canvas widgets, routes and the suggested\n * layout must be well formed and refer only to what the experience declares.\n * The same rules `defineExperience` enforces, re-run on the loaded definition\n * so a definition built by an older SDK, or by hand, cannot slip past.\n */\nexport function checkSurfaces(\n project: ExperienceProject,\n definition: LoadedExperienceDefinition,\n): Finding[] {\n const built = buildSurfaces(project, definition);\n const parsed = ExperienceSurfacesSchema.safeParse(built);\n if (parsed.success) return [];\n\n return parsed.error.issues.map((issue) => ({\n check: SURFACES_CHECK,\n severity: 'error' as const,\n message: `${issue.path.length > 0 ? `${issue.path.join('.')}: ` : ''}${issue.message}`,\n hint: 'Fix the page kinds, canvas widgets or suggestedLayout in the experience definition.',\n file: project.entry,\n }));\n}\n\n/** `dist/surfaces.json`: the surfaces and suggested layout as data, no code. */\nexport function buildSurfaces(\n project: ExperienceProject,\n definition: LoadedExperienceDefinition,\n): ExperienceSurfaces {\n return buildExperienceSurfaces(project.slug, definition);\n}\n\n// ─── fixtures ───────────────────────────────────────────────────────────────\n\nconst FIXTURE_NAME = /^(tool|action)-(.+)\\.(default|empty|error)\\.json$/;\n\n/** `fixtures/<integration>/<kind>-<name>.<variant>.json` must satisfy the pinned output schema. */\nexport function checkFixtures(\n project: ExperienceProject,\n pinned: readonly PinnedIntegration[],\n): Finding[] {\n const findings: Finding[] = [];\n const root = path.join(project.dir, 'fixtures');\n if (!fs.existsSync(root)) return findings;\n\n for (const { use, contract } of pinned) {\n const dir = path.join(root, use.name);\n if (!fs.existsSync(dir)) continue;\n for (const name of fs.readdirSync(dir)) {\n const rel = `fixtures/${use.name}/${name}`;\n const match = FIXTURE_NAME.exec(name);\n if (!match) {\n findings.push(\n warn(\n `${rel} is not <kind>-<name>.<default|empty|error>.json.`,\n 'Rename it so the harness can find it.',\n rel,\n ),\n );\n continue;\n }\n const [, kind, op, variant] = match;\n if (variant === 'error') continue;\n const operation = contract.operations.find(\n (o) => o.kind === kind && o.name === op,\n );\n if (!operation) {\n findings.push(\n err(\n `${rel}: ${use.name}@${use.version} has no ${kind}/${op}.`,\n 'Delete the fixture or fix its name.',\n rel,\n ),\n );\n continue;\n }\n if (operation.opaque.output) continue;\n let value: unknown;\n try {\n value = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));\n } catch {\n findings.push(err(`${rel} is not valid JSON.`, 'Fix the syntax.', rel));\n continue;\n }\n const problems = validateAgainstSchema(operation.output, value);\n if (problems.length > 0) {\n findings.push(\n err(\n `${rel} violates the pinned output schema: ${problems[0]}`,\n 'A fixture must satisfy the contract, or the harness would show data the integration can never return.',\n rel,\n ),\n );\n }\n }\n }\n\n return findings;\n}\n\n// ─── manifest ───────────────────────────────────────────────────────────────\n\nexport function buildManifest(input: {\n project: ExperienceProject;\n definition: LoadedExperienceDefinition;\n pinned: readonly PinnedIntegration[];\n workflows: readonly WorkflowTemplate[];\n version: string;\n sdk: string;\n surfaces: ExperienceSurfaces;\n}): ExperienceManifest {\n const { project, definition, pinned } = input;\n const body = {\n schemaVersion: 1 as const,\n slug: project.slug,\n form: 'composed' as const,\n version: input.version,\n sdk: input.sdk,\n integrations: project.integrations,\n contractRefs: pinned.map(({ use, contract }) => ({\n integration: use.name,\n version: use.version,\n contractVersion: contract.contractVersion,\n digest: contract.digest,\n })),\n ...(definition.sidebar ? { sidebar: definition.sidebar } : {}),\n widgets: definition.widgets.map((w) => ({\n id: w.id,\n title: w.title,\n integrations: [...w.integrations],\n ...(w.width ? { width: w.width } : {}),\n ...(w.size ? { size: w.size } : {}),\n ...(w.layouts ? { layouts: w.layouts } : {}),\n ...(w.isCollapsible === undefined\n ? {}\n : { isCollapsible: w.isCollapsible }),\n ...(w.aiFooterEnabled === undefined\n ? {}\n : { aiFooterEnabled: w.aiFooterEnabled }),\n })),\n pages: definition.pages.map((p) => ({\n id: p.id,\n ...(p.path === undefined ? {} : { path: p.path }),\n title: p.title,\n integrations: [...(p.integrations ?? [])],\n ...(p.kind === undefined ? {} : { kind: p.kind }),\n ...(p.widgets === undefined ? {} : { widgets: [...p.widgets] }),\n ...(p.routes && p.routes.length > 0\n ? { routes: p.routes.map((r) => ({ path: r.path, title: r.title })) }\n : {}),\n })),\n surfacesDigest: input.surfaces.digest,\n workflowTemplates: [...input.workflows],\n ...(definition.reviewQueue\n ? {\n reviewQueue: {\n readsOnly: true as const,\n sections: definition.reviewQueue.sections.map((s) => ({\n id: s.id,\n integration: s.integration,\n read: s.read,\n })),\n },\n }\n : {}),\n };\n\n return {\n ...body,\n digest: `sha256:${sha256Hex(canonicalJson(body))}`,\n };\n}\n"]}
1
+ {"version":3,"file":"definition-checks.js","sourceRoot":"","sources":["../../src/experience/definition-checks.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ExperienceManifest,\n type ExperienceSurfaces,\n ExperienceSurfacesSchema,\n type Finding,\n type WorkflowTemplate,\n WorkflowTemplateSchema,\n EKANOS_CHECK_STAGE_IDS,\n buildExperienceSurfaces,\n canonicalJson,\n interpretErrorFixture,\n sha256Hex,\n validateAgainstSchema,\n workflowTemplateProblems,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type {\n LoadedExperienceDefinition,\n LoadedExperienceModule,\n} from './definition-shape';\nimport { declaredOperationKeys } from './integrations-codegen';\nimport { type PinnedIntegration, effectLookup } from './pins';\nimport type { ExperienceProject } from './project';\n\nexport const DEFINITION_CHECK = 'checks/experience-definition';\nexport const SURFACES_CHECK = EKANOS_CHECK_STAGE_IDS.experienceSurfaces;\n\nconst err = (message: string, hint: string, file?: string): Finding => ({\n check: DEFINITION_CHECK,\n severity: 'error',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\nconst warn = (message: string, hint: string, file?: string): Finding => ({\n check: DEFINITION_CHECK,\n severity: 'warn',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\nexport interface DefinitionAnalysis {\n findings: Finding[];\n workflows: WorkflowTemplate[];\n}\n\n/**\n * Cross-check the loaded definition against `ekanos.json` and the pinned\n * contracts: every integration a widget, page, review section or workflow step names\n * must be declared, every operation must be in that integration's allowlist, the\n * review queue reads only, and each template serializes to the engine's DSL.\n */\nexport function analyzeDefinition(\n project: ExperienceProject,\n loaded: LoadedExperienceModule,\n pinned: readonly PinnedIntegration[],\n): DefinitionAnalysis {\n const { definition } = loaded;\n const findings: Finding[] = [];\n const workflows: WorkflowTemplate[] = [];\n const declaredIntegrations = new Map(\n project.integrations.map((u) => [u.name, u]),\n );\n const declared = new Map(\n project.integrations.map((u) => [\n u.name,\n new Set(declaredOperationKeys(u)),\n ]),\n );\n const contractOps = new Map(\n pinned.map(({ use, contract }) => [\n use.name,\n new Map(contract.operations.map((op) => [`${op.kind}/${op.name}`, op])),\n ]),\n );\n\n if (definition.slug !== project.slug) {\n findings.push(\n err(\n `the definition's slug \"${definition.slug}\" differs from ekanos.json \"${project.slug}\".`,\n 'Make them equal.',\n project.entry,\n ),\n );\n }\n\n const checkIntegration = (integration: string, owner: string) => {\n if (!declaredIntegrations.has(integration)) {\n findings.push(\n err(\n `${owner} uses integration \"${integration}\", which ekanos.json \"integrations\" does not declare.`,\n `Add it with \"ekanos add ${integration}@<version>\".`,\n project.entry,\n ),\n );\n\n return false;\n }\n\n return true;\n };\n\n for (const widget of definition.widgets) {\n for (const integration of widget.integrations)\n checkIntegration(integration, `widget \"${widget.id}\"`);\n }\n for (const page of definition.pages) {\n for (const integration of page.integrations ?? [])\n checkIntegration(integration, `page \"${page.id}\"`);\n }\n\n findings.push(...checkSurfaces(project, definition));\n findings.push(...checkWidgetLayouts(project, definition));\n\n for (const section of definition.reviewQueue?.sections ?? []) {\n if (\n !checkIntegration(section.integration, `review section \"${section.id}\"`)\n )\n continue;\n if (!declared.get(section.integration)?.has(section.read)) {\n findings.push(\n err(\n `review section \"${section.id}\" reads ${section.read}, which integration \"${section.integration}\" does not declare.`,\n 'Add the operation to the integration in ekanos.json, or read another one.',\n project.entry,\n ),\n );\n } else if (\n contractOps.get(section.integration)?.get(section.read)?.effect !== 'read'\n ) {\n findings.push(\n err(\n `review section \"${section.id}\" reads ${section.read}, which is not a read operation.`,\n 'The review queue is reads-only; writes belong behind a workflow approval.',\n project.entry,\n ),\n );\n }\n }\n\n const effectOf = effectLookup(pinned);\n for (const template of definition.workflows) {\n const where = `workflow \"${template.id}\"`;\n let steps: ReturnType<typeof template.build>;\n try {\n steps = template.build();\n } catch (error) {\n findings.push(\n err(\n `${where}: build() threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the template.',\n project.entry,\n ),\n );\n continue;\n }\n\n let stepsOk = true;\n for (const step of steps) {\n if (step.type !== 'tool' || !step.integration || !step.op) continue;\n if (!checkIntegration(step.integration, `${where} step \"${step.id}\"`)) {\n stepsOk = false;\n } else if (!declared.get(step.integration)?.has(step.op)) {\n stepsOk = false;\n findings.push(\n err(\n `${where} step \"${step.id}\" calls ${step.integration} ${step.op}, which the integration does not declare.`,\n 'Add the operation to the integration\\'s \"operations\" in ekanos.json (ekanos add --ops).',\n project.entry,\n ),\n );\n }\n }\n if (!stepsOk) continue;\n\n let dsl: unknown;\n try {\n dsl = loaded.serializeWorkflowTemplate(template, {\n effectOf,\n experience: project.slug,\n });\n } catch (error) {\n findings.push(\n err(\n `${where}: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the template.',\n project.entry,\n ),\n );\n continue;\n }\n const parsed = WorkflowTemplateSchema.safeParse(dsl);\n if (!parsed.success) {\n findings.push(\n err(\n `${where} does not serialize to a valid workflow: ${parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ')}`,\n 'Fix the step definitions.',\n project.entry,\n ),\n );\n continue;\n }\n for (const problem of workflowTemplateProblems(parsed.data)) {\n findings.push(\n err(`${where}: ${problem}.`, 'Fix the template.', project.entry),\n );\n }\n\n const gated = new Set<string>();\n const preds = new Map<string, string[]>();\n for (const e of parsed.data.edges)\n preds.set(e.to, [...(preds.get(e.to) ?? []), e.from]);\n const hasGate = (id: string, seen = new Set<string>()): boolean => {\n if (seen.has(id)) return false;\n seen.add(id);\n\n return (preds.get(id) ?? []).some(\n (p) =>\n parsed.data.steps.find((s) => s.id === p)?.type === 'approval_gate' ||\n hasGate(p, seen),\n );\n };\n for (const s of parsed.data.steps) {\n if (s.type === 'fusion_tool' && s.effect === 'write' && !hasGate(s.id)) {\n gated.add(s.id);\n }\n }\n for (const id of gated) {\n findings.push(\n warn(\n `${where}: write step \"${id}\" has no approval gate upstream.`,\n 'Put step.approval(...) before a write so a person confirms it.',\n project.entry,\n ),\n );\n }\n\n workflows.push(parsed.data);\n }\n\n return { findings, workflows };\n}\n\n// ─── surfaces ───────────────────────────────────────────────────────────────\n\n/**\n * The surfaces contract: page kinds, canvas widgets, routes and the suggested\n * layout must be well formed and refer only to what the experience declares.\n * The same rules `defineExperience` enforces, re-run on the loaded definition\n * so a definition built by an older SDK, or by hand, cannot slip past.\n */\nexport function checkSurfaces(\n project: ExperienceProject,\n definition: LoadedExperienceDefinition,\n): Finding[] {\n const built = buildSurfaces(project, definition);\n const parsed = ExperienceSurfacesSchema.safeParse(built);\n if (parsed.success) return [];\n\n return parsed.error.issues.map((issue) => ({\n check: SURFACES_CHECK,\n severity: 'error' as const,\n message: `${issue.path.length > 0 ? `${issue.path.join('.')}: ` : ''}${issue.message}`,\n hint: 'Fix the page kinds, canvas widgets or suggestedLayout in the experience definition.',\n file: project.entry,\n }));\n}\n\n/**\n * The dashboard reads a widget's `size`, `layouts.lg.w` and `layouts.lg.maxHeight`\n * and nothing else. `x`, `y` and `h` are required by the layout type, so their\n * presence says nothing; a `md` or `sm` box is optional and is never read, so\n * declaring one is a finding.\n */\nexport function checkWidgetLayouts(\n project: ExperienceProject,\n definition: LoadedExperienceDefinition,\n): Finding[] {\n return definition.widgets.flatMap((widget) => {\n const unused = (['md', 'sm'] as const).filter(\n (breakpoint) => widget.layouts?.[breakpoint] !== undefined,\n );\n\n if (unused.length === 0) return [];\n\n return [\n warn(\n `widget \"${widget.id}\" declares layouts.${unused.join(' and layouts.')}, which the dashboard does not read.`,\n 'Only size, layouts.lg.w and layouts.lg.maxHeight take effect. Delete the unused box, or keep it knowing it changes nothing.',\n project.entry,\n ),\n ];\n });\n}\n\n/** `dist/surfaces.json`: the surfaces and suggested layout as data, no code. */\nexport function buildSurfaces(\n project: ExperienceProject,\n definition: LoadedExperienceDefinition,\n): ExperienceSurfaces {\n return buildExperienceSurfaces(project.slug, definition);\n}\n\n// ─── fixtures ───────────────────────────────────────────────────────────────\n\nconst FIXTURE_NAME = /^(tool|action)-(.+)\\.(default|empty|error)\\.json$/;\n\n/** `fixtures/<integration>/<kind>-<name>.<variant>.json` must satisfy the pinned output schema. */\nexport function checkFixtures(\n project: ExperienceProject,\n pinned: readonly PinnedIntegration[],\n): Finding[] {\n const findings: Finding[] = [];\n const root = path.join(project.dir, 'fixtures');\n if (!fs.existsSync(root)) return findings;\n\n for (const { use, contract } of pinned) {\n const dir = path.join(root, use.name);\n if (!fs.existsSync(dir)) continue;\n for (const name of fs.readdirSync(dir)) {\n const rel = `fixtures/${use.name}/${name}`;\n const match = FIXTURE_NAME.exec(name);\n if (!match) {\n findings.push(\n warn(\n `${rel} is not <kind>-<name>.<default|empty|error>.json.`,\n 'Rename it so the harness can find it.',\n rel,\n ),\n );\n continue;\n }\n const [, kind, op, variant] = match;\n const operation = contract.operations.find(\n (o) => o.kind === kind && o.name === op,\n );\n if (!operation) {\n findings.push(\n err(\n `${rel}: ${use.name}@${use.version} has no ${kind}/${op}.`,\n 'Delete the fixture or fix its name.',\n rel,\n ),\n );\n continue;\n }\n if (variant === 'error') {\n // An error variant is a refusal, not output: it is never held to the\n // output schema, only to the refusal reasons the executor can give.\n let authored: unknown;\n try {\n authored = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));\n } catch {\n findings.push(\n err(`${rel} is not valid JSON.`, 'Fix the syntax.', rel),\n );\n continue;\n }\n const error = interpretErrorFixture(authored);\n if (error.kind === 'invalid') {\n findings.push(\n err(\n `${rel}: ${error.problem}`,\n 'An error fixture is { \"reason\": \"<refusal reason>\", \"message\": \"<optional detail>\" }.',\n rel,\n ),\n );\n }\n continue;\n }\n if (operation.opaque.output) continue;\n let value: unknown;\n try {\n value = JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));\n } catch {\n findings.push(err(`${rel} is not valid JSON.`, 'Fix the syntax.', rel));\n continue;\n }\n const problems = validateAgainstSchema(operation.output, value);\n if (problems.length > 0) {\n findings.push(\n err(\n `${rel} violates the pinned output schema: ${problems[0]}`,\n 'A fixture must satisfy the contract, or the harness would show data the integration can never return.',\n rel,\n ),\n );\n }\n }\n }\n\n return findings;\n}\n\n// ─── manifest ───────────────────────────────────────────────────────────────\n\nexport function buildManifest(input: {\n project: ExperienceProject;\n definition: LoadedExperienceDefinition;\n pinned: readonly PinnedIntegration[];\n workflows: readonly WorkflowTemplate[];\n version: string;\n sdk: string;\n surfaces: ExperienceSurfaces;\n}): ExperienceManifest {\n const { project, definition, pinned } = input;\n const body = {\n schemaVersion: 1 as const,\n slug: project.slug,\n form: 'composed' as const,\n version: input.version,\n sdk: input.sdk,\n integrations: project.integrations,\n contractRefs: pinned.map(({ use, contract }) => ({\n integration: use.name,\n version: use.version,\n contractVersion: contract.contractVersion,\n digest: contract.digest,\n })),\n ...(definition.sidebar ? { sidebar: definition.sidebar } : {}),\n widgets: definition.widgets.map((w) => ({\n id: w.id,\n title: w.title,\n integrations: [...w.integrations],\n ...(w.width ? { width: w.width } : {}),\n ...(w.size ? { size: w.size } : {}),\n ...(w.layouts ? { layouts: w.layouts } : {}),\n ...(w.isCollapsible === undefined\n ? {}\n : { isCollapsible: w.isCollapsible }),\n ...(w.aiFooterEnabled === undefined\n ? {}\n : { aiFooterEnabled: w.aiFooterEnabled }),\n })),\n pages: definition.pages.map((p) => ({\n id: p.id,\n ...(p.path === undefined ? {} : { path: p.path }),\n title: p.title,\n integrations: [...(p.integrations ?? [])],\n ...(p.kind === undefined ? {} : { kind: p.kind }),\n ...(p.widgets === undefined ? {} : { widgets: [...p.widgets] }),\n ...(p.routes && p.routes.length > 0\n ? { routes: p.routes.map((r) => ({ path: r.path, title: r.title })) }\n : {}),\n })),\n surfacesDigest: input.surfaces.digest,\n workflowTemplates: [...input.workflows],\n ...(definition.reviewQueue\n ? {\n reviewQueue: {\n readsOnly: true as const,\n sections: definition.reviewQueue.sections.map((s) => ({\n id: s.id,\n integration: s.integration,\n read: s.read,\n })),\n },\n }\n : {}),\n };\n\n return {\n ...body,\n digest: `sha256:${sha256Hex(canonicalJson(body))}`,\n };\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import { invalidStateError, usageError } from '../errors.js';
4
+ import { ensureBuildScriptsAnswered } from '../pnpm-builds.js';
4
5
  import { classifyPath, writeFileNoFollow } from '../safe-fs.js';
5
6
  import { readTemplate, toDisplayName } from '../templates.js';
6
7
  const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -12,12 +13,17 @@ const FILES = [
12
13
  { template: 'gitignore.tmpl', dest: '.gitignore' },
13
14
  { template: 'eslint.config.mjs.tmpl', dest: 'eslint.config.mjs' },
14
15
  { template: 'AGENTS.md.tmpl', dest: 'AGENTS.md' },
16
+ { template: 'vitest.config.ts.tmpl', dest: 'vitest.config.ts' },
15
17
  { template: 'ekanos.lock.json.tmpl', dest: 'ekanos.lock.json' },
16
18
  { template: 'src/experience.ts.tmpl', dest: 'src/experience.ts' },
17
19
  {
18
20
  template: 'src/widgets/hello-widget.tsx.tmpl',
19
21
  dest: 'src/widgets/hello-widget.tsx',
20
22
  },
23
+ {
24
+ template: 'src/widgets/hello-widget.test.tsx.tmpl',
25
+ dest: 'src/widgets/hello-widget.test.tsx',
26
+ },
21
27
  {
22
28
  template: 'src/.ekanos/integrations.d.ts.tmpl',
23
29
  dest: 'src/.ekanos/integrations.d.ts',
@@ -48,6 +54,10 @@ export function runInitExperience(ctx, args) {
48
54
  writeFileNoFollow(targetDir, destPath, readTemplate(`experience/${template}`, vars));
49
55
  created.push(dest);
50
56
  }
57
+ // vitest brings esbuild, whose build script pnpm refuses until it is answered.
58
+ if (ensureBuildScriptsAnswered(targetDir).changed.length > 0) {
59
+ created.push('pnpm-workspace.yaml');
60
+ }
51
61
  for (const keep of ['contracts/.gitkeep', 'fixtures/.gitkeep']) {
52
62
  const destPath = path.join(targetDir, keep);
53
63
  if (classifyPath(destPath) === 'missing') {
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/experience/init.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { classifyPath, writeFileNoFollow } from '../safe-fs';\nimport { readTemplate, toDisplayName } from '../templates';\n\nconst SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/** template (under templates/experience/) -> destination. */\nconst FILES: ReadonlyArray<{ template: string; dest: string }> = [\n { template: 'ekanos.json.tmpl', dest: 'ekanos.json' },\n { template: 'package.json.tmpl', dest: 'package.json' },\n { template: 'tsconfig.json.tmpl', dest: 'tsconfig.json' },\n { template: 'gitignore.tmpl', dest: '.gitignore' },\n { template: 'eslint.config.mjs.tmpl', dest: 'eslint.config.mjs' },\n { template: 'AGENTS.md.tmpl', dest: 'AGENTS.md' },\n { template: 'ekanos.lock.json.tmpl', dest: 'ekanos.lock.json' },\n { template: 'src/experience.ts.tmpl', dest: 'src/experience.ts' },\n {\n template: 'src/widgets/hello-widget.tsx.tmpl',\n dest: 'src/widgets/hello-widget.tsx',\n },\n {\n template: 'src/.ekanos/integrations.d.ts.tmpl',\n dest: 'src/.ekanos/integrations.d.ts',\n },\n];\n\nexport interface InitExperienceArgs {\n slug?: string;\n dir?: string;\n cwd: string;\n force: boolean;\n}\n\n/** `ekanos init --kind experience`: scaffold a project with no integrations yet. */\nexport function runInitExperience(\n ctx: CliContext,\n args: InitExperienceArgs,\n): ExitCode {\n const slug = args.slug;\n if (!slug || !SLUG_PATTERN.test(slug)) {\n throw usageError(\n slug ? `Invalid slug \"${slug}\".` : 'init requires a slug.',\n 'Pass kebab-case: \"ekanos init --kind experience --slug content-engine\".',\n );\n }\n const targetDir = path.resolve(args.cwd, args.dir ?? slug);\n if (fs.existsSync(targetDir) && fs.lstatSync(targetDir).isSymbolicLink()) {\n throw invalidStateError(\n `The target directory ${targetDir} is a symlink.`,\n 'Scaffold into the real directory.',\n );\n }\n fs.mkdirSync(targetDir, { recursive: true });\n\n const vars = { SLUG: slug, DISPLAY_NAME: toDisplayName(slug) };\n const created: string[] = [];\n const skipped: string[] = [];\n for (const { template, dest } of FILES) {\n const destPath = path.join(targetDir, dest);\n const kind = classifyPath(destPath);\n if (kind !== 'missing' && kind !== 'symlink' && !args.force) {\n skipped.push(dest);\n continue;\n }\n writeFileNoFollow(\n targetDir,\n destPath,\n readTemplate(`experience/${template}`, vars),\n );\n created.push(dest);\n }\n for (const keep of ['contracts/.gitkeep', 'fixtures/.gitkeep']) {\n const destPath = path.join(targetDir, keep);\n if (classifyPath(destPath) === 'missing') {\n writeFileNoFollow(targetDir, destPath, '');\n created.push(keep);\n }\n }\n\n for (const file of created) ctx.log(` created ${file}`);\n for (const file of skipped)\n ctx.log(` skipped ${file} (already exists; --force overwrites)`);\n\n return ctx.succeed(\n { kind: 'experience', slug, dir: targetDir, created, skipped },\n `Scaffolded experience \"${slug}\". Next: cd ${path.relative(args.cwd, targetDir) || '.'} && install, then \"ekanos add <integration>@<version> --from-dir <contracts folder>\".`,\n );\n}\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/experience/init.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { CliContext } from '../context';\nimport { invalidStateError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { ensureBuildScriptsAnswered } from '../pnpm-builds';\nimport { classifyPath, writeFileNoFollow } from '../safe-fs';\nimport { readTemplate, toDisplayName } from '../templates';\n\nconst SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/** template (under templates/experience/) -> destination. */\nconst FILES: ReadonlyArray<{ template: string; dest: string }> = [\n { template: 'ekanos.json.tmpl', dest: 'ekanos.json' },\n { template: 'package.json.tmpl', dest: 'package.json' },\n { template: 'tsconfig.json.tmpl', dest: 'tsconfig.json' },\n { template: 'gitignore.tmpl', dest: '.gitignore' },\n { template: 'eslint.config.mjs.tmpl', dest: 'eslint.config.mjs' },\n { template: 'AGENTS.md.tmpl', dest: 'AGENTS.md' },\n { template: 'vitest.config.ts.tmpl', dest: 'vitest.config.ts' },\n { template: 'ekanos.lock.json.tmpl', dest: 'ekanos.lock.json' },\n { template: 'src/experience.ts.tmpl', dest: 'src/experience.ts' },\n {\n template: 'src/widgets/hello-widget.tsx.tmpl',\n dest: 'src/widgets/hello-widget.tsx',\n },\n {\n template: 'src/widgets/hello-widget.test.tsx.tmpl',\n dest: 'src/widgets/hello-widget.test.tsx',\n },\n {\n template: 'src/.ekanos/integrations.d.ts.tmpl',\n dest: 'src/.ekanos/integrations.d.ts',\n },\n];\n\nexport interface InitExperienceArgs {\n slug?: string;\n dir?: string;\n cwd: string;\n force: boolean;\n}\n\n/** `ekanos init --kind experience`: scaffold a project with no integrations yet. */\nexport function runInitExperience(\n ctx: CliContext,\n args: InitExperienceArgs,\n): ExitCode {\n const slug = args.slug;\n if (!slug || !SLUG_PATTERN.test(slug)) {\n throw usageError(\n slug ? `Invalid slug \"${slug}\".` : 'init requires a slug.',\n 'Pass kebab-case: \"ekanos init --kind experience --slug content-engine\".',\n );\n }\n const targetDir = path.resolve(args.cwd, args.dir ?? slug);\n if (fs.existsSync(targetDir) && fs.lstatSync(targetDir).isSymbolicLink()) {\n throw invalidStateError(\n `The target directory ${targetDir} is a symlink.`,\n 'Scaffold into the real directory.',\n );\n }\n fs.mkdirSync(targetDir, { recursive: true });\n\n const vars = { SLUG: slug, DISPLAY_NAME: toDisplayName(slug) };\n const created: string[] = [];\n const skipped: string[] = [];\n for (const { template, dest } of FILES) {\n const destPath = path.join(targetDir, dest);\n const kind = classifyPath(destPath);\n if (kind !== 'missing' && kind !== 'symlink' && !args.force) {\n skipped.push(dest);\n continue;\n }\n writeFileNoFollow(\n targetDir,\n destPath,\n readTemplate(`experience/${template}`, vars),\n );\n created.push(dest);\n }\n // vitest brings esbuild, whose build script pnpm refuses until it is answered.\n if (ensureBuildScriptsAnswered(targetDir).changed.length > 0) {\n created.push('pnpm-workspace.yaml');\n }\n for (const keep of ['contracts/.gitkeep', 'fixtures/.gitkeep']) {\n const destPath = path.join(targetDir, keep);\n if (classifyPath(destPath) === 'missing') {\n writeFileNoFollow(targetDir, destPath, '');\n created.push(keep);\n }\n }\n\n for (const file of created) ctx.log(` created ${file}`);\n for (const file of skipped)\n ctx.log(` skipped ${file} (already exists; --force overwrites)`);\n\n return ctx.succeed(\n { kind: 'experience', slug, dir: targetDir, created, skipped },\n `Scaffolded experience \"${slug}\". Next: cd ${path.relative(args.cwd, targetDir) || '.'} && install, then \"ekanos add <integration>@<version> --from-dir <contracts folder>\".`,\n );\n}\n"]}
@@ -4,6 +4,33 @@ import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
5
5
  import { pathToFileURL } from 'node:url';
6
6
  import { preconditionError } from '../errors.js';
7
+ /**
8
+ * ESM output has no `require`, so esbuild's shim throws "Dynamic require of
9
+ * \"react\" is not supported" the moment a bundled CommonJS dependency (a
10
+ * `use-sync-external-store`, a UI kit's transitive deps) requires one of the
11
+ * packages kept external. Giving the bundle a real `require` lets that call
12
+ * reach the external package the same way the rest of the entry does.
13
+ */
14
+ const REQUIRE_BANNER = "import { createRequire as __ekanosCreateRequire } from 'node:module';\n" +
15
+ 'const require = __ekanosCreateRequire(import.meta.url);';
16
+ /**
17
+ * Every `@ekanos/*` package is imported natively (so the entry and the host
18
+ * share one copy of the SDK) except `@ekanos/ui`. Its `page` entry is built
19
+ * with a bundler's `require` shim for the Next internals it carries, and
20
+ * Node's ESM loader has no `require` for that shim to find: imported natively
21
+ * it throws "Calling `require` for \"react\" in an environment that doesn't
22
+ * expose the `require` function". Bundling it here lets the banner's
23
+ * `require` serve it. The loader only reads the definition and never renders
24
+ * a component, so a second copy of the UI kit costs nothing.
25
+ */
26
+ const externalizeEkanosExceptUi = {
27
+ name: 'ekanos-external-except-ui',
28
+ setup(b) {
29
+ b.onResolve({ filter: /^@ekanos\// }, (args) => args.path === '@ekanos/ui' || args.path.startsWith('@ekanos/ui/')
30
+ ? undefined
31
+ : { path: args.path, external: true });
32
+ },
33
+ };
7
34
  const stubServerOnly = {
8
35
  name: 'ekanos-stub-server-only',
9
36
  setup(b) {
@@ -35,7 +62,7 @@ export async function loadExperience(project, options = {}) {
35
62
  const inlineSdk = (_a = options.inlineSdk) !== null && _a !== void 0 ? _a : process.env.EKANOS_INLINE_SDK;
36
63
  const external = inlineSdk
37
64
  ? ['react', 'react-dom', '@tanstack/react-query']
38
- : ['@ekanos/*', 'react', 'react-dom', '@tanstack/react-query', 'zod'];
65
+ : ['react', 'react-dom', '@tanstack/react-query', 'zod'];
39
66
  const alias = inlineSdk
40
67
  ? Object.fromEntries([
41
68
  ['experience', 'index.ts'],
@@ -64,8 +91,12 @@ export async function loadExperience(project, options = {}) {
64
91
  format: 'esm',
65
92
  bundle: true,
66
93
  jsx: 'automatic',
94
+ banner: { js: REQUIRE_BANNER },
67
95
  external,
68
- plugins: [stubServerOnly],
96
+ plugins: [
97
+ ...(inlineSdk ? [] : [externalizeEkanosExceptUi]),
98
+ stubServerOnly,
99
+ ],
69
100
  loader: { '.css': 'empty', '.svg': 'dataurl', '.png': 'dataurl' },
70
101
  logLevel: 'silent',
71
102
  absWorkingDir: project.dir,
@@ -1 +1 @@
1
- {"version":3,"file":"load-experience.js","sourceRoot":"","sources":["../../src/experience/load-experience.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Plugin, build } from 'esbuild';\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { preconditionError } from '../errors';\nimport type {\n LoadedExperienceDefinition,\n LoadedExperienceModule,\n} from './definition-shape';\nimport type { ExperienceProject } from './project';\n\nconst stubServerOnly: Plugin = {\n name: 'ekanos-stub-server-only',\n setup(b) {\n b.onResolve({ filter: /^server-only$/ }, () => ({\n path: 'server-only',\n namespace: 'ekanos-server-only-stub',\n }));\n b.onLoad({ filter: /.*/, namespace: 'ekanos-server-only-stub' }, () => ({\n contents: '',\n loader: 'js',\n }));\n },\n};\n\nexport interface LoadExperienceOptions {\n /**\n * Root of an `@ekanos/sdk` checkout to bundle instead of importing\n * `@ekanos/sdk` from node_modules. Needed only when the SDK's exports point\n * at TypeScript source (the monorepo's own tests); a published SDK ships\n * built output. Also settable as EKANOS_INLINE_SDK.\n */\n inlineSdk?: string;\n}\n\nexport type LoadedExperience =\n | ({ ok: true } & LoadedExperienceModule)\n | { ok: false; message: string };\n\n/**\n * Evaluate the experience entry in Node to read its definition, including the\n * workflow templates' `build()` output. Components are loaded but never\n * rendered, so a widget needs no browser to be inspected.\n */\nexport async function loadExperience(\n project: ExperienceProject,\n options: LoadExperienceOptions = {},\n): Promise<LoadedExperience> {\n const entry = path.join(project.dir, project.entry);\n const nodeModules = path.join(project.dir, 'node_modules');\n if (!fs.existsSync(nodeModules)) {\n throw preconditionError(\n `No node_modules in ${project.dir}: the packages the experience imports are not installed.`,\n 'Install dependencies first, then re-run.',\n );\n }\n\n const cacheDir = path.join(nodeModules, '.cache', 'ekanos-cli');\n fs.mkdirSync(cacheDir, { recursive: true });\n const outfile = path.join(\n cacheDir,\n `experience-${crypto.randomBytes(6).toString('hex')}.mjs`,\n );\n\n const inlineSdk = options.inlineSdk ?? process.env.EKANOS_INLINE_SDK;\n const external = inlineSdk\n ? ['react', 'react-dom', '@tanstack/react-query']\n : ['@ekanos/*', 'react', 'react-dom', '@tanstack/react-query', 'zod'];\n const alias = inlineSdk\n ? Object.fromEntries(\n [\n ['experience', 'index.ts'],\n ['experience/client', 'client.tsx'],\n ['experience/server', 'server.ts'],\n ['experience/runtime', 'runtime.ts'],\n ].map(([sub, file]) => [\n `@ekanos/sdk/${sub}`,\n path.join(inlineSdk, 'src', 'experience', file as string),\n ]),\n )\n : undefined;\n\n try {\n try {\n await build({\n stdin: {\n contents:\n `import definition from ${JSON.stringify(entry)};\\n` +\n \"export { serializeWorkflowTemplate, slotsUsedBy } from '@ekanos/sdk/experience';\\n\" +\n 'export default definition;\\n',\n resolveDir: project.dir,\n sourcefile: 'ekanos-experience-loader.ts',\n loader: 'ts',\n },\n outfile,\n alias,\n platform: 'node',\n format: 'esm',\n bundle: true,\n jsx: 'automatic',\n external,\n plugins: [stubServerOnly],\n loader: { '.css': 'empty', '.svg': 'dataurl', '.png': 'dataurl' },\n logLevel: 'silent',\n absWorkingDir: project.dir,\n });\n } catch (error) {\n return {\n ok: false,\n message: `Could not bundle ${project.entry}: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n let mod: Partial<LoadedExperienceModule> & { default?: unknown };\n try {\n mod = (await import(pathToFileURL(outfile).href)) as typeof mod;\n } catch (error) {\n return {\n ok: false,\n message: `${project.entry} threw while loading: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n const def = mod.default as { kind?: unknown } | undefined;\n if (!def || typeof def !== 'object' || def.kind !== 'experience') {\n return {\n ok: false,\n message: `${project.entry} must \"export default defineExperience({...})\".`,\n };\n }\n\n if (\n typeof mod.serializeWorkflowTemplate !== 'function' ||\n typeof mod.slotsUsedBy !== 'function'\n ) {\n return {\n ok: false,\n message:\n 'The installed @ekanos/sdk has no experience API. Upgrade it (ekanos upgrade).',\n };\n }\n\n return {\n ok: true,\n definition: def as LoadedExperienceDefinition,\n serializeWorkflowTemplate: mod.serializeWorkflowTemplate,\n slotsUsedBy: mod.slotsUsedBy,\n };\n } finally {\n fs.rmSync(outfile, { force: true });\n }\n}\n"]}
1
+ {"version":3,"file":"load-experience.js","sourceRoot":"","sources":["../../src/experience/load-experience.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAO9C;;;;;;GAMG;AACH,MAAM,cAAc,GAClB,yEAAyE;IACzE,yDAAyD,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,yBAAyB,GAAW;IACxC,IAAI,EAAE,2BAA2B;IACjC,KAAK,CAAC,CAAC;QACL,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7C,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAC/D,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CACxC,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,MAAM,cAAc,GAAW;IAC7B,IAAI,EAAE,yBAAyB;IAC/B,KAAK,CAAC,CAAC;QACL,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAC9C,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,yBAAyB;SACrC,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,yBAAyB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACtE,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,IAAI;SACb,CAAC,CAAC,CAAC;IACN,CAAC;CACF,CAAC;AAgBF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA0B,EAC1B,OAAO,GAA0B,EAAE;;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,MAAM,iBAAiB,CACrB,sBAAsB,OAAO,CAAC,GAAG,0DAA0D,EAC3F,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAChE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,QAAQ,EACR,cAAc,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAC1D,CAAC;IAEF,MAAM,SAAS,SAAG,OAAO,CAAC,SAAS,mCAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACrE,MAAM,QAAQ,GAAG,SAAS;QACxB,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,uBAAuB,CAAC;QACjD,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,SAAS;QACrB,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB;YACE,CAAC,YAAY,EAAE,UAAU,CAAC;YAC1B,CAAC,mBAAmB,EAAE,YAAY,CAAC;YACnC,CAAC,mBAAmB,EAAE,WAAW,CAAC;YAClC,CAAC,oBAAoB,EAAE,YAAY,CAAC;SACrC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YACrB,eAAe,GAAG,EAAE;YACpB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,IAAc,CAAC;SAC1D,CAAC,CACH;QACH,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,CAAC;QACH,IAAI,CAAC;YACH,MAAM,KAAK,CAAC;gBACV,KAAK,EAAE;oBACL,QAAQ,EACN,0BAA0B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK;wBACpD,oFAAoF;wBACpF,8BAA8B;oBAChC,UAAU,EAAE,OAAO,CAAC,GAAG;oBACvB,UAAU,EAAE,6BAA6B;oBACzC,MAAM,EAAE,IAAI;iBACb;gBACD,OAAO;gBACP,KAAK;gBACL,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,IAAI;gBACZ,GAAG,EAAE,WAAW;gBAChB,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE;gBAC9B,QAAQ;gBACR,OAAO,EAAE;oBACP,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;oBACjD,cAAc;iBACf;gBACD,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;gBACjE,QAAQ,EAAE,QAAQ;gBAClB,aAAa,EAAE,OAAO,CAAC,GAAG;aAC3B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,oBAAoB,OAAO,CAAC,KAAK,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aACxG,CAAC;QACJ,CAAC;QAED,IAAI,GAA4D,CAAC;QACjE,IAAI,CAAC;YACH,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAe,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,GAAG,OAAO,CAAC,KAAK,yBAAyB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;aAC3G,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,CAAC,OAAyC,CAAC;QAC1D,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjE,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,GAAG,OAAO,CAAC,KAAK,iDAAiD;aAC3E,CAAC;QACJ,CAAC;QAED,IACE,OAAO,GAAG,CAAC,yBAAyB,KAAK,UAAU;YACnD,OAAO,GAAG,CAAC,WAAW,KAAK,UAAU,EACrC,CAAC;YACD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EACL,+EAA+E;aAClF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,EAAE,EAAE,IAAI;YACR,UAAU,EAAE,GAAiC;YAC7C,yBAAyB,EAAE,GAAG,CAAC,yBAAyB;YACxD,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;AACH,CAAC","sourcesContent":["import { type Plugin, build } from 'esbuild';\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { preconditionError } from '../errors';\nimport type {\n LoadedExperienceDefinition,\n LoadedExperienceModule,\n} from './definition-shape';\nimport type { ExperienceProject } from './project';\n\n/**\n * ESM output has no `require`, so esbuild's shim throws \"Dynamic require of\n * \\\"react\\\" is not supported\" the moment a bundled CommonJS dependency (a\n * `use-sync-external-store`, a UI kit's transitive deps) requires one of the\n * packages kept external. Giving the bundle a real `require` lets that call\n * reach the external package the same way the rest of the entry does.\n */\nconst REQUIRE_BANNER =\n \"import { createRequire as __ekanosCreateRequire } from 'node:module';\\n\" +\n 'const require = __ekanosCreateRequire(import.meta.url);';\n\n/**\n * Every `@ekanos/*` package is imported natively (so the entry and the host\n * share one copy of the SDK) except `@ekanos/ui`. Its `page` entry is built\n * with a bundler's `require` shim for the Next internals it carries, and\n * Node's ESM loader has no `require` for that shim to find: imported natively\n * it throws \"Calling `require` for \\\"react\\\" in an environment that doesn't\n * expose the `require` function\". Bundling it here lets the banner's\n * `require` serve it. The loader only reads the definition and never renders\n * a component, so a second copy of the UI kit costs nothing.\n */\nconst externalizeEkanosExceptUi: Plugin = {\n name: 'ekanos-external-except-ui',\n setup(b) {\n b.onResolve({ filter: /^@ekanos\\// }, (args) =>\n args.path === '@ekanos/ui' || args.path.startsWith('@ekanos/ui/')\n ? undefined\n : { path: args.path, external: true },\n );\n },\n};\n\nconst stubServerOnly: Plugin = {\n name: 'ekanos-stub-server-only',\n setup(b) {\n b.onResolve({ filter: /^server-only$/ }, () => ({\n path: 'server-only',\n namespace: 'ekanos-server-only-stub',\n }));\n b.onLoad({ filter: /.*/, namespace: 'ekanos-server-only-stub' }, () => ({\n contents: '',\n loader: 'js',\n }));\n },\n};\n\nexport interface LoadExperienceOptions {\n /**\n * Root of an `@ekanos/sdk` checkout to bundle instead of importing\n * `@ekanos/sdk` from node_modules. Needed only when the SDK's exports point\n * at TypeScript source (the monorepo's own tests); a published SDK ships\n * built output. Also settable as EKANOS_INLINE_SDK.\n */\n inlineSdk?: string;\n}\n\nexport type LoadedExperience =\n | ({ ok: true } & LoadedExperienceModule)\n | { ok: false; message: string };\n\n/**\n * Evaluate the experience entry in Node to read its definition, including the\n * workflow templates' `build()` output. Components are loaded but never\n * rendered, so a widget needs no browser to be inspected.\n */\nexport async function loadExperience(\n project: ExperienceProject,\n options: LoadExperienceOptions = {},\n): Promise<LoadedExperience> {\n const entry = path.join(project.dir, project.entry);\n const nodeModules = path.join(project.dir, 'node_modules');\n if (!fs.existsSync(nodeModules)) {\n throw preconditionError(\n `No node_modules in ${project.dir}: the packages the experience imports are not installed.`,\n 'Install dependencies first, then re-run.',\n );\n }\n\n const cacheDir = path.join(nodeModules, '.cache', 'ekanos-cli');\n fs.mkdirSync(cacheDir, { recursive: true });\n const outfile = path.join(\n cacheDir,\n `experience-${crypto.randomBytes(6).toString('hex')}.mjs`,\n );\n\n const inlineSdk = options.inlineSdk ?? process.env.EKANOS_INLINE_SDK;\n const external = inlineSdk\n ? ['react', 'react-dom', '@tanstack/react-query']\n : ['react', 'react-dom', '@tanstack/react-query', 'zod'];\n const alias = inlineSdk\n ? Object.fromEntries(\n [\n ['experience', 'index.ts'],\n ['experience/client', 'client.tsx'],\n ['experience/server', 'server.ts'],\n ['experience/runtime', 'runtime.ts'],\n ].map(([sub, file]) => [\n `@ekanos/sdk/${sub}`,\n path.join(inlineSdk, 'src', 'experience', file as string),\n ]),\n )\n : undefined;\n\n try {\n try {\n await build({\n stdin: {\n contents:\n `import definition from ${JSON.stringify(entry)};\\n` +\n \"export { serializeWorkflowTemplate, slotsUsedBy } from '@ekanos/sdk/experience';\\n\" +\n 'export default definition;\\n',\n resolveDir: project.dir,\n sourcefile: 'ekanos-experience-loader.ts',\n loader: 'ts',\n },\n outfile,\n alias,\n platform: 'node',\n format: 'esm',\n bundle: true,\n jsx: 'automatic',\n banner: { js: REQUIRE_BANNER },\n external,\n plugins: [\n ...(inlineSdk ? [] : [externalizeEkanosExceptUi]),\n stubServerOnly,\n ],\n loader: { '.css': 'empty', '.svg': 'dataurl', '.png': 'dataurl' },\n logLevel: 'silent',\n absWorkingDir: project.dir,\n });\n } catch (error) {\n return {\n ok: false,\n message: `Could not bundle ${project.entry}: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n let mod: Partial<LoadedExperienceModule> & { default?: unknown };\n try {\n mod = (await import(pathToFileURL(outfile).href)) as typeof mod;\n } catch (error) {\n return {\n ok: false,\n message: `${project.entry} threw while loading: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n const def = mod.default as { kind?: unknown } | undefined;\n if (!def || typeof def !== 'object' || def.kind !== 'experience') {\n return {\n ok: false,\n message: `${project.entry} must \"export default defineExperience({...})\".`,\n };\n }\n\n if (\n typeof mod.serializeWorkflowTemplate !== 'function' ||\n typeof mod.slotsUsedBy !== 'function'\n ) {\n return {\n ok: false,\n message:\n 'The installed @ekanos/sdk has no experience API. Upgrade it (ekanos upgrade).',\n };\n }\n\n return {\n ok: true,\n definition: def as LoadedExperienceDefinition,\n serializeWorkflowTemplate: mod.serializeWorkflowTemplate,\n slotsUsedBy: mod.slotsUsedBy,\n };\n } finally {\n fs.rmSync(outfile, { force: true });\n }\n}\n"]}
@@ -31,5 +31,15 @@ export declare function checkIntegrationPins(project: ExperienceProject, lock: L
31
31
  findings: Finding[];
32
32
  pinned: PinnedIntegration[];
33
33
  };
34
+ export declare const CONNECTION_LEVELS_CHECK = "checks/connection-levels";
35
+ /**
36
+ * Each pinned integration's `modes` against the connection levels its
37
+ * contract states: an entry that only declares modes the levels cannot serve
38
+ * is an error (it has never been served); a dead mode beside one that serves,
39
+ * or `team` on a contract without the `team` level, is a warning. Kept apart
40
+ * from {@link checkIntegrationPins} so a warning here never holds back the
41
+ * stages that wait on clean pins.
42
+ */
43
+ export declare function checkConnectionLevels(pinned: readonly PinnedIntegration[]): Finding[];
34
44
  /** The effect of `integration` + `kind/name` from the pinned contracts, for workflow serialization. */
35
45
  export declare function effectLookup(pinned: readonly PinnedIntegration[]): (integration: string, op: string) => "read" | "write" | undefined;
@@ -1,4 +1,4 @@
1
- import { operationKey, verifyContract, } from '@ekanos/integration-schema';
1
+ import { connectionLevelProblems, operationKey, verifyContract, } from '@ekanos/integration-schema';
2
2
  import * as fs from 'node:fs';
3
3
  import { snapshotFile } from './contract-sources.js';
4
4
  export const INTEGRATION_PINS_CHECK = 'checks/integration-pins';
@@ -78,6 +78,24 @@ export function checkIntegrationPins(project, lock, resolve) {
78
78
  }
79
79
  return { findings, pinned };
80
80
  }
81
+ export const CONNECTION_LEVELS_CHECK = 'checks/connection-levels';
82
+ /**
83
+ * Each pinned integration's `modes` against the connection levels its
84
+ * contract states: an entry that only declares modes the levels cannot serve
85
+ * is an error (it has never been served); a dead mode beside one that serves,
86
+ * or `team` on a contract without the `team` level, is a warning. Kept apart
87
+ * from {@link checkIntegrationPins} so a warning here never holds back the
88
+ * stages that wait on clean pins.
89
+ */
90
+ export function checkConnectionLevels(pinned) {
91
+ return pinned.flatMap(({ use, contract }) => connectionLevelProblems(use, contract).map((problem) => ({
92
+ check: CONNECTION_LEVELS_CHECK,
93
+ severity: problem.severity,
94
+ message: problem.message,
95
+ hint: problem.hint,
96
+ file: 'ekanos.json',
97
+ })));
98
+ }
81
99
  /** The effect of `integration` + `kind/name` from the pinned contracts, for workflow serialization. */
82
100
  export function effectLookup(pinned) {
83
101
  const effects = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"pins.js","sourceRoot":"","sources":["../../src/experience/pins.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Contract,\n type Finding,\n type Lockfile,\n type IntegrationEntry,\n operationKey,\n verifyContract,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\n\nimport { snapshotFile } from './contract-sources';\nimport type { ExperienceProject } from './project';\n\nexport const INTEGRATION_PINS_CHECK = 'checks/integration-pins';\n\nexport const DEPRECATED_USES =\n '\"uses\" in ekanos.json is deprecated: an experience declares its dependencies as \"integrations\" (name = the integration, version = the compat line). \"ekanos sync\" rewrites the file.';\n\n/** What a `uses` -> `integrations` upgrade changed in code terms, or null when nothing was renamed. */\nexport function renamesNotice(renames: Record<string, string>): string | null {\n const entries = Object.entries(renames);\n if (entries.length === 0) return null;\n\n return `An integration is now addressed by its own name; update your code: ${entries\n .map(([alias, integration]) => `'${alias}' -> '${integration}'`)\n .join(', ')}.`;\n}\n\nexport interface PinnedIntegration {\n use: IntegrationEntry;\n contract: Contract;\n}\n\n/**\n * Resolves an integration's contract through the harness registry chain (catalog,\n * published-package cache, contracts directory), as `createPinsResolver`\n * returns it. `null` falls back to the committed snapshot.\n */\nexport type PinsResolver = (integration: {\n name: string;\n version: string;\n}) => { contract: Contract; lines: string[] } | null;\n\nexport function loadPinnedContract(\n project: ExperienceProject,\n use: IntegrationEntry,\n): Contract | null {\n const file = snapshotFile(project, use.name, use.version);\n if (!fs.existsSync(file)) return null;\n try {\n return verifyContract(JSON.parse(fs.readFileSync(file, 'utf8'))).contract;\n } catch {\n return null;\n }\n}\n\nconst finding = (message: string, hint: string, file?: string): Finding => ({\n check: INTEGRATION_PINS_CHECK,\n severity: 'error',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\n/**\n * Every `integrations` entry must resolve, against the pinned contract snapshot, to\n * the EXACT compat line and contain each declared operation, with the digest\n * the lockfile recorded. Fails with the first-principles message naming the\n * integration, so \"pinning a line missing an op\" is a one-line fix.\n */\nexport function checkIntegrationPins(\n project: ExperienceProject,\n lock: Lockfile,\n resolve?: PinsResolver,\n): { findings: Finding[]; pinned: PinnedIntegration[] } {\n const findings: Finding[] = [];\n const pinned: PinnedIntegration[] = [];\n\n if (project.deprecatedUses) {\n findings.push({\n check: INTEGRATION_PINS_CHECK,\n severity: 'warn',\n message: DEPRECATED_USES,\n hint: 'Run \"ekanos sync\".',\n file: 'ekanos.json',\n });\n }\n\n if (project.integrations.length === 0) {\n findings.push(\n finding(\n 'ekanos.json declares no integrations.',\n 'Add one with \"ekanos add <integration>@<version> --from-dir <contracts folder>\".',\n 'ekanos.json',\n ),\n );\n }\n\n for (const use of project.integrations) {\n const contract =\n resolve?.({ name: use.name, version: use.version })?.contract ??\n loadPinnedContract(project, use);\n if (!contract) {\n findings.push(\n finding(\n `integration \"${use.name}\": no pinned contract for ${use.name}@${use.version}.`,\n `Run \"ekanos add ${use.name}@${use.version} --from-dir <contracts folder>\" or \"ekanos sync\".`,\n 'ekanos.json',\n ),\n );\n continue;\n }\n if (contract.compatLine !== use.version) {\n findings.push(\n finding(\n `integration \"${use.name}\" pins ${use.name}@${use.version} but the pinned contract is version ${contract.compatLine}.`,\n 'Re-pin with \"ekanos sync\".',\n 'ekanos.json',\n ),\n );\n continue;\n }\n\n const byId = new Map(contract.operations.map((op) => [op.id, op]));\n for (const id of use.operations) {\n const op = byId.get(id);\n if (!op) {\n const key = operationKey(id) ?? id;\n findings.push(\n finding(\n `integration \"${use.name}\": ${use.name}@${use.version} does not provide ${key}.`,\n `Remove ${key} from the integration's operations, or pin a version that has it (known versions come from \"ekanos add\").`,\n 'ekanos.json',\n ),\n );\n }\n }\n\n const locked = lock.integrations[use.name];\n if (!locked) {\n findings.push(\n finding(\n `integration \"${use.name}\" is not in ekanos.lock.json.`,\n 'Run \"ekanos sync\" to record the pin.',\n 'ekanos.lock.json',\n ),\n );\n } else if (\n locked.digest !== contract.digest ||\n locked.version !== use.version\n ) {\n findings.push(\n finding(\n `integration \"${use.name}\": the pinned contract (${contract.digest.slice(0, 15)}…) does not match ekanos.lock.json (${locked.digest.slice(0, 15)}…).`,\n 'Run \"ekanos sync\" to accept the new contract, or restore the old snapshot.',\n 'ekanos.lock.json',\n ),\n );\n }\n\n pinned.push({ use, contract });\n }\n\n return { findings, pinned };\n}\n\n/** The effect of `integration` + `kind/name` from the pinned contracts, for workflow serialization. */\nexport function effectLookup(pinned: readonly PinnedIntegration[]) {\n const effects = new Map<string, 'read' | 'write'>();\n for (const { use, contract } of pinned) {\n for (const op of contract.operations) {\n effects.set(`${use.name} ${op.kind}/${op.name}`, op.effect);\n }\n }\n\n return (integration: string, op: string) =>\n effects.get(`${integration} ${op}`);\n}\n"]}
1
+ {"version":3,"file":"pins.js","sourceRoot":"","sources":["../../src/experience/pins.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Contract,\n type Finding,\n type Lockfile,\n type IntegrationEntry,\n connectionLevelProblems,\n operationKey,\n verifyContract,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\n\nimport { snapshotFile } from './contract-sources';\nimport type { ExperienceProject } from './project';\n\nexport const INTEGRATION_PINS_CHECK = 'checks/integration-pins';\n\nexport const DEPRECATED_USES =\n '\"uses\" in ekanos.json is deprecated: an experience declares its dependencies as \"integrations\" (name = the integration, version = the compat line). \"ekanos sync\" rewrites the file.';\n\n/** What a `uses` -> `integrations` upgrade changed in code terms, or null when nothing was renamed. */\nexport function renamesNotice(renames: Record<string, string>): string | null {\n const entries = Object.entries(renames);\n if (entries.length === 0) return null;\n\n return `An integration is now addressed by its own name; update your code: ${entries\n .map(([alias, integration]) => `'${alias}' -> '${integration}'`)\n .join(', ')}.`;\n}\n\nexport interface PinnedIntegration {\n use: IntegrationEntry;\n contract: Contract;\n}\n\n/**\n * Resolves an integration's contract through the harness registry chain (catalog,\n * published-package cache, contracts directory), as `createPinsResolver`\n * returns it. `null` falls back to the committed snapshot.\n */\nexport type PinsResolver = (integration: {\n name: string;\n version: string;\n}) => { contract: Contract; lines: string[] } | null;\n\nexport function loadPinnedContract(\n project: ExperienceProject,\n use: IntegrationEntry,\n): Contract | null {\n const file = snapshotFile(project, use.name, use.version);\n if (!fs.existsSync(file)) return null;\n try {\n return verifyContract(JSON.parse(fs.readFileSync(file, 'utf8'))).contract;\n } catch {\n return null;\n }\n}\n\nconst finding = (message: string, hint: string, file?: string): Finding => ({\n check: INTEGRATION_PINS_CHECK,\n severity: 'error',\n message,\n hint,\n ...(file ? { file } : {}),\n});\n\n/**\n * Every `integrations` entry must resolve, against the pinned contract snapshot, to\n * the EXACT compat line and contain each declared operation, with the digest\n * the lockfile recorded. Fails with the first-principles message naming the\n * integration, so \"pinning a line missing an op\" is a one-line fix.\n */\nexport function checkIntegrationPins(\n project: ExperienceProject,\n lock: Lockfile,\n resolve?: PinsResolver,\n): { findings: Finding[]; pinned: PinnedIntegration[] } {\n const findings: Finding[] = [];\n const pinned: PinnedIntegration[] = [];\n\n if (project.deprecatedUses) {\n findings.push({\n check: INTEGRATION_PINS_CHECK,\n severity: 'warn',\n message: DEPRECATED_USES,\n hint: 'Run \"ekanos sync\".',\n file: 'ekanos.json',\n });\n }\n\n if (project.integrations.length === 0) {\n findings.push(\n finding(\n 'ekanos.json declares no integrations.',\n 'Add one with \"ekanos add <integration>@<version> --from-dir <contracts folder>\".',\n 'ekanos.json',\n ),\n );\n }\n\n for (const use of project.integrations) {\n const contract =\n resolve?.({ name: use.name, version: use.version })?.contract ??\n loadPinnedContract(project, use);\n if (!contract) {\n findings.push(\n finding(\n `integration \"${use.name}\": no pinned contract for ${use.name}@${use.version}.`,\n `Run \"ekanos add ${use.name}@${use.version} --from-dir <contracts folder>\" or \"ekanos sync\".`,\n 'ekanos.json',\n ),\n );\n continue;\n }\n if (contract.compatLine !== use.version) {\n findings.push(\n finding(\n `integration \"${use.name}\" pins ${use.name}@${use.version} but the pinned contract is version ${contract.compatLine}.`,\n 'Re-pin with \"ekanos sync\".',\n 'ekanos.json',\n ),\n );\n continue;\n }\n\n const byId = new Map(contract.operations.map((op) => [op.id, op]));\n for (const id of use.operations) {\n const op = byId.get(id);\n if (!op) {\n const key = operationKey(id) ?? id;\n findings.push(\n finding(\n `integration \"${use.name}\": ${use.name}@${use.version} does not provide ${key}.`,\n `Remove ${key} from the integration's operations, or pin a version that has it (known versions come from \"ekanos add\").`,\n 'ekanos.json',\n ),\n );\n }\n }\n\n const locked = lock.integrations[use.name];\n if (!locked) {\n findings.push(\n finding(\n `integration \"${use.name}\" is not in ekanos.lock.json.`,\n 'Run \"ekanos sync\" to record the pin.',\n 'ekanos.lock.json',\n ),\n );\n } else if (\n locked.digest !== contract.digest ||\n locked.version !== use.version\n ) {\n findings.push(\n finding(\n `integration \"${use.name}\": the pinned contract (${contract.digest.slice(0, 15)}…) does not match ekanos.lock.json (${locked.digest.slice(0, 15)}…).`,\n 'Run \"ekanos sync\" to accept the new contract, or restore the old snapshot.',\n 'ekanos.lock.json',\n ),\n );\n }\n\n pinned.push({ use, contract });\n }\n\n return { findings, pinned };\n}\n\nexport const CONNECTION_LEVELS_CHECK = 'checks/connection-levels';\n\n/**\n * Each pinned integration's `modes` against the connection levels its\n * contract states: an entry that only declares modes the levels cannot serve\n * is an error (it has never been served); a dead mode beside one that serves,\n * or `team` on a contract without the `team` level, is a warning. Kept apart\n * from {@link checkIntegrationPins} so a warning here never holds back the\n * stages that wait on clean pins.\n */\nexport function checkConnectionLevels(\n pinned: readonly PinnedIntegration[],\n): Finding[] {\n return pinned.flatMap(({ use, contract }) =>\n connectionLevelProblems(use, contract).map((problem) => ({\n check: CONNECTION_LEVELS_CHECK,\n severity: problem.severity,\n message: problem.message,\n hint: problem.hint,\n file: 'ekanos.json',\n })),\n );\n}\n\n/** The effect of `integration` + `kind/name` from the pinned contracts, for workflow serialization. */\nexport function effectLookup(pinned: readonly PinnedIntegration[]) {\n const effects = new Map<string, 'read' | 'write'>();\n for (const { use, contract } of pinned) {\n for (const op of contract.operations) {\n effects.set(`${use.name} ${op.kind}/${op.name}`, op.effect);\n }\n }\n\n return (integration: string, op: string) =>\n effects.get(`${integration} ${op}`);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const PHOSPHOR_VERSION = "2.1.2";
2
+ /** Every icon name `@ekanos/ui`'s `Icon` draws. */
3
+ export declare const PHOSPHOR_ICON_NAMES: ReadonlySet<string>;