@ekanos/cli 0.3.6 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/commands/dev.js +5 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.js +12 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/upgrade.js +58 -7
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/compatibility.d.ts +4 -1
- package/dist/compatibility.js +4 -1
- package/dist/compatibility.js.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.js +5 -5
- package/dist/context.js.map +1 -1
- package/dist/design-findings.d.ts +22 -0
- package/dist/design-findings.js +47 -0
- package/dist/design-findings.js.map +1 -0
- package/dist/docs-links.d.ts +20 -0
- package/dist/docs-links.js +33 -0
- package/dist/docs-links.js.map +1 -0
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +5 -1
- package/dist/errors.js.map +1 -1
- package/dist/findings-renderer.js +5 -0
- package/dist/findings-renderer.js.map +1 -1
- package/dist/harness-scaffold.d.ts +4 -0
- package/dist/harness-scaffold.js +18 -1
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/pnpm-builds.d.ts +41 -6
- package/dist/pnpm-builds.js +169 -0
- package/dist/pnpm-builds.js.map +1 -1
- package/dist/schema-skew.js +2 -1
- package/dist/schema-skew.js.map +1 -1
- package/dist/validate-findings.js +2 -0
- package/dist/validate-findings.js.map +1 -1
- package/package.json +3 -2
- package/templates/AGENTS.md.tmpl +77 -9
- package/templates/CLAUDE.md.tmpl +5 -0
- package/templates/claude-skill.md.tmpl +7 -0
- package/templates/eslint.config.mjs.tmpl +62 -0
- package/templates/harness/app/[slug]/page.tsx.tmpl +1 -0
- package/templates/harness.config.entry.ts.tmpl +8 -0
- package/templates/mcp.json.tmpl +4 -0
- package/templates/package.json.tmpl +7 -4
- package/templates/skills/build-integration/SKILL.md +11 -0
- package/templates/skills/build-integration/references/widget-design.md +128 -32
- package/templates/skills/polish-widgets/SKILL.md +35 -13
- package/templates/skills/polish-widgets/references/patterns.md +90 -58
- package/templates/src/integration.ts.tmpl +50 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { resolveAuthEnvironment } from '../auth/session';\nimport { cliVersion } from '../compatibility';\nimport type { CliContext } from '../context';\nimport { networkError, preconditionError, validationError } from '../errors';\nimport { EXIT_CODES } from '../exit-codes';\nimport { readInstalledPackageManifest } from '../harness-scaffold';\nimport {\n type PackageManager,\n detectPackageManager,\n installExactArgs,\n lockfileName,\n} from '../package-manager';\nimport { loadProject } from '../project';\nimport { classifyPath, writeFileNoFollow } from '../safe-fs';\nimport { renderTemplate, toDisplayName } from '../templates';\nimport {\n TOOLCHAIN_PACKAGES,\n type ToolchainKey,\n type ToolchainVersions,\n} from '../toolchain';\nimport { resolveToolchainTarget } from '../toolchain-resolve';\nimport { type Ui, displayPath } from '../ui';\nimport { collectAllFindings } from '../validate-findings';\nimport {\n AGENT_CONTEXT_FILES,\n DOCS_GROUNDING_FILES,\n copyBundledSkillTrees,\n} from './init';\nimport { promptYesNo } from './publish';\n\n/**\n * `ekanos upgrade` — move a project's toolchain to a coherent target version\n * and VERIFY it before calling the job done.\n *\n * The whole point of this verb is that it cannot leave a project worse off\n * than it found it: `package.json` and the lockfile are snapshotted before\n * anything installs, the target set is only ever a coherence-checked whole\n * (never \"latest of each, independently\" — see `toolchain-resolve.ts`), and\n * any failure from install through validate through the project's own test\n * script rolls everything back to the snapshot and says exactly which step\n * failed. A partner (or an agent) running this unattended should never end up\n * with a half-upgraded, uninstallable project.\n */\n\nexport interface UpgradeArgs {\n dir: string;\n host?: string;\n env: Record<string, string | undefined>;\n /** Report current vs. target and exit 0. Never mutates anything. */\n check: boolean;\n /** Skip the interactive confirm; required to mutate outside a TTY. */\n yes: boolean;\n /** Skip the post-install validate + test-script verification. */\n noVerify: boolean;\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/** Injectable seams so tests can exercise install/verify/rollback without shelling out. */\nexport interface UpgradeDeps {\n resolveTarget?: typeof resolveToolchainTarget;\n runInstall?: (\n argv: string[],\n bin: string,\n cwd: string,\n ) => Promise<{ code: number; output: string }>;\n runValidateStep?: (\n projectDir: string,\n ) => Promise<{ ok: boolean; findings?: Finding[] }>;\n runTestStep?: (\n projectDir: string,\n pm: PackageManager,\n ) => Promise<{ code: number; output: string }>;\n}\n\ninterface DeltaEntry {\n current: string | null;\n target: string;\n changed: boolean;\n}\n\nexport async function runUpgrade(\n ctx: CliContext,\n args: UpgradeArgs,\n deps: UpgradeDeps = {},\n): Promise<number> {\n const loaded = loadProject(args.dir);\n const pm = detectPackageManager(loaded.projectDir);\n\n // Captured BEFORE anything installs: the templates the project's CURRENT\n // (pre-upgrade) local `@ekanos/cli` ships, which is what actually\n // generated the agent-context files on disk — not necessarily this\n // process's own bundled templates, since `upgrade` is a machine-level verb\n // that never delegates and is routinely invoked via a DIFFERENT (global)\n // install. See `regenerateAgentContextFiles`.\n const oldAgentTemplates = captureAgentTemplates(loaded.projectDir);\n\n const current = readCurrentToolchain(loaded.projectDir);\n\n const session = resolveSessionQuietly(ctx, args);\n const resolveTarget = deps.resolveTarget ?? resolveToolchainTarget;\n const resolution = await resolveTarget({\n host: session?.host,\n session: session?.session,\n });\n\n if (resolution.status === 'unavailable') {\n throw networkError(\n 'Could not resolve a toolchain target from the Ekanos host or the ' +\n 'npm registry.',\n 'Check connectivity and retry. If this deployment has no ' +\n '\"/api/partner/toolchain\" route yet, the npm registry is the ' +\n 'fallback and a failure there means npm itself is unreachable.',\n );\n }\n\n if (resolution.status === 'incoherent') {\n throw preconditionError(\n `The resolved toolchain versions do not form an installable set: ` +\n resolution.detail,\n 'Retry in a moment — this is almost always a multi-package publish ' +\n 'still in flight, and it self-resolves once every package finishes ' +\n 'publishing.',\n );\n }\n\n const target = resolution.target;\n const deltas = computeDeltas(current, target);\n\n if (args.check) {\n return ctx.succeed(\n {\n source: resolution.source,\n current,\n target,\n deltas,\n ...(resolution.source === 'host'\n ? { minimum: resolution.minimum, notes: resolution.notes }\n : {}),\n },\n checkSummary(ctx.ui, resolution.source, deltas),\n );\n }\n\n const changedKeys = (Object.keys(deltas) as ToolchainKey[]).filter(\n (key) => deltas[key]!.changed,\n );\n\n if (changedKeys.length === 0) {\n return ctx.succeed(\n { source: resolution.source, current, target, deltas },\n ctx.ui.result({\n title: 'Already up to date',\n rows: [['Target', `resolved from ${resolution.source}`]],\n }),\n );\n }\n\n const isHuman = !ctx.jsonMode;\n const stdinIsTTY = args.stdinIsTTY ?? process.stdin.isTTY === true;\n const canPrompt = isHuman && stdinIsTTY;\n\n if (!args.yes) {\n if (!canPrompt) {\n throw validationError(\n 'Refusing to modify the project non-interactively without --yes.',\n 'Pass \"ekanos upgrade --yes\" to proceed, or \"ekanos upgrade --check\" ' +\n 'to preview the target with no changes.',\n );\n }\n\n ctx.log(planSummary(ctx.ui, resolution.source, deltas));\n const confirm = args.confirm ?? promptYesNo;\n const confirmed = await confirm('Upgrade now? [y/N]');\n\n if (!confirmed) {\n throw validationError(\n 'Upgrade was not confirmed.',\n 'Re-run \"ekanos upgrade --yes\" to proceed non-interactively, or ' +\n '\"ekanos upgrade --check\" to preview with no changes. Nothing was ' +\n 'modified.',\n );\n }\n }\n\n const packageJsonPath = path.join(loaded.projectDir, 'package.json');\n const manifest = readManifest(packageJsonPath);\n const specs = buildInstallSpecs(manifest, target, changedKeys);\n\n if (specs.length === 0) {\n return ctx.succeed(\n { source: resolution.source, current, target, deltas },\n ctx.ui.result({\n title: 'Nothing to install',\n tone: 'warn',\n notes: [\n 'None of the changed packages are direct dependencies of this project.',\n 'Their versions follow from whichever direct dependency pins them.',\n ],\n }),\n );\n }\n\n const snapshot = snapshotProject(loaded.projectDir, pm);\n\n try {\n const runInstall = deps.runInstall ?? defaultRunInstall;\n\n for (const group of [\n specs.filter((s) => !s.dev),\n specs.filter((s) => s.dev),\n ]) {\n if (group.length === 0) continue;\n\n const argv = installExactArgs(\n pm,\n group.map((s) => `${s.name}@${s.version}`),\n group[0]!.dev,\n );\n ctx.log(\n ctx.ui.dim(\n `Running \"${pm.bin} ${argv.join(' ')}\" in ${displayPath(loaded.projectDir, process.cwd())}…`,\n ),\n );\n const result = await runInstall(argv, pm.bin, loaded.projectDir);\n\n if (result.code !== 0) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'install',\n exitCode: EXIT_CODES.PRECONDITION_FAILED,\n message: `\"${pm.bin} ${argv.join(' ')}\" exited with code ${result.code}.`,\n output: result.output,\n },\n );\n }\n }\n\n if (!args.noVerify) {\n const runValidateStep = deps.runValidateStep ?? defaultRunValidateStep;\n const validateResult = await runValidateStep(loaded.projectDir);\n\n if (!validateResult.ok) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'validate',\n exitCode: EXIT_CODES.VALIDATION,\n message:\n 'The upgraded toolchain fails \"ekanos validate\" against this ' +\n \"project's own integration definition.\",\n output: JSON.stringify(validateResult.findings ?? [], null, 2),\n },\n );\n }\n\n const runTestStep = deps.runTestStep ?? defaultRunTestStep;\n const testResult = await runTestStep(loaded.projectDir, pm);\n\n if (testResult.code !== 0) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'test',\n exitCode: testResult.code,\n message: `The project's test script exited with code ${testResult.code} on the upgraded toolchain.`,\n output: testResult.output,\n },\n );\n }\n }\n } finally {\n snapshot.dispose();\n }\n\n const newTemplatesDir = path.join(\n loaded.projectDir,\n 'node_modules',\n '@ekanos',\n 'cli',\n 'templates',\n );\n\n const regenerated = regenerateAgentContextFiles({\n projectDir: loaded.projectDir,\n slug: loaded.primary.slug,\n oldTemplates: oldAgentTemplates,\n newTemplatesDir,\n });\n\n // The regenerated AGENTS.md and skills may now REFERENCE artifacts this\n // project predates (docs/api-notes.md, .mcp.json, bundled skill trees) —\n // instructions pointing at files that don't exist are exactly the stale-docs\n // failure the docs-grounding feature closes, so create what's missing.\n // Create-if-missing ONLY: these files are partner/agent-authored after the\n // scaffold and are never regenerated.\n const scaffolded = scaffoldMissingDocsArtifacts({\n projectDir: loaded.projectDir,\n slug: loaded.primary.slug,\n newTemplatesDir,\n });\n\n // `specs` only ever covers DIRECT dependencies (see `buildInstallSpecs`) —\n // a changed key with no spec is transitive and was never actually\n // installed here, so the report (and the human summary) must say so\n // explicitly rather than implying every changed key was upgraded. This\n // matters most for exactly the scenario this PR's own delegation feature\n // targets: a globally-installed `ekanos` with no local `@ekanos/cli`\n // devDependency, where `cli` changes in `deltas` but the running global\n // binary itself is untouched by this command.\n const installedKeys = specs.map((spec) => spec.key);\n const skippedKeys = changedKeys.filter((key) => !installedKeys.includes(key));\n\n return ctx.succeed(\n {\n source: resolution.source,\n current,\n target,\n deltas,\n installed: installedKeys,\n skippedTransitive: skippedKeys,\n regenerated,\n scaffolded,\n },\n successSummary(\n ctx.ui,\n installedKeys,\n skippedKeys,\n deltas,\n regenerated,\n scaffolded,\n ),\n );\n}\n\n/**\n * Best-effort host/session resolution — NEVER throws. `upgrade` must work for\n * a partner who has never logged in at all (pure npm-registry flow), so the\n * throwing `resolveAuthEnvironment`/`requireSession` machinery is unusable\n * here; this mirrors the tolerant lookup `update-notice.ts` uses.\n */\nfunction resolveSessionQuietly(\n ctx: CliContext,\n args: UpgradeArgs,\n): { host: string; session: { accessToken: string } } | null {\n try {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const session = env.store.read(env.host);\n return session ? { host: env.host, session } : null;\n } catch {\n return null;\n }\n}\n\nfunction readCurrentToolchain(\n projectDir: string,\n): Record<ToolchainKey, string | null> {\n const result = {} as Record<ToolchainKey, string | null>;\n\n for (const [key, pkg] of Object.entries(TOOLCHAIN_PACKAGES) as [\n ToolchainKey,\n string,\n ][]) {\n const installed = readInstalledPackageManifest(projectDir, pkg);\n result[key] = installed?.version ?? (key === 'cli' ? cliVersion() : null);\n }\n\n return result;\n}\n\nfunction computeDeltas(\n current: Record<ToolchainKey, string | null>,\n target: ToolchainVersions,\n): Record<ToolchainKey, DeltaEntry> {\n const keys = Object.keys(TOOLCHAIN_PACKAGES) as ToolchainKey[];\n const result = {} as Record<ToolchainKey, DeltaEntry>;\n\n for (const key of keys) {\n result[key] = {\n current: current[key],\n target: target[key],\n changed: current[key] !== target[key],\n };\n }\n\n return result;\n}\n\ninterface InstallSpec {\n key: ToolchainKey;\n name: string;\n version: string;\n dev: boolean;\n}\n\n/**\n * Only packages the project depends on DIRECTLY are installed explicitly —\n * `@ekanos/integration-schema` and often `@ekanos/harness` are transitive\n * (pulled in by `@ekanos/sdk`), and forcing an exact transitive version would\n * need a package-manager-specific override mechanism this CLI does not\n * manage. Their versions follow from whichever direct dependency pins them,\n * which is exactly what the coherent target guarantees is already correct.\n */\nfunction buildInstallSpecs(\n manifest: Record<string, unknown>,\n target: ToolchainVersions,\n changedKeys: readonly ToolchainKey[],\n): InstallSpec[] {\n const deps = (manifest.dependencies ?? {}) as Record<string, unknown>;\n const devDeps = (manifest.devDependencies ?? {}) as Record<string, unknown>;\n\n const specs: InstallSpec[] = [];\n\n for (const key of changedKeys) {\n const pkg = TOOLCHAIN_PACKAGES[key];\n if (pkg in deps) {\n specs.push({ key, name: pkg, version: target[key], dev: false });\n } else if (pkg in devDeps) {\n specs.push({ key, name: pkg, version: target[key], dev: true });\n }\n }\n\n return specs;\n}\n\nfunction readManifest(packageJsonPath: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));\n } catch (error) {\n throw preconditionError(\n `Could not read ${packageJsonPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'Ensure the project has a valid package.json, then re-run \"ekanos upgrade\".',\n );\n }\n if (typeof parsed !== 'object' || parsed === null) {\n throw preconditionError(\n `${packageJsonPath} does not contain a JSON object.`,\n 'Fix package.json, then re-run \"ekanos upgrade\".',\n );\n }\n return parsed as Record<string, unknown>;\n}\n\ninterface Snapshot {\n restore: () => void;\n dispose: () => void;\n}\n\n/**\n * Copy `package.json` and the lockfile to a temp directory before anything\n * installs. `restore()` copies them back (and removes a lockfile that did not\n * exist before, if the failed install created one); `dispose()` cleans up the\n * temp copies once the run is over, success or failure.\n */\nfunction snapshotProject(projectDir: string, pm: PackageManager): Snapshot {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ekanos-upgrade-'));\n const packageJsonPath = path.join(projectDir, 'package.json');\n\n // bun has shipped both a text (`bun.lock`) and a legacy binary\n // (`bun.lockb`) lockfile; snapshot whichever is actually present.\n const lockCandidates =\n pm.name === 'bun' ? ['bun.lock', 'bun.lockb'] : [lockfileName(pm)];\n const lockName = lockCandidates.find((name) =>\n fs.existsSync(path.join(projectDir, name)),\n );\n const lockfilePath = lockName\n ? path.join(projectDir, lockName)\n : path.join(projectDir, lockfileName(pm));\n const lockfileExisted = lockName !== undefined;\n\n fs.copyFileSync(packageJsonPath, path.join(tmpDir, 'package.json'));\n if (lockfileExisted) {\n fs.copyFileSync(lockfilePath, path.join(tmpDir, 'lockfile.snapshot'));\n }\n\n return {\n restore: () => {\n fs.copyFileSync(path.join(tmpDir, 'package.json'), packageJsonPath);\n if (lockfileExisted) {\n fs.copyFileSync(path.join(tmpDir, 'lockfile.snapshot'), lockfilePath);\n } else if (fs.existsSync(lockfilePath)) {\n fs.rmSync(lockfilePath);\n }\n },\n dispose: () => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n },\n };\n}\n\ninterface StepFailure {\n step: 'install' | 'validate' | 'test';\n exitCode: number;\n message: string;\n output: string;\n}\n\n/**\n * The one rollback path every failure funnels through: restore the snapshot,\n * reinstall to put `node_modules` back in sync with the restored\n * `package.json`/lockfile, and report exactly which step failed and what it\n * said — with an explicit statement that the project was restored, so a\n * partner (or an agent) never has to wonder whether they are looking at a\n * half-upgraded tree.\n */\nasync function failAndRollback(\n ctx: CliContext,\n snapshot: Snapshot,\n pm: PackageManager,\n projectDir: string,\n runInstall: (\n argv: string[],\n bin: string,\n cwd: string,\n ) => Promise<{ code: number; output: string }>,\n failure: StepFailure,\n): Promise<number> {\n ctx.warn(\n `ekanos: the \"${failure.step}\" step failed — rolling back package.json ` +\n 'and the lockfile, then reinstalling to restore node_modules…',\n );\n\n snapshot.restore();\n // The SAME injectable installer seam used for the forward install — a test\n // that mocks it never shells out for the rollback path either.\n const restore = await runInstall(['install'], pm.bin, projectDir);\n\n return ctx.failWith({\n code: `upgrade_${failure.step}_failed`,\n message: failure.message,\n hint:\n `The project HAS BEEN RESTORED to its pre-upgrade state (package.json, ` +\n `lockfile and node_modules all rolled back${\n restore.code === 0\n ? ''\n : ' — though the restore install itself also failed with code ' +\n `${restore.code}; run \"${pm.bin} install\" by hand to finish ` +\n 'repairing node_modules'\n }). Read the output in data.output, fix the underlying issue, and ` +\n 're-run \"ekanos upgrade\".',\n exitCode: failure.exitCode,\n data: { step: failure.step, output: failure.output },\n });\n}\n\nasync function defaultRunInstall(\n argv: string[],\n bin: string,\n cwd: string,\n): Promise<{ code: number; output: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, argv, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });\n let output = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => resolve({ code: code ?? 1, output }));\n });\n}\n\nasync function defaultRunValidateStep(\n projectDir: string,\n): Promise<{ ok: boolean; findings?: Finding[] }> {\n const loaded = loadProject(projectDir);\n const findings = await collectAllFindings(loaded);\n const errorCount = findings.filter((f) => f.severity === 'error').length;\n return { ok: errorCount === 0, findings };\n}\n\nasync function defaultRunTestStep(\n projectDir: string,\n pm: PackageManager,\n): Promise<{ code: number; output: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(pm.bin, ['run', 'test'], {\n cwd: projectDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let output = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => resolve({ code: code ?? 1, output }));\n });\n}\n\ninterface RegenerationReport {\n updated: string[];\n unchanged: string[];\n needsAttention: string[];\n}\n\n/**\n * Read every `AGENT_CONTEXT_FILES` template source out of the project's\n * CURRENT (pre-upgrade) local `@ekanos/cli` install, before anything installs\n * over it. Missing entirely (the package isn't a resolvable local dependency)\n * just means every file below is treated conservatively — see\n * `regenerateAgentContextFiles`.\n */\nfunction captureAgentTemplates(projectDir: string): Map<string, string> {\n const templatesDir = path.join(\n projectDir,\n 'node_modules',\n '@ekanos',\n 'cli',\n 'templates',\n );\n const captured = new Map<string, string>();\n\n for (const { template } of AGENT_CONTEXT_FILES) {\n const templatePath = path.join(templatesDir, template);\n try {\n captured.set(template, fs.readFileSync(templatePath, 'utf8'));\n } catch {\n // Not resolvable — left out of the map, handled as \"can't verify\" below.\n }\n }\n\n return captured;\n}\n\n/**\n * Create the docs-grounding artifacts a pre-0.1.7 project is missing, from\n * the NEWLY installed CLI's bundled templates: `docs/api-notes.md`,\n * `.mcp.json`, and any bundled skill trees. Strictly create-if-missing —\n * an existing file is the partner's (api-notes is agent-authored, .mcp.json\n * may carry local servers) and is never touched, force or not. Writes go\n * through safe-fs like init's own scaffold pass.\n */\nfunction scaffoldMissingDocsArtifacts(params: {\n projectDir: string;\n slug: string;\n newTemplatesDir: string;\n}): { created: string[]; needsAttention: string[] } {\n const vars = { SLUG: params.slug, DISPLAY_NAME: toDisplayName(params.slug) };\n const created: string[] = [];\n const needsAttention: string[] = [];\n\n // This runs AFTER snapshot.dispose(): the toolchain upgrade has already\n // succeeded and there is no rollback left to protect. A refused write here\n // (a symlinked `docs/` or `.claude` ancestor — safe-fs throws rather than\n // follow it) must therefore be REPORTED, never thrown — the same stance\n // `regenerateAgentContextFiles` takes, for the same reason: a hard failure\n // now would misreport a successful upgrade.\n for (const { template, dest } of DOCS_GROUNDING_FILES) {\n const destPath = path.join(params.projectDir, dest);\n const kind = classifyPath(destPath);\n // A real file or directory is the partner's — skipping it quietly IS the\n // contract. A symlink (or fifo, socket, …) is not \"already there\": it is\n // a path we refuse to write through, and silence would hide that — same\n // reporting stance as regenerateAgentContextFiles.\n if (kind === 'file' || kind === 'directory') continue;\n if (kind !== 'missing') {\n needsAttention.push(dest);\n continue;\n }\n\n const templatePath = path.join(params.newTemplatesDir, template);\n if (!fs.existsSync(templatePath)) continue; // older target toolchain\n\n try {\n writeFileNoFollow(\n params.projectDir,\n destPath,\n renderTemplate(fs.readFileSync(templatePath, 'utf8'), vars),\n );\n created.push(dest);\n } catch {\n needsAttention.push(dest);\n }\n }\n\n try {\n // 'collect': a refused file is recorded and the walk continues, so files\n // that DID land — in this skill tree or an earlier one — stay in\n // `created` instead of vanishing when a later write refuses.\n const skills = copyBundledSkillTrees(\n params.projectDir,\n false,\n path.join(params.newTemplatesDir, 'skills'),\n 'collect',\n );\n created.push(...skills.created);\n needsAttention.push(...skills.refused);\n } catch {\n // Last resort (an unreadable templates dir, not a refused write — those\n // are collected above).\n needsAttention.push('.claude/skills');\n }\n\n return { created, needsAttention };\n}\n\n/**\n * Regenerate `AGENTS.md`, `CLAUDE.md` and the Claude Code skill from the\n * NEWLY installed CLI's bundled templates — using the exact byte-comparison\n * discipline `harness-scaffold.ts` applies to the dev harness shell: a file\n * whose current bytes match what the project's PRE-upgrade local CLI would\n * have rendered (captured in `oldTemplates`, before install ran) is\n * untouched by the partner and safe to regenerate; anything else has been\n * edited and is left alone, reported so a human can merge it by hand. A\n * stale AGENTS.md teaches an agent yesterday's contract — that is as harmful\n * as a stale binary, which is why this runs on every successful upgrade\n * rather than only on `init`.\n */\nfunction regenerateAgentContextFiles(params: {\n projectDir: string;\n slug: string;\n oldTemplates: Map<string, string>;\n newTemplatesDir: string;\n}): RegenerationReport {\n const vars = { SLUG: params.slug, DISPLAY_NAME: toDisplayName(params.slug) };\n const updated: string[] = [];\n const unchanged: string[] = [];\n const needsAttention: string[] = [];\n\n for (const { template, dest } of AGENT_CONTEXT_FILES) {\n const destPath = path.join(params.projectDir, dest);\n const kind = classifyPath(destPath);\n if (kind === 'missing') continue; // never scaffolded — nothing to upgrade\n if (kind !== 'file') {\n // A symlink (or anything else odd) is not ours to write through — same\n // stance as init's scaffold pass, but reported instead of thrown: the\n // upgrade itself already succeeded, so surface it for a human.\n needsAttention.push(dest);\n continue;\n }\n\n const current = fs.readFileSync(destPath, 'utf8');\n const oldSource = params.oldTemplates.get(template);\n\n const oldRendered =\n oldSource === undefined ? null : renderTemplate(oldSource, vars);\n\n if (oldRendered === null || current !== oldRendered) {\n needsAttention.push(dest);\n continue;\n }\n\n const newTemplatePath = path.join(params.newTemplatesDir, template);\n if (!fs.existsSync(newTemplatePath)) continue;\n\n const newRendered = renderTemplate(\n fs.readFileSync(newTemplatePath, 'utf8'),\n vars,\n );\n\n if (newRendered === current) {\n unchanged.push(dest);\n continue;\n }\n\n try {\n writeFileNoFollow(params.projectDir, destPath, newRendered);\n updated.push(dest);\n } catch {\n // A symlinked ANCESTOR (.claude centralized across projects) passes the\n // leaf classifyPath check above but is refused by the guarded write —\n // and this runs post-rollback, so a throw here would misreport a\n // successful toolchain upgrade as failed. Report it instead, like every\n // other post-rollback write path in this file.\n needsAttention.push(dest);\n }\n }\n\n return { updated, unchanged, needsAttention };\n}\n\nfunction describeDelta(delta: DeltaEntry): string {\n return `${delta.current ?? 'not installed'} → ${delta.target}`;\n}\n\nfunction checkSummary(\n ui: Ui,\n source: 'host' | 'npm',\n deltas: Record<ToolchainKey, DeltaEntry>,\n): string {\n const entries = Object.entries(deltas) as [ToolchainKey, DeltaEntry][];\n const pending = entries.filter(([, delta]) => delta.changed).length;\n\n return ui.result({\n title:\n pending === 0 ? 'Toolchain is current' : 'Toolchain update available',\n tone: pending === 0 ? 'ok' : 'warn',\n rows: entries.map(([key, delta]): [string, string] => [\n key,\n delta.changed ? describeDelta(delta) : `${delta.target} · current`,\n ]),\n notes: [\n `Target resolved from ${source}.` +\n (pending > 0 ? ' Run \"ekanos upgrade\" to apply it.' : ''),\n ],\n });\n}\n\nfunction planSummary(\n ui: Ui,\n source: string,\n deltas: Record<ToolchainKey, DeltaEntry>,\n): string {\n return ui.result({\n title: 'Upgrading',\n rows: (Object.entries(deltas) as [ToolchainKey, DeltaEntry][])\n .filter(([, delta]) => delta.changed)\n .map(([key, delta]): [string, string] => [key, describeDelta(delta)]),\n notes: [`Target resolved from ${source}.`],\n });\n}\n\nfunction successSummary(\n ui: Ui,\n installedKeys: readonly ToolchainKey[],\n skippedKeys: readonly ToolchainKey[],\n deltas: Record<ToolchainKey, DeltaEntry>,\n regenerated: RegenerationReport,\n scaffolded: { created: string[]; needsAttention: string[] },\n): string {\n const arrow = (key: ToolchainKey) => `${key} → ${deltas[key]!.target}`;\n const attention =\n regenerated.needsAttention.length > 0 ||\n scaffolded.needsAttention.length > 0;\n\n const notes: string[] = [];\n if (scaffolded.created.length > 0) {\n notes.push(\n 'New in this toolchain: see AGENTS.md\\'s \"API documentation\" section.',\n );\n }\n if (scaffolded.needsAttention.length > 0) {\n // Never suggest --force here — it overwrites every scaffolded file,\n // including src/integration.ts.\n notes.push(\n 'A path component is a symlink or unwritable, so those files were not created. ' +\n 'Fix the path, then run \"ekanos init --slug <slug> --dir .\" WITHOUT --force: ' +\n 'init is per-file idempotent and creates only what is missing.',\n );\n }\n if (regenerated.needsAttention.length > 0) {\n notes.push(\n 'Locally modified files were left untouched — merge the new template by hand.',\n );\n }\n\n return ui.result({\n title:\n installedKeys.length > 0 ? 'Toolchain upgraded' : 'Nothing to install',\n tone: attention || installedKeys.length === 0 ? 'warn' : 'ok',\n rows: [\n ...(installedKeys.length > 0\n ? [['Installed', installedKeys.map(arrow)] as const]\n : []),\n ...(skippedKeys.length > 0\n ? [['Not installed', skippedKeys.map(arrow)] as const]\n : []),\n ...(regenerated.updated.length > 0\n ? [['Regenerated', regenerated.updated] as const]\n : []),\n ...(scaffolded.created.length > 0\n ? [['Created', scaffolded.created] as const]\n : []),\n ...(regenerated.needsAttention.length > 0\n ? [['Modified', regenerated.needsAttention] as const]\n : []),\n ...(scaffolded.needsAttention.length > 0\n ? [['Could not create', scaffolded.needsAttention] as const]\n : []),\n ],\n notes:\n skippedKeys.length > 0\n ? [\n 'Not installed = transitive, or not a local dependency (e.g. a global CLI).',\n ...notes,\n ]\n : notes,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { resolveAuthEnvironment } from '../auth/session';\nimport { cliVersion } from '../compatibility';\nimport type { CliContext } from '../context';\nimport { networkError, preconditionError, validationError } from '../errors';\nimport { EXIT_CODES } from '../exit-codes';\nimport { readInstalledPackageManifest } from '../harness-scaffold';\nimport {\n type PackageManager,\n detectPackageManager,\n installExactArgs,\n lockfileName,\n} from '../package-manager';\nimport {\n type BuildScriptsResult,\n ensureBuildScriptsAnswered,\n skippedBuildScriptsHint,\n findIgnoredBuilds,\n ignoredBuildsHint,\n isIgnoredBuildsFailure,\n WORKSPACE_FILE,\n} from '../pnpm-builds';\nimport { loadProject } from '../project';\nimport { classifyPath, writeFileNoFollow } from '../safe-fs';\nimport { renderTemplate, toDisplayName } from '../templates';\nimport {\n TOOLCHAIN_PACKAGES,\n type ToolchainKey,\n type ToolchainVersions,\n} from '../toolchain';\nimport { resolveToolchainTarget } from '../toolchain-resolve';\nimport { type Ui, displayPath } from '../ui';\nimport { collectAllFindings } from '../validate-findings';\nimport {\n AGENT_CONTEXT_FILES,\n DOCS_GROUNDING_FILES,\n copyBundledSkillTrees,\n} from './init';\nimport { promptYesNo } from './publish';\n\n/**\n * `ekanos upgrade` — move a project's toolchain to a coherent target version\n * and VERIFY it before calling the job done.\n *\n * The whole point of this verb is that it cannot leave a project worse off\n * than it found it: `package.json` and the lockfile are snapshotted before\n * anything installs, the target set is only ever a coherence-checked whole\n * (never \"latest of each, independently\" — see `toolchain-resolve.ts`), and\n * any failure from install through validate through the project's own test\n * script rolls everything back to the snapshot and says exactly which step\n * failed. A partner (or an agent) running this unattended should never end up\n * with a half-upgraded, uninstallable project.\n */\n\nexport interface UpgradeArgs {\n dir: string;\n host?: string;\n env: Record<string, string | undefined>;\n /** Report current vs. target and exit 0. Never mutates anything. */\n check: boolean;\n /** Skip the interactive confirm; required to mutate outside a TTY. */\n yes: boolean;\n /** Skip the post-install validate + test-script verification. */\n noVerify: boolean;\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/** Injectable seams so tests can exercise install/verify/rollback without shelling out. */\nexport interface UpgradeDeps {\n resolveTarget?: typeof resolveToolchainTarget;\n runInstall?: (\n argv: string[],\n bin: string,\n cwd: string,\n ) => Promise<{ code: number; output: string }>;\n runValidateStep?: (\n projectDir: string,\n ) => Promise<{ ok: boolean; findings?: Finding[] }>;\n runTestStep?: (\n projectDir: string,\n pm: PackageManager,\n ) => Promise<{ code: number; output: string }>;\n}\n\ninterface DeltaEntry {\n current: string | null;\n target: string;\n changed: boolean;\n}\n\nexport async function runUpgrade(\n ctx: CliContext,\n args: UpgradeArgs,\n deps: UpgradeDeps = {},\n): Promise<number> {\n const loaded = loadProject(args.dir);\n const pm = detectPackageManager(loaded.projectDir);\n\n // Captured BEFORE anything installs: the templates the project's CURRENT\n // (pre-upgrade) local `@ekanos/cli` ships, which is what actually\n // generated the agent-context files on disk — not necessarily this\n // process's own bundled templates, since `upgrade` is a machine-level verb\n // that never delegates and is routinely invoked via a DIFFERENT (global)\n // install. See `regenerateAgentContextFiles`.\n const oldAgentTemplates = captureAgentTemplates(loaded.projectDir);\n\n const current = readCurrentToolchain(loaded.projectDir);\n\n const session = resolveSessionQuietly(ctx, args);\n const resolveTarget = deps.resolveTarget ?? resolveToolchainTarget;\n const resolution = await resolveTarget({\n host: session?.host,\n session: session?.session,\n });\n\n if (resolution.status === 'unavailable') {\n throw networkError(\n 'Could not resolve a toolchain target from the Ekanos host or the ' +\n 'npm registry.',\n 'Check connectivity and retry. If this deployment has no ' +\n '\"/api/partner/toolchain\" route yet, the npm registry is the ' +\n 'fallback and a failure there means npm itself is unreachable.',\n );\n }\n\n if (resolution.status === 'incoherent') {\n throw preconditionError(\n `The resolved toolchain versions do not form an installable set: ` +\n resolution.detail,\n 'Retry in a moment — this is almost always a multi-package publish ' +\n 'still in flight, and it self-resolves once every package finishes ' +\n 'publishing.',\n );\n }\n\n const target = resolution.target;\n const deltas = computeDeltas(current, target);\n\n if (args.check) {\n return ctx.succeed(\n {\n source: resolution.source,\n current,\n target,\n deltas,\n ...(resolution.source === 'host'\n ? { minimum: resolution.minimum, notes: resolution.notes }\n : {}),\n },\n checkSummary(ctx.ui, resolution.source, deltas),\n );\n }\n\n const changedKeys = (Object.keys(deltas) as ToolchainKey[]).filter(\n (key) => deltas[key]!.changed,\n );\n\n if (changedKeys.length === 0) {\n return ctx.succeed(\n { source: resolution.source, current, target, deltas },\n ctx.ui.result({\n title: 'Already up to date',\n rows: [['Target', `resolved from ${resolution.source}`]],\n }),\n );\n }\n\n const isHuman = !ctx.jsonMode;\n const stdinIsTTY = args.stdinIsTTY ?? process.stdin.isTTY === true;\n const canPrompt = isHuman && stdinIsTTY;\n\n if (!args.yes) {\n if (!canPrompt) {\n throw validationError(\n 'Refusing to modify the project non-interactively without --yes.',\n 'Pass \"ekanos upgrade --yes\" to proceed, or \"ekanos upgrade --check\" ' +\n 'to preview the target with no changes.',\n );\n }\n\n ctx.log(planSummary(ctx.ui, resolution.source, deltas));\n const confirm = args.confirm ?? promptYesNo;\n const confirmed = await confirm('Upgrade now? [y/N]');\n\n if (!confirmed) {\n throw validationError(\n 'Upgrade was not confirmed.',\n 'Re-run \"ekanos upgrade --yes\" to proceed non-interactively, or ' +\n '\"ekanos upgrade --check\" to preview with no changes. Nothing was ' +\n 'modified.',\n );\n }\n }\n\n const packageJsonPath = path.join(loaded.projectDir, 'package.json');\n const manifest = readManifest(packageJsonPath);\n const specs = buildInstallSpecs(manifest, target, changedKeys);\n\n if (specs.length === 0) {\n return ctx.succeed(\n { source: resolution.source, current, target, deltas },\n ctx.ui.result({\n title: 'Nothing to install',\n tone: 'warn',\n notes: [\n 'None of the changed packages are direct dependencies of this project.',\n 'Their versions follow from whichever direct dependency pins them.',\n ],\n }),\n );\n }\n\n const snapshot = snapshotProject(loaded.projectDir, pm);\n let answeredBuildScripts: string[] = [];\n let buildScriptsSkipped: BuildScriptsResult['skipped'];\n\n try {\n const runInstall = deps.runInstall ?? defaultRunInstall;\n\n // pnpm 10+ refuses dependency build scripts nobody has answered, and a\n // new toolchain release can grow that list (0.4.0 added @swc/core and\n // @parcel/watcher via next-intl). A project scaffolded under an older\n // CLI has no line for them, so answer the closure BEFORE `pnpm add`, or\n // the install writes placeholders and exits ERR_PNPM_IGNORED_BUILDS.\n const buildScripts: BuildScriptsResult =\n pm.name === 'pnpm'\n ? ensureBuildScriptsAnswered(loaded.projectDir)\n : { changed: [] };\n answeredBuildScripts = buildScripts.changed;\n if (buildScripts.skipped) {\n buildScriptsSkipped = buildScripts.skipped;\n ctx.log(ctx.ui.dim(skippedBuildScriptsHint(buildScripts.skipped)));\n }\n if (answeredBuildScripts.length > 0) {\n ctx.log(\n ctx.ui.dim(\n `Answered dependency build scripts in pnpm-workspace.yaml: ${answeredBuildScripts.join(', ')}.`,\n ),\n );\n }\n\n for (const group of [\n specs.filter((s) => !s.dev),\n specs.filter((s) => s.dev),\n ]) {\n if (group.length === 0) continue;\n\n const argv = installExactArgs(\n pm,\n group.map((s) => `${s.name}@${s.version}`),\n group[0]!.dev,\n );\n ctx.log(\n ctx.ui.dim(\n `Running \"${pm.bin} ${argv.join(' ')}\" in ${displayPath(loaded.projectDir, process.cwd())}…`,\n ),\n );\n const result = await runInstall(argv, pm.bin, loaded.projectDir);\n\n if (result.code !== 0) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'install',\n exitCode: EXIT_CODES.PRECONDITION_FAILED,\n message: isIgnoredBuildsFailure(result.output)\n ? `\"${pm.bin} ${argv.join(' ')}\" exited with code ${result.code}: ${ignoredBuildsHint(findIgnoredBuilds(result.output))}`\n : `\"${pm.bin} ${argv.join(' ')}\" exited with code ${result.code}.`,\n output: result.output,\n },\n );\n }\n }\n\n if (!args.noVerify) {\n const runValidateStep = deps.runValidateStep ?? defaultRunValidateStep;\n const validateResult = await runValidateStep(loaded.projectDir);\n\n if (!validateResult.ok) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'validate',\n exitCode: EXIT_CODES.VALIDATION,\n message:\n 'The upgraded toolchain fails \"ekanos validate\" against this ' +\n \"project's own integration definition.\",\n output: JSON.stringify(validateResult.findings ?? [], null, 2),\n },\n );\n }\n\n const runTestStep = deps.runTestStep ?? defaultRunTestStep;\n const testResult = await runTestStep(loaded.projectDir, pm);\n\n if (testResult.code !== 0) {\n return await failAndRollback(\n ctx,\n snapshot,\n pm,\n loaded.projectDir,\n runInstall,\n {\n step: 'test',\n exitCode: testResult.code,\n message: `The project's test script exited with code ${testResult.code} on the upgraded toolchain.`,\n output: testResult.output,\n },\n );\n }\n }\n } finally {\n snapshot.dispose();\n }\n\n const newTemplatesDir = path.join(\n loaded.projectDir,\n 'node_modules',\n '@ekanos',\n 'cli',\n 'templates',\n );\n\n const regenerated = regenerateAgentContextFiles({\n projectDir: loaded.projectDir,\n slug: loaded.primary.slug,\n oldTemplates: oldAgentTemplates,\n newTemplatesDir,\n });\n\n // The regenerated AGENTS.md and skills may now REFERENCE artifacts this\n // project predates (docs/api-notes.md, .mcp.json, bundled skill trees) —\n // instructions pointing at files that don't exist are exactly the stale-docs\n // failure the docs-grounding feature closes, so create what's missing.\n // Create-if-missing ONLY: these files are partner/agent-authored after the\n // scaffold and are never regenerated.\n const scaffolded = scaffoldMissingDocsArtifacts({\n projectDir: loaded.projectDir,\n slug: loaded.primary.slug,\n newTemplatesDir,\n });\n\n // `specs` only ever covers DIRECT dependencies (see `buildInstallSpecs`) —\n // a changed key with no spec is transitive and was never actually\n // installed here, so the report (and the human summary) must say so\n // explicitly rather than implying every changed key was upgraded. This\n // matters most for exactly the scenario this PR's own delegation feature\n // targets: a globally-installed `ekanos` with no local `@ekanos/cli`\n // devDependency, where `cli` changes in `deltas` but the running global\n // binary itself is untouched by this command.\n const installedKeys = specs.map((spec) => spec.key);\n const skippedKeys = changedKeys.filter((key) => !installedKeys.includes(key));\n\n return ctx.succeed(\n {\n source: resolution.source,\n current,\n target,\n deltas,\n installed: installedKeys,\n skippedTransitive: skippedKeys,\n buildScripts: {\n answered: answeredBuildScripts,\n ...(buildScriptsSkipped ? { skipped: buildScriptsSkipped } : {}),\n },\n regenerated,\n scaffolded,\n },\n successSummary(\n ctx.ui,\n installedKeys,\n skippedKeys,\n deltas,\n regenerated,\n scaffolded,\n ),\n );\n}\n\n/**\n * Best-effort host/session resolution — NEVER throws. `upgrade` must work for\n * a partner who has never logged in at all (pure npm-registry flow), so the\n * throwing `resolveAuthEnvironment`/`requireSession` machinery is unusable\n * here; this mirrors the tolerant lookup `update-notice.ts` uses.\n */\nfunction resolveSessionQuietly(\n ctx: CliContext,\n args: UpgradeArgs,\n): { host: string; session: { accessToken: string } } | null {\n try {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const session = env.store.read(env.host);\n return session ? { host: env.host, session } : null;\n } catch {\n return null;\n }\n}\n\nfunction readCurrentToolchain(\n projectDir: string,\n): Record<ToolchainKey, string | null> {\n const result = {} as Record<ToolchainKey, string | null>;\n\n for (const [key, pkg] of Object.entries(TOOLCHAIN_PACKAGES) as [\n ToolchainKey,\n string,\n ][]) {\n const installed = readInstalledPackageManifest(projectDir, pkg);\n result[key] = installed?.version ?? (key === 'cli' ? cliVersion() : null);\n }\n\n return result;\n}\n\nfunction computeDeltas(\n current: Record<ToolchainKey, string | null>,\n target: ToolchainVersions,\n): Record<ToolchainKey, DeltaEntry> {\n const keys = Object.keys(TOOLCHAIN_PACKAGES) as ToolchainKey[];\n const result = {} as Record<ToolchainKey, DeltaEntry>;\n\n for (const key of keys) {\n result[key] = {\n current: current[key],\n target: target[key],\n changed: current[key] !== target[key],\n };\n }\n\n return result;\n}\n\ninterface InstallSpec {\n key: ToolchainKey;\n name: string;\n version: string;\n dev: boolean;\n}\n\n/**\n * Only packages the project depends on DIRECTLY are installed explicitly —\n * `@ekanos/integration-schema` and often `@ekanos/harness` are transitive\n * (pulled in by `@ekanos/sdk`), and forcing an exact transitive version would\n * need a package-manager-specific override mechanism this CLI does not\n * manage. Their versions follow from whichever direct dependency pins them,\n * which is exactly what the coherent target guarantees is already correct.\n */\nfunction buildInstallSpecs(\n manifest: Record<string, unknown>,\n target: ToolchainVersions,\n changedKeys: readonly ToolchainKey[],\n): InstallSpec[] {\n const deps = (manifest.dependencies ?? {}) as Record<string, unknown>;\n const devDeps = (manifest.devDependencies ?? {}) as Record<string, unknown>;\n\n const specs: InstallSpec[] = [];\n\n for (const key of changedKeys) {\n const pkg = TOOLCHAIN_PACKAGES[key];\n if (pkg in deps) {\n specs.push({ key, name: pkg, version: target[key], dev: false });\n } else if (pkg in devDeps) {\n specs.push({ key, name: pkg, version: target[key], dev: true });\n }\n }\n\n return specs;\n}\n\nfunction readManifest(packageJsonPath: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));\n } catch (error) {\n throw preconditionError(\n `Could not read ${packageJsonPath}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'Ensure the project has a valid package.json, then re-run \"ekanos upgrade\".',\n );\n }\n if (typeof parsed !== 'object' || parsed === null) {\n throw preconditionError(\n `${packageJsonPath} does not contain a JSON object.`,\n 'Fix package.json, then re-run \"ekanos upgrade\".',\n );\n }\n return parsed as Record<string, unknown>;\n}\n\ninterface Snapshot {\n restore: () => void;\n dispose: () => void;\n}\n\n/**\n * Copy `package.json`, `pnpm-workspace.yaml` and the lockfile to a temp directory before anything\n * installs. `restore()` copies them back (and removes a lockfile that did not\n * exist before, if the failed install created one); `dispose()` cleans up the\n * temp copies once the run is over, success or failure.\n */\nfunction snapshotProject(projectDir: string, pm: PackageManager): Snapshot {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ekanos-upgrade-'));\n const packageJsonPath = path.join(projectDir, 'package.json');\n\n // bun has shipped both a text (`bun.lock`) and a legacy binary\n // (`bun.lockb`) lockfile; snapshot whichever is actually present.\n const lockCandidates =\n pm.name === 'bun' ? ['bun.lock', 'bun.lockb'] : [lockfileName(pm)];\n const lockName = lockCandidates.find((name) =>\n fs.existsSync(path.join(projectDir, name)),\n );\n const lockfilePath = lockName\n ? path.join(projectDir, lockName)\n : path.join(projectDir, lockfileName(pm));\n const lockfileExisted = lockName !== undefined;\n\n const workspacePath = path.join(projectDir, WORKSPACE_FILE);\n const workspaceExisted = fs.existsSync(workspacePath);\n\n fs.copyFileSync(packageJsonPath, path.join(tmpDir, 'package.json'));\n if (workspaceExisted) {\n fs.copyFileSync(workspacePath, path.join(tmpDir, 'workspace.snapshot'));\n }\n if (lockfileExisted) {\n fs.copyFileSync(lockfilePath, path.join(tmpDir, 'lockfile.snapshot'));\n }\n\n return {\n restore: () => {\n fs.copyFileSync(path.join(tmpDir, 'package.json'), packageJsonPath);\n if (workspaceExisted) {\n fs.copyFileSync(path.join(tmpDir, 'workspace.snapshot'), workspacePath);\n } else if (fs.existsSync(workspacePath)) {\n fs.rmSync(workspacePath);\n }\n if (lockfileExisted) {\n fs.copyFileSync(path.join(tmpDir, 'lockfile.snapshot'), lockfilePath);\n } else if (fs.existsSync(lockfilePath)) {\n fs.rmSync(lockfilePath);\n }\n },\n dispose: () => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n },\n };\n}\n\ninterface StepFailure {\n step: 'install' | 'validate' | 'test';\n exitCode: number;\n message: string;\n output: string;\n}\n\n/**\n * The one rollback path every failure funnels through: restore the snapshot,\n * reinstall to put `node_modules` back in sync with the restored\n * `package.json`/lockfile, and report exactly which step failed and what it\n * said — with an explicit statement that the project was restored, so a\n * partner (or an agent) never has to wonder whether they are looking at a\n * half-upgraded tree.\n */\nasync function failAndRollback(\n ctx: CliContext,\n snapshot: Snapshot,\n pm: PackageManager,\n projectDir: string,\n runInstall: (\n argv: string[],\n bin: string,\n cwd: string,\n ) => Promise<{ code: number; output: string }>,\n failure: StepFailure,\n): Promise<number> {\n ctx.warn(\n `ekanos: the \"${failure.step}\" step failed — rolling back package.json ` +\n 'and the lockfile, then reinstalling to restore node_modules…',\n );\n\n snapshot.restore();\n // The SAME injectable installer seam used for the forward install — a test\n // that mocks it never shells out for the rollback path either.\n const restore = await runInstall(['install'], pm.bin, projectDir);\n\n return ctx.failWith({\n code: `upgrade_${failure.step}_failed`,\n message: failure.message,\n hint:\n `The project HAS BEEN RESTORED to its pre-upgrade state (package.json, ` +\n `lockfile and node_modules all rolled back${\n restore.code === 0\n ? ''\n : ' — though the restore install itself also failed with code ' +\n `${restore.code}; run \"${pm.bin} install\" by hand to finish ` +\n 'repairing node_modules'\n }). Read the output in data.output, fix the underlying issue, and ` +\n 're-run \"ekanos upgrade\".',\n exitCode: failure.exitCode,\n data: { step: failure.step, output: failure.output },\n });\n}\n\nasync function defaultRunInstall(\n argv: string[],\n bin: string,\n cwd: string,\n): Promise<{ code: number; output: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(bin, argv, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });\n let output = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => resolve({ code: code ?? 1, output }));\n });\n}\n\nasync function defaultRunValidateStep(\n projectDir: string,\n): Promise<{ ok: boolean; findings?: Finding[] }> {\n const loaded = loadProject(projectDir);\n const findings = await collectAllFindings(loaded);\n const errorCount = findings.filter((f) => f.severity === 'error').length;\n return { ok: errorCount === 0, findings };\n}\n\nasync function defaultRunTestStep(\n projectDir: string,\n pm: PackageManager,\n): Promise<{ code: number; output: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn(pm.bin, ['run', 'test'], {\n cwd: projectDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let output = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n output += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => resolve({ code: code ?? 1, output }));\n });\n}\n\n/** Why a scaffolded doc file was left alone. Reported so a human knows whether to merge or to investigate. */\ntype SkipReason = 'edited-locally' | 'not-a-file' | 'write-refused';\n\ninterface RegenerationReport {\n updated: string[];\n unchanged: string[];\n needsAttention: string[];\n /** One entry per `needsAttention` path. */\n skipped: { file: string; reason: SkipReason }[];\n}\n\n/**\n * Read every `AGENT_CONTEXT_FILES` template source out of the project's\n * CURRENT (pre-upgrade) local `@ekanos/cli` install, before anything installs\n * over it. Missing entirely (the package isn't a resolvable local dependency)\n * just means every file below is treated conservatively — see\n * `regenerateAgentContextFiles`.\n */\nfunction captureAgentTemplates(projectDir: string): Map<string, string> {\n const templatesDir = path.join(\n projectDir,\n 'node_modules',\n '@ekanos',\n 'cli',\n 'templates',\n );\n const captured = new Map<string, string>();\n\n for (const { template } of AGENT_CONTEXT_FILES) {\n const templatePath = path.join(templatesDir, template);\n try {\n captured.set(template, fs.readFileSync(templatePath, 'utf8'));\n } catch {\n // Not resolvable — left out of the map, handled as \"can't verify\" below.\n }\n }\n\n return captured;\n}\n\n/**\n * Create the docs-grounding artifacts a pre-0.1.7 project is missing, from\n * the NEWLY installed CLI's bundled templates: `docs/api-notes.md`,\n * `.mcp.json`, and any bundled skill trees. Strictly create-if-missing —\n * an existing file is the partner's (api-notes is agent-authored, .mcp.json\n * may carry local servers) and is never touched, force or not. Writes go\n * through safe-fs like init's own scaffold pass.\n */\nfunction scaffoldMissingDocsArtifacts(params: {\n projectDir: string;\n slug: string;\n newTemplatesDir: string;\n}): { created: string[]; needsAttention: string[] } {\n const vars = { SLUG: params.slug, DISPLAY_NAME: toDisplayName(params.slug) };\n const created: string[] = [];\n const needsAttention: string[] = [];\n\n // This runs AFTER snapshot.dispose(): the toolchain upgrade has already\n // succeeded and there is no rollback left to protect. A refused write here\n // (a symlinked `docs/` or `.claude` ancestor — safe-fs throws rather than\n // follow it) must therefore be REPORTED, never thrown — the same stance\n // `regenerateAgentContextFiles` takes, for the same reason: a hard failure\n // now would misreport a successful upgrade.\n for (const { template, dest } of DOCS_GROUNDING_FILES) {\n const destPath = path.join(params.projectDir, dest);\n const kind = classifyPath(destPath);\n // A real file or directory is the partner's — skipping it quietly IS the\n // contract. A symlink (or fifo, socket, …) is not \"already there\": it is\n // a path we refuse to write through, and silence would hide that — same\n // reporting stance as regenerateAgentContextFiles.\n if (kind === 'file' || kind === 'directory') continue;\n if (kind !== 'missing') {\n needsAttention.push(dest);\n continue;\n }\n\n const templatePath = path.join(params.newTemplatesDir, template);\n if (!fs.existsSync(templatePath)) continue; // older target toolchain\n\n try {\n writeFileNoFollow(\n params.projectDir,\n destPath,\n renderTemplate(fs.readFileSync(templatePath, 'utf8'), vars),\n );\n created.push(dest);\n } catch {\n needsAttention.push(dest);\n }\n }\n\n try {\n // 'collect': a refused file is recorded and the walk continues, so files\n // that DID land — in this skill tree or an earlier one — stay in\n // `created` instead of vanishing when a later write refuses.\n const skills = copyBundledSkillTrees(\n params.projectDir,\n false,\n path.join(params.newTemplatesDir, 'skills'),\n 'collect',\n );\n created.push(...skills.created);\n needsAttention.push(...skills.refused);\n } catch {\n // Last resort (an unreadable templates dir, not a refused write — those\n // are collected above).\n needsAttention.push('.claude/skills');\n }\n\n return { created, needsAttention };\n}\n\n/**\n * Regenerate `AGENTS.md`, `CLAUDE.md` and the Claude Code skill from the\n * NEWLY installed CLI's bundled templates — using the exact byte-comparison\n * discipline `harness-scaffold.ts` applies to the dev harness shell: a file\n * whose current bytes match what the project's PRE-upgrade local CLI would\n * have rendered (captured in `oldTemplates`, before install ran) is\n * untouched by the partner and safe to regenerate; anything else has been\n * edited and is left alone, reported so a human can merge it by hand. A\n * stale AGENTS.md teaches an agent yesterday's contract — that is as harmful\n * as a stale binary, which is why this runs on every successful upgrade\n * rather than only on `init`.\n */\nfunction regenerateAgentContextFiles(params: {\n projectDir: string;\n slug: string;\n oldTemplates: Map<string, string>;\n newTemplatesDir: string;\n}): RegenerationReport {\n const vars = { SLUG: params.slug, DISPLAY_NAME: toDisplayName(params.slug) };\n const updated: string[] = [];\n const unchanged: string[] = [];\n const needsAttention: string[] = [];\n const skipped: { file: string; reason: SkipReason }[] = [];\n const skip = (file: string, reason: SkipReason) => {\n needsAttention.push(file);\n skipped.push({ file, reason });\n };\n\n for (const { template, dest } of AGENT_CONTEXT_FILES) {\n const destPath = path.join(params.projectDir, dest);\n const kind = classifyPath(destPath);\n if (kind === 'missing') continue; // never scaffolded — nothing to upgrade\n if (kind !== 'file') {\n // A symlink (or anything else odd) is not ours to write through — same\n // stance as init's scaffold pass, but reported instead of thrown: the\n // upgrade itself already succeeded, so surface it for a human.\n skip(dest, 'not-a-file');\n continue;\n }\n\n const current = fs.readFileSync(destPath, 'utf8');\n const oldSource = params.oldTemplates.get(template);\n\n const oldRendered =\n oldSource === undefined ? null : renderTemplate(oldSource, vars);\n\n if (oldRendered === null || current !== oldRendered) {\n // Differs from what the pre-upgrade CLI rendered: edited by the partner\n // (or the project was renamed after scaffold — same thing to us).\n skip(dest, 'edited-locally');\n continue;\n }\n\n const newTemplatePath = path.join(params.newTemplatesDir, template);\n if (!fs.existsSync(newTemplatePath)) continue;\n\n const newRendered = renderTemplate(\n fs.readFileSync(newTemplatePath, 'utf8'),\n vars,\n );\n\n if (newRendered === current) {\n unchanged.push(dest);\n continue;\n }\n\n try {\n writeFileNoFollow(params.projectDir, destPath, newRendered);\n updated.push(dest);\n } catch {\n // A symlinked ANCESTOR (.claude centralized across projects) passes the\n // leaf classifyPath check above but is refused by the guarded write —\n // and this runs post-rollback, so a throw here would misreport a\n // successful toolchain upgrade as failed. Report it instead, like every\n // other post-rollback write path in this file.\n skip(dest, 'write-refused');\n }\n }\n\n return { updated, unchanged, needsAttention, skipped };\n}\n\nfunction describeDelta(delta: DeltaEntry): string {\n return `${delta.current ?? 'not installed'} → ${delta.target}`;\n}\n\nfunction checkSummary(\n ui: Ui,\n source: 'host' | 'npm',\n deltas: Record<ToolchainKey, DeltaEntry>,\n): string {\n const entries = Object.entries(deltas) as [ToolchainKey, DeltaEntry][];\n const pending = entries.filter(([, delta]) => delta.changed).length;\n\n return ui.result({\n title:\n pending === 0 ? 'Toolchain is current' : 'Toolchain update available',\n tone: pending === 0 ? 'ok' : 'warn',\n rows: entries.map(([key, delta]): [string, string] => [\n key,\n delta.changed ? describeDelta(delta) : `${delta.target} · current`,\n ]),\n notes: [\n `Target resolved from ${source}.` +\n (pending > 0 ? ' Run \"ekanos upgrade\" to apply it.' : ''),\n ],\n });\n}\n\nfunction planSummary(\n ui: Ui,\n source: string,\n deltas: Record<ToolchainKey, DeltaEntry>,\n): string {\n return ui.result({\n title: 'Upgrading',\n rows: (Object.entries(deltas) as [ToolchainKey, DeltaEntry][])\n .filter(([, delta]) => delta.changed)\n .map(([key, delta]): [string, string] => [key, describeDelta(delta)]),\n notes: [`Target resolved from ${source}.`],\n });\n}\n\nfunction successSummary(\n ui: Ui,\n installedKeys: readonly ToolchainKey[],\n skippedKeys: readonly ToolchainKey[],\n deltas: Record<ToolchainKey, DeltaEntry>,\n regenerated: RegenerationReport,\n scaffolded: { created: string[]; needsAttention: string[] },\n): string {\n const arrow = (key: ToolchainKey) => `${key} → ${deltas[key]!.target}`;\n const attention =\n regenerated.needsAttention.length > 0 ||\n scaffolded.needsAttention.length > 0;\n\n const notes: string[] = [];\n if (scaffolded.created.length > 0) {\n notes.push(\n 'New in this toolchain: see AGENTS.md\\'s \"API documentation\" section.',\n );\n }\n if (scaffolded.needsAttention.length > 0) {\n // Never suggest --force here — it overwrites every scaffolded file,\n // including src/integration.ts.\n notes.push(\n 'A path component is a symlink or unwritable, so those files were not created. ' +\n 'Fix the path, then run \"ekanos init --slug <slug> --dir .\" WITHOUT --force: ' +\n 'init is per-file idempotent and creates only what is missing.',\n );\n }\n if (regenerated.needsAttention.length > 0) {\n const edited = regenerated.skipped\n .filter((s) => s.reason === 'edited-locally')\n .map((s) => s.file);\n const other = regenerated.skipped.filter(\n (s) => s.reason !== 'edited-locally',\n );\n if (edited.length > 0) {\n notes.push(\n `${edited.join(', ')} differ${edited.length === 1 ? 's' : ''} from what the previous CLI scaffolded (edited, or the project was renamed), so the new template was not applied — merge it by hand, or delete the file and run \"ekanos init --slug <slug> --dir .\" to re-create it.`,\n );\n }\n for (const { file, reason } of other) {\n notes.push(\n reason === 'not-a-file'\n ? `${file} is a symlink or not a regular file, so it was left alone.`\n : `${file} could not be written (a symlinked ancestor?), so it was left alone.`,\n );\n }\n }\n\n return ui.result({\n title:\n installedKeys.length > 0 ? 'Toolchain upgraded' : 'Nothing to install',\n tone: attention || installedKeys.length === 0 ? 'warn' : 'ok',\n rows: [\n ...(installedKeys.length > 0\n ? [['Installed', installedKeys.map(arrow)] as const]\n : []),\n ...(skippedKeys.length > 0\n ? [['Not installed', skippedKeys.map(arrow)] as const]\n : []),\n ...(regenerated.updated.length > 0\n ? [['Regenerated', regenerated.updated] as const]\n : []),\n ...(scaffolded.created.length > 0\n ? [['Created', scaffolded.created] as const]\n : []),\n ...(regenerated.needsAttention.length > 0\n ? [['Modified', regenerated.needsAttention] as const]\n : []),\n ...(scaffolded.needsAttention.length > 0\n ? [['Could not create', scaffolded.needsAttention] as const]\n : []),\n ],\n notes:\n skippedKeys.length > 0\n ? [\n 'Not installed = transitive, or not a local dependency (e.g. a global CLI).',\n ...notes,\n ]\n : notes,\n });\n}\n"]}
|
package/dist/compatibility.d.ts
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* shell must contain. Editing a comment in a template does not count — that is
|
|
32
32
|
* what the template fingerprint in the marker is for.
|
|
33
33
|
*/
|
|
34
|
-
export declare const SHELL_CONTRACT =
|
|
34
|
+
export declare const SHELL_CONTRACT = 3;
|
|
35
35
|
/**
|
|
36
36
|
* Contract history — what each bump changed, so a mismatch message can be
|
|
37
37
|
* read against it:
|
|
@@ -42,6 +42,9 @@ export declare const SHELL_CONTRACT = 2;
|
|
|
42
42
|
* registry into the new `@ekanos/harness/api` server entry. A harness
|
|
43
43
|
* without that export cannot back the route; a shell without the route
|
|
44
44
|
* leaves that harness's live-mode OAuth loop unreachable.
|
|
45
|
+
* 3 adds `app/[slug]/page.tsx`, re-exporting the new
|
|
46
|
+
* `IntegrationIndexPage` from `/routes` so `/<slug>` redirects to
|
|
47
|
+
* `/<slug>/widgets` instead of answering 404 under a working toolbar.
|
|
45
48
|
*/
|
|
46
49
|
/**
|
|
47
50
|
* The contract an installed `@ekanos/harness` declares it needs, from
|
package/dist/compatibility.js
CHANGED
|
@@ -36,7 +36,7 @@ import { readTemplateSource, templatesDir } from './templates.js';
|
|
|
36
36
|
* shell must contain. Editing a comment in a template does not count — that is
|
|
37
37
|
* what the template fingerprint in the marker is for.
|
|
38
38
|
*/
|
|
39
|
-
export const SHELL_CONTRACT =
|
|
39
|
+
export const SHELL_CONTRACT = 3;
|
|
40
40
|
/**
|
|
41
41
|
* Contract history — what each bump changed, so a mismatch message can be
|
|
42
42
|
* read against it:
|
|
@@ -47,6 +47,9 @@ export const SHELL_CONTRACT = 2;
|
|
|
47
47
|
* registry into the new `@ekanos/harness/api` server entry. A harness
|
|
48
48
|
* without that export cannot back the route; a shell without the route
|
|
49
49
|
* leaves that harness's live-mode OAuth loop unreachable.
|
|
50
|
+
* 3 adds `app/[slug]/page.tsx`, re-exporting the new
|
|
51
|
+
* `IntegrationIndexPage` from `/routes` so `/<slug>` redirects to
|
|
52
|
+
* `/<slug>/widgets` instead of answering 404 under a working toolbar.
|
|
50
53
|
*/
|
|
51
54
|
/**
|
|
52
55
|
* The contract an installed `@ekanos/harness` declares it needs, from
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { preconditionError } from './errors';\nimport { readTemplateSource, templatesDir } from './templates';\n\n/**\n * The shell templates ship with `@ekanos/cli`; the code they import ships with\n * `@ekanos/harness`. The two version independently, so a partner can upgrade\n * one without the other — and the interesting failure is the quiet one:\n *\n * `pnpm up @ekanos/harness` → 0.2, which moves an export.\n * `ekanos dev` regenerates from the OLD CLI's templates and stamps \"0.2\"\n * into the marker. Every later run now considers the shell current. It is\n * not: it was generated against an obsolete contract, and what the partner\n * sees is a module-resolution error rather than \"these are incompatible\".\n *\n * That directly attacks the promise the package boundary exists to keep — ship\n * a harness fix as a version bump a partner picks up with `pnpm up`. So the\n * CLI declares which `@ekanos/harness` versions ITS templates are written\n * against, checks the installed one before generating, and names the\n * incompatibility instead of letting a resolution error stand in for it.\n */\n\n/**\n * The shell contract this CLI's templates GENERATE.\n *\n * An integer, not a semver range. A range can only INFER compatibility from\n * version numbers — it cannot tell a harness bugfix from a change to the shell\n * the harness requires, so it either blocks upgrades that were fine or waves\n * through ones that were not. The integer is declared by both sides and is\n * authoritative.\n *\n * **Bump this only when the generated shell's coupling to the package\n * changes**: an export renamed or moved between `/app` and `/routes`, the\n * props of `RootLayout` or `IndexPage`, the server/client split, the alias\n * specifier, which side owns `@import 'tailwindcss'`, or the set of files the\n * shell must contain. Editing a comment in a template does not count — that is\n * what the template fingerprint in the marker is for.\n */\nexport const SHELL_CONTRACT = 2;\n\n/**\n * Contract history — what each bump changed, so a mismatch message can be\n * read against it:\n *\n * 1 the original ten-file shell: pages re-exporting `/routes`, the client\n * shell + index page injecting the registry into `/app`.\n * 2 adds `app/api/integrations/[slug]/[...path]/route.ts`, injecting the\n * registry into the new `@ekanos/harness/api` server entry. A harness\n * without that export cannot back the route; a shell without the route\n * leaves that harness's live-mode OAuth loop unreachable.\n */\n\n/**\n * The contract an installed `@ekanos/harness` declares it needs, from\n * `{ \"ekanos\": { \"shellContract\": N } }` in its package.json.\n *\n * A package that declares nothing is read as contract 1 — the contract that\n * shipped first — so the harness released before this existed keeps working.\n * That default is deliberately silent, which is why `@ekanos/harness` asserts\n * the field's presence in its own pack test rather than relying on it.\n */\nexport function declaredShellContract(harnessManifest: unknown): number {\n if (typeof harnessManifest !== 'object' || harnessManifest === null) return 1;\n const ekanos = (harnessManifest as { ekanos?: unknown }).ekanos;\n if (typeof ekanos !== 'object' || ekanos === null) return 1;\n const declared = (ekanos as { shellContract?: unknown }).shellContract;\n return Number.isInteger(declared) ? (declared as number) : 1;\n}\n\n/** `[major, minor, patch]`, with anything non-numeric treated as 0. */\nfunction parseVersion(version: string): [number, number, number] {\n const core = version.split('+')[0]!.split('-')[0]!;\n const parts = core.split('.').map((part) => Number.parseInt(part, 10));\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nexport function compareVersions(a: string, b: string): number {\n const left = parseVersion(a);\n const right = parseVersion(b);\n for (let i = 0; i < 3; i++) {\n if (left[i]! !== right[i]!) return left[i]! < right[i]! ? -1 : 1;\n }\n return 0;\n}\n\n/** This CLI's own version, read from its package.json at runtime. */\nexport function cliVersion(): string {\n const manifestPath = path.join(templatesDir(), '..', 'package.json');\n const parsed: unknown = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n const version =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as { version?: unknown }).version\n : undefined;\n return typeof version === 'string' ? version : '0.0.0';\n}\n\n/**\n * Fail unless this CLI's templates generate the shell the installed harness\n * expects.\n *\n * The templates ship with `@ekanos/cli`; the code they import ships with\n * `@ekanos/harness`. The two version independently, so a partner can upgrade\n * one without the other — and the failure that matters is the quiet one:\n * `pnpm up @ekanos/harness` moves an export, `ekanos dev` regenerates from the\n * OLD CLI's templates, and the partner sees a module-resolution error rather\n * than anything naming the incompatibility.\n *\n * Byte-comparing generated files cannot catch it: the old templates' bytes are\n * exactly what the old CLI intends, so nothing regenerates differently and the\n * shell stays wired to something that moved. Only a declared contract can.\n *\n * Runs before anything is written, so an incompatible pair produces no shell\n * at all — a broken shell that builds is worse than no shell.\n */\nexport function assertHarnessCompatible(params: {\n harnessVersion: string;\n harnessManifest: unknown;\n installHint: (packageSpec: string) => string;\n}): void {\n const required = declaredShellContract(params.harnessManifest);\n if (required === SHELL_CONTRACT) return;\n\n if (required > SHELL_CONTRACT) {\n throw preconditionError(\n `@ekanos/cli ${cliVersion()} is too old for @ekanos/harness ` +\n `${params.harnessVersion}: that harness needs shell contract ` +\n `${required}, and this CLI generates ${SHELL_CONTRACT}.`,\n `Upgrade the CLI: ${params.installHint('@ekanos/cli@latest')}. Then ` +\n 're-run \"ekanos dev\" and the shell is regenerated for you.',\n );\n }\n\n throw preconditionError(\n `@ekanos/harness ${params.harnessVersion} is too old for @ekanos/cli ` +\n `${cliVersion()}: this CLI generates shell contract ${SHELL_CONTRACT}, ` +\n `and that harness needs ${required}.`,\n `Upgrade it: ${params.installHint('@ekanos/harness@latest')}.`,\n );\n}\n\n/**\n * A fingerprint of the template SOURCES, independent of the slug they are\n * rendered with.\n *\n * The harness version alone cannot certify a shell: the templates can change\n * while it stays put (a CLI patch release), and it can change while they stay\n * put. Hashing the sources means any edit to what we generate invalidates\n * every shell generated before it, including one produced by a CLI version\n * that never shipped.\n */\nexport function templatesFingerprint(templateNames: readonly string[]): string {\n const hash = createHash('sha256');\n for (const name of [...templateNames].sort()) {\n hash.update(name);\n hash.update('\\0');\n hash.update(readTemplateSource(name));\n hash.update('\\0');\n }\n return hash.digest('hex').slice(0, 16);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { preconditionError } from './errors';\nimport { readTemplateSource, templatesDir } from './templates';\n\n/**\n * The shell templates ship with `@ekanos/cli`; the code they import ships with\n * `@ekanos/harness`. The two version independently, so a partner can upgrade\n * one without the other — and the interesting failure is the quiet one:\n *\n * `pnpm up @ekanos/harness` → 0.2, which moves an export.\n * `ekanos dev` regenerates from the OLD CLI's templates and stamps \"0.2\"\n * into the marker. Every later run now considers the shell current. It is\n * not: it was generated against an obsolete contract, and what the partner\n * sees is a module-resolution error rather than \"these are incompatible\".\n *\n * That directly attacks the promise the package boundary exists to keep — ship\n * a harness fix as a version bump a partner picks up with `pnpm up`. So the\n * CLI declares which `@ekanos/harness` versions ITS templates are written\n * against, checks the installed one before generating, and names the\n * incompatibility instead of letting a resolution error stand in for it.\n */\n\n/**\n * The shell contract this CLI's templates GENERATE.\n *\n * An integer, not a semver range. A range can only INFER compatibility from\n * version numbers — it cannot tell a harness bugfix from a change to the shell\n * the harness requires, so it either blocks upgrades that were fine or waves\n * through ones that were not. The integer is declared by both sides and is\n * authoritative.\n *\n * **Bump this only when the generated shell's coupling to the package\n * changes**: an export renamed or moved between `/app` and `/routes`, the\n * props of `RootLayout` or `IndexPage`, the server/client split, the alias\n * specifier, which side owns `@import 'tailwindcss'`, or the set of files the\n * shell must contain. Editing a comment in a template does not count — that is\n * what the template fingerprint in the marker is for.\n */\nexport const SHELL_CONTRACT = 3;\n\n/**\n * Contract history — what each bump changed, so a mismatch message can be\n * read against it:\n *\n * 1 the original ten-file shell: pages re-exporting `/routes`, the client\n * shell + index page injecting the registry into `/app`.\n * 2 adds `app/api/integrations/[slug]/[...path]/route.ts`, injecting the\n * registry into the new `@ekanos/harness/api` server entry. A harness\n * without that export cannot back the route; a shell without the route\n * leaves that harness's live-mode OAuth loop unreachable.\n * 3 adds `app/[slug]/page.tsx`, re-exporting the new\n * `IntegrationIndexPage` from `/routes` so `/<slug>` redirects to\n * `/<slug>/widgets` instead of answering 404 under a working toolbar.\n */\n\n/**\n * The contract an installed `@ekanos/harness` declares it needs, from\n * `{ \"ekanos\": { \"shellContract\": N } }` in its package.json.\n *\n * A package that declares nothing is read as contract 1 — the contract that\n * shipped first — so the harness released before this existed keeps working.\n * That default is deliberately silent, which is why `@ekanos/harness` asserts\n * the field's presence in its own pack test rather than relying on it.\n */\nexport function declaredShellContract(harnessManifest: unknown): number {\n if (typeof harnessManifest !== 'object' || harnessManifest === null) return 1;\n const ekanos = (harnessManifest as { ekanos?: unknown }).ekanos;\n if (typeof ekanos !== 'object' || ekanos === null) return 1;\n const declared = (ekanos as { shellContract?: unknown }).shellContract;\n return Number.isInteger(declared) ? (declared as number) : 1;\n}\n\n/** `[major, minor, patch]`, with anything non-numeric treated as 0. */\nfunction parseVersion(version: string): [number, number, number] {\n const core = version.split('+')[0]!.split('-')[0]!;\n const parts = core.split('.').map((part) => Number.parseInt(part, 10));\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nexport function compareVersions(a: string, b: string): number {\n const left = parseVersion(a);\n const right = parseVersion(b);\n for (let i = 0; i < 3; i++) {\n if (left[i]! !== right[i]!) return left[i]! < right[i]! ? -1 : 1;\n }\n return 0;\n}\n\n/** This CLI's own version, read from its package.json at runtime. */\nexport function cliVersion(): string {\n const manifestPath = path.join(templatesDir(), '..', 'package.json');\n const parsed: unknown = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n const version =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as { version?: unknown }).version\n : undefined;\n return typeof version === 'string' ? version : '0.0.0';\n}\n\n/**\n * Fail unless this CLI's templates generate the shell the installed harness\n * expects.\n *\n * The templates ship with `@ekanos/cli`; the code they import ships with\n * `@ekanos/harness`. The two version independently, so a partner can upgrade\n * one without the other — and the failure that matters is the quiet one:\n * `pnpm up @ekanos/harness` moves an export, `ekanos dev` regenerates from the\n * OLD CLI's templates, and the partner sees a module-resolution error rather\n * than anything naming the incompatibility.\n *\n * Byte-comparing generated files cannot catch it: the old templates' bytes are\n * exactly what the old CLI intends, so nothing regenerates differently and the\n * shell stays wired to something that moved. Only a declared contract can.\n *\n * Runs before anything is written, so an incompatible pair produces no shell\n * at all — a broken shell that builds is worse than no shell.\n */\nexport function assertHarnessCompatible(params: {\n harnessVersion: string;\n harnessManifest: unknown;\n installHint: (packageSpec: string) => string;\n}): void {\n const required = declaredShellContract(params.harnessManifest);\n if (required === SHELL_CONTRACT) return;\n\n if (required > SHELL_CONTRACT) {\n throw preconditionError(\n `@ekanos/cli ${cliVersion()} is too old for @ekanos/harness ` +\n `${params.harnessVersion}: that harness needs shell contract ` +\n `${required}, and this CLI generates ${SHELL_CONTRACT}.`,\n `Upgrade the CLI: ${params.installHint('@ekanos/cli@latest')}. Then ` +\n 're-run \"ekanos dev\" and the shell is regenerated for you.',\n );\n }\n\n throw preconditionError(\n `@ekanos/harness ${params.harnessVersion} is too old for @ekanos/cli ` +\n `${cliVersion()}: this CLI generates shell contract ${SHELL_CONTRACT}, ` +\n `and that harness needs ${required}.`,\n `Upgrade it: ${params.installHint('@ekanos/harness@latest')}.`,\n );\n}\n\n/**\n * A fingerprint of the template SOURCES, independent of the slug they are\n * rendered with.\n *\n * The harness version alone cannot certify a shell: the templates can change\n * while it stays put (a CLI patch release), and it can change while they stay\n * put. Hashing the sources means any edit to what we generate invalidates\n * every shell generated before it, including one produced by a CLI version\n * that never shipped.\n */\nexport function templatesFingerprint(templateNames: readonly string[]): string {\n const hash = createHash('sha256');\n for (const name of [...templateNames].sort()) {\n hash.update(name);\n hash.update('\\0');\n hash.update(readTemplateSource(name));\n hash.update('\\0');\n }\n return hash.digest('hex').slice(0, 16);\n}\n"]}
|
package/dist/context.d.ts
CHANGED
|
@@ -125,6 +125,8 @@ export declare class CliContext {
|
|
|
125
125
|
code: string;
|
|
126
126
|
message: string;
|
|
127
127
|
hint: string;
|
|
128
|
+
/** A docs URL for this error; JSON gets a `docs` field, human mode a line. */
|
|
129
|
+
docs?: string;
|
|
128
130
|
exitCode: number;
|
|
129
131
|
data?: unknown;
|
|
130
132
|
findingsSummary?: FindingsSummary;
|
package/dist/context.js
CHANGED
|
@@ -115,6 +115,7 @@ export class CliContext {
|
|
|
115
115
|
code: error.code,
|
|
116
116
|
message: error.message,
|
|
117
117
|
hint: error.hint,
|
|
118
|
+
docs: error.docs,
|
|
118
119
|
exitCode: error.exitCode,
|
|
119
120
|
data,
|
|
120
121
|
findingsSummary: options === null || options === void 0 ? void 0 : options.findingsSummary,
|
|
@@ -135,11 +136,7 @@ export class CliContext {
|
|
|
135
136
|
'error must carry an imperative remediation.');
|
|
136
137
|
}
|
|
137
138
|
if (this.jsonMode) {
|
|
138
|
-
const envelope = Object.assign(Object.assign({ ok: false }, (params.data !== undefined ? { data: params.data } : {})), { error: {
|
|
139
|
-
code: params.code,
|
|
140
|
-
message: params.message,
|
|
141
|
-
hint: params.hint,
|
|
142
|
-
} });
|
|
139
|
+
const envelope = Object.assign(Object.assign({ ok: false }, (params.data !== undefined ? { data: params.data } : {})), { error: Object.assign({ code: params.code, message: params.message, hint: params.hint }, (params.docs ? { docs: params.docs } : {})) });
|
|
143
140
|
this.stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
144
141
|
}
|
|
145
142
|
else if (params.findingsSummary) {
|
|
@@ -149,6 +146,9 @@ export class CliContext {
|
|
|
149
146
|
else {
|
|
150
147
|
this.stderr.write(`${this.ui.err('Error:')} ${params.message}\n`);
|
|
151
148
|
this.stderr.write(`${this.ui.dim('Hint:')} ${params.hint}\n`);
|
|
149
|
+
if (params.docs) {
|
|
150
|
+
this.stderr.write(`${this.ui.dim('Docs:')} ${params.docs}\n`);
|
|
151
|
+
}
|
|
152
152
|
}
|
|
153
153
|
return params.exitCode;
|
|
154
154
|
}
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors';\nimport { EXIT_CODES, type ExitCode } from './exit-codes';\nimport { type Ui, createUi } from './ui';\n\n/**\n * A single writable sink. Real streams satisfy this; tests pass a capturing\n * buffer so the stdout-purity invariant can be asserted byte-for-byte.\n */\nexport interface WriteStream {\n write(chunk: string): void;\n isTTY?: boolean;\n}\n\nexport interface ContextInput {\n /**\n * The user's EXPLICIT preference, already parsed: `true` for `--json`,\n * `false` for `--no-json`, `undefined` when neither was passed. The\n * undefined case is what allows the mode to be inferred instead.\n */\n jsonFlag?: boolean;\n stdout?: WriteStream;\n stderr?: WriteStream;\n /** Overrides process.env for CLAUDECODE detection (tests). */\n env?: Record<string, string | undefined>;\n}\n\n/** The success envelope. */\ninterface OkEnvelope {\n ok: true;\n data: unknown;\n}\n\n/** The error envelope. `data` is optional — validate carries its findings here. */\ninterface ErrEnvelope {\n ok: false;\n data?: unknown;\n error: { code: string; message: string; hint: string };\n}\n\n/** See `fail`'s doc comment — the human-mode epilogue seam for a command that already rendered a findings block. */\ninterface FindingsSummary {\n /** The command name to name in the summary line, e.g. \"ekanos validate\". */\n command: string;\n errorCount: number;\n}\n\nexport interface FailOptions {\n findingsSummary?: FindingsSummary;\n}\n\n/**\n * `data` is deliberately `unknown` above — each verb owns its own shape — but\n * one convention spans several of them: `validate`, `dev`, `publish` and\n * `status` all add an OPTIONAL `toolchain` field to `data` (never to the\n * envelope's top level) when the proactive update check in `update-notice.ts`\n * finds this CLI is behind. See that file's `ToolchainNoticeData` for the\n * shape, and `README.md`'s \"Keeping the toolchain current\" section for the\n * full contract. It is absent, not `null`, when there is nothing to report.\n */\n\n/**\n * The agent-native output envelope, resolved ONCE at startup and threaded\n * through every command.\n *\n * The load-bearing invariant: in JSON mode, stdout receives EXACTLY ONE JSON\n * object for the whole process — nothing else, ever. Every progress line, warn,\n * and scrap of human prose goes to stderr. This is the single most common way\n * an agent's tool call breaks (a stray log line on stdout makes the JSON\n * unparseable), so the context enforces it structurally: `succeed`/`fail` are\n * the only writers of stdout, and a `settled` latch makes a second call throw\n * rather than emit a second object.\n */\nexport class CliContext {\n readonly jsonMode: boolean;\n /**\n * The environment the context resolved against — exposed so decoration\n * (the gradient banner) can honour `NO_COLOR` / `EKANOS_NO_BANNER` without\n * every call site threading `process.env` through by hand.\n */\n readonly env: Readonly<Record<string, string | undefined>>;\n /**\n * The style layer (`ui.ts`), resolved once against stderr — the stream\n * every human-mode render target uses — so every command shares one color\n * decision instead of each re-deriving it. See `ui.ts` for the tokens and\n * components this carries.\n */\n readonly ui: Ui;\n private readonly stdout: WriteStream;\n private readonly stderr: WriteStream;\n private settled = false;\n\n constructor(input: ContextInput = {}) {\n const stdout = input.stdout ?? defaultStream(process.stdout);\n const stderr = input.stderr ?? defaultStream(process.stderr);\n const env = input.env ?? process.env;\n\n this.stdout = stdout;\n this.stderr = stderr;\n this.env = env;\n this.ui = createUi({ isTTY: stderr.isTTY === true, env });\n\n // Resolve JSON mode once. An EXPLICIT flag always wins: `--json` forces the\n // envelope on even at a terminal, `--no-json` forces the human form even\n // when piped. Only when the user expressed no preference is the mode\n // inferred — from a non-TTY stdout (piped into another program or an agent)\n // or the CLAUDECODE marker.\n const nonTty = stdout.isTTY !== true;\n this.jsonMode = input.jsonFlag ?? (nonTty || env.CLAUDECODE === '1');\n }\n\n /** Whether stderr is a real terminal — decoration (the banner) gates on this. */\n get stderrIsTTY(): boolean {\n return this.stderr.isTTY === true;\n }\n\n /**\n * Whether stdout is a real terminal — `wizard.ts`'s `canWizard` gates on\n * this (clack renders to stdout, unlike the rest of this CLI's human\n * output). `ctx.jsonMode` being false does not by itself guarantee this:\n * `--no-json` forces human mode even against a piped stdout.\n */\n get stdoutIsTTY(): boolean {\n return this.stdout.isTTY === true;\n }\n\n /** Human/progress output — ALWAYS stderr, so stdout stays pure in JSON mode. */\n log(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /** A warning — stderr, no ANSI. */\n warn(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /**\n * Emit the `claude-code-hint` protocol line to STDERR. Used on --help and on\n * an unknown command so an agent reading stderr is told what to do next\n * without the line ever touching stdout.\n */\n emitClaudeCodeHint(payload: Record<string, unknown>): void {\n // The protocol line is machine-readable JSON for an agent reading\n // stderr. A person at a terminal (human mode on a real stderr TTY) gets\n // the readable error or help text instead of a wall of JSON above it.\n if (!this.jsonMode && this.stderrIsTTY) return;\n\n this.stderr.write(`claude-code-hint: ${JSON.stringify(payload)}\\n`);\n }\n\n /**\n * Terminal success. Writes the single stdout object (JSON mode) or a concise\n * human line (human mode). Returns the OK exit code so the caller can end the\n * process with it. Idempotent-by-latch: a second settle throws.\n */\n succeed(data: unknown, humanSummary?: string): ExitCode {\n this.settle();\n if (this.jsonMode) {\n const envelope: OkEnvelope = { ok: true, data };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (humanSummary !== '') {\n // An explicit empty summary means \"already said it\" — a wizard flow's\n // outro is the result, and a trailing line would just repeat it.\n this.stdout.write(`${humanSummary ?? 'OK'}\\n`);\n }\n return EXIT_CODES.OK;\n }\n\n /**\n * Terminal failure. Writes the single stdout error object (JSON mode) or the\n * message + hint to stderr (human mode). Returns the error's exit code.\n *\n * `error.hint` is guaranteed non-empty by CliError's constructor, so the\n * envelope's \"every error carries a hint\" invariant holds for every path\n * that reaches here.\n *\n * `options.findingsSummary` is the seam for a command that has ALREADY\n * rendered the shared findings block to stderr (human mode) before calling\n * this — `validate`'s and `publish`'s gate-refusal paths. Passing it swaps\n * the default two-line `Error: … / Hint: …` epilogue (whose hint always\n * points at the JSON-only `data.findings`) for one short summary line,\n * `✖ <command> failed: <n> error(s)`, so a partner never reads the same\n * finding jargon twice. JSON mode is completely unaffected either way —\n * `error.hint` always carries the original, JSON-only-appropriate text in\n * the envelope.\n */\n fail(error: CliError, data?: unknown, options?: FailOptions): ExitCode {\n this.failWith({\n code: error.code,\n message: error.message,\n hint: error.hint,\n exitCode: error.exitCode,\n data,\n findingsSummary: options?.findingsSummary,\n });\n return error.exitCode;\n }\n\n /**\n * The low-level failure emitter. Used directly by `test`, whose exit code is\n * a TRANSPARENT passthrough of the delegated runner's exit code (which is not\n * one of the CLI's own frozen numeric conditions) and whose error `code` is\n * an out-of-taxonomy string. Enforces the same non-empty-hint invariant as\n * CliError so no failure path can emit an empty hint.\n */\n failWith(params: {\n code: string;\n message: string;\n hint: string;\n exitCode: number;\n data?: unknown;\n findingsSummary?: FindingsSummary;\n }): number {\n this.settle();\n if (!params.hint || params.hint.trim().length === 0) {\n throw new Error(\n `failWith for \"${params.message}\" was given an empty hint. Every CLI ` +\n 'error must carry an imperative remediation.',\n );\n }\n if (this.jsonMode) {\n const envelope: ErrEnvelope = {\n ok: false,\n ...(params.data !== undefined ? { data: params.data } : {}),\n error: {\n code: params.code,\n message: params.message,\n hint: params.hint,\n },\n };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (params.findingsSummary) {\n const { command, errorCount } = params.findingsSummary;\n this.stderr.write(\n `${this.ui.err(\n `${this.ui.glyphs.err} ${command} failed: ${errorCount} error${\n errorCount === 1 ? '' : 's'\n }`,\n )}\\n`,\n );\n } else {\n this.stderr.write(`${this.ui.err('Error:')} ${params.message}\\n`);\n this.stderr.write(`${this.ui.dim('Hint:')} ${params.hint}\\n`);\n }\n return params.exitCode;\n }\n\n private settle(): void {\n if (this.settled) {\n throw new Error(\n 'CliContext settled twice — a command tried to emit a second ' +\n 'terminal result. In JSON mode this would corrupt stdout with two ' +\n 'objects. This is a bug in the command.',\n );\n }\n this.settled = true;\n }\n}\n\nfunction defaultStream(stream: NodeJS.WriteStream): WriteStream {\n return {\n write: (chunk: string) => {\n stream.write(chunk);\n },\n isTTY: stream.isTTY,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors';\nimport { EXIT_CODES, type ExitCode } from './exit-codes';\nimport { type Ui, createUi } from './ui';\n\n/**\n * A single writable sink. Real streams satisfy this; tests pass a capturing\n * buffer so the stdout-purity invariant can be asserted byte-for-byte.\n */\nexport interface WriteStream {\n write(chunk: string): void;\n isTTY?: boolean;\n}\n\nexport interface ContextInput {\n /**\n * The user's EXPLICIT preference, already parsed: `true` for `--json`,\n * `false` for `--no-json`, `undefined` when neither was passed. The\n * undefined case is what allows the mode to be inferred instead.\n */\n jsonFlag?: boolean;\n stdout?: WriteStream;\n stderr?: WriteStream;\n /** Overrides process.env for CLAUDECODE detection (tests). */\n env?: Record<string, string | undefined>;\n}\n\n/** The success envelope. */\ninterface OkEnvelope {\n ok: true;\n data: unknown;\n}\n\n/** The error envelope. `data` is optional — validate carries its findings here. */\ninterface ErrEnvelope {\n ok: false;\n data?: unknown;\n error: { code: string; message: string; hint: string; docs?: string };\n}\n\n/** See `fail`'s doc comment — the human-mode epilogue seam for a command that already rendered a findings block. */\ninterface FindingsSummary {\n /** The command name to name in the summary line, e.g. \"ekanos validate\". */\n command: string;\n errorCount: number;\n}\n\nexport interface FailOptions {\n findingsSummary?: FindingsSummary;\n}\n\n/**\n * `data` is deliberately `unknown` above — each verb owns its own shape — but\n * one convention spans several of them: `validate`, `dev`, `publish` and\n * `status` all add an OPTIONAL `toolchain` field to `data` (never to the\n * envelope's top level) when the proactive update check in `update-notice.ts`\n * finds this CLI is behind. See that file's `ToolchainNoticeData` for the\n * shape, and `README.md`'s \"Keeping the toolchain current\" section for the\n * full contract. It is absent, not `null`, when there is nothing to report.\n */\n\n/**\n * The agent-native output envelope, resolved ONCE at startup and threaded\n * through every command.\n *\n * The load-bearing invariant: in JSON mode, stdout receives EXACTLY ONE JSON\n * object for the whole process — nothing else, ever. Every progress line, warn,\n * and scrap of human prose goes to stderr. This is the single most common way\n * an agent's tool call breaks (a stray log line on stdout makes the JSON\n * unparseable), so the context enforces it structurally: `succeed`/`fail` are\n * the only writers of stdout, and a `settled` latch makes a second call throw\n * rather than emit a second object.\n */\nexport class CliContext {\n readonly jsonMode: boolean;\n /**\n * The environment the context resolved against — exposed so decoration\n * (the gradient banner) can honour `NO_COLOR` / `EKANOS_NO_BANNER` without\n * every call site threading `process.env` through by hand.\n */\n readonly env: Readonly<Record<string, string | undefined>>;\n /**\n * The style layer (`ui.ts`), resolved once against stderr — the stream\n * every human-mode render target uses — so every command shares one color\n * decision instead of each re-deriving it. See `ui.ts` for the tokens and\n * components this carries.\n */\n readonly ui: Ui;\n private readonly stdout: WriteStream;\n private readonly stderr: WriteStream;\n private settled = false;\n\n constructor(input: ContextInput = {}) {\n const stdout = input.stdout ?? defaultStream(process.stdout);\n const stderr = input.stderr ?? defaultStream(process.stderr);\n const env = input.env ?? process.env;\n\n this.stdout = stdout;\n this.stderr = stderr;\n this.env = env;\n this.ui = createUi({ isTTY: stderr.isTTY === true, env });\n\n // Resolve JSON mode once. An EXPLICIT flag always wins: `--json` forces the\n // envelope on even at a terminal, `--no-json` forces the human form even\n // when piped. Only when the user expressed no preference is the mode\n // inferred — from a non-TTY stdout (piped into another program or an agent)\n // or the CLAUDECODE marker.\n const nonTty = stdout.isTTY !== true;\n this.jsonMode = input.jsonFlag ?? (nonTty || env.CLAUDECODE === '1');\n }\n\n /** Whether stderr is a real terminal — decoration (the banner) gates on this. */\n get stderrIsTTY(): boolean {\n return this.stderr.isTTY === true;\n }\n\n /**\n * Whether stdout is a real terminal — `wizard.ts`'s `canWizard` gates on\n * this (clack renders to stdout, unlike the rest of this CLI's human\n * output). `ctx.jsonMode` being false does not by itself guarantee this:\n * `--no-json` forces human mode even against a piped stdout.\n */\n get stdoutIsTTY(): boolean {\n return this.stdout.isTTY === true;\n }\n\n /** Human/progress output — ALWAYS stderr, so stdout stays pure in JSON mode. */\n log(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /** A warning — stderr, no ANSI. */\n warn(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /**\n * Emit the `claude-code-hint` protocol line to STDERR. Used on --help and on\n * an unknown command so an agent reading stderr is told what to do next\n * without the line ever touching stdout.\n */\n emitClaudeCodeHint(payload: Record<string, unknown>): void {\n // The protocol line is machine-readable JSON for an agent reading\n // stderr. A person at a terminal (human mode on a real stderr TTY) gets\n // the readable error or help text instead of a wall of JSON above it.\n if (!this.jsonMode && this.stderrIsTTY) return;\n\n this.stderr.write(`claude-code-hint: ${JSON.stringify(payload)}\\n`);\n }\n\n /**\n * Terminal success. Writes the single stdout object (JSON mode) or a concise\n * human line (human mode). Returns the OK exit code so the caller can end the\n * process with it. Idempotent-by-latch: a second settle throws.\n */\n succeed(data: unknown, humanSummary?: string): ExitCode {\n this.settle();\n if (this.jsonMode) {\n const envelope: OkEnvelope = { ok: true, data };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (humanSummary !== '') {\n // An explicit empty summary means \"already said it\" — a wizard flow's\n // outro is the result, and a trailing line would just repeat it.\n this.stdout.write(`${humanSummary ?? 'OK'}\\n`);\n }\n return EXIT_CODES.OK;\n }\n\n /**\n * Terminal failure. Writes the single stdout error object (JSON mode) or the\n * message + hint to stderr (human mode). Returns the error's exit code.\n *\n * `error.hint` is guaranteed non-empty by CliError's constructor, so the\n * envelope's \"every error carries a hint\" invariant holds for every path\n * that reaches here.\n *\n * `options.findingsSummary` is the seam for a command that has ALREADY\n * rendered the shared findings block to stderr (human mode) before calling\n * this — `validate`'s and `publish`'s gate-refusal paths. Passing it swaps\n * the default two-line `Error: … / Hint: …` epilogue (whose hint always\n * points at the JSON-only `data.findings`) for one short summary line,\n * `✖ <command> failed: <n> error(s)`, so a partner never reads the same\n * finding jargon twice. JSON mode is completely unaffected either way —\n * `error.hint` always carries the original, JSON-only-appropriate text in\n * the envelope.\n */\n fail(error: CliError, data?: unknown, options?: FailOptions): ExitCode {\n this.failWith({\n code: error.code,\n message: error.message,\n hint: error.hint,\n docs: error.docs,\n exitCode: error.exitCode,\n data,\n findingsSummary: options?.findingsSummary,\n });\n return error.exitCode;\n }\n\n /**\n * The low-level failure emitter. Used directly by `test`, whose exit code is\n * a TRANSPARENT passthrough of the delegated runner's exit code (which is not\n * one of the CLI's own frozen numeric conditions) and whose error `code` is\n * an out-of-taxonomy string. Enforces the same non-empty-hint invariant as\n * CliError so no failure path can emit an empty hint.\n */\n failWith(params: {\n code: string;\n message: string;\n hint: string;\n /** A docs URL for this error; JSON gets a `docs` field, human mode a line. */\n docs?: string;\n exitCode: number;\n data?: unknown;\n findingsSummary?: FindingsSummary;\n }): number {\n this.settle();\n if (!params.hint || params.hint.trim().length === 0) {\n throw new Error(\n `failWith for \"${params.message}\" was given an empty hint. Every CLI ` +\n 'error must carry an imperative remediation.',\n );\n }\n if (this.jsonMode) {\n const envelope: ErrEnvelope = {\n ok: false,\n ...(params.data !== undefined ? { data: params.data } : {}),\n error: {\n code: params.code,\n message: params.message,\n hint: params.hint,\n ...(params.docs ? { docs: params.docs } : {}),\n },\n };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (params.findingsSummary) {\n const { command, errorCount } = params.findingsSummary;\n this.stderr.write(\n `${this.ui.err(\n `${this.ui.glyphs.err} ${command} failed: ${errorCount} error${\n errorCount === 1 ? '' : 's'\n }`,\n )}\\n`,\n );\n } else {\n this.stderr.write(`${this.ui.err('Error:')} ${params.message}\\n`);\n this.stderr.write(`${this.ui.dim('Hint:')} ${params.hint}\\n`);\n if (params.docs) {\n this.stderr.write(`${this.ui.dim('Docs:')} ${params.docs}\\n`);\n }\n }\n return params.exitCode;\n }\n\n private settle(): void {\n if (this.settled) {\n throw new Error(\n 'CliContext settled twice — a command tried to emit a second ' +\n 'terminal result. In JSON mode this would corrupt stdout with two ' +\n 'objects. This is a bug in the command.',\n );\n }\n this.settled = true;\n }\n}\n\nfunction defaultStream(stream: NodeJS.WriteStream): WriteStream {\n return {\n write: (chunk: string) => {\n stream.write(chunk);\n },\n isTTY: stream.isTTY,\n };\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Finding } from '@ekanos/integration-schema';
|
|
2
|
+
/**
|
|
3
|
+
* Reports design-system drift in a project's own widget source, so a partner
|
|
4
|
+
* sees it on their machine rather than in a reviewer's comment.
|
|
5
|
+
*
|
|
6
|
+
* Modelled on `icon-findings.ts`, and for the same reason: `validate` has no
|
|
7
|
+
* live component tree to inspect, and by the time `loadDefinition` resolves
|
|
8
|
+
* them the definition's `component` fields are React function references with
|
|
9
|
+
* no file path to walk back to. So this scans `src/**\/*.{ts,tsx}` on disk.
|
|
10
|
+
*
|
|
11
|
+
* The matching itself lives in `@ekanos/integration-schema`
|
|
12
|
+
* (`collectDesignSourceFindings`) because the admission gate's
|
|
13
|
+
* design stage runs the same patterns over a submitted archive, and
|
|
14
|
+
* the gate's package cannot depend on this CLI. One matcher, two walks, no
|
|
15
|
+
* drift between what a partner is told before publish and what the gate
|
|
16
|
+
* reports after.
|
|
17
|
+
*
|
|
18
|
+
* WARN, not error, on every finding — see that module's doc comment. Off-
|
|
19
|
+
* system UI is a cohesion defect a reviewer weighs, never a reason `publish`
|
|
20
|
+
* refuses a submission.
|
|
21
|
+
*/
|
|
22
|
+
export declare function collectDesignFindings(projectDir: string): Finding[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { collectDesignSourceFindings } from '@ekanos/integration-schema';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Reports design-system drift in a project's own widget source, so a partner
|
|
6
|
+
* sees it on their machine rather than in a reviewer's comment.
|
|
7
|
+
*
|
|
8
|
+
* Modelled on `icon-findings.ts`, and for the same reason: `validate` has no
|
|
9
|
+
* live component tree to inspect, and by the time `loadDefinition` resolves
|
|
10
|
+
* them the definition's `component` fields are React function references with
|
|
11
|
+
* no file path to walk back to. So this scans `src/**\/*.{ts,tsx}` on disk.
|
|
12
|
+
*
|
|
13
|
+
* The matching itself lives in `@ekanos/integration-schema`
|
|
14
|
+
* (`collectDesignSourceFindings`) because the admission gate's
|
|
15
|
+
* design stage runs the same patterns over a submitted archive, and
|
|
16
|
+
* the gate's package cannot depend on this CLI. One matcher, two walks, no
|
|
17
|
+
* drift between what a partner is told before publish and what the gate
|
|
18
|
+
* reports after.
|
|
19
|
+
*
|
|
20
|
+
* WARN, not error, on every finding — see that module's doc comment. Off-
|
|
21
|
+
* system UI is a cohesion defect a reviewer weighs, never a reason `publish`
|
|
22
|
+
* refuses a submission.
|
|
23
|
+
*/
|
|
24
|
+
export function collectDesignFindings(projectDir) {
|
|
25
|
+
const srcDir = path.join(projectDir, 'src');
|
|
26
|
+
if (!fs.existsSync(srcDir))
|
|
27
|
+
return [];
|
|
28
|
+
const findings = [];
|
|
29
|
+
for (const file of walkTsFiles(srcDir)) {
|
|
30
|
+
findings.push(...collectDesignSourceFindings(fs.readFileSync(file, 'utf8'), file, {
|
|
31
|
+
jsx: file.endsWith('.tsx'),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
return findings;
|
|
35
|
+
}
|
|
36
|
+
function* walkTsFiles(dir) {
|
|
37
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
38
|
+
const full = path.join(dir, entry.name);
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
yield* walkTsFiles(full);
|
|
41
|
+
}
|
|
42
|
+
else if (/\.(ts|tsx)$/.test(entry.name)) {
|
|
43
|
+
yield full;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=design-findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-findings.js","sourceRoot":"","sources":["../src/design-findings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,QAAQ,CAAC,IAAI,CACX,GAAG,2BAA2B,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE;YAClE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;SAC3B,CAAC,CACH,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,QAAQ,CAAC,CAAC,WAAW,CAAC,GAAW;IAC/B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,CAAC;QACb,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport { collectDesignSourceFindings } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Reports design-system drift in a project's own widget source, so a partner\n * sees it on their machine rather than in a reviewer's comment.\n *\n * Modelled on `icon-findings.ts`, and for the same reason: `validate` has no\n * live component tree to inspect, and by the time `loadDefinition` resolves\n * them the definition's `component` fields are React function references with\n * no file path to walk back to. So this scans `src/**\\/*.{ts,tsx}` on disk.\n *\n * The matching itself lives in `@ekanos/integration-schema`\n * (`collectDesignSourceFindings`) because the admission gate's\n * design stage runs the same patterns over a submitted archive, and\n * the gate's package cannot depend on this CLI. One matcher, two walks, no\n * drift between what a partner is told before publish and what the gate\n * reports after.\n *\n * WARN, not error, on every finding — see that module's doc comment. Off-\n * system UI is a cohesion defect a reviewer weighs, never a reason `publish`\n * refuses a submission.\n */\nexport function collectDesignFindings(projectDir: string): Finding[] {\n const srcDir = path.join(projectDir, 'src');\n if (!fs.existsSync(srcDir)) return [];\n\n const findings: Finding[] = [];\n for (const file of walkTsFiles(srcDir)) {\n findings.push(\n ...collectDesignSourceFindings(fs.readFileSync(file, 'utf8'), file, {\n jsx: file.endsWith('.tsx'),\n }),\n );\n }\n return findings;\n}\n\nfunction* walkTsFiles(dir: string): Generator<string> {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkTsFiles(full);\n } else if (/\\.(ts|tsx)$/.test(entry.name)) {\n yield full;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public Ekanos SDK docs. Every docs URL the CLI prints or emits is built
|
|
3
|
+
* from this one constant, so a move of the site is a one-line change.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SDK_DOCS_URL = "https://sdk.ekanos.dev";
|
|
6
|
+
/** A page on the docs site, e.g. `docsPage('cli/commands')`. */
|
|
7
|
+
export declare function docsPage(page: string, anchor?: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* The common-errors entries for the CLI error codes the docs document. Anchors
|
|
10
|
+
* are the headings under "CLI errors" in common-errors.mdx.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ERROR_DOCS: Readonly<Record<string, string>>;
|
|
13
|
+
/** The schema-skew entry: documented under `precondition_failed`, but only for skew. */
|
|
14
|
+
export declare const SCHEMA_SKEW_DOCS: string;
|
|
15
|
+
/**
|
|
16
|
+
* The validation findings the common-errors page documents, by `check` id.
|
|
17
|
+
* Anchors are the headings under "Validation findings". A check absent here
|
|
18
|
+
* has no docs entry, so the renderer prints no link rather than a dead one.
|
|
19
|
+
*/
|
|
20
|
+
export declare const FINDING_DOCS: Readonly<Record<string, string>>;
|