@ekanos/cli 0.3.2 → 0.3.4
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 +13 -13
- package/dist/auth/credential-store.d.ts +1 -1
- package/dist/auth/credential-store.js +3 -2
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/device-flow.d.ts +1 -1
- package/dist/auth/device-flow.js +11 -10
- package/dist/auth/device-flow.js.map +1 -1
- package/dist/auth/{fusion-api.d.ts → ekanos-api.d.ts} +9 -9
- package/dist/auth/{fusion-api.js → ekanos-api.js} +28 -28
- package/dist/auth/ekanos-api.js.map +1 -0
- package/dist/auth/session.d.ts +5 -5
- package/dist/auth/session.js +21 -11
- package/dist/auth/session.js.map +1 -1
- package/dist/banner.d.ts +1 -1
- package/dist/banner.js +4 -13
- package/dist/banner.js.map +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/commands/dev.d.ts +2 -2
- package/dist/commands/dev.js +11 -3
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.js +72 -30
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +28 -17
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +31 -5
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/publish.d.ts +2 -2
- package/dist/commands/publish.js +28 -15
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/sources.js +26 -16
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.js +56 -45
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/test.js +15 -5
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/upgrade.js +86 -54
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/commands/use.js +11 -3
- package/dist/commands/use.js.map +1 -1
- package/dist/commands/validate.js +21 -3
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/whoami.d.ts +1 -1
- package/dist/commands/whoami.js +17 -7
- package/dist/commands/whoami.js.map +1 -1
- package/dist/compatibility.js.map +1 -1
- package/dist/context.js +10 -3
- package/dist/context.js.map +1 -1
- package/dist/delegate.js.map +1 -1
- package/dist/did-you-mean.js +26 -15
- package/dist/did-you-mean.js.map +1 -1
- package/dist/exit-codes.d.ts +10 -10
- package/dist/findings-renderer.js +6 -4
- package/dist/findings-renderer.js.map +1 -1
- package/dist/generated/fa-free-names.d.ts +1 -1
- package/dist/generated/fa-free-names.js +1 -1
- package/dist/generated/fa-free-names.js.map +1 -1
- package/dist/harness-scaffold.d.ts +1 -1
- package/dist/harness-scaffold.js +4 -2
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/icon-findings.d.ts +1 -1
- package/dist/icon-findings.js +2 -2
- package/dist/icon-findings.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/merge-manifest.js.map +1 -1
- package/dist/pack.js +1 -1
- package/dist/pack.js.map +1 -1
- package/dist/project-checks.js.map +1 -1
- package/dist/project.d.ts +7 -84
- package/dist/project.js +3 -3
- package/dist/project.js.map +1 -1
- package/dist/publish-api.d.ts +5 -5
- package/dist/publish-api.js +27 -33
- package/dist/publish-api.js.map +1 -1
- package/dist/safe-fs.js.map +1 -1
- package/dist/schema-skew.js.map +1 -1
- package/dist/source-locator.js.map +1 -1
- package/dist/sources-api.d.ts +3 -3
- package/dist/sources-api.js +11 -14
- package/dist/sources-api.js.map +1 -1
- package/dist/templates.js.map +1 -1
- package/dist/test-report.js.map +1 -1
- package/dist/toolchain-api.d.ts +4 -4
- package/dist/toolchain-api.js +1 -1
- package/dist/toolchain-api.js.map +1 -1
- package/dist/toolchain-resolve.js.map +1 -1
- package/dist/toolchain.d.ts +5 -5
- package/dist/ui.d.ts +36 -0
- package/dist/ui.js +79 -10
- package/dist/ui.js.map +1 -1
- package/dist/update-notice.d.ts +1 -1
- package/dist/update-notice.js.map +1 -1
- package/dist/validate-findings.js.map +1 -1
- package/dist/wizard.js.map +1 -1
- package/package.json +15 -20
- package/templates/AGENTS.md.tmpl +13 -8
- package/templates/CLAUDE.md.tmpl +1 -1
- package/templates/claude-skill.md.tmpl +2 -2
- package/templates/harness/next.config.mjs.tmpl +1 -1
- package/templates/package.json.tmpl +6 -5
- package/templates/pnpm-workspace.yaml.tmpl +8 -0
- package/templates/skills/build-integration/SKILL.md +3 -3
- package/templates/skills/build-integration/references/api-wiring.md +2 -2
- package/templates/skills/build-integration/references/widget-design.md +1 -1
- package/dist/auth/fusion-api.js.map +0 -1
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 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 {\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(`Error: ${params.message}\\n`);\n this.stderr.write(`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 };\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"]}
|
package/dist/delegate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../src/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAU1E,uGAAuG;AACvG,SAAS,YAAY,CAAC,IAAuB;IAC3C,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM;QAC1B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iEAAiE;AACjE,SAAS,WAAW,CAAC,IAAuB;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM;QAC1B,IAAI,KAAK,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAuB,EACvB,GAAuC,EACvC,GAAW;;IAEX,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;IAEhC,yEAAyE;IACzE,IAAI,GAAG,CAAC,gBAAgB,KAAK,GAAG,IAAI,GAAG,CAAC,kBAAkB,KAAK,GAAG,EAAE,CAAC;QACnE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../src/delegate.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport * as path from 'node:path';\n\nimport { cliVersion } from './compatibility';\nimport { readInstalledPackageManifest } from './harness-scaffold';\n\n/**\n * Wrapper-style delegation to the project-local `@ekanos/cli` — the\n * Gradle-wrapper / Yarn / `npx` pattern, applied to this CLI.\n *\n * A global install bundles ONE `@ekanos/integration-schema` version but\n * routinely serves N projects on different `@ekanos/sdk` versions — it\n * cannot be correct for all of them simultaneously (this is exactly the\n * failure mode `schema-skew.ts` detects). Delegation dissolves the tension:\n * `ekanos` stays on PATH for convenience, but the four verbs that actually\n * read or generate project files always run through the project's OWN\n * pinned copy when one is installed and differs from the invoked binary.\n *\n * Machine-level verbs (`init`, `login`, `logout`, `whoami`, `sources`,\n * `use`, `status`, `upgrade`) are deliberately NEVER delegated: you never\n * want an old local copy handling credentials, and `upgrade` must always be\n * the newest logic doing the upgrading — delegating it could have an old CLI\n * \"upgrade\" a project using its own out-of-date resolution.\n */\n\nconst DELEGATABLE_VERBS = new Set(['validate', 'publish', 'dev', 'test']);\n\nexport interface DelegationPlan {\n shouldDelegate: boolean;\n ownVersion: string;\n localVersion?: string;\n /** Absolute path to the local CLI's bin entry, when `shouldDelegate`. */\n localBinPath?: string;\n}\n\n/** The first bare (non-flag) token before a standalone `--` — mirrors `splitCommand` in `index.ts`. */\nfunction firstCommand(argv: readonly string[]): string | null {\n for (const token of argv) {\n if (token === '--') break;\n if (!token.startsWith('-')) return token;\n }\n return null;\n}\n\n/** `--dir <path>` / `--dir=<path>`, before a standalone `--`. */\nfunction scanDirFlag(argv: readonly string[]): string | undefined {\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i]!;\n if (token === '--') break;\n if (token === '--dir') return argv[i + 1];\n if (token.startsWith('--dir=')) return token.slice('--dir='.length);\n }\n return undefined;\n}\n\n/**\n * Decide whether this invocation should delegate. Pure and side-effect-free\n * (beyond the one file read of the local `@ekanos/cli` manifest, mirroring\n * `readInstalledHarness`/`dev`'s own project-package resolution rather than\n * writing a second one) so it is directly testable without spawning anything.\n */\nexport function planDelegation(\n argv: readonly string[],\n env: Record<string, string | undefined>,\n cwd: string,\n): DelegationPlan {\n const ownVersion = cliVersion();\n\n // The recursion guard, and the explicit escape hatch, both win outright.\n if (env.EKANOS_DELEGATED === '1' || env.EKANOS_NO_DELEGATE === '1') {\n return { shouldDelegate: false, ownVersion };\n }\n\n const command = firstCommand(argv);\n if (!command || !DELEGATABLE_VERBS.has(command)) {\n return { shouldDelegate: false, ownVersion };\n }\n\n const projectDir = path.resolve(cwd, scanDirFlag(argv) ?? '.');\n // Best-effort, like every other resolution this function does: a corrupt\n // local manifest must fall through to \"don't delegate\", never throw. This\n // runs in `bin.ts` BEFORE `run()`'s try/catch exists, so an uncaught throw\n // here would bypass the JSON-envelope error machinery entirely and print a\n // raw stderr string instead — a real regression in the \"exactly one\n // terminal emission\" contract the rest of this package guarantees.\n let local: ReturnType<typeof readInstalledPackageManifest> = null;\n try {\n local = readInstalledPackageManifest(projectDir, '@ekanos/cli');\n } catch {\n local = null;\n }\n\n if (!local || local.version === ownVersion) {\n return { shouldDelegate: false, ownVersion, localVersion: local?.version };\n }\n\n return {\n shouldDelegate: true,\n ownVersion,\n localVersion: local.version,\n localBinPath: path.join(\n projectDir,\n 'node_modules',\n '@ekanos',\n 'cli',\n 'dist',\n 'bin.js',\n ),\n };\n}\n\n/**\n * Same JSON-mode inference `CliContext` uses (`context.ts`) — duplicated\n * deliberately rather than shared, because this runs BEFORE a `CliContext`\n * exists (delegation is decided ahead of the whole `run()` machinery). Keep\n * this in sync with `CliContext`'s constructor if that heuristic ever\n * changes: an explicit `--json`/`--no-json` wins, otherwise a non-TTY stdout\n * or `CLAUDECODE=1` means JSON mode.\n */\nfunction looksLikeJsonMode(\n argv: readonly string[],\n env: Record<string, string | undefined>,\n stdoutIsTTY: boolean,\n): boolean {\n for (const token of argv) {\n if (token === '--') break;\n if (token === '--json') return true;\n if (token === '--no-json') return false;\n }\n return !stdoutIsTTY || env.CLAUDECODE === '1';\n}\n\n/**\n * The one-line stderr announcement — human mode only, and NEVER on stdout\n * (a delegated `validate --json` must still emit exactly one JSON object on\n * stdout, from the CHILD, with nothing of ours ahead of it).\n */\nexport function announceDelegation(\n plan: DelegationPlan,\n argv: readonly string[],\n env: Record<string, string | undefined>,\n stdoutIsTTY: boolean,\n): void {\n if (!plan.shouldDelegate) return;\n if (looksLikeJsonMode(argv, env, stdoutIsTTY)) return;\n\n process.stderr.write(\n `ekanos: using this project's pinned CLI ${plan.localVersion} (global: ` +\n `${plan.ownVersion}). Set EKANOS_NO_DELEGATE=1 to bypass.\\n`,\n );\n}\n\n/**\n * Spawn the local CLI's own bin entry with the SAME node executable,\n * `stdio: 'inherit'` so the JSON envelope and banner gating are\n * byte-identical to a direct run, and propagate its exit code exactly.\n * `spawnFn` is injectable so tests never actually fork a process.\n */\nexport function delegate(\n plan: DelegationPlan,\n argv: readonly string[],\n env: NodeJS.ProcessEnv,\n spawnFn: typeof spawn = spawn,\n): Promise<number> {\n return new Promise((resolve) => {\n const child = spawnFn(process.execPath, [plan.localBinPath!, ...argv], {\n stdio: 'inherit',\n env: { ...env, EKANOS_DELEGATED: '1' },\n });\n child.on('error', () => resolve(1));\n child.on('exit', (code) => resolve(code ?? 1));\n });\n}\n"]}
|
package/dist/did-you-mean.js
CHANGED
|
@@ -79,22 +79,33 @@ function asZodLike(value) {
|
|
|
79
79
|
}
|
|
80
80
|
return null;
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
82
|
+
/** A node's kind in zod 4's lower-case vocabulary, whichever major built it. */
|
|
83
|
+
function kindOf(schema) {
|
|
84
|
+
const { typeName, type } = schema._def;
|
|
85
|
+
return typeName ? typeName.replace(/^Zod/, '').toLowerCase() : (type !== null && type !== void 0 ? type : '');
|
|
86
|
+
}
|
|
87
|
+
const INNER_TYPE_WRAPPERS = new Set([
|
|
88
|
+
'optional',
|
|
89
|
+
'default',
|
|
90
|
+
'nullable',
|
|
91
|
+
'prefault',
|
|
92
|
+
]);
|
|
93
|
+
/** Peels refinements/transforms (zod 3 `ZodEffects`, zod 4 `pipe`), `optional`, `default`, and `nullable` down to the schema they wrap. */
|
|
83
94
|
function unwrap(schema) {
|
|
84
95
|
let current = schema;
|
|
85
96
|
for (;;) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
const kind = kindOf(current);
|
|
98
|
+
const next = kind === 'effects'
|
|
99
|
+
? current._def.schema
|
|
100
|
+
: kind === 'pipe'
|
|
101
|
+
? current._def.in
|
|
102
|
+
: INNER_TYPE_WRAPPERS.has(kind)
|
|
103
|
+
? current._def.innerType
|
|
104
|
+
: undefined;
|
|
105
|
+
if (!next) {
|
|
106
|
+
return current;
|
|
96
107
|
}
|
|
97
|
-
|
|
108
|
+
current = next;
|
|
98
109
|
}
|
|
99
110
|
}
|
|
100
111
|
/**
|
|
@@ -107,14 +118,14 @@ function unwrap(schema) {
|
|
|
107
118
|
function resolveObjectAt(root, segments) {
|
|
108
119
|
let current = unwrap(root);
|
|
109
120
|
for (const segment of segments) {
|
|
110
|
-
if (current
|
|
121
|
+
if (kindOf(current) === 'object' && current.shape) {
|
|
111
122
|
const next = current.shape[segment];
|
|
112
123
|
if (!next)
|
|
113
124
|
return null;
|
|
114
125
|
current = unwrap(next);
|
|
115
126
|
continue;
|
|
116
127
|
}
|
|
117
|
-
if (current
|
|
128
|
+
if (kindOf(current) === 'array' &&
|
|
118
129
|
current.element &&
|
|
119
130
|
/^\d+$/.test(segment)) {
|
|
120
131
|
current = unwrap(current.element);
|
|
@@ -122,7 +133,7 @@ function resolveObjectAt(root, segments) {
|
|
|
122
133
|
}
|
|
123
134
|
return null;
|
|
124
135
|
}
|
|
125
|
-
return current
|
|
136
|
+
return kindOf(current) === 'object' ? current : null;
|
|
126
137
|
}
|
|
127
138
|
/**
|
|
128
139
|
* Fallback for the two spots a partner is most likely to typo a key — the
|
package/dist/did-you-mean.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"did-you-mean.js","sourceRoot":"","sources":["../src/did-you-mean.ts"],"names":[],"mappings":"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","sourcesContent":["import { IntegrationDefinitionSchema } from '@ekanos/integration-schema';\n\nimport { isRootPath, splitDotPath } from './source-locator';\n\n/**\n * \"Did you mean?\" for a zod `unrecognized_keys` finding — the typo case\n * (`entrypiont` instead of `entrypoint`). Two pieces: a hand-rolled\n * Levenshtein distance (no new dependency — this package deliberately keeps\n * its runtime dependency set to picocolors + @clack/prompts only) and a\n * structural walk of the REAL `IntegrationDefinitionSchema` to find the\n * sibling keys a given path actually accepts.\n */\n\n/**\n * Classic single-rolling-row DP, O(a.length * b.length). Fine at CLI scale —\n * this compares key names, never paragraphs.\n */\nexport function levenshteinDistance(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n let previousRow = Array.from({ length: b.length + 1 }, (_, j) => j);\n\n for (let i = 1; i <= a.length; i += 1) {\n const currentRow = [i];\n for (let j = 1; j <= b.length; j += 1) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n currentRow.push(\n Math.min(\n (previousRow[j] ?? Infinity) + 1, // deletion\n (currentRow[j - 1] ?? Infinity) + 1, // insertion\n (previousRow[j - 1] ?? Infinity) + cost, // substitution\n ),\n );\n }\n previousRow = currentRow;\n }\n\n return previousRow[b.length] ?? Math.max(a.length, b.length);\n}\n\nconst MAX_SUGGESTION_DISTANCE = 2;\n\n/**\n * The single closest candidate within `MAX_SUGGESTION_DISTANCE`, or `null`\n * when nothing is close enough. Never a wrong-confident guess for a key that\n * isn't really a typo of anything this schema accepts.\n */\nexport function suggestKey(\n key: string,\n candidates: readonly string[],\n): string | null {\n let best: string | null = null;\n let bestDistance = MAX_SUGGESTION_DISTANCE + 1;\n\n for (const candidate of candidates) {\n const distance = levenshteinDistance(key, candidate);\n if (distance < bestDistance) {\n bestDistance = distance;\n best = candidate;\n }\n }\n\n return bestDistance <= MAX_SUGGESTION_DISTANCE ? best : null;\n}\n\n/**\n * Parses the literal, comma-separated, single-quoted key list zod's\n * `unrecognized_keys` issue produces (`Unrecognized key(s) in object: 'a',\n * 'b'`) — this exact wording is what `collectDefinitionFindings` bakes into\n * `Finding.message` verbatim (see its doc comment), so this is a text match\n * against a stable, committed third-party format, not a guess at prose.\n * `null` for a message tail that isn't this issue.\n */\nexport function extractUnrecognizedKeys(rest: string): string[] | null {\n const match = /^Unrecognized key\\(s\\) in object: (.+)$/.exec(rest);\n if (!match) return null;\n\n const list = match[1];\n if (!list) return null;\n\n const keys = [...list.matchAll(/'([^']*)'/g)].map((m) => m[1] ?? '');\n return keys.length > 0 ? keys : null;\n}\n\n/**\n * A structural, minimal view of a zod schema instance's internals — `_def`,\n * `.shape` (a `ZodObject`), `.element` (a `ZodArray`) — used ONLY to walk\n * `IntegrationDefinitionSchema` for candidate keys. Deliberately NOT `import\n * { ... } from 'zod'`: this package has no direct `zod` dependency (only\n * `@ekanos/integration-schema` does), the constraint on this feature is no\n * new runtime dependency, and these three properties are the only ones this\n * module reads — stable across zod's v3 line.\n */\ninterface ZodLike {\n _def: {\n typeName: string;\n schema?: ZodLike;\n innerType?: ZodLike;\n };\n shape?: Record<string, ZodLike>;\n element?: ZodLike;\n}\n\nfunction asZodLike(value: unknown): ZodLike | null {\n if (\n typeof value === 'object' &&\n value !== null &&\n '_def' in value &&\n typeof (value as { _def: unknown })._def === 'object' &&\n (value as { _def: unknown })._def !== null\n ) {\n return value as ZodLike;\n }\n return null;\n}\n\n/** Peels `ZodEffects` (`.superRefine`/`.refine`), `ZodOptional`, `ZodDefault`, and `ZodNullable` down to the schema they wrap. */\nfunction unwrap(schema: ZodLike): ZodLike {\n let current = schema;\n\n for (;;) {\n if (current._def.typeName === 'ZodEffects' && current._def.schema) {\n current = current._def.schema;\n continue;\n }\n if (\n (current._def.typeName === 'ZodOptional' ||\n current._def.typeName === 'ZodDefault' ||\n current._def.typeName === 'ZodNullable') &&\n current._def.innerType\n ) {\n current = current._def.innerType;\n continue;\n }\n return current;\n }\n}\n\n/**\n * Walks `root` through `segments` (`.shape` for an object key, `.element`\n * for a numeric array index, unwrapping wrappers at every step), returning\n * the `ZodObject` found at the end — or `null` the moment it hits anything\n * it can't structurally walk (a union, a record, a segment the shape\n * doesn't have). The caller falls back to a curated list in that case.\n */\nfunction resolveObjectAt(\n root: ZodLike,\n segments: readonly string[],\n): ZodLike | null {\n let current = unwrap(root);\n\n for (const segment of segments) {\n if (current._def.typeName === 'ZodObject' && current.shape) {\n const next = current.shape[segment];\n if (!next) return null;\n current = unwrap(next);\n continue;\n }\n if (\n current._def.typeName === 'ZodArray' &&\n current.element &&\n /^\\d+$/.test(segment)\n ) {\n current = unwrap(current.element);\n continue;\n }\n return null;\n }\n\n return current._def.typeName === 'ZodObject' ? current : null;\n}\n\n/**\n * Fallback for the two spots a partner is most likely to typo a key — the\n * top-level declaration and a widget entry — used only when the structural\n * walk above can't resolve the parent path. Keep in sync with\n * `IntegrationDefinitionSchema`'s top-level shape and `widgetSchema` in\n * `@ekanos/integration-schema`'s `integration-definition.ts`; the structural\n * walk is tried first and should cover both of these in practice; this is\n * the safety net for whenever it doesn't.\n */\nconst CURATED_TOP_LEVEL_KEYS = [\n 'slug',\n 'name',\n 'description',\n 'version',\n 'capabilities',\n 'permissions',\n 'components',\n 'workspaceTargets',\n 'tools',\n 'storage',\n 'egress',\n 'webhooks',\n 'schedules',\n 'oauth',\n 'onActivate',\n 'proposes',\n];\n\nconst CURATED_WIDGET_KEYS = [\n 'id',\n 'name',\n 'component',\n 'widgetState',\n 'gridSize',\n 'gridPosition',\n 'layouts',\n 'category',\n 'isCollapsible',\n 'isPinnable',\n 'aiFooterEnabled',\n];\n\nfunction curatedKeysAt(parentDotPath: string): readonly string[] | null {\n if (isRootPath(parentDotPath)) return CURATED_TOP_LEVEL_KEYS;\n if (/^components\\.widgets\\.\\d+$/.test(parentDotPath)) {\n return CURATED_WIDGET_KEYS;\n }\n return null;\n}\n\n/**\n * The keys `IntegrationDefinitionSchema` actually accepts at\n * `parentDotPath` — the zod issue's own `path` for an `unrecognized_keys`\n * finding, so this always names the OBJECT the extra key was found on, never\n * the extra key itself. Structural introspection first, the curated list\n * second, `[]` (no suggestion offered — never a wrong-confident one) last.\n */\nexport function acceptedKeysAt(parentDotPath: string): readonly string[] {\n const root = asZodLike(IntegrationDefinitionSchema);\n const resolved = root\n ? resolveObjectAt(root, splitDotPath(parentDotPath))\n : null;\n\n if (resolved?.shape) return Object.keys(resolved.shape);\n\n return curatedKeysAt(parentDotPath) ?? [];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"did-you-mean.js","sourceRoot":"","sources":["../src/did-you-mean.ts"],"names":[],"mappings":"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","sourcesContent":["import { IntegrationDefinitionSchema } from '@ekanos/integration-schema';\n\nimport { isRootPath, splitDotPath } from './source-locator';\n\n/**\n * \"Did you mean?\" for a zod `unrecognized_keys` finding — the typo case\n * (`entrypiont` instead of `entrypoint`). Two pieces: a hand-rolled\n * Levenshtein distance (no new dependency — this package deliberately keeps\n * its runtime dependency set to picocolors + @clack/prompts only) and a\n * structural walk of the REAL `IntegrationDefinitionSchema` to find the\n * sibling keys a given path actually accepts.\n */\n\n/**\n * Classic single-rolling-row DP, O(a.length * b.length). Fine at CLI scale —\n * this compares key names, never paragraphs.\n */\nexport function levenshteinDistance(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n let previousRow = Array.from({ length: b.length + 1 }, (_, j) => j);\n\n for (let i = 1; i <= a.length; i += 1) {\n const currentRow = [i];\n for (let j = 1; j <= b.length; j += 1) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n currentRow.push(\n Math.min(\n (previousRow[j] ?? Infinity) + 1, // deletion\n (currentRow[j - 1] ?? Infinity) + 1, // insertion\n (previousRow[j - 1] ?? Infinity) + cost, // substitution\n ),\n );\n }\n previousRow = currentRow;\n }\n\n return previousRow[b.length] ?? Math.max(a.length, b.length);\n}\n\nconst MAX_SUGGESTION_DISTANCE = 2;\n\n/**\n * The single closest candidate within `MAX_SUGGESTION_DISTANCE`, or `null`\n * when nothing is close enough. Never a wrong-confident guess for a key that\n * isn't really a typo of anything this schema accepts.\n */\nexport function suggestKey(\n key: string,\n candidates: readonly string[],\n): string | null {\n let best: string | null = null;\n let bestDistance = MAX_SUGGESTION_DISTANCE + 1;\n\n for (const candidate of candidates) {\n const distance = levenshteinDistance(key, candidate);\n if (distance < bestDistance) {\n bestDistance = distance;\n best = candidate;\n }\n }\n\n return bestDistance <= MAX_SUGGESTION_DISTANCE ? best : null;\n}\n\n/**\n * Parses the literal, comma-separated, single-quoted key list zod's\n * `unrecognized_keys` issue produces (`Unrecognized key(s) in object: 'a',\n * 'b'`) — this exact wording is what `collectDefinitionFindings` bakes into\n * `Finding.message` verbatim (see its doc comment), so this is a text match\n * against a stable, committed third-party format, not a guess at prose.\n * `null` for a message tail that isn't this issue.\n */\nexport function extractUnrecognizedKeys(rest: string): string[] | null {\n const match = /^Unrecognized key\\(s\\) in object: (.+)$/.exec(rest);\n if (!match) return null;\n\n const list = match[1];\n if (!list) return null;\n\n const keys = [...list.matchAll(/'([^']*)'/g)].map((m) => m[1] ?? '');\n return keys.length > 0 ? keys : null;\n}\n\n/**\n * A structural, minimal view of a zod schema instance's internals — `_def`,\n * `.shape` (a `ZodObject`), `.element` (a `ZodArray`) — used ONLY to walk\n * `IntegrationDefinitionSchema` for candidate keys. Deliberately NOT `import\n * { ... } from 'zod'`: this package has no direct `zod` dependency (only\n * `@ekanos/integration-schema` does), the constraint on this feature is no\n * new runtime dependency, and these few properties are the only ones this\n * module reads. The partner's install decides the zod major (the peer range\n * is `^3.25.76 || ^4.0.0`), so both shapes are read: zod 3 names a node's\n * kind `_def.typeName` (`'ZodObject'`), zod 4 `_def.type` (`'object'`).\n */\ninterface ZodLike {\n _def: {\n typeName?: string;\n type?: string;\n schema?: ZodLike;\n innerType?: ZodLike;\n in?: ZodLike;\n };\n shape?: Record<string, ZodLike>;\n element?: ZodLike;\n}\n\nfunction asZodLike(value: unknown): ZodLike | null {\n if (\n typeof value === 'object' &&\n value !== null &&\n '_def' in value &&\n typeof (value as { _def: unknown })._def === 'object' &&\n (value as { _def: unknown })._def !== null\n ) {\n return value as ZodLike;\n }\n return null;\n}\n\n/** A node's kind in zod 4's lower-case vocabulary, whichever major built it. */\nfunction kindOf(schema: ZodLike): string {\n const { typeName, type } = schema._def;\n\n return typeName ? typeName.replace(/^Zod/, '').toLowerCase() : (type ?? '');\n}\n\nconst INNER_TYPE_WRAPPERS = new Set([\n 'optional',\n 'default',\n 'nullable',\n 'prefault',\n]);\n\n/** Peels refinements/transforms (zod 3 `ZodEffects`, zod 4 `pipe`), `optional`, `default`, and `nullable` down to the schema they wrap. */\nfunction unwrap(schema: ZodLike): ZodLike {\n let current = schema;\n\n for (;;) {\n const kind = kindOf(current);\n const next =\n kind === 'effects'\n ? current._def.schema\n : kind === 'pipe'\n ? current._def.in\n : INNER_TYPE_WRAPPERS.has(kind)\n ? current._def.innerType\n : undefined;\n\n if (!next) {\n return current;\n }\n\n current = next;\n }\n}\n\n/**\n * Walks `root` through `segments` (`.shape` for an object key, `.element`\n * for a numeric array index, unwrapping wrappers at every step), returning\n * the `ZodObject` found at the end — or `null` the moment it hits anything\n * it can't structurally walk (a union, a record, a segment the shape\n * doesn't have). The caller falls back to a curated list in that case.\n */\nfunction resolveObjectAt(\n root: ZodLike,\n segments: readonly string[],\n): ZodLike | null {\n let current = unwrap(root);\n\n for (const segment of segments) {\n if (kindOf(current) === 'object' && current.shape) {\n const next = current.shape[segment];\n if (!next) return null;\n current = unwrap(next);\n continue;\n }\n if (\n kindOf(current) === 'array' &&\n current.element &&\n /^\\d+$/.test(segment)\n ) {\n current = unwrap(current.element);\n continue;\n }\n return null;\n }\n\n return kindOf(current) === 'object' ? current : null;\n}\n\n/**\n * Fallback for the two spots a partner is most likely to typo a key — the\n * top-level declaration and a widget entry — used only when the structural\n * walk above can't resolve the parent path. Keep in sync with\n * `IntegrationDefinitionSchema`'s top-level shape and `widgetSchema` in\n * `@ekanos/integration-schema`'s `integration-definition.ts`; the structural\n * walk is tried first and should cover both of these in practice; this is\n * the safety net for whenever it doesn't.\n */\nconst CURATED_TOP_LEVEL_KEYS = [\n 'slug',\n 'name',\n 'description',\n 'version',\n 'capabilities',\n 'permissions',\n 'components',\n 'workspaceTargets',\n 'tools',\n 'storage',\n 'egress',\n 'webhooks',\n 'schedules',\n 'oauth',\n 'onActivate',\n 'proposes',\n];\n\nconst CURATED_WIDGET_KEYS = [\n 'id',\n 'name',\n 'component',\n 'widgetState',\n 'gridSize',\n 'gridPosition',\n 'layouts',\n 'category',\n 'isCollapsible',\n 'isPinnable',\n 'aiFooterEnabled',\n];\n\nfunction curatedKeysAt(parentDotPath: string): readonly string[] | null {\n if (isRootPath(parentDotPath)) return CURATED_TOP_LEVEL_KEYS;\n if (/^components\\.widgets\\.\\d+$/.test(parentDotPath)) {\n return CURATED_WIDGET_KEYS;\n }\n return null;\n}\n\n/**\n * The keys `IntegrationDefinitionSchema` actually accepts at\n * `parentDotPath` — the zod issue's own `path` for an `unrecognized_keys`\n * finding, so this always names the OBJECT the extra key was found on, never\n * the extra key itself. Structural introspection first, the curated list\n * second, `[]` (no suggestion offered — never a wrong-confident one) last.\n */\nexport function acceptedKeysAt(parentDotPath: string): readonly string[] {\n const root = asZodLike(IntegrationDefinitionSchema);\n const resolved = root\n ? resolveObjectAt(root, splitDotPath(parentDotPath))\n : null;\n\n if (resolved?.shape) return Object.keys(resolved.shape);\n\n return curatedKeysAt(parentDotPath) ?? [];\n}\n"]}
|
package/dist/exit-codes.d.ts
CHANGED
|
@@ -38,15 +38,15 @@ export type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];
|
|
|
38
38
|
* integer. One code per numeric exit that this taxonomy can emit.
|
|
39
39
|
*/
|
|
40
40
|
export declare const ERROR_CODES: {
|
|
41
|
-
readonly INTERNAL:
|
|
42
|
-
readonly USAGE:
|
|
43
|
-
readonly VALIDATION:
|
|
44
|
-
readonly AUTH_REQUIRED:
|
|
45
|
-
readonly FORBIDDEN:
|
|
46
|
-
readonly NOT_FOUND:
|
|
47
|
-
readonly INVALID_STATE:
|
|
48
|
-
readonly NETWORK:
|
|
49
|
-
readonly PRECONDITION_FAILED:
|
|
50
|
-
readonly GATE_FAILED:
|
|
41
|
+
readonly INTERNAL: 'internal';
|
|
42
|
+
readonly USAGE: 'usage';
|
|
43
|
+
readonly VALIDATION: 'validation';
|
|
44
|
+
readonly AUTH_REQUIRED: 'auth_required';
|
|
45
|
+
readonly FORBIDDEN: 'forbidden';
|
|
46
|
+
readonly NOT_FOUND: 'not_found';
|
|
47
|
+
readonly INVALID_STATE: 'invalid_state';
|
|
48
|
+
readonly NETWORK: 'network';
|
|
49
|
+
readonly PRECONDITION_FAILED: 'precondition_failed';
|
|
50
|
+
readonly GATE_FAILED: 'gate_failed';
|
|
51
51
|
};
|
|
52
52
|
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
@@ -134,7 +134,8 @@ function renderDetailLines(ui, detail) {
|
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
function buildGroupHeader(ui, group, opts) {
|
|
137
|
-
var _a
|
|
137
|
+
var _a;
|
|
138
|
+
var _b;
|
|
138
139
|
const errorCount = group.findings.filter((f) => f.severity === 'error').length;
|
|
139
140
|
const warnCount = group.findings.filter((f) => f.severity === 'warn').length;
|
|
140
141
|
const infoCount = group.findings.filter((f) => f.severity === 'info').length;
|
|
@@ -231,9 +232,10 @@ export function formatFindings(ui, findings, options = {}) {
|
|
|
231
232
|
group.findings.sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity]);
|
|
232
233
|
}
|
|
233
234
|
groups.sort((a, b) => {
|
|
234
|
-
var _a, _b
|
|
235
|
-
|
|
236
|
-
const
|
|
235
|
+
var _a, _b;
|
|
236
|
+
var _c, _d;
|
|
237
|
+
const worstA = SEVERITY_RANK[(_c = (_a = a.findings[0]) === null || _a === void 0 ? void 0 : _a.severity) !== null && _c !== void 0 ? _c : 'info'];
|
|
238
|
+
const worstB = SEVERITY_RANK[(_d = (_b = b.findings[0]) === null || _b === void 0 ? void 0 : _b.severity) !== null && _d !== void 0 ? _d : 'info'];
|
|
237
239
|
return worstA - worstB || a.order - b.order;
|
|
238
240
|
});
|
|
239
241
|
const blocks = groups.map((group) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findings-renderer.js","sourceRoot":"","sources":["../src/findings-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { CliContext } from './context';\nimport type { GateFinding } from './publish-api';\nimport { ENCLOSING_NOTE } from './source-locator';\nimport type { BadgeKind, Ui } from './ui';\n\n/**\n * The shared findings block: one rendering used by `validate` (a failed run),\n * `publish` (a gate refusal), and `status --findings`, so a partner sees the\n * exact same shape wherever a finding shows up. This is the ONLY findings\n * renderer in the package — nothing else may hand-format a `Finding`/\n * `GateFinding` array for a human.\n *\n * Deliberately structural rather than importing `Finding` or `GateFinding`\n * directly as the parameter type: both already satisfy this shape (their\n * extra/missing fields are all optional), and a structural type keeps this\n * module from caring which of the two ships that array.\n */\nexport interface RenderableFinding {\n check: string;\n severity: 'error' | 'warn' | 'info';\n file?: string;\n line?: number;\n message: string;\n hint: string;\n /** `'gate' | 'ci' | 'host' | 'revocation'` on the wire — see `GateFinding`. */\n origin?: string;\n createdAt?: string;\n resolvedAt?: string | null;\n /**\n * Optional multi-line supplement rendered directly under the finding's\n * message — currently only `ekanos test`'s curated failures appendix sets\n * this (an assertion diff). Additive: neither `Finding` nor `GateFinding`\n * carries it, so every pre-existing caller renders byte-identically to\n * before. Lines are shown as-is except a leading `-`/`+` (unified-diff\n * style), which is colored red/green respectively.\n */\n detail?: string;\n}\n\n// Compile-time proof the two real shapes this renders are both assignable.\nconst _typeCheck: (f: Finding | GateFinding) => RenderableFinding = (f) => f;\nvoid _typeCheck;\n\nexport interface RenderFindingsOptions {\n /** Findings shown per group before an overflow line takes over. Default 10. */\n maxPerGroup?: number;\n /** Base for resolving a finding's `file` before reading it for a codeframe. Default `process.cwd()`. */\n cwd?: string;\n /** Injectable for `relativeTime` snapshot tests. Default `new Date()`. */\n now?: Date;\n}\n\nconst DEFAULT_MAX_PER_GROUP = 10;\n\nconst SEVERITY_RANK: Record<RenderableFinding['severity'], number> = {\n error: 0,\n warn: 1,\n info: 2,\n};\n\ninterface Group {\n check: string;\n findings: RenderableFinding[];\n /** Insertion order, for a stable tie-break when sorting groups. */\n order: number;\n}\n\n/**\n * `relativeTime('2026-09-01T10:00:00Z')` → `\"2h ago\"`. Deliberately coarse\n * (rounds to the nearest unit, one unit at a time) — this is a findings-list\n * badge, not an audit-log timestamp, and a partner scanning for \"is this\n * recent\" doesn't need sub-minute precision.\n */\nexport function relativeTime(iso: string, now: Date = new Date()): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) return iso;\n\n const diffSec = Math.max(0, Math.round((now.getTime() - then) / 1000));\n\n if (diffSec < 5) return 'just now';\n if (diffSec < 60) return `${diffSec}s ago`;\n\n const diffMin = Math.round(diffSec / 60);\n if (diffMin < 60) return `${diffMin}m ago`;\n\n const diffHour = Math.round(diffMin / 60);\n if (diffHour < 24) return `${diffHour}h ago`;\n\n const diffDay = Math.round(diffHour / 24);\n if (diffDay < 30) return `${diffDay}d ago`;\n\n const diffMonth = Math.round(diffDay / 30);\n if (diffMonth < 12) return `${diffMonth}mo ago`;\n\n const diffYear = Math.round(diffMonth / 12);\n return `${diffYear}y ago`;\n}\n\n/**\n * A message beginning with a zod-style dot-path (`components.widgets[2].id: …`,\n * the shape `collectDefinitionFindings` produces — see the `Finding` doc\n * comment in `@ekanos/integration-schema`). Captures the path and the rest\n * separately so the renderer can dim the path instead of shouting the whole\n * sentence in one uniform color.\n */\nconst DOT_PATH_MESSAGE =\n /^([A-Za-z0-9_]+(?:\\.[A-Za-z0-9_]+|\\[\\d+\\])*): ([^]+)$/;\n\n/**\n * Render one finding's message: a leading dot-path identical to the\n * finding's own `file` is pure duplication (the path would just repeat what\n * `file:line` already told the reader) and is dropped; any other dot-path\n * prefix is kept but dimmed, so the sentence itself reads at full contrast.\n * A message with no dot-path prefix passes through untouched.\n *\n * A trailing `source-locator.ts` `ENCLOSING_NOTE` (plain text in the data —\n * see that module's doc comment on why it never carries color itself) is\n * peeled off before the dot-path handling above and dimmed on its own, then\n * reattached — so it stays visually secondary to the message itself in\n * exactly the case where the frame it accompanies points at the enclosing\n * object rather than the missing key.\n */\nfunction renderMessage(ui: Ui, finding: RenderableFinding): string {\n const enclosingSuffix = ` ${ENCLOSING_NOTE}`;\n const hasEnclosingNote = finding.message.endsWith(enclosingSuffix);\n const message = hasEnclosingNote\n ? finding.message.slice(0, -enclosingSuffix.length)\n : finding.message;\n\n const match = DOT_PATH_MESSAGE.exec(message);\n const rendered = (() => {\n if (!match) return message;\n\n const [, dotPath, rest] = match;\n if (dotPath === finding.file) return rest ?? message;\n\n return `${ui.dim(dotPath ?? '')}: ${rest ?? ''}`;\n })();\n\n return hasEnclosingNote ? `${rendered} ${ui.dim(ENCLOSING_NOTE)}` : rendered;\n}\n\nfunction severityColor(\n ui: Ui,\n severity: RenderableFinding['severity'],\n): (text: string) => string {\n if (severity === 'error') return ui.err;\n if (severity === 'warn') return ui.warn;\n return ui.dim;\n}\n\nfunction severityGlyph(\n ui: Ui,\n severity: RenderableFinding['severity'],\n): string {\n if (severity === 'warn') return ui.glyphs.warn;\n if (severity === 'info') return ui.glyphs.info;\n return ui.glyphs.err;\n}\n\nfunction ellipsis(ui: Ui): string {\n return ui.glyphs.ok === '✓' ? '…' : '...';\n}\n\n/** Attempts a codeframe for `finding`; `null` when it isn't renderable (no line, or the file can't be read locally). */\nfunction tryCodeframe(\n ui: Ui,\n finding: RenderableFinding,\n cwd: string,\n): string | null {\n if (finding.file === undefined || finding.line === undefined) return null;\n\n const resolved = path.resolve(cwd, finding.file);\n if (!fs.existsSync(resolved)) return null;\n\n try {\n const source = fs.readFileSync(resolved, 'utf8');\n return ui.codeframe({ file: finding.file, line: finding.line, source });\n } catch {\n // Best-effort decoration — an unreadable file (permissions, a race with\n // a concurrent edit) just means no codeframe, never a renderer failure.\n return null;\n }\n}\n\nfunction originBadgeKind(_origin: string): BadgeKind {\n return 'dim';\n}\n\n/**\n * Renders a finding's `detail` block, one line per source line: a\n * unified-diff `-` prefix is red, a `+` prefix is green, everything else\n * (context lines, \"Expected\"/\"Received\" headers, an overflow note) is dim.\n * `---`/`+++` file-header lines never appear here — `test-report.ts` never\n * emits them — but are guarded against anyway since this is the one place\n * that would mis-color them.\n */\nfunction renderDetailLines(ui: Ui, detail: string): string[] {\n return detail.split('\\n').map((line) => {\n if (line.startsWith('-') && !line.startsWith('---')) return ui.err(line);\n if (line.startsWith('+') && !line.startsWith('+++')) return ui.ok(line);\n return ui.dim(line);\n });\n}\n\nfunction buildGroupHeader(\n ui: Ui,\n group: Group,\n opts: Required<Pick<RenderFindingsOptions, 'now'>>,\n): string {\n const errorCount = group.findings.filter(\n (f) => f.severity === 'error',\n ).length;\n const warnCount = group.findings.filter((f) => f.severity === 'warn').length;\n const infoCount = group.findings.filter((f) => f.severity === 'info').length;\n\n const worst = group.findings[0]?.severity ?? 'info';\n const color = severityColor(ui, worst);\n const glyph = severityGlyph(ui, worst);\n\n const parts: string[] = [];\n if (errorCount > 0)\n parts.push(`${errorCount} error${errorCount === 1 ? '' : 's'}`);\n if (warnCount > 0)\n parts.push(`${warnCount} warning${warnCount === 1 ? '' : 's'}`);\n if (infoCount > 0) parts.push(`${infoCount} info`);\n\n // The representative for the group's origin badge is the first (i.e.\n // worst-severity, then earliest) finding that carries one — a check\n // almost always shares one origin, and this avoids a badge per line.\n const withOrigin = group.findings.find((f) => f.origin !== undefined);\n const badge =\n withOrigin?.origin === undefined\n ? ''\n : ` ${ui.badge(\n withOrigin.createdAt\n ? `${withOrigin.origin} · ${relativeTime(withOrigin.createdAt, opts.now)}`\n : withOrigin.origin,\n originBadgeKind(withOrigin.origin),\n )}`;\n\n return `${color(`${glyph} ${group.check}`)} · ${parts.join(', ')}${badge}`;\n}\n\nfunction buildGroupBody(\n ui: Ui,\n group: Group,\n opts: Required<Pick<RenderFindingsOptions, 'maxPerGroup' | 'cwd'>>,\n): string[] {\n const uniqueHints = [...new Set(group.findings.map((f) => f.hint))];\n const [firstHint] = uniqueHints;\n const dedupedHint =\n uniqueHints.length === 1 && firstHint !== undefined ? firstHint : null;\n\n const visible = group.findings.slice(0, opts.maxPerGroup);\n const overflow = group.findings.length - visible.length;\n\n const lines: string[] = [];\n let codeframeRendered = false;\n\n for (const finding of visible) {\n const location =\n finding.file !== undefined\n ? ui.accent(\n finding.line !== undefined\n ? `${finding.file}:${finding.line}`\n : finding.file,\n )\n : null;\n const message = renderMessage(ui, finding);\n\n lines.push(` ${ui.dim('│')}${location ? ` ${location}` : ''} ${message}`);\n\n if (finding.detail !== undefined) {\n lines.push(\n ...renderDetailLines(ui, finding.detail).map((line) => ` ${line}`),\n );\n }\n\n if (dedupedHint === null) {\n lines.push(` ${ui.hint(finding.hint)}`);\n }\n\n if (!codeframeRendered) {\n const frame = tryCodeframe(ui, finding, opts.cwd);\n if (frame !== null) {\n codeframeRendered = true;\n lines.push(\n frame\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n'),\n );\n }\n }\n }\n\n if (overflow > 0) {\n lines.push(\n ` ${ui.dim(`${ellipsis(ui)} and ${overflow} more in this group`)}`,\n );\n }\n\n if (dedupedHint !== null) {\n lines.push(` ${ui.hint(dedupedHint)}`);\n }\n\n return lines;\n}\n\n/**\n * Pure formatter — no I/O beyond an optional codeframe file read, no\n * printing. Kept separate from `renderFindings` so tests can assert exact\n * strings against a `Ui` built with a known color/glyph decision, without\n * constructing a full `CliContext`.\n */\nexport function formatFindings(\n ui: Ui,\n findings: readonly RenderableFinding[],\n options: RenderFindingsOptions = {},\n): string {\n if (findings.length === 0) return '';\n\n const maxPerGroup = options.maxPerGroup ?? DEFAULT_MAX_PER_GROUP;\n const cwd = options.cwd ?? process.cwd();\n const now = options.now ?? new Date();\n\n const groupsByCheck = new Map<string, Group>();\n findings.forEach((finding, index) => {\n const existing = groupsByCheck.get(finding.check);\n if (existing) {\n existing.findings.push(finding);\n return;\n }\n groupsByCheck.set(finding.check, {\n check: finding.check,\n findings: [finding],\n order: index,\n });\n });\n\n const groups = [...groupsByCheck.values()];\n for (const group of groups) {\n group.findings.sort(\n (a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity],\n );\n }\n groups.sort((a, b) => {\n const worstA = SEVERITY_RANK[a.findings[0]?.severity ?? 'info'];\n const worstB = SEVERITY_RANK[b.findings[0]?.severity ?? 'info'];\n return worstA - worstB || a.order - b.order;\n });\n\n const blocks = groups.map((group) => {\n const header = buildGroupHeader(ui, group, { now });\n const body = buildGroupBody(ui, group, { maxPerGroup, cwd });\n return [header, ...body].join('\\n');\n });\n\n const totalErrors = findings.filter((f) => f.severity === 'error').length;\n const totalWarnings = findings.filter((f) => f.severity === 'warn').length;\n const totalInfo = findings.filter((f) => f.severity === 'info').length;\n\n const summaryParts: string[] = [];\n if (totalErrors > 0)\n summaryParts.push(`${totalErrors} error${totalErrors === 1 ? '' : 's'}`);\n if (totalWarnings > 0)\n summaryParts.push(\n `${totalWarnings} warning${totalWarnings === 1 ? '' : 's'}`,\n );\n if (totalInfo > 0 && totalErrors === 0 && totalWarnings === 0) {\n summaryParts.push(`${totalInfo} info`);\n }\n\n const summaryColor =\n totalErrors > 0 ? ui.err : totalWarnings > 0 ? ui.warn : ui.dim;\n const summaryGlyph =\n totalErrors > 0\n ? ui.glyphs.err\n : totalWarnings > 0\n ? ui.glyphs.warn\n : ui.glyphs.info;\n const checksCount = groups.length;\n\n const summary = summaryColor(\n `${summaryGlyph} ${summaryParts.join(', ')} across ${checksCount} check${\n checksCount === 1 ? '' : 's'\n }`,\n );\n\n return [...blocks, summary].join('\\n\\n');\n}\n\n/** Render the shared findings block to `ctx`'s human-mode output (stderr). A no-op for an empty findings array. */\nexport function renderFindings(\n ctx: CliContext,\n findings: readonly RenderableFinding[],\n options: RenderFindingsOptions = {},\n): void {\n const block = formatFindings(ctx.ui, findings, options);\n if (block !== '') ctx.log(block);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"findings-renderer.js","sourceRoot":"","sources":["../src/findings-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { CliContext } from './context';\nimport type { GateFinding } from './publish-api';\nimport { ENCLOSING_NOTE } from './source-locator';\nimport type { BadgeKind, Ui } from './ui';\n\n/**\n * The shared findings block: one rendering used by `validate` (a failed run),\n * `publish` (a gate refusal), and `status --findings`, so a partner sees the\n * exact same shape wherever a finding shows up. This is the ONLY findings\n * renderer in the package — nothing else may hand-format a `Finding`/\n * `GateFinding` array for a human.\n *\n * Deliberately structural rather than importing `Finding` or `GateFinding`\n * directly as the parameter type: both already satisfy this shape (their\n * extra/missing fields are all optional), and a structural type keeps this\n * module from caring which of the two ships that array.\n */\nexport interface RenderableFinding {\n check: string;\n severity: 'error' | 'warn' | 'info';\n file?: string;\n line?: number;\n message: string;\n hint: string;\n /** `'gate' | 'ci' | 'host' | 'revocation'` on the wire — see `GateFinding`. */\n origin?: string;\n createdAt?: string;\n resolvedAt?: string | null;\n /**\n * Optional multi-line supplement rendered directly under the finding's\n * message — currently only `ekanos test`'s curated failures appendix sets\n * this (an assertion diff). Additive: neither `Finding` nor `GateFinding`\n * carries it, so every pre-existing caller renders byte-identically to\n * before. Lines are shown as-is except a leading `-`/`+` (unified-diff\n * style), which is colored red/green respectively.\n */\n detail?: string;\n}\n\n// Compile-time proof the two real shapes this renders are both assignable.\nconst _typeCheck: (f: Finding | GateFinding) => RenderableFinding = (f) => f;\nvoid _typeCheck;\n\nexport interface RenderFindingsOptions {\n /** Findings shown per group before an overflow line takes over. Default 10. */\n maxPerGroup?: number;\n /** Base for resolving a finding's `file` before reading it for a codeframe. Default `process.cwd()`. */\n cwd?: string;\n /** Injectable for `relativeTime` snapshot tests. Default `new Date()`. */\n now?: Date;\n}\n\nconst DEFAULT_MAX_PER_GROUP = 10;\n\nconst SEVERITY_RANK: Record<RenderableFinding['severity'], number> = {\n error: 0,\n warn: 1,\n info: 2,\n};\n\ninterface Group {\n check: string;\n findings: RenderableFinding[];\n /** Insertion order, for a stable tie-break when sorting groups. */\n order: number;\n}\n\n/**\n * `relativeTime('2026-09-01T10:00:00Z')` → `\"2h ago\"`. Deliberately coarse\n * (rounds to the nearest unit, one unit at a time) — this is a findings-list\n * badge, not an audit-log timestamp, and a partner scanning for \"is this\n * recent\" doesn't need sub-minute precision.\n */\nexport function relativeTime(iso: string, now: Date = new Date()): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) return iso;\n\n const diffSec = Math.max(0, Math.round((now.getTime() - then) / 1000));\n\n if (diffSec < 5) return 'just now';\n if (diffSec < 60) return `${diffSec}s ago`;\n\n const diffMin = Math.round(diffSec / 60);\n if (diffMin < 60) return `${diffMin}m ago`;\n\n const diffHour = Math.round(diffMin / 60);\n if (diffHour < 24) return `${diffHour}h ago`;\n\n const diffDay = Math.round(diffHour / 24);\n if (diffDay < 30) return `${diffDay}d ago`;\n\n const diffMonth = Math.round(diffDay / 30);\n if (diffMonth < 12) return `${diffMonth}mo ago`;\n\n const diffYear = Math.round(diffMonth / 12);\n return `${diffYear}y ago`;\n}\n\n/**\n * A message beginning with a zod-style dot-path (`components.widgets[2].id: …`,\n * the shape `collectDefinitionFindings` produces — see the `Finding` doc\n * comment in `@ekanos/integration-schema`). Captures the path and the rest\n * separately so the renderer can dim the path instead of shouting the whole\n * sentence in one uniform color.\n */\nconst DOT_PATH_MESSAGE =\n /^([A-Za-z0-9_]+(?:\\.[A-Za-z0-9_]+|\\[\\d+\\])*): ([^]+)$/;\n\n/**\n * Render one finding's message: a leading dot-path identical to the\n * finding's own `file` is pure duplication (the path would just repeat what\n * `file:line` already told the reader) and is dropped; any other dot-path\n * prefix is kept but dimmed, so the sentence itself reads at full contrast.\n * A message with no dot-path prefix passes through untouched.\n *\n * A trailing `source-locator.ts` `ENCLOSING_NOTE` (plain text in the data —\n * see that module's doc comment on why it never carries color itself) is\n * peeled off before the dot-path handling above and dimmed on its own, then\n * reattached — so it stays visually secondary to the message itself in\n * exactly the case where the frame it accompanies points at the enclosing\n * object rather than the missing key.\n */\nfunction renderMessage(ui: Ui, finding: RenderableFinding): string {\n const enclosingSuffix = ` ${ENCLOSING_NOTE}`;\n const hasEnclosingNote = finding.message.endsWith(enclosingSuffix);\n const message = hasEnclosingNote\n ? finding.message.slice(0, -enclosingSuffix.length)\n : finding.message;\n\n const match = DOT_PATH_MESSAGE.exec(message);\n const rendered = (() => {\n if (!match) return message;\n\n const [, dotPath, rest] = match;\n if (dotPath === finding.file) return rest ?? message;\n\n return `${ui.dim(dotPath ?? '')}: ${rest ?? ''}`;\n })();\n\n return hasEnclosingNote ? `${rendered} ${ui.dim(ENCLOSING_NOTE)}` : rendered;\n}\n\nfunction severityColor(\n ui: Ui,\n severity: RenderableFinding['severity'],\n): (text: string) => string {\n if (severity === 'error') return ui.err;\n if (severity === 'warn') return ui.warn;\n return ui.dim;\n}\n\nfunction severityGlyph(\n ui: Ui,\n severity: RenderableFinding['severity'],\n): string {\n if (severity === 'warn') return ui.glyphs.warn;\n if (severity === 'info') return ui.glyphs.info;\n return ui.glyphs.err;\n}\n\nfunction ellipsis(ui: Ui): string {\n return ui.glyphs.ok === '✓' ? '…' : '...';\n}\n\n/** Attempts a codeframe for `finding`; `null` when it isn't renderable (no line, or the file can't be read locally). */\nfunction tryCodeframe(\n ui: Ui,\n finding: RenderableFinding,\n cwd: string,\n): string | null {\n if (finding.file === undefined || finding.line === undefined) return null;\n\n const resolved = path.resolve(cwd, finding.file);\n if (!fs.existsSync(resolved)) return null;\n\n try {\n const source = fs.readFileSync(resolved, 'utf8');\n return ui.codeframe({ file: finding.file, line: finding.line, source });\n } catch {\n // Best-effort decoration — an unreadable file (permissions, a race with\n // a concurrent edit) just means no codeframe, never a renderer failure.\n return null;\n }\n}\n\nfunction originBadgeKind(_origin: string): BadgeKind {\n return 'dim';\n}\n\n/**\n * Renders a finding's `detail` block, one line per source line: a\n * unified-diff `-` prefix is red, a `+` prefix is green, everything else\n * (context lines, \"Expected\"/\"Received\" headers, an overflow note) is dim.\n * `---`/`+++` file-header lines never appear here — `test-report.ts` never\n * emits them — but are guarded against anyway since this is the one place\n * that would mis-color them.\n */\nfunction renderDetailLines(ui: Ui, detail: string): string[] {\n return detail.split('\\n').map((line) => {\n if (line.startsWith('-') && !line.startsWith('---')) return ui.err(line);\n if (line.startsWith('+') && !line.startsWith('+++')) return ui.ok(line);\n return ui.dim(line);\n });\n}\n\nfunction buildGroupHeader(\n ui: Ui,\n group: Group,\n opts: Required<Pick<RenderFindingsOptions, 'now'>>,\n): string {\n const errorCount = group.findings.filter(\n (f) => f.severity === 'error',\n ).length;\n const warnCount = group.findings.filter((f) => f.severity === 'warn').length;\n const infoCount = group.findings.filter((f) => f.severity === 'info').length;\n\n const worst = group.findings[0]?.severity ?? 'info';\n const color = severityColor(ui, worst);\n const glyph = severityGlyph(ui, worst);\n\n const parts: string[] = [];\n if (errorCount > 0)\n parts.push(`${errorCount} error${errorCount === 1 ? '' : 's'}`);\n if (warnCount > 0)\n parts.push(`${warnCount} warning${warnCount === 1 ? '' : 's'}`);\n if (infoCount > 0) parts.push(`${infoCount} info`);\n\n // The representative for the group's origin badge is the first (i.e.\n // worst-severity, then earliest) finding that carries one — a check\n // almost always shares one origin, and this avoids a badge per line.\n const withOrigin = group.findings.find((f) => f.origin !== undefined);\n const badge =\n withOrigin?.origin === undefined\n ? ''\n : ` ${ui.badge(\n withOrigin.createdAt\n ? `${withOrigin.origin} · ${relativeTime(withOrigin.createdAt, opts.now)}`\n : withOrigin.origin,\n originBadgeKind(withOrigin.origin),\n )}`;\n\n return `${color(`${glyph} ${group.check}`)} · ${parts.join(', ')}${badge}`;\n}\n\nfunction buildGroupBody(\n ui: Ui,\n group: Group,\n opts: Required<Pick<RenderFindingsOptions, 'maxPerGroup' | 'cwd'>>,\n): string[] {\n const uniqueHints = [...new Set(group.findings.map((f) => f.hint))];\n const [firstHint] = uniqueHints;\n const dedupedHint =\n uniqueHints.length === 1 && firstHint !== undefined ? firstHint : null;\n\n const visible = group.findings.slice(0, opts.maxPerGroup);\n const overflow = group.findings.length - visible.length;\n\n const lines: string[] = [];\n let codeframeRendered = false;\n\n for (const finding of visible) {\n const location =\n finding.file !== undefined\n ? ui.accent(\n finding.line !== undefined\n ? `${finding.file}:${finding.line}`\n : finding.file,\n )\n : null;\n const message = renderMessage(ui, finding);\n\n lines.push(` ${ui.dim('│')}${location ? ` ${location}` : ''} ${message}`);\n\n if (finding.detail !== undefined) {\n lines.push(\n ...renderDetailLines(ui, finding.detail).map((line) => ` ${line}`),\n );\n }\n\n if (dedupedHint === null) {\n lines.push(` ${ui.hint(finding.hint)}`);\n }\n\n if (!codeframeRendered) {\n const frame = tryCodeframe(ui, finding, opts.cwd);\n if (frame !== null) {\n codeframeRendered = true;\n lines.push(\n frame\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n'),\n );\n }\n }\n }\n\n if (overflow > 0) {\n lines.push(\n ` ${ui.dim(`${ellipsis(ui)} and ${overflow} more in this group`)}`,\n );\n }\n\n if (dedupedHint !== null) {\n lines.push(` ${ui.hint(dedupedHint)}`);\n }\n\n return lines;\n}\n\n/**\n * Pure formatter — no I/O beyond an optional codeframe file read, no\n * printing. Kept separate from `renderFindings` so tests can assert exact\n * strings against a `Ui` built with a known color/glyph decision, without\n * constructing a full `CliContext`.\n */\nexport function formatFindings(\n ui: Ui,\n findings: readonly RenderableFinding[],\n options: RenderFindingsOptions = {},\n): string {\n if (findings.length === 0) return '';\n\n const maxPerGroup = options.maxPerGroup ?? DEFAULT_MAX_PER_GROUP;\n const cwd = options.cwd ?? process.cwd();\n const now = options.now ?? new Date();\n\n const groupsByCheck = new Map<string, Group>();\n findings.forEach((finding, index) => {\n const existing = groupsByCheck.get(finding.check);\n if (existing) {\n existing.findings.push(finding);\n return;\n }\n groupsByCheck.set(finding.check, {\n check: finding.check,\n findings: [finding],\n order: index,\n });\n });\n\n const groups = [...groupsByCheck.values()];\n for (const group of groups) {\n group.findings.sort(\n (a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity],\n );\n }\n groups.sort((a, b) => {\n const worstA = SEVERITY_RANK[a.findings[0]?.severity ?? 'info'];\n const worstB = SEVERITY_RANK[b.findings[0]?.severity ?? 'info'];\n return worstA - worstB || a.order - b.order;\n });\n\n const blocks = groups.map((group) => {\n const header = buildGroupHeader(ui, group, { now });\n const body = buildGroupBody(ui, group, { maxPerGroup, cwd });\n return [header, ...body].join('\\n');\n });\n\n const totalErrors = findings.filter((f) => f.severity === 'error').length;\n const totalWarnings = findings.filter((f) => f.severity === 'warn').length;\n const totalInfo = findings.filter((f) => f.severity === 'info').length;\n\n const summaryParts: string[] = [];\n if (totalErrors > 0)\n summaryParts.push(`${totalErrors} error${totalErrors === 1 ? '' : 's'}`);\n if (totalWarnings > 0)\n summaryParts.push(\n `${totalWarnings} warning${totalWarnings === 1 ? '' : 's'}`,\n );\n if (totalInfo > 0 && totalErrors === 0 && totalWarnings === 0) {\n summaryParts.push(`${totalInfo} info`);\n }\n\n const summaryColor =\n totalErrors > 0 ? ui.err : totalWarnings > 0 ? ui.warn : ui.dim;\n const summaryGlyph =\n totalErrors > 0\n ? ui.glyphs.err\n : totalWarnings > 0\n ? ui.glyphs.warn\n : ui.glyphs.info;\n const checksCount = groups.length;\n\n const summary = summaryColor(\n `${summaryGlyph} ${summaryParts.join(', ')} across ${checksCount} check${\n checksCount === 1 ? '' : 's'\n }`,\n );\n\n return [...blocks, summary].join('\\n\\n');\n}\n\n/** Render the shared findings block to `ctx`'s human-mode output (stderr). A no-op for an empty findings array. */\nexport function renderFindings(\n ctx: CliContext,\n findings: readonly RenderableFinding[],\n options: RenderFindingsOptions = {},\n): void {\n const block = formatFindings(ctx.ui, findings, options);\n if (block !== '') ctx.log(block);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const FA_FREE_VERSION = "7.3.1";
|
|
2
|
-
/** Every icon name Font Awesome Free ships — NOT
|
|
2
|
+
/** Every icon name Font Awesome Free ships — NOT Ekanos's set (Pro, a superset). */
|
|
3
3
|
export declare const FA_FREE_ICON_NAMES: ReadonlySet<string>;
|
|
4
4
|
/**
|
|
5
5
|
* Hand-curated Pro-only name → nearest Free alternative, sourced from
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// Regenerated by this package's generate-fa-free-names script; drift against
|
|
15
15
|
// the host's icon set is pinned by fa-free-names-drift.test.ts.
|
|
16
16
|
export const FA_FREE_VERSION = '7.3.1';
|
|
17
|
-
/** Every icon name Font Awesome Free ships — NOT
|
|
17
|
+
/** Every icon name Font Awesome Free ships — NOT Ekanos's set (Pro, a superset). */
|
|
18
18
|
export const FA_FREE_ICON_NAMES = new Set([
|
|
19
19
|
'11ty',
|
|
20
20
|
'42-group',
|