@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
package/README.md CHANGED
@@ -423,6 +423,12 @@ pnpm add -D eslint @typescript-eslint/parser # or npm install -D / yarn add -D
423
423
  `ekanos validate` warns (`project.capability-lint-tooling`) when either is missing
424
424
  and prints the config to paste.
425
425
 
426
+ `ekanos validate` and `ekanos dev` also warn (`project.duplicate-sdk-instance`)
427
+ when the lockfile installs `@ekanos/sdk` or `@ekanos/ui` more than once, which
428
+ under pnpm happens when a workspace resolves `zod` at two versions. Two copies
429
+ mean the harness's providers are invisible to your hooks; align `zod` across
430
+ the workspace and check with `pnpm why @ekanos/sdk`.
431
+
426
432
  ## Keeping the toolchain current
427
433
 
428
434
  Three independent defenses against a stale toolchain, all landing together
@@ -455,10 +461,18 @@ turned into an uninstallable tree.
455
461
  nothing. Safe to run anytime, including from CI or an agent.
456
462
  - `ekanos upgrade` — snapshots `package.json` and the lockfile, installs the
457
463
  target versions, then VERIFIES with `ekanos validate` and the project's own
458
- test script. **Any failure at any step rolls everything back** — package.json,
459
- lockfile and `node_modules` all restored — and reports exactly which step
460
- failed with its output. `--yes` skips the interactive confirm (required
461
- outside a real TTY); `--no-verify` skips the post-install verification.
464
+ test script. **Any failure at any step rolls everything back** — package.json
465
+ and the lockfile restored, then `node_modules` reinstalled frozen to that
466
+ lockfile — and reports exactly which step failed with its output. If the
467
+ rollback reinstall itself fails, it says so and prints the repair command
468
+ rather than claiming a restore. `--yes` skips the interactive confirm
469
+ (required outside a real TTY); `--no-verify` skips the post-install
470
+ verification.
471
+ - It installs with the project's own package manager, found from the project
472
+ up to its workspace root (lockfile, then the `packageManager` field, then a
473
+ `pnpm-workspace.yaml`): a package in a pnpm workspace is upgraded with
474
+ `pnpm add`, never npm. At a repo root (`"kind": "repo"`) it upgrades the
475
+ root and every package that uses the toolchain in one run.
462
476
  - On success, the agent-context files (`AGENTS.md`, `CLAUDE.md`, the Claude
463
477
  Code skill) are regenerated from the newly installed CLI's templates —
464
478
  byte-compared against what the PRE-upgrade CLI would have rendered, so a
@@ -6,7 +6,11 @@ import { inContractOrder, readOperationIds, resolveOpTokens, } from '../experien
6
6
  import { DEPRECATED_USES } from '../experience/pins.js';
7
7
  import { readExperienceProject, writeIntegrations, } from '../experience/project.js';
8
8
  import { loadPins, regenerateIntegrations } from '../experience/regenerate.js';
9
- const SPEC = /^((?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\/)?[a-z][a-z0-9-]*)@(\d+(?:\.\d+)?)$/;
9
+ const SPEC = /^((?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\/)?[a-z][a-z0-9-]*)@(\d+(?:\.\d+)?(?:\.\d+(?:[-+][0-9A-Za-z.-]+)?)?)$/;
10
+ /** `1.2.3` (or `1.2.3-rc.1`) pins by its compat line, `1.2`; `0.x` lines keep minor. */
11
+ function toCompatLine(version) {
12
+ return version.split(/[-+]/)[0].split('.').slice(0, 2).join('.');
13
+ }
10
14
  export const addCommand = {
11
15
  name: 'add',
12
16
  usage: [
@@ -22,7 +26,7 @@ export const addCommand = {
22
26
  },
23
27
  ops: {
24
28
  type: 'string',
25
- description: 'Operations to allow, comma-separated (tool/name, action/name or a unique bare name). Default on a new integration: every read operation. Writes are opt-in.',
29
+ description: 'Operations to allow, comma-separated (tool/name, action/name or a unique bare name). On a new integration the list is exactly the operations named; prefix a name with + (e.g. +action/create-draft) to add it to the default, every read operation. With no --ops a new integration gets every read. On an existing pin the list is added to what is already allowed.',
26
30
  },
27
31
  as: {
28
32
  type: 'string',
@@ -43,10 +47,14 @@ export const addCommand = {
43
47
  const match = spec ? SPEC.exec(spec) : null;
44
48
  if (!match) {
45
49
  throw usageError(spec
46
- ? `"${spec}" is not <integration>@<version>.`
47
- : 'add needs <integration>@<version>.', 'e.g. "ekanos add sanity@0.2 --from-dir ../contracts".');
50
+ ? `"${spec}" is not <integration>@<major>.<minor>.`
51
+ : 'add needs <integration>@<major>.<minor>.', 'Pins are by compat line, e.g. "ekanos add sanity@0.2 --from-dir ../contracts".');
52
+ }
53
+ const [, integration, rawVersion] = match;
54
+ const version = toCompatLine(rawVersion);
55
+ if (version !== rawVersion) {
56
+ ctx.warn(`Pins are by compat line: using ${integration}@${version} (from ${rawVersion}).`);
48
57
  }
49
- const [, integration, version] = match;
50
58
  if (args.flags.as !== undefined) {
51
59
  throw usageError('--as is gone: an experience addresses an integration by its own name.', `Use "${integration}" in useOperation('${integration}', ...).`);
52
60
  }
@@ -67,11 +75,14 @@ export const addCommand = {
67
75
  .split(',')
68
76
  .map((t) => t.trim())
69
77
  .filter(Boolean);
70
- const explicit = resolveOpTokens(contract, requested);
71
- const operations = inContractOrder(contract, [
72
- ...(existing ? existing.operations : readOperationIds(contract)),
73
- ...explicit,
74
- ]);
78
+ const withDefaults = requested.some((t) => t.startsWith('+'));
79
+ const explicit = resolveOpTokens(contract, requested.map((t) => t.replace(/^\+/, '')));
80
+ const base = existing
81
+ ? existing.operations
82
+ : requested.length === 0 || withDefaults
83
+ ? readOperationIds(contract)
84
+ : [];
85
+ const operations = inContractOrder(contract, [...base, ...explicit]);
75
86
  if (operations.length === 0) {
76
87
  throw usageError(`${integration}@${version} has no read operations to allow by default.`, 'Pass --ops <tool/name,...> to choose operations.');
77
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IntegrationEntry } from '@ekanos/integration-schema';\n\nimport { harnessContractSources } from '../dev-experience';\nimport { invalidStateError, usageError } from '../errors';\nimport {\n defaultSources,\n resolveContract,\n} from '../experience/contract-sources';\nimport { pinIntegration } from '../experience/pin-integration';\nimport {\n inContractOrder,\n readOperationIds,\n resolveOpTokens,\n} from '../experience/pin-ops';\nimport { DEPRECATED_USES } from '../experience/pins';\nimport {\n readExperienceProject,\n writeIntegrations,\n} from '../experience/project';\nimport { loadPins, regenerateIntegrations } from '../experience/regenerate';\nimport type { ExperienceCommand } from './index-experience';\n\nconst SPEC =\n /^((?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\\/)?[a-z][a-z0-9-]*)@(\\d+(?:\\.\\d+)?)$/;\n\nexport const addCommand: ExperienceCommand = {\n name: 'add',\n usage: [\n ' add Add an integration to an experience: pin its contract,',\n ' record it in ekanos.json + ekanos.lock.json, regenerate types',\n ' (add <integration>@<version> [--ops a,b] [--from-dir <dir>])',\n ],\n positionals: ['spec'],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n ops: {\n type: 'string',\n description:\n 'Operations to allow, comma-separated (tool/name, action/name or a unique bare name). Default on a new integration: every read operation. Writes are opt-in.',\n },\n as: {\n type: 'string',\n description:\n 'Removed: an experience addresses an integration by its own name',\n },\n 'from-dir': {\n type: 'string',\n description:\n 'Directory of <integration>.contract.json files (the contract source)',\n },\n 'from-path': {\n type: 'string',\n description:\n 'An integration project directory whose contract.json to pin',\n },\n },\n async run(ctx, args) {\n const spec = args.positionals[0];\n const match = spec ? SPEC.exec(spec) : null;\n if (!match) {\n throw usageError(\n spec\n ? `\"${spec}\" is not <integration>@<version>.`\n : 'add needs <integration>@<version>.',\n 'e.g. \"ekanos add sanity@0.2 --from-dir ../contracts\".',\n );\n }\n const [, integration, version] = match as unknown as [\n string,\n string,\n string,\n ];\n if (args.flags.as !== undefined) {\n throw usageError(\n '--as is gone: an experience addresses an integration by its own name.',\n `Use \"${integration}\" in useOperation('${integration}', ...).`,\n );\n }\n\n const project = readExperienceProject(args.dir);\n if (project.deprecatedUses) ctx.warn(DEPRECATED_USES);\n const sources = defaultSources(\n project,\n {\n fromDir: args.flags['from-dir'] as string | undefined,\n fromPath: args.flags['from-path'] as string | undefined,\n env: args.env,\n },\n await harnessContractSources(project.dir, args.env),\n );\n const { contract, origin } = await resolveContract(\n sources,\n integration,\n version,\n );\n\n const existing = project.integrations.find((u) => u.name === integration);\n if (existing && existing.version !== version) {\n throw invalidStateError(\n `Integration \"${integration}\" is already pinned at ${existing.version}.`,\n `Move it to ${version} by editing its \"version\" in ekanos.json, then run \"ekanos sync\".`,\n );\n }\n\n const requested = ((args.flags.ops as string | undefined) ?? '')\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const explicit = resolveOpTokens(contract, requested);\n const operations = inContractOrder(contract, [\n ...(existing ? existing.operations : readOperationIds(contract)),\n ...explicit,\n ]);\n if (operations.length === 0) {\n throw usageError(\n `${integration}@${version} has no read operations to allow by default.`,\n 'Pass --ops <tool/name,...> to choose operations.',\n );\n }\n\n const entry: IntegrationEntry = {\n name: integration,\n version,\n operations,\n required: existing?.required ?? 'required',\n modes: existing?.modes ?? ['team'],\n };\n const integrations = existing\n ? project.integrations.map((u) => (u.name === integration ? entry : u))\n : [...project.integrations, entry];\n const integrationsChanged = writeIntegrations(project, integrations);\n\n const updated = { ...project, integrations };\n const pins = pinIntegration(updated, entry, contract);\n const { pinned } = loadPins(updated);\n const typesChanged = regenerateIntegrations(updated, pinned);\n\n const changed =\n integrationsChanged ||\n pins.snapshotChanged ||\n pins.lockChanged ||\n typesChanged;\n const writes = operations.filter((id) =>\n contract.operations.find((op) => op.id === id && op.effect === 'write'),\n );\n\n return ctx.succeed(\n {\n integration,\n version,\n contractVersion: contract.contractVersion,\n digest: contract.digest,\n operations,\n writes,\n origin,\n changed,\n files: {\n integrationsChanged,\n snapshotChanged: pins.snapshotChanged,\n lockChanged: pins.lockChanged,\n typesChanged,\n },\n },\n changed\n ? `Added integration \"${integration}\" (${integration}@${version}, contract ${contract.contractVersion}) with ${operations.length} operation${operations.length === 1 ? '' : 's'}${writes.length ? `, ${writes.length} write${writes.length === 1 ? '' : 's'}` : ''}.`\n : `Integration \"${integration}\" is already up to date (no files changed).`,\n );\n },\n};\n"]}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IntegrationEntry } from '@ekanos/integration-schema';\n\nimport { harnessContractSources } from '../dev-experience';\nimport { invalidStateError, usageError } from '../errors';\nimport {\n defaultSources,\n resolveContract,\n} from '../experience/contract-sources';\nimport { pinIntegration } from '../experience/pin-integration';\nimport {\n inContractOrder,\n readOperationIds,\n resolveOpTokens,\n} from '../experience/pin-ops';\nimport { DEPRECATED_USES } from '../experience/pins';\nimport {\n readExperienceProject,\n writeIntegrations,\n} from '../experience/project';\nimport { loadPins, regenerateIntegrations } from '../experience/regenerate';\nimport type { ExperienceCommand } from './index-experience';\n\nconst SPEC =\n /^((?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\\/)?[a-z][a-z0-9-]*)@(\\d+(?:\\.\\d+)?(?:\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)?)$/;\n\n/** `1.2.3` (or `1.2.3-rc.1`) pins by its compat line, `1.2`; `0.x` lines keep minor. */\nfunction toCompatLine(version: string): string {\n return version.split(/[-+]/)[0]!.split('.').slice(0, 2).join('.');\n}\n\nexport const addCommand: ExperienceCommand = {\n name: 'add',\n usage: [\n ' add Add an integration to an experience: pin its contract,',\n ' record it in ekanos.json + ekanos.lock.json, regenerate types',\n ' (add <integration>@<version> [--ops a,b] [--from-dir <dir>])',\n ],\n positionals: ['spec'],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n ops: {\n type: 'string',\n description:\n 'Operations to allow, comma-separated (tool/name, action/name or a unique bare name). On a new integration the list is exactly the operations named; prefix a name with + (e.g. +action/create-draft) to add it to the default, every read operation. With no --ops a new integration gets every read. On an existing pin the list is added to what is already allowed.',\n },\n as: {\n type: 'string',\n description:\n 'Removed: an experience addresses an integration by its own name',\n },\n 'from-dir': {\n type: 'string',\n description:\n 'Directory of <integration>.contract.json files (the contract source)',\n },\n 'from-path': {\n type: 'string',\n description:\n 'An integration project directory whose contract.json to pin',\n },\n },\n async run(ctx, args) {\n const spec = args.positionals[0];\n const match = spec ? SPEC.exec(spec) : null;\n if (!match) {\n throw usageError(\n spec\n ? `\"${spec}\" is not <integration>@<major>.<minor>.`\n : 'add needs <integration>@<major>.<minor>.',\n 'Pins are by compat line, e.g. \"ekanos add sanity@0.2 --from-dir ../contracts\".',\n );\n }\n const [, integration, rawVersion] = match as unknown as [\n string,\n string,\n string,\n ];\n const version = toCompatLine(rawVersion);\n if (version !== rawVersion) {\n ctx.warn(\n `Pins are by compat line: using ${integration}@${version} (from ${rawVersion}).`,\n );\n }\n if (args.flags.as !== undefined) {\n throw usageError(\n '--as is gone: an experience addresses an integration by its own name.',\n `Use \"${integration}\" in useOperation('${integration}', ...).`,\n );\n }\n\n const project = readExperienceProject(args.dir);\n if (project.deprecatedUses) ctx.warn(DEPRECATED_USES);\n const sources = defaultSources(\n project,\n {\n fromDir: args.flags['from-dir'] as string | undefined,\n fromPath: args.flags['from-path'] as string | undefined,\n env: args.env,\n },\n await harnessContractSources(project.dir, args.env),\n );\n const { contract, origin } = await resolveContract(\n sources,\n integration,\n version,\n );\n\n const existing = project.integrations.find((u) => u.name === integration);\n if (existing && existing.version !== version) {\n throw invalidStateError(\n `Integration \"${integration}\" is already pinned at ${existing.version}.`,\n `Move it to ${version} by editing its \"version\" in ekanos.json, then run \"ekanos sync\".`,\n );\n }\n\n const requested = ((args.flags.ops as string | undefined) ?? '')\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const withDefaults = requested.some((t) => t.startsWith('+'));\n const explicit = resolveOpTokens(\n contract,\n requested.map((t) => t.replace(/^\\+/, '')),\n );\n const base = existing\n ? existing.operations\n : requested.length === 0 || withDefaults\n ? readOperationIds(contract)\n : [];\n const operations = inContractOrder(contract, [...base, ...explicit]);\n if (operations.length === 0) {\n throw usageError(\n `${integration}@${version} has no read operations to allow by default.`,\n 'Pass --ops <tool/name,...> to choose operations.',\n );\n }\n\n const entry: IntegrationEntry = {\n name: integration,\n version,\n operations,\n required: existing?.required ?? 'required',\n modes: existing?.modes ?? ['team'],\n };\n const integrations = existing\n ? project.integrations.map((u) => (u.name === integration ? entry : u))\n : [...project.integrations, entry];\n const integrationsChanged = writeIntegrations(project, integrations);\n\n const updated = { ...project, integrations };\n const pins = pinIntegration(updated, entry, contract);\n const { pinned } = loadPins(updated);\n const typesChanged = regenerateIntegrations(updated, pinned);\n\n const changed =\n integrationsChanged ||\n pins.snapshotChanged ||\n pins.lockChanged ||\n typesChanged;\n const writes = operations.filter((id) =>\n contract.operations.find((op) => op.id === id && op.effect === 'write'),\n );\n\n return ctx.succeed(\n {\n integration,\n version,\n contractVersion: contract.contractVersion,\n digest: contract.digest,\n operations,\n writes,\n origin,\n changed,\n files: {\n integrationsChanged,\n snapshotChanged: pins.snapshotChanged,\n lockChanged: pins.lockChanged,\n typesChanged,\n },\n },\n changed\n ? `Added integration \"${integration}\" (${integration}@${version}, contract ${contract.contractVersion}) with ${operations.length} operation${operations.length === 1 ? '' : 's'}${writes.length ? `, ${writes.length} write${writes.length === 1 ? '' : 's'}` : ''}.`\n : `Integration \"${integration}\" is already up to date (no files changed).`,\n );\n },\n};\n"]}
@@ -78,9 +78,19 @@ export async function runContract(ctx, args) {
78
78
  throw preconditionError('An experience has no contract of its own.', 'Run "ekanos contract" in the integration project.');
79
79
  }
80
80
  const configPath = loaded.configPath;
81
- const declared = (_a = loaded.project.contract) === null || _a === void 0 ? void 0 : _a.version;
81
+ const DEFAULT_CONTRACT_VERSION = '0.1.0';
82
+ let declared = (_a = loaded.project.contract) === null || _a === void 0 ? void 0 : _a.version;
82
83
  if (!declared) {
83
- throw preconditionError('ekanos.json declares no contract version.', 'Add "contract": { "version": "0.1.0" } to ekanos.json; the compat line follows it.');
84
+ if (args.check) {
85
+ throw preconditionError('ekanos.json declares no contract version.', `Run "ekanos contract" once to add "contract": { "version": "${DEFAULT_CONTRACT_VERSION}" }, or add it yourself.`);
86
+ }
87
+ const raw = readJson(configPath);
88
+ if (!raw) {
89
+ throw preconditionError(`${configPath} is not readable.`, 'Fix ekanos.json, then re-run.');
90
+ }
91
+ fs.writeFileSync(configPath, `${JSON.stringify(Object.assign(Object.assign({}, raw), { contract: { version: DEFAULT_CONTRACT_VERSION } }), null, 2)}\n`);
92
+ declared = DEFAULT_CONTRACT_VERSION;
93
+ ctx.log(`ekanos.json had no contract version: added "contract": { "version": "${DEFAULT_CONTRACT_VERSION}" }.`);
84
94
  }
85
95
  const pkg = readJson(path.join(loaded.projectDir, 'package.json'));
86
96
  if (!(pkg === null || pkg === void 0 ? void 0 : pkg.version)) {
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/commands/contract.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Contract,\n type ContractProblem,\n assessContractTransition,\n checkContractFreshness,\n diffContract,\n validateAgainstSchema,\n verifyContract,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport type { CliContext } from '../context';\nimport { type HarnessResolver, loadHarnessResolver } from '../dev-experience';\nimport { preconditionError, usageError, validationError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { loadDefinition } from '../load-definition';\nimport { loadProject } from '../project';\nimport type { ExperienceCommand } from './index-experience';\n\n/** The slice of `@ekanos/sdk/contract` this command uses. */\nexport interface ContractModule {\n analyzeContract(\n definition: unknown,\n options: {\n packageVersion: string;\n contractVersion: string;\n previous?: Contract | null;\n examples?: Readonly<Record<string, unknown>>;\n },\n ): {\n contract: Contract;\n diagnostics: Array<{\n rule: string;\n severity: 'error' | 'warn' | 'info';\n message: string;\n operation?: string;\n }>;\n };\n synthesizeExample(schema: unknown): unknown;\n}\n\nexport interface ContractArgs {\n dir: string;\n check: boolean;\n record: boolean;\n bump: boolean;\n env?: Record<string, string | undefined>;\n /**\n * `--record --op tool/x[,action/y]`: record REAL examples for these\n * operations from a run through the harness runner, instead of writing\n * placeholders.\n */\n ops?: string[];\n /** Which run mode produces the example (default `fixtures`). */\n from?: 'fixtures' | 'live';\n /** JSON input for the recorded run (single `--op` only); default: synthesized from the input schema. */\n input?: string;\n /** Test seam; the default loads the project's installed `@ekanos/harness/resolver`. */\n loadHarness?: (projectDir: string) => Promise<HarnessResolver>;\n /** Test seam; the default loads `@ekanos/sdk/contract` from the project. */\n loadModule?: (projectDir: string) => Promise<ContractModule>;\n}\n\nasync function loadProjectModule(projectDir: string): Promise<ContractModule> {\n try {\n const require = createRequire(path.join(projectDir, 'package.json'));\n return (await import(\n pathToFileURL(require.resolve('@ekanos/sdk/contract')).href\n )) as ContractModule;\n } catch {\n throw preconditionError(\n 'This project\\'s @ekanos/sdk does not provide \"@ekanos/sdk/contract\".',\n 'Upgrade @ekanos/sdk to a version that ships contract emission, then re-run.',\n );\n }\n}\n\nfunction readJson<T>(file: string): T | null {\n try {\n return JSON.parse(fs.readFileSync(file, 'utf8')) as T;\n } catch {\n return null;\n }\n}\n\nfunction readExamples(dir: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!fs.existsSync(dir)) return out;\n for (const name of fs.readdirSync(dir)) {\n const match = /^(tool|action)-(.+)\\.json$/.exec(name);\n const value = match ? readJson<unknown>(path.join(dir, name)) : null;\n if (match && value !== null) out[`${match[1]}/${match[2]}`] = value;\n }\n return out;\n}\n\n/** The smallest contractVersion that satisfies the transition rules. */\nexport function nextContractVersion(\n previous: Contract,\n next: Contract,\n): string | null {\n const diff = diffContract(previous, next);\n if (diff.breaking.length === 0 && diff.compatible.length === 0) {\n return canonicalSurfaceEqual(previous, next)\n ? null\n : bump(previous.contractVersion, 'patch');\n }\n const zero = previous.compatLine.startsWith('0.');\n if (diff.breaking.length > 0)\n return bump(previous.contractVersion, zero ? 'minor' : 'major');\n return bump(previous.contractVersion, zero ? 'patch' : 'minor');\n}\n\nfunction canonicalSurfaceEqual(a: Contract, b: Contract): boolean {\n return checkContractFreshness(b, a).length === 0;\n}\n\nfunction bump(version: string, part: 'major' | 'minor' | 'patch'): string {\n const [major = 0, minor = 0, patch = 0] = version.split(/[.+-]/).map(Number);\n if (part === 'major') return `${major + 1}.0.0`;\n if (part === 'minor') return `${major}.${minor + 1}.0`;\n return `${major}.${minor}.${patch + 1}`;\n}\n\nfunction describe(problem: ContractProblem): string {\n return `${problem.operation ? `${problem.operation}: ` : ''}${problem.message}`;\n}\n\n/**\n * `ekanos contract`: derive `contract.json` from the integration definition.\n * See the command's usage text for the three modes.\n */\nexport async function runContract(\n ctx: CliContext,\n args: ContractArgs,\n): Promise<ExitCode> {\n if (args.check && (args.record || args.bump)) {\n throw usageError(\n '--check cannot be combined with --record or --bump.',\n 'Run them separately: \"ekanos contract --record\", then \"ekanos contract --check\".',\n );\n }\n const loaded = loadProject(args.dir);\n if (loaded.project.kind === 'experience') {\n throw preconditionError(\n 'An experience has no contract of its own.',\n 'Run \"ekanos contract\" in the integration project.',\n );\n }\n const configPath = loaded.configPath;\n const declared = loaded.project.contract?.version;\n if (!declared) {\n throw preconditionError(\n 'ekanos.json declares no contract version.',\n 'Add \"contract\": { \"version\": \"0.1.0\" } to ekanos.json; the compat line follows it.',\n );\n }\n const pkg = readJson<{ version?: string }>(\n path.join(loaded.projectDir, 'package.json'),\n );\n if (!pkg?.version) {\n throw preconditionError(\n 'package.json has no readable \"version\".',\n 'Add a semver version to package.json.',\n );\n }\n\n const sdk = await (args.loadModule ?? loadProjectModule)(loaded.projectDir);\n const def = await loadDefinition(loaded.primary.entryPath, loaded.projectDir);\n if (!def.ok) {\n throw validationError(\n `The integration definition did not load: ${def.message}`,\n 'Run \"ekanos validate\" first and fix what it reports.',\n );\n }\n\n const contractFile = path.join(loaded.projectDir, 'contract.json');\n const examplesDir = path.join(loaded.projectDir, 'contracts', 'examples');\n const previous = fs.existsSync(contractFile)\n ? verifyContract(readJson<unknown>(contractFile)).contract\n : null;\n\n let contractVersion = declared;\n const analyze = () =>\n sdk.analyzeContract(def.definition, {\n packageVersion: pkg.version as string,\n contractVersion,\n previous,\n examples: readExamples(examplesDir),\n });\n\n let result = analyze();\n\n const wanted = args.ops ?? [];\n if (wanted.length > 0 && !args.record) {\n throw usageError(\n '--op only applies with --record.',\n 'Run \"ekanos contract --record --op tool/<name>\".',\n );\n }\n if (args.input !== undefined && wanted.length !== 1) {\n throw usageError(\n '--input needs exactly one --op.',\n 'Record one operation at a time with its own --input.',\n );\n }\n\n if (args.record && wanted.length > 0) {\n let input: unknown;\n if (args.input !== undefined) {\n try {\n input = JSON.parse(args.input);\n } catch {\n throw usageError(\n '--input is not valid JSON.',\n 'Pass the operation input as a JSON object, e.g. --input \\'{\"limit\":5}\\'.',\n );\n }\n }\n const mode = args.from ?? 'fixtures';\n const harness = await (args.loadHarness ?? loadHarnessResolver)(\n loaded.projectDir,\n );\n if (typeof harness.runOperationOnce !== 'function') {\n throw preconditionError(\n 'The installed @ekanos/harness cannot run an operation for recording.',\n 'Upgrade @ekanos/harness and @ekanos/cli together, then re-run.',\n );\n }\n const wrote: string[] = [];\n for (const key of wanted) {\n const op = result.contract.operations.find((o) =>\n o.id.endsWith(`/${key}`),\n );\n if (!op) {\n throw validationError(\n `The contract has no operation \"${key}\".`,\n `Known operations: ${result.contract.operations.map((o) => `${o.kind}/${o.name}`).join(', ') || 'none'}.`,\n );\n }\n if (op.effect === 'write') {\n // A write is only ever recorded from a scenario fixture: reading a\n // file performs nothing. Running it live would perform it for real.\n const fixture = writeFixturePath(loaded.primary.slug, key);\n if (mode === 'live') {\n throw validationError(\n `${key} is a write; --from live would perform it for real, and a recording never does.`,\n `Add ${fixture} (a real-shaped response), then run \"ekanos contract --record --op ${key} --from fixtures\".`,\n );\n }\n if (!fs.existsSync(path.join(loaded.projectDir, fixture))) {\n throw validationError(\n `${key} is a write with no scenario fixture to record from.`,\n `Add ${fixture} holding a real-shaped response, then re-run \"ekanos contract --record --op ${key} --from fixtures\". Nothing is called.`,\n );\n }\n }\n if (op.opaque.output) {\n throw validationError(\n `${key} has an opaque output schema, so a recording cannot be validated.`,\n 'Declare an output schema first.',\n );\n }\n const run = await harness.runOperationOnce({\n projectRoot: loaded.projectDir,\n op: key,\n input: input ?? sdk.synthesizeExample(op.input),\n mode,\n env: args.env,\n deriveContract: () => result.contract,\n });\n if (!run.ok) {\n throw validationError(\n `Recording ${key} (${mode}) failed: ${run.reason}${run.detail ? ` - ${run.detail}` : ` - ${run.message}`}`,\n mode === 'live'\n ? 'Check the credentials (ekanos dev -> Connect) and the input, then re-run.'\n : `Fixtures mode reads fixtures/<slug>/${key.replace('/', '-')}.default.json (or an existing outputExample). Author that file, or record from a real run with \"--from live\".`,\n );\n }\n const problems = validateAgainstSchema(op.output, run.data);\n if (problems.length > 0) {\n throw validationError(\n `${key} returned data that does not satisfy its output schema: ${problems[0]}`,\n 'Fix the output schema or the handler; nothing was written.',\n );\n }\n const file = path.join(examplesDir, `${key.replace('/', '-')}.json`);\n fs.mkdirSync(examplesDir, { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify(run.data, null, 2)}\\n`);\n wrote.push(path.relative(loaded.projectDir, file));\n }\n ctx.log(\n `Recorded ${wrote.length} example(s) from a ${mode} run: ${wrote.join(', ')}. Review them before committing${mode === 'live' ? ' (live data may contain real records)' : ''}.`,\n );\n result = analyze();\n } else if (args.record) {\n const wrote: string[] = [];\n const advice: string[] = [];\n for (const diag of result.diagnostics) {\n if (diag.rule !== 'contract/example-missing' || !diag.operation) continue;\n const op = result.contract.operations.find((o) =>\n o.id.endsWith(`/${diag.operation}`),\n );\n if (!op || op.opaque.output) continue;\n const file = path.join(\n examplesDir,\n `${diag.operation.replace('/', '-')}.json`,\n );\n fs.mkdirSync(examplesDir, { recursive: true });\n fs.writeFileSync(\n file,\n `${JSON.stringify(sdk.synthesizeExample(op.output), null, 2)}\\n`,\n );\n wrote.push(path.relative(loaded.projectDir, file));\n advice.push(\n op.effect === 'write'\n ? `${diag.operation}: add ${writeFixturePath(loaded.primary.slug, diag.operation)} with a real-shaped response, then \"ekanos contract --record --op ${diag.operation} --from fixtures\" (writes are never recorded live)`\n : `${diag.operation}: add ${writeFixturePath(loaded.primary.slug, diag.operation)}, or \"ekanos contract --record --op ${diag.operation} --from live\"`,\n );\n }\n if (wrote.length > 0) {\n ctx.log(\n `Wrote ${wrote.length} placeholder example(s) synthesized from the output schema (not recorded from a run): ${wrote.join(', ')}. Fixtures mode will serve these placeholders until you replace them:\\n ${advice.join('\\n ')}`,\n );\n result = analyze();\n }\n }\n\n if (args.bump && previous) {\n const wanted = nextContractVersion(previous, result.contract);\n if (wanted && wanted !== contractVersion) {\n contractVersion = wanted;\n const raw = readJson<Record<string, unknown>>(configPath) ?? {};\n raw.contract = {\n ...(raw.contract as object | undefined),\n version: wanted,\n };\n fs.writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}\\n`);\n ctx.log(`contract.version ${declared} -> ${wanted} in ekanos.json`);\n result = analyze();\n }\n }\n\n for (const diag of result.diagnostics) {\n ctx.log(\n `${diag.severity === 'error' ? 'error' : diag.severity === 'warn' ? 'warn ' : 'info '} ${diag.operation ? `${diag.operation}: ` : ''}${diag.message} (${diag.rule})`,\n );\n }\n const errors = result.diagnostics.filter((d) => d.severity === 'error');\n if (errors.length > 0) {\n throw validationError(\n `${errors.length} contract error(s): ${errors\n .slice(0, 3)\n .map((e) => `${e.operation ?? ''} ${e.message}`.trim())\n .join('; ')}`,\n 'Fix them (declare outputs and examples, or run \"ekanos contract --record\"), then re-run.',\n );\n }\n\n const transition = previous\n ? assessContractTransition(previous, result.contract).problems\n : [];\n\n if (args.check) {\n const problems = checkContractFreshness(result.contract, previous, {\n strictPackageVersion: true,\n });\n if (problems.length > 0) {\n throw validationError(\n `contract.json is out of date: ${problems.map(describe).join(' | ')}`,\n 'Run \"ekanos contract\" (add --bump for the version) and commit contract.json.',\n );\n }\n return ctx.succeed(\n {\n ok: true,\n digest: result.contract.digest,\n operations: result.contract.operations.length,\n diagnostics: result.diagnostics,\n },\n `contract.json is current (${result.contract.operations.length} operations).`,\n );\n }\n\n if (transition.length > 0) {\n throw validationError(\n `This change is not allowed on the current contract version: ${transition.map(describe).join(' | ')}`,\n 'Run \"ekanos contract --bump\", or set contract.version in ekanos.json by hand (a breaking change needs a new compat line).',\n );\n }\n fs.writeFileSync(\n contractFile,\n `${JSON.stringify(result.contract, null, 2)}\\n`,\n );\n return ctx.succeed(\n {\n written: 'contract.json',\n digest: result.contract.digest,\n operations: result.contract.operations.length,\n diagnostics: result.diagnostics,\n },\n `Wrote contract.json (${result.contract.operations.length} operations, ${result.contract.compatLine} line, contract ${result.contract.contractVersion}).`,\n );\n}\n\nexport const contractCommand: ExperienceCommand = {\n name: 'contract',\n usage: [\n ' contract Derive ./contract.json from the integration definition;',\n ' --check fails on a stale file (CI, prepack), --record writes',\n ' missing output examples, --bump bumps the contract version',\n ],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n check: {\n type: 'boolean',\n description: 'Derive in memory and fail if contract.json differs',\n },\n record: {\n type: 'boolean',\n description:\n 'Write placeholder examples (contracts/examples) for operations that have none; with --op, record real ones from a run',\n },\n op: {\n type: 'string',\n description:\n 'With --record: operation(s) to record from a real run, comma separated (tool/list_posts)',\n },\n from: {\n type: 'string',\n description:\n 'With --op: run mode to record from, fixtures (default) or live',\n },\n input: {\n type: 'string',\n description: 'With --op: JSON input for the recorded run',\n },\n bump: {\n type: 'boolean',\n description:\n 'Rewrite ekanos.json contract.version to match the surface change',\n },\n },\n run(ctx, args) {\n const from = args.flags.from;\n if (from !== undefined && from !== 'live' && from !== 'fixtures') {\n throw usageError(\n `--from must be \"fixtures\" or \"live\", not \"${String(from)}\".`,\n 'Run \"ekanos contract --record --op tool/<name> --from live\".',\n );\n }\n\n return runContract(ctx, {\n dir: args.dir,\n check: args.flags.check === true,\n record: args.flags.record === true,\n bump: args.flags.bump === true,\n env: args.env,\n ...(typeof args.flags.op === 'string' && args.flags.op !== ''\n ? { ops: args.flags.op.split(',').map((o) => o.trim()) }\n : {}),\n ...(args.flags.from === 'live' || args.flags.from === 'fixtures'\n ? { from: args.flags.from }\n : {}),\n ...(typeof args.flags.input === 'string'\n ? { input: args.flags.input }\n : {}),\n });\n },\n};\n\n/** Where a scenario fixture for an operation lives, project-relative. */\nfunction writeFixturePath(slug: string, opKey: string): string {\n return path.join('fixtures', slug, `${opKey.replace('/', '-')}.default.json`);\n}\n"]}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/commands/contract.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Contract,\n type ContractProblem,\n assessContractTransition,\n checkContractFreshness,\n diffContract,\n validateAgainstSchema,\n verifyContract,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport type { CliContext } from '../context';\nimport { type HarnessResolver, loadHarnessResolver } from '../dev-experience';\nimport { preconditionError, usageError, validationError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { loadDefinition } from '../load-definition';\nimport { loadProject } from '../project';\nimport type { ExperienceCommand } from './index-experience';\n\n/** The slice of `@ekanos/sdk/contract` this command uses. */\nexport interface ContractModule {\n analyzeContract(\n definition: unknown,\n options: {\n packageVersion: string;\n contractVersion: string;\n previous?: Contract | null;\n examples?: Readonly<Record<string, unknown>>;\n },\n ): {\n contract: Contract;\n diagnostics: Array<{\n rule: string;\n severity: 'error' | 'warn' | 'info';\n message: string;\n operation?: string;\n }>;\n };\n synthesizeExample(schema: unknown): unknown;\n}\n\nexport interface ContractArgs {\n dir: string;\n check: boolean;\n record: boolean;\n bump: boolean;\n env?: Record<string, string | undefined>;\n /**\n * `--record --op tool/x[,action/y]`: record REAL examples for these\n * operations from a run through the harness runner, instead of writing\n * placeholders.\n */\n ops?: string[];\n /** Which run mode produces the example (default `fixtures`). */\n from?: 'fixtures' | 'live';\n /** JSON input for the recorded run (single `--op` only); default: synthesized from the input schema. */\n input?: string;\n /** Test seam; the default loads the project's installed `@ekanos/harness/resolver`. */\n loadHarness?: (projectDir: string) => Promise<HarnessResolver>;\n /** Test seam; the default loads `@ekanos/sdk/contract` from the project. */\n loadModule?: (projectDir: string) => Promise<ContractModule>;\n}\n\nasync function loadProjectModule(projectDir: string): Promise<ContractModule> {\n try {\n const require = createRequire(path.join(projectDir, 'package.json'));\n return (await import(\n pathToFileURL(require.resolve('@ekanos/sdk/contract')).href\n )) as ContractModule;\n } catch {\n throw preconditionError(\n 'This project\\'s @ekanos/sdk does not provide \"@ekanos/sdk/contract\".',\n 'Upgrade @ekanos/sdk to a version that ships contract emission, then re-run.',\n );\n }\n}\n\nfunction readJson<T>(file: string): T | null {\n try {\n return JSON.parse(fs.readFileSync(file, 'utf8')) as T;\n } catch {\n return null;\n }\n}\n\nfunction readExamples(dir: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!fs.existsSync(dir)) return out;\n for (const name of fs.readdirSync(dir)) {\n const match = /^(tool|action)-(.+)\\.json$/.exec(name);\n const value = match ? readJson<unknown>(path.join(dir, name)) : null;\n if (match && value !== null) out[`${match[1]}/${match[2]}`] = value;\n }\n return out;\n}\n\n/** The smallest contractVersion that satisfies the transition rules. */\nexport function nextContractVersion(\n previous: Contract,\n next: Contract,\n): string | null {\n const diff = diffContract(previous, next);\n if (diff.breaking.length === 0 && diff.compatible.length === 0) {\n return canonicalSurfaceEqual(previous, next)\n ? null\n : bump(previous.contractVersion, 'patch');\n }\n const zero = previous.compatLine.startsWith('0.');\n if (diff.breaking.length > 0)\n return bump(previous.contractVersion, zero ? 'minor' : 'major');\n return bump(previous.contractVersion, zero ? 'patch' : 'minor');\n}\n\nfunction canonicalSurfaceEqual(a: Contract, b: Contract): boolean {\n return checkContractFreshness(b, a).length === 0;\n}\n\nfunction bump(version: string, part: 'major' | 'minor' | 'patch'): string {\n const [major = 0, minor = 0, patch = 0] = version.split(/[.+-]/).map(Number);\n if (part === 'major') return `${major + 1}.0.0`;\n if (part === 'minor') return `${major}.${minor + 1}.0`;\n return `${major}.${minor}.${patch + 1}`;\n}\n\nfunction describe(problem: ContractProblem): string {\n return `${problem.operation ? `${problem.operation}: ` : ''}${problem.message}`;\n}\n\n/**\n * `ekanos contract`: derive `contract.json` from the integration definition.\n * See the command's usage text for the three modes.\n */\nexport async function runContract(\n ctx: CliContext,\n args: ContractArgs,\n): Promise<ExitCode> {\n if (args.check && (args.record || args.bump)) {\n throw usageError(\n '--check cannot be combined with --record or --bump.',\n 'Run them separately: \"ekanos contract --record\", then \"ekanos contract --check\".',\n );\n }\n const loaded = loadProject(args.dir);\n if (loaded.project.kind === 'experience') {\n throw preconditionError(\n 'An experience has no contract of its own.',\n 'Run \"ekanos contract\" in the integration project.',\n );\n }\n const configPath = loaded.configPath;\n const DEFAULT_CONTRACT_VERSION = '0.1.0';\n let declared = loaded.project.contract?.version;\n if (!declared) {\n if (args.check) {\n throw preconditionError(\n 'ekanos.json declares no contract version.',\n `Run \"ekanos contract\" once to add \"contract\": { \"version\": \"${DEFAULT_CONTRACT_VERSION}\" }, or add it yourself.`,\n );\n }\n const raw = readJson<Record<string, unknown>>(configPath);\n if (!raw) {\n throw preconditionError(\n `${configPath} is not readable.`,\n 'Fix ekanos.json, then re-run.',\n );\n }\n fs.writeFileSync(\n configPath,\n `${JSON.stringify({ ...raw, contract: { version: DEFAULT_CONTRACT_VERSION } }, null, 2)}\\n`,\n );\n declared = DEFAULT_CONTRACT_VERSION;\n ctx.log(\n `ekanos.json had no contract version: added \"contract\": { \"version\": \"${DEFAULT_CONTRACT_VERSION}\" }.`,\n );\n }\n const pkg = readJson<{ version?: string }>(\n path.join(loaded.projectDir, 'package.json'),\n );\n if (!pkg?.version) {\n throw preconditionError(\n 'package.json has no readable \"version\".',\n 'Add a semver version to package.json.',\n );\n }\n\n const sdk = await (args.loadModule ?? loadProjectModule)(loaded.projectDir);\n const def = await loadDefinition(loaded.primary.entryPath, loaded.projectDir);\n if (!def.ok) {\n throw validationError(\n `The integration definition did not load: ${def.message}`,\n 'Run \"ekanos validate\" first and fix what it reports.',\n );\n }\n\n const contractFile = path.join(loaded.projectDir, 'contract.json');\n const examplesDir = path.join(loaded.projectDir, 'contracts', 'examples');\n const previous = fs.existsSync(contractFile)\n ? verifyContract(readJson<unknown>(contractFile)).contract\n : null;\n\n let contractVersion = declared;\n const analyze = () =>\n sdk.analyzeContract(def.definition, {\n packageVersion: pkg.version as string,\n contractVersion,\n previous,\n examples: readExamples(examplesDir),\n });\n\n let result = analyze();\n\n const wanted = args.ops ?? [];\n if (wanted.length > 0 && !args.record) {\n throw usageError(\n '--op only applies with --record.',\n 'Run \"ekanos contract --record --op tool/<name>\".',\n );\n }\n if (args.input !== undefined && wanted.length !== 1) {\n throw usageError(\n '--input needs exactly one --op.',\n 'Record one operation at a time with its own --input.',\n );\n }\n\n if (args.record && wanted.length > 0) {\n let input: unknown;\n if (args.input !== undefined) {\n try {\n input = JSON.parse(args.input);\n } catch {\n throw usageError(\n '--input is not valid JSON.',\n 'Pass the operation input as a JSON object, e.g. --input \\'{\"limit\":5}\\'.',\n );\n }\n }\n const mode = args.from ?? 'fixtures';\n const harness = await (args.loadHarness ?? loadHarnessResolver)(\n loaded.projectDir,\n );\n if (typeof harness.runOperationOnce !== 'function') {\n throw preconditionError(\n 'The installed @ekanos/harness cannot run an operation for recording.',\n 'Upgrade @ekanos/harness and @ekanos/cli together, then re-run.',\n );\n }\n const wrote: string[] = [];\n for (const key of wanted) {\n const op = result.contract.operations.find((o) =>\n o.id.endsWith(`/${key}`),\n );\n if (!op) {\n throw validationError(\n `The contract has no operation \"${key}\".`,\n `Known operations: ${result.contract.operations.map((o) => `${o.kind}/${o.name}`).join(', ') || 'none'}.`,\n );\n }\n if (op.effect === 'write') {\n // A write is only ever recorded from a scenario fixture: reading a\n // file performs nothing. Running it live would perform it for real.\n const fixture = writeFixturePath(loaded.primary.slug, key);\n if (mode === 'live') {\n throw validationError(\n `${key} is a write; --from live would perform it for real, and a recording never does.`,\n `Add ${fixture} (a real-shaped response), then run \"ekanos contract --record --op ${key} --from fixtures\".`,\n );\n }\n if (!fs.existsSync(path.join(loaded.projectDir, fixture))) {\n throw validationError(\n `${key} is a write with no scenario fixture to record from.`,\n `Add ${fixture} holding a real-shaped response, then re-run \"ekanos contract --record --op ${key} --from fixtures\". Nothing is called.`,\n );\n }\n }\n if (op.opaque.output) {\n throw validationError(\n `${key} has an opaque output schema, so a recording cannot be validated.`,\n 'Declare an output schema first.',\n );\n }\n const run = await harness.runOperationOnce({\n projectRoot: loaded.projectDir,\n op: key,\n input: input ?? sdk.synthesizeExample(op.input),\n mode,\n env: args.env,\n deriveContract: () => result.contract,\n });\n if (!run.ok) {\n throw validationError(\n `Recording ${key} (${mode}) failed: ${run.reason}${run.detail ? ` - ${run.detail}` : ` - ${run.message}`}`,\n mode === 'live'\n ? 'Check the credentials (ekanos dev -> Connect) and the input, then re-run.'\n : `Fixtures mode reads fixtures/<slug>/${key.replace('/', '-')}.default.json (or an existing outputExample). Author that file, or record from a real run with \"--from live\".`,\n );\n }\n const problems = validateAgainstSchema(op.output, run.data);\n if (problems.length > 0) {\n throw validationError(\n `${key} returned data that does not satisfy its output schema: ${problems[0]}`,\n 'Fix the output schema or the handler; nothing was written.',\n );\n }\n const file = path.join(examplesDir, `${key.replace('/', '-')}.json`);\n fs.mkdirSync(examplesDir, { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify(run.data, null, 2)}\\n`);\n wrote.push(path.relative(loaded.projectDir, file));\n }\n ctx.log(\n `Recorded ${wrote.length} example(s) from a ${mode} run: ${wrote.join(', ')}. Review them before committing${mode === 'live' ? ' (live data may contain real records)' : ''}.`,\n );\n result = analyze();\n } else if (args.record) {\n const wrote: string[] = [];\n const advice: string[] = [];\n for (const diag of result.diagnostics) {\n if (diag.rule !== 'contract/example-missing' || !diag.operation) continue;\n const op = result.contract.operations.find((o) =>\n o.id.endsWith(`/${diag.operation}`),\n );\n if (!op || op.opaque.output) continue;\n const file = path.join(\n examplesDir,\n `${diag.operation.replace('/', '-')}.json`,\n );\n fs.mkdirSync(examplesDir, { recursive: true });\n fs.writeFileSync(\n file,\n `${JSON.stringify(sdk.synthesizeExample(op.output), null, 2)}\\n`,\n );\n wrote.push(path.relative(loaded.projectDir, file));\n advice.push(\n op.effect === 'write'\n ? `${diag.operation}: add ${writeFixturePath(loaded.primary.slug, diag.operation)} with a real-shaped response, then \"ekanos contract --record --op ${diag.operation} --from fixtures\" (writes are never recorded live)`\n : `${diag.operation}: add ${writeFixturePath(loaded.primary.slug, diag.operation)}, or \"ekanos contract --record --op ${diag.operation} --from live\"`,\n );\n }\n if (wrote.length > 0) {\n ctx.log(\n `Wrote ${wrote.length} placeholder example(s) synthesized from the output schema (not recorded from a run): ${wrote.join(', ')}. Fixtures mode will serve these placeholders until you replace them:\\n ${advice.join('\\n ')}`,\n );\n result = analyze();\n }\n }\n\n if (args.bump && previous) {\n const wanted = nextContractVersion(previous, result.contract);\n if (wanted && wanted !== contractVersion) {\n contractVersion = wanted;\n const raw = readJson<Record<string, unknown>>(configPath) ?? {};\n raw.contract = {\n ...(raw.contract as object | undefined),\n version: wanted,\n };\n fs.writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}\\n`);\n ctx.log(`contract.version ${declared} -> ${wanted} in ekanos.json`);\n result = analyze();\n }\n }\n\n for (const diag of result.diagnostics) {\n ctx.log(\n `${diag.severity === 'error' ? 'error' : diag.severity === 'warn' ? 'warn ' : 'info '} ${diag.operation ? `${diag.operation}: ` : ''}${diag.message} (${diag.rule})`,\n );\n }\n const errors = result.diagnostics.filter((d) => d.severity === 'error');\n if (errors.length > 0) {\n throw validationError(\n `${errors.length} contract error(s): ${errors\n .slice(0, 3)\n .map((e) => `${e.operation ?? ''} ${e.message}`.trim())\n .join('; ')}`,\n 'Fix them (declare outputs and examples, or run \"ekanos contract --record\"), then re-run.',\n );\n }\n\n const transition = previous\n ? assessContractTransition(previous, result.contract).problems\n : [];\n\n if (args.check) {\n const problems = checkContractFreshness(result.contract, previous, {\n strictPackageVersion: true,\n });\n if (problems.length > 0) {\n throw validationError(\n `contract.json is out of date: ${problems.map(describe).join(' | ')}`,\n 'Run \"ekanos contract\" (add --bump for the version) and commit contract.json.',\n );\n }\n return ctx.succeed(\n {\n ok: true,\n digest: result.contract.digest,\n operations: result.contract.operations.length,\n diagnostics: result.diagnostics,\n },\n `contract.json is current (${result.contract.operations.length} operations).`,\n );\n }\n\n if (transition.length > 0) {\n throw validationError(\n `This change is not allowed on the current contract version: ${transition.map(describe).join(' | ')}`,\n 'Run \"ekanos contract --bump\", or set contract.version in ekanos.json by hand (a breaking change needs a new compat line).',\n );\n }\n fs.writeFileSync(\n contractFile,\n `${JSON.stringify(result.contract, null, 2)}\\n`,\n );\n return ctx.succeed(\n {\n written: 'contract.json',\n digest: result.contract.digest,\n operations: result.contract.operations.length,\n diagnostics: result.diagnostics,\n },\n `Wrote contract.json (${result.contract.operations.length} operations, ${result.contract.compatLine} line, contract ${result.contract.contractVersion}).`,\n );\n}\n\nexport const contractCommand: ExperienceCommand = {\n name: 'contract',\n usage: [\n ' contract Derive ./contract.json from the integration definition;',\n ' --check fails on a stale file (CI, prepack), --record writes',\n ' missing output examples, --bump bumps the contract version',\n ],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n check: {\n type: 'boolean',\n description: 'Derive in memory and fail if contract.json differs',\n },\n record: {\n type: 'boolean',\n description:\n 'Write placeholder examples (contracts/examples) for operations that have none; with --op, record real ones from a run',\n },\n op: {\n type: 'string',\n description:\n 'With --record: operation(s) to record from a real run, comma separated (tool/list_posts)',\n },\n from: {\n type: 'string',\n description:\n 'With --op: run mode to record from, fixtures (default) or live',\n },\n input: {\n type: 'string',\n description: 'With --op: JSON input for the recorded run',\n },\n bump: {\n type: 'boolean',\n description:\n 'Rewrite ekanos.json contract.version to match the surface change',\n },\n },\n run(ctx, args) {\n const from = args.flags.from;\n if (from !== undefined && from !== 'live' && from !== 'fixtures') {\n throw usageError(\n `--from must be \"fixtures\" or \"live\", not \"${String(from)}\".`,\n 'Run \"ekanos contract --record --op tool/<name> --from live\".',\n );\n }\n\n return runContract(ctx, {\n dir: args.dir,\n check: args.flags.check === true,\n record: args.flags.record === true,\n bump: args.flags.bump === true,\n env: args.env,\n ...(typeof args.flags.op === 'string' && args.flags.op !== ''\n ? { ops: args.flags.op.split(',').map((o) => o.trim()) }\n : {}),\n ...(args.flags.from === 'live' || args.flags.from === 'fixtures'\n ? { from: args.flags.from }\n : {}),\n ...(typeof args.flags.input === 'string'\n ? { input: args.flags.input }\n : {}),\n });\n },\n};\n\n/** Where a scenario fixture for an operation lives, project-relative. */\nfunction writeFixturePath(slug: string, opKey: string): string {\n return path.join('fixtures', slug, `${opKey.replace('/', '-')}.default.json`);\n}\n"]}
@@ -7,12 +7,14 @@ import { assertHarnessCompatible } from '../compatibility.js';
7
7
  import { detectKind, loadHarnessResolver, readExperienceProject, writeSessionCatalog, } from '../dev-experience.js';
8
8
  import { preconditionError, usageError } from '../errors.js';
9
9
  import { BUILD_CACHE_DIR, HARNESS_DIR, HARNESS_PACKAGE, SHELL_REGISTRY_FILENAME, assertShellDirIsOurs, bootstrapHarnessConfig, ensureGitignoreEntry, missingDependencies, readInstalledHarness, scaffoldShell, } from '../harness-scaffold.js';
10
+ import { DUPLICATE_INSTANCE_HINT, describeDuplicates, scanLockfileInstances, } from '../lockfile-instances.js';
10
11
  import { detectPackageManager, execArgs, formatCommand, installCommand, } from '../package-manager.js';
11
12
  import { createOutputTail, findIgnoredBuilds, ignoredBuildsHint, } from '../pnpm-builds.js';
12
13
  import { loadProject } from '../project.js';
13
14
  import { resolveSourceTarget } from '../source-target.js';
14
15
  import { displayPath } from '../ui.js';
15
16
  import { announceUpdate, checkForUpdate } from '../update-notice.js';
17
+ import { findWorkspaceRoot } from '../workspace-root.js';
16
18
  const DEFAULT_PORT = 3100;
17
19
  /**
18
20
  * Loopback, NOT Next's default.
@@ -82,6 +84,7 @@ export async function runDev(ctx, args) {
82
84
  `in ${loaded.projectDir}: ${missing.join(', ')}.`, `Run "${installCommand(pm, missing)}" in ${loaded.projectDir}, then ` +
83
85
  're-run "ekanos dev".');
84
86
  }
87
+ warnOnDuplicateInstances(ctx, loaded.projectDir);
85
88
  const harness = readInstalledHarness(loaded.projectDir);
86
89
  const harnessVersion = harness === null || harness === void 0 ? void 0 : harness.version;
87
90
  if (!harnessVersion) {
@@ -126,7 +129,14 @@ export async function runDev(ctx, args) {
126
129
  configPath: path.join(loaded.projectDir, HARNESS_DIR, SHELL_REGISTRY_FILENAME),
127
130
  }
128
131
  : bootstrapHarnessConfig(loaded.projectDir, loaded.integrations);
129
- const shell = scaffoldShell(Object.assign(Object.assign({ projectDir: loaded.projectDir, slug: loaded.primary.slug, harnessVersion, force: args.force, sourceGlobs: loaded.project.sourceGlobs }, (experience
132
+ // A package inside a workspace resolves `next` and the harness from the
133
+ // workspace root's node_modules (pnpm symlinks them there), so Turbopack's
134
+ // root has to be that root, not the package.
135
+ const turbopackRoot = findWorkspaceRoot(loaded.projectDir);
136
+ if (turbopackRoot !== loaded.projectDir) {
137
+ ctx.log(ctx.ui.dim(`Workspace package: Turbopack uses the workspace root ${displayPath(turbopackRoot, process.cwd())}.`));
138
+ }
139
+ const shell = scaffoldShell(Object.assign(Object.assign({ projectDir: loaded.projectDir, turbopackRoot, slug: loaded.primary.slug, harnessVersion, force: args.force, sourceGlobs: loaded.project.sourceGlobs }, (experience
130
140
  ? { experienceEntry: readExperienceProject(loaded.projectDir).entry }
131
141
  : {})), (repo
132
142
  ? {
@@ -206,7 +216,7 @@ export async function runDev(ctx, args) {
206
216
  ? repo.packages
207
217
  .filter((p) => p.kind === 'integration')
208
218
  .map((p) => p.name)
209
- : loaded.integrations.map((i) => i.slug), projectDir: loaded.projectDir, harnessDir: shell.harnessDir, harnessVersion, previousVersion: shell.previousVersion, previousMarker: shell.previousMarker, stale: shell.stale, staleReasons: shell.staleReasons, buildCacheCleared: shell.buildCacheCleared, sourceGlobs: (_b = loaded.project.sourceGlobs) !== null && _b !== void 0 ? _b : [], created: shell.created, updated: shell.updated, unchanged: shell.unchanged, configBootstrapped: config.bootstrapped, configPath: config.configPath, gitignoreUpdated }), (notice ? { toolchain: notice } : {}));
219
+ : loaded.integrations.map((i) => i.slug), projectDir: loaded.projectDir, turbopackRoot, harnessDir: shell.harnessDir, harnessVersion, previousVersion: shell.previousVersion, previousMarker: shell.previousMarker, stale: shell.stale, staleReasons: shell.staleReasons, buildCacheCleared: shell.buildCacheCleared, sourceGlobs: (_b = loaded.project.sourceGlobs) !== null && _b !== void 0 ? _b : [], created: shell.created, updated: shell.updated, unchanged: shell.unchanged, configBootstrapped: config.bootstrapped, configPath: config.configPath, gitignoreUpdated }), (notice ? { toolchain: notice } : {}));
210
220
  if (exposed) {
211
221
  ctx.warn(`WARNING: --host ${host} exposes the harness beyond this machine. It ` +
212
222
  'has no authentication, and it renders your fixtures and — in live ' +
@@ -274,6 +284,27 @@ export async function runDev(ctx, args) {
274
284
  data,
275
285
  });
276
286
  }
287
+ /**
288
+ * Warn — never fail — when the lockfile resolves `@ekanos/sdk` or `@ekanos/ui`
289
+ * more than once: the harness would mount its providers from one copy and the
290
+ * project's hooks would read the other's, which throws at render time with a
291
+ * message that points nowhere near the lockfile.
292
+ */
293
+ function warnOnDuplicateInstances(ctx, projectDir) {
294
+ const scan = scanLockfileInstances(projectDir);
295
+ if (scan.status === 'unreadable') {
296
+ ctx.log(ctx.ui.dim(`Could not check ${scan.lockfile} for duplicate @ekanos/sdk copies: ${scan.reason}`));
297
+ return;
298
+ }
299
+ if (scan.status !== 'ok')
300
+ return;
301
+ const lines = describeDuplicates(scan.duplicates);
302
+ if (lines.length === 0)
303
+ return;
304
+ ctx.warn(`WARNING: ${lines.join('; ')} (${scan.lockfile}). The harness and your ` +
305
+ 'code may load different copies, and a provider from one is invisible ' +
306
+ `to hooks from the other. ${DUPLICATE_INSTANCE_HINT}`);
307
+ }
277
308
  function spawnServer(params) {
278
309
  return new Promise((resolve, reject) => {
279
310
  var _a, _b;