@ekanos/cli 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAiB9C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAe,EACf,IAAe;;IAEf,0EAA0E;IAC1E,0EAA0E;IAC1E,qEAAqE;IACrE,yEAAyE;IACzE,yEAAyE;IACzE,0EAA0E;IAC1E,uDAAuD;IACvD,MAAM,GAAG,GAAG,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IAClE,IAAI,SAAS;QAAE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAE/C,IAAI,QAAQ,EAAE,CAAC;gBACb,WAAW,CAAC,GAAG,CAAC,CAAC;gBAEjB,MAAM,KAAK,SAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,mCAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtD,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,CAAC,KAAK,CACV,wBAAwB,KAAK,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAC3D,CAAC;gBACJ,CAAC;gBAED,OAAO,GAAG,CAAC,OAAO,CAChB;oBACE,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,uBAAuB;oBAC/B,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,eAAe,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ;iBACpC,EACD,SAAS;oBACP,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;wBACZ,KAAK,EAAE,mBAAmB;wBAC1B,IAAI,EAAE;4BACJ,CAAC,SAAS,EAAE,KAAK,CAAC;4BAClB,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;yBAC9B;qBACF,CAAC,CACP,CAAC;YACJ,CAAC;YAED,GAAG,CAAC,GAAG,CACL,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,uDAAuD,CAAC,CACpE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,OAAO,SACX,aAAa,CAAC,uBAAuB,mCAAI,aAAa,CAAC,eAAe,CAAC;IAEzE,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,CAAC,UAAU,OAAO,EAAE,EAAE,UAAU,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC5E,IAAI,aAAa,CAAC,uBAAuB,EAAE,CAAC;YAC1C,SAAS,CAAC,IAAI,CACZ,iCAAiC,aAAa,CAAC,eAAe,GAAG,CAClE,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,YAAY,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE9C,IAAI,aAAa,CAAC,uBAAuB,EAAE,CAAC;YAC1C,GAAG,CAAC,GAAG,CACL,mCAAmC,aAAa,CAAC,eAAe,GAAG,CACpE,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAExE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,CAAC,sBAAsB,MAAA,OAAO,CAAC,KAAK,mCAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvE,MAAM,MAAM,GAAkB;QAC5B,iBAAiB,EAAE,MAAM,CAAC,YAAY;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAElC,WAAW,CAAC,GAAG,CAAC,CAAC;IAEjB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CACV,gBAAgB,MAAA,OAAO,CAAC,KAAK,mCAAI,OAAO,CAAC,MAAM,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAC7E,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC,OAAO,CAChB;QACE,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,eAAe;QACvB,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;QAClD,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,eAAe,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ;KACpC,EACD,SAAS;QACP,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;YACZ,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE;gBACJ,CAAC,SAAS,QAAE,OAAO,CAAC,KAAK,mCAAI,OAAO,CAAC,MAAM,CAAC;gBAC5C,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;aAC9B;SACF,CAAC,CACP,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,QAAQ,CACrB,GAA8C,EAC9C,QAAuB;IAKvB,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEnE,OAAO;YACL,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE;YAChD,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,aAAa,CAAC;AAC/E,CAAC","sourcesContent":["import type { StoredSession } from '../auth/credential-store';\nimport {\n pollForDeviceTokens,\n startDeviceAuthorization,\n} from '../auth/device-flow';\nimport { createEkanosSession, fetchCliAuthConfig } from '../auth/ekanos-api';\nimport { resolveAuthEnvironment, resolveIdentity } from '../auth/session';\nimport { printBanner } from '../banner';\nimport type { CliContext } from '../context';\nimport { CliError } from '../errors';\nimport { ERROR_CODES } from '../exit-codes';\nimport type { ExitCode } from '../exit-codes';\nimport { shortHost } from '../ui';\nimport { canWizard, wizard } from '../wizard';\n\nexport interface LoginArgs {\n host?: string;\n /** Start a new browser login even if a working session is already stored. */\n force: boolean;\n /** Where a project's ekanos.json may sit — read-only here, never written. */\n cwd: string;\n env: Record<string, string | undefined>;\n /**\n * Test-only override for the clack wizard gate (`canWizard` in\n * `wizard.ts`) — never set from real CLI wiring. See `RunOptions` in\n * `index.ts`.\n */\n stdinIsTTY?: boolean;\n}\n\n/**\n * `login` — authenticate this machine against an Ekanos deployment via the\n * Auth0 device authorization flow.\n *\n * Idempotent: with a stored session that still authenticates, it reports that\n * and exits 0 without opening a browser. `--force` skips the check.\n *\n * The user code and verification URL go to STDERR. They have to be visible\n * even when stdout is a pipe into an agent, and stdout in this CLI carries\n * exactly one JSON object.\n *\n * In human mode at a real TTY (`canWizard`), this runs behind a clack\n * `intro`/`outro` flow with a spinner over the approval wait — see\n * `wizard.ts`. The device code and URL themselves stay plain, copy-pasteable\n * text (a clack `note`, not a prompt) either way: a partner needs to select\n * and open them, not interact with them through clack. JSON mode and human\n * non-TTY mode are byte-for-byte what they were before this existed.\n */\nexport async function runLogin(\n ctx: CliContext,\n args: LoginArgs,\n): Promise<ExitCode> {\n // No `projectDir`: login is the one verb that CREATES credentials, so its\n // host must come from something the developer chose (--host, EKANOS_HOST)\n // or already trusts (the sole stored login) — never from a committed\n // ekanos.json, which an attacker can set in any cloned repo to point the\n // device flow at their own tenant. Every other verb may read the project\n // host because their bearer tokens are looked up per-host from the store:\n // an unfamiliar host simply has no session to present.\n const env = resolveAuthEnvironment(ctx, args.host, args.env);\n\n const useWizard = canWizard(ctx, { stdinIsTTY: args.stdinIsTTY });\n if (useWizard) wizard.intro('ekanos login');\n\n if (!args.force) {\n const existing = env.store.read(env.host);\n\n if (existing) {\n const reusable = await tryReuse(env, existing);\n\n if (reusable) {\n printBanner(ctx);\n\n const email = reusable.user.email ?? reusable.user.id;\n if (useWizard) {\n wizard.outro(\n `Already signed in as ${email} on ${shortHost(env.host)}.`,\n );\n }\n\n return ctx.succeed(\n {\n host: env.host,\n status: 'already-authenticated',\n user: reusable.user,\n expiresAt: reusable.expiresAt,\n credentialsPath: env.store.filePath,\n },\n useWizard\n ? ''\n : ctx.ui.result({\n title: 'Already signed in',\n rows: [\n ['Account', email],\n ['Host', shortHost(env.host)],\n ],\n }),\n );\n }\n\n ctx.log(\n ctx.ui.dim('The stored session has expired. Starting a new login…'),\n );\n }\n }\n\n const config = await fetchCliAuthConfig(env.host);\n const authorization = await startDeviceAuthorization(config);\n const openUrl =\n authorization.verificationUriComplete ?? authorization.verificationUri;\n\n if (useWizard) {\n const noteLines = [`Open: ${openUrl}`, `Code: ${authorization.userCode}`];\n if (authorization.verificationUriComplete) {\n noteLines.push(\n `(without the pre-filled code: ${authorization.verificationUri})`,\n );\n }\n wizard.note(noteLines.join('\\n'), 'Device login');\n } else {\n ctx.log('');\n ctx.log(` Open: ${openUrl}`);\n ctx.log(` Code: ${authorization.userCode}`);\n\n if (authorization.verificationUriComplete) {\n ctx.log(\n ` (without the pre-filled code: ${authorization.verificationUri})`,\n );\n }\n\n ctx.log('');\n ctx.log('Waiting for approval…');\n }\n\n const spinner = useWizard ? wizard.spinner() : null;\n spinner?.start('Waiting for approval…');\n\n const tokens = await pollForDeviceTokens(config, authorization);\n const session = await createEkanosSession(env.host, tokens.accessToken);\n\n spinner?.stop(`✓ authenticated as ${session.email ?? session.userId}`);\n\n const stored: StoredSession = {\n auth0RefreshToken: tokens.refreshToken,\n accessToken: session.accessToken,\n expiresAt: session.expiresAt,\n userId: session.userId,\n email: session.email,\n updatedAt: new Date().toISOString(),\n };\n\n env.store.write(env.host, stored);\n\n printBanner(ctx);\n\n if (useWizard) {\n wizard.outro(\n `Signed in as ${session.email ?? session.userId} on ${shortHost(env.host)}.`,\n );\n }\n\n return ctx.succeed(\n {\n host: env.host,\n status: 'authenticated',\n user: { id: session.userId, email: session.email },\n expiresAt: session.expiresAt,\n credentialsPath: env.store.filePath,\n },\n useWizard\n ? ''\n : ctx.ui.result({\n title: 'Signed in',\n rows: [\n ['Account', session.email ?? session.userId],\n ['Host', shortHost(env.host)],\n ],\n }),\n );\n}\n\n/**\n * Probe a stored session. Returns null when it cannot be revived, so `login`\n * falls through to a fresh device flow rather than failing — \"log in again\"\n * is the whole point of the command being run.\n *\n * Only auth failures are absorbed. A network or configuration error still\n * propagates: silently starting a browser login because the host was\n * unreachable would be the wrong recovery, and would hide the real fault.\n */\nasync function tryReuse(\n env: ReturnType<typeof resolveAuthEnvironment>,\n existing: StoredSession,\n): Promise<{\n user: { id: string; email: string | null };\n expiresAt: string;\n} | null> {\n try {\n const { identity, session } = await resolveIdentity(env, existing);\n\n return {\n user: { id: identity.id, email: identity.email },\n expiresAt: session.expiresAt,\n };\n } catch (error) {\n if (isAuthFailure(error)) {\n return null;\n }\n\n throw error;\n }\n}\n\nfunction isAuthFailure(error: unknown): boolean {\n return error instanceof CliError && error.code === ERROR_CODES.AUTH_REQUIRED;\n}\n"]}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StoredSession } from '../auth/credential-store';\nimport {\n pollForDeviceTokens,\n startDeviceAuthorization,\n} from '../auth/device-flow';\nimport { createEkanosSession, fetchCliAuthConfig } from '../auth/ekanos-api';\nimport { resolveAuthEnvironment, resolveIdentity } from '../auth/session';\nimport { printBanner } from '../banner';\nimport { claudeDocsRow, offerDocsToClaude } from '../claude-docs';\nimport type { CliContext } from '../context';\nimport { CliError } from '../errors';\nimport { ERROR_CODES } from '../exit-codes';\nimport type { ExitCode } from '../exit-codes';\nimport { shortHost } from '../ui';\nimport { canWizard, wizard } from '../wizard';\nimport { promptYesNo } from './publish';\n\nexport interface LoginArgs {\n host?: string;\n /** Start a new browser login even if a working session is already stored. */\n force: boolean;\n /** Where a project's ekanos.json may sit — read-only here, never written. */\n cwd: string;\n env: Record<string, string | undefined>;\n /**\n * Test-only override for the clack wizard gate (`canWizard` in\n * `wizard.ts`) — never set from real CLI wiring. See `RunOptions` in\n * `index.ts`.\n */\n stdinIsTTY?: boolean;\n /** `--claude` adds the Ekanos docs to Claude Code without asking; `--no-claude` skips the offer. */\n claude?: boolean;\n /** Test seam for the Claude Code offer's question. */\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/**\n * `login` — authenticate this machine against an Ekanos deployment via the\n * Auth0 device authorization flow.\n *\n * Idempotent: with a stored session that still authenticates, it reports that\n * and exits 0 without opening a browser. `--force` skips the check.\n *\n * The user code and verification URL go to STDERR. They have to be visible\n * even when stdout is a pipe into an agent, and stdout in this CLI carries\n * exactly one JSON object.\n *\n * In human mode at a real TTY (`canWizard`), this runs behind a clack\n * `intro`/`outro` flow with a spinner over the approval wait — see\n * `wizard.ts`. The device code and URL themselves stay plain, copy-pasteable\n * text (a clack `note`, not a prompt) either way: a partner needs to select\n * and open them, not interact with them through clack. JSON mode and human\n * non-TTY mode are byte-for-byte what they were before this existed.\n */\nexport async function runLogin(\n ctx: CliContext,\n args: LoginArgs,\n): Promise<ExitCode> {\n // No `projectDir`: login is the one verb that CREATES credentials, so its\n // host must come from something the developer chose (--host, EKANOS_HOST)\n // or already trusts (the sole stored login) — never from a committed\n // ekanos.json, which an attacker can set in any cloned repo to point the\n // device flow at their own tenant. Every other verb may read the project\n // host because their bearer tokens are looked up per-host from the store:\n // an unfamiliar host simply has no session to present.\n const env = resolveAuthEnvironment(ctx, args.host, args.env);\n\n const useWizard = canWizard(ctx, { stdinIsTTY: args.stdinIsTTY });\n if (useWizard) wizard.intro('ekanos login');\n\n if (!args.force) {\n const existing = env.store.read(env.host);\n\n if (existing) {\n const reusable = await tryReuse(env, existing);\n\n if (reusable) {\n printBanner(ctx);\n\n const email = reusable.user.email ?? reusable.user.id;\n if (useWizard) {\n wizard.outro(\n `Already signed in as ${email} on ${shortHost(env.host)}.`,\n );\n }\n\n return ctx.succeed(\n {\n host: env.host,\n status: 'already-authenticated',\n user: reusable.user,\n expiresAt: reusable.expiresAt,\n credentialsPath: env.store.filePath,\n },\n useWizard\n ? ''\n : ctx.ui.result({\n title: 'Already signed in',\n rows: [\n ['Account', email],\n ['Host', shortHost(env.host)],\n ],\n }),\n );\n }\n\n ctx.log(\n ctx.ui.dim('The stored session has expired. Starting a new login…'),\n );\n }\n }\n\n const config = await fetchCliAuthConfig(env.host);\n const authorization = await startDeviceAuthorization(config);\n const openUrl =\n authorization.verificationUriComplete ?? authorization.verificationUri;\n\n if (useWizard) {\n const noteLines = [`Open: ${openUrl}`, `Code: ${authorization.userCode}`];\n if (authorization.verificationUriComplete) {\n noteLines.push(\n `(without the pre-filled code: ${authorization.verificationUri})`,\n );\n }\n wizard.note(noteLines.join('\\n'), 'Device login');\n } else {\n ctx.log('');\n ctx.log(` Open: ${openUrl}`);\n ctx.log(` Code: ${authorization.userCode}`);\n\n if (authorization.verificationUriComplete) {\n ctx.log(\n ` (without the pre-filled code: ${authorization.verificationUri})`,\n );\n }\n\n ctx.log('');\n ctx.log('Waiting for approval…');\n }\n\n const spinner = useWizard ? wizard.spinner() : null;\n spinner?.start('Waiting for approval…');\n\n const tokens = await pollForDeviceTokens(config, authorization);\n const session = await createEkanosSession(env.host, tokens.accessToken);\n\n spinner?.stop(`✓ authenticated as ${session.email ?? session.userId}`);\n\n const stored: StoredSession = {\n auth0RefreshToken: tokens.refreshToken,\n accessToken: session.accessToken,\n expiresAt: session.expiresAt,\n userId: session.userId,\n email: session.email,\n updatedAt: new Date().toISOString(),\n };\n\n env.store.write(env.host, stored);\n\n // A first sign-in is when a developer is setting up: offer the docs to\n // Claude Code once, so it can look Ekanos up instead of guessing.\n const claudeDocs = await offerDocsToClaude({\n choice: args.claude,\n canPrompt:\n !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true),\n confirm: args.confirm ?? promptYesNo,\n env: args.env,\n });\n const claudeRow = claudeDocsRow(claudeDocs);\n\n printBanner(ctx);\n\n if (useWizard) {\n wizard.outro(\n `Signed in as ${session.email ?? session.userId} on ${shortHost(env.host)}.`,\n );\n }\n\n return ctx.succeed(\n {\n host: env.host,\n status: 'authenticated',\n user: { id: session.userId, email: session.email },\n expiresAt: session.expiresAt,\n credentialsPath: env.store.filePath,\n claudeDocs,\n },\n useWizard\n ? ''\n : ctx.ui.result({\n title: 'Signed in',\n rows: [\n ['Account', session.email ?? session.userId],\n ['Host', shortHost(env.host)],\n ...(claudeRow ? [claudeRow] : []),\n ],\n }),\n );\n}\n\n/**\n * Probe a stored session. Returns null when it cannot be revived, so `login`\n * falls through to a fresh device flow rather than failing — \"log in again\"\n * is the whole point of the command being run.\n *\n * Only auth failures are absorbed. A network or configuration error still\n * propagates: silently starting a browser login because the host was\n * unreachable would be the wrong recovery, and would hide the real fault.\n */\nasync function tryReuse(\n env: ReturnType<typeof resolveAuthEnvironment>,\n existing: StoredSession,\n): Promise<{\n user: { id: string; email: string | null };\n expiresAt: string;\n} | null> {\n try {\n const { identity, session } = await resolveIdentity(env, existing);\n\n return {\n user: { id: identity.id, email: identity.email },\n expiresAt: session.expiresAt,\n };\n } catch (error) {\n if (isAuthFailure(error)) {\n return null;\n }\n\n throw error;\n }\n}\n\nfunction isAuthFailure(error: unknown): boolean {\n return error instanceof CliError && error.code === ERROR_CODES.AUTH_REQUIRED;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,9 @@ export interface RunOptions {
16
16
  */
17
17
  stdinIsTTY?: boolean;
18
18
  confirm?: (question: string) => Promise<boolean>;
19
+ /** Test-only answers for `apps set`'s questions — never set from real CLI wiring. */
20
+ ask?: (question: string) => Promise<string>;
21
+ askSecret?: (question: string) => Promise<string>;
19
22
  /**
20
23
  * Test-only override for `status --watch`'s poll delay — see `StatusArgs`
21
24
  * in `commands/status.ts`. Never set this from real CLI wiring; it exists
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import { runAgents } from './commands/agents.js';
3
+ import { runApps } from './commands/apps.js';
3
4
  import { runCatalog } from './commands/catalog.js';
4
5
  import { runDev } from './commands/dev.js';
5
6
  import { runInit } from './commands/init.js';
@@ -56,6 +57,7 @@ const COMMAND_SPECS = {
56
57
  login: {
57
58
  host: { type: 'string' },
58
59
  force: { type: 'boolean' },
60
+ claude: { type: 'boolean' },
59
61
  },
60
62
  logout: {
61
63
  host: { type: 'string' },
@@ -80,6 +82,11 @@ const COMMAND_SPECS = {
80
82
  source: { type: 'string' },
81
83
  dir: { type: 'string' },
82
84
  },
85
+ apps: {
86
+ host: { type: 'string' },
87
+ source: { type: 'string' },
88
+ dir: { type: 'string' },
89
+ },
83
90
  agents: {
84
91
  host: { type: 'string' },
85
92
  source: { type: 'string' },
@@ -91,6 +98,7 @@ const COMMAND_SPECS = {
91
98
  out: { type: 'string' },
92
99
  yes: { type: 'boolean' },
93
100
  force: { type: 'boolean' },
101
+ claude: { type: 'boolean' },
94
102
  },
95
103
  use: {
96
104
  host: { type: 'string' },
@@ -116,6 +124,7 @@ const COMMAND_SPECS = {
116
124
  const POSITIONAL_COMMANDS = {
117
125
  use: ['source-slug'],
118
126
  catalog: ['product-slug'],
127
+ apps: ['subcommand', 'product-slug'],
119
128
  agents: ['subcommand', 'key-or-path'],
120
129
  };
121
130
  const COMMANDS = Object.keys(COMMAND_SPECS);
@@ -130,7 +139,8 @@ const USAGE = [
130
139
  ' For a vitest test script, also renders a curated failures',
131
140
  ' appendix from a JSON reporter report; --raw skips that and',
132
141
  ' the reporter injection entirely.',
133
- ' login Authenticate against an Ekanos host in a browser (--host <url>)',
142
+ ' login Authenticate against an Ekanos host in a browser (--host <url>;',
143
+ ' offers to add the Ekanos docs to Claude Code: --claude|--no-claude)',
134
144
  ' logout Revoke and delete the stored session (--host <url> | --all)',
135
145
  ' whoami Print the identity the stored session authenticates as, plus',
136
146
  ' a compact list of the sources you hold a seat on',
@@ -141,8 +151,12 @@ const USAGE = [
141
151
  ' sources List every source you hold a developer/source-admin seat on',
142
152
  ' catalog What a source can already use, and how to set it up',
143
153
  ' ("ekanos catalog [<product-slug>] --source <slug>", --json)',
154
+ " apps The Source's app for an integration teams sign in through:",
155
+ ' show <product> | set <product> (Source admin; takes the secret',
156
+ ' at your terminal)',
144
157
  " agents The source's agent templates, held by Ekanos:",
145
- ' init [<dir>] (skills + docs MCP for designing agents with Claude)',
158
+ ' init [<dir>] [--claude|--no-claude] (skills + docs MCP for designing',
159
+ ' agents with Claude; offers to add the docs to Claude Code)',
146
160
  ' list | show <key> | pull <key> [--out <dir>]',
147
161
  ' apply <dir|file> [--base-version <n>] [--overwrite]',
148
162
  ' publish <key> [--to <n>] --yes | rollback <key> --to <n> --yes',
@@ -160,7 +174,7 @@ const USAGE = [
160
174
  ' bare "ekanos upgrade" MUTATES the project (installs the target versions,',
161
175
  ' verifies with validate + the test script, rolls back on any failure).',
162
176
  '',
163
- 'Host resolution (logout, whoami, status, sources, catalog, agents, use, publish, upgrade):',
177
+ 'Host resolution (logout, whoami, status, sources, catalog, apps, agents, use, publish, upgrade):',
164
178
  ' --host, else EKANOS_HOST, else the "host" field in ekanos.json, else the',
165
179
  ' sole stored login. "ekanos publish" saves host and source to ekanos.json.',
166
180
  ' "ekanos login" never reads ekanos.json for a host (--host, else',
@@ -276,6 +290,7 @@ export async function run(argv, options = {}) {
276
290
  return await runLogin(ctx, {
277
291
  host: parsed.flags.host,
278
292
  force: parsed.flags.force === true,
293
+ claude: parsed.flags.claude,
279
294
  cwd,
280
295
  env,
281
296
  stdinIsTTY: options.stdinIsTTY,
@@ -318,6 +333,19 @@ export async function run(argv, options = {}) {
318
333
  dir,
319
334
  env,
320
335
  });
336
+ case 'apps':
337
+ return await runApps(ctx, {
338
+ host: parsed.flags.host,
339
+ source: parsed.flags.source,
340
+ subcommand: parsed.positionals[0],
341
+ product: parsed.positionals[1],
342
+ dir,
343
+ env,
344
+ stdinIsTTY: options.stdinIsTTY,
345
+ ask: options.ask,
346
+ askSecret: options.askSecret,
347
+ confirm: options.confirm,
348
+ });
321
349
  case 'agents':
322
350
  return await runAgents(ctx, {
323
351
  host: parsed.flags.host,
@@ -330,6 +358,7 @@ export async function run(argv, options = {}) {
330
358
  out: parsed.flags.out,
331
359
  yes: parsed.flags.yes === true,
332
360
  force: parsed.flags.force === true,
361
+ claude: parsed.flags.claude,
333
362
  dir,
334
363
  env,
335
364
  stdinIsTTY: options.stdinIsTTY,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\n\nimport { runAgents } from './commands/agents';\nimport { runCatalog } from './commands/catalog';\nimport { runDev } from './commands/dev';\nimport { runInit } from './commands/init';\nimport { runLogin } from './commands/login';\nimport { runLogout } from './commands/logout';\nimport { runPublish } from './commands/publish';\nimport { runSources } from './commands/sources';\nimport { runStatus } from './commands/status';\nimport { runTest } from './commands/test';\nimport { runUpgrade } from './commands/upgrade';\nimport { runUse } from './commands/use';\nimport { runValidate } from './commands/validate';\nimport { runWhoami } from './commands/whoami';\nimport { CliContext, type WriteStream } from './context';\nimport { SDK_DOCS_URL, docsPage } from './docs-links';\nimport { toCliError, usageError } from './errors';\nimport { EXIT_CODES } from './exit-codes';\nimport { type FlagSpecs, parseArgv } from './parse-argv';\n\nexport { CliContext } from './context';\nexport { EXIT_CODES, ERROR_CODES } from './exit-codes';\nexport type { ExitCode, ErrorCode } from './exit-codes';\n\nconst GLOBAL_SPECS: FlagSpecs = {\n json: { type: 'boolean' },\n help: { type: 'boolean' },\n version: { type: 'boolean' },\n};\n\nconst COMMAND_SPECS: Record<string, FlagSpecs> = {\n init: {\n slug: { type: 'string' },\n dir: { type: 'string' },\n force: { type: 'boolean' },\n yes: { type: 'boolean' },\n // Repeatable: each occurrence appends one docs entry (URL or relative\n // path) to the scaffolded ekanos.json.\n docs: { type: 'string', repeatable: true },\n },\n validate: {\n dir: { type: 'string' },\n },\n dev: {\n dir: { type: 'string' },\n port: { type: 'string' },\n host: { type: 'string' },\n force: { type: 'boolean' },\n start: { type: 'boolean' },\n },\n test: {\n dir: { type: 'string' },\n // Skips the vitest JSON-reporter injection and the curated failures\n // appendix, reproducing the pre-appendix raw-passthrough behavior —\n // also the escape hatch if the vitest-detection heuristic ever guesses\n // wrong for a project. See `test-report.ts`.\n raw: { type: 'boolean' },\n },\n login: {\n host: { type: 'string' },\n force: { type: 'boolean' },\n },\n logout: {\n host: { type: 'string' },\n all: { type: 'boolean' },\n },\n whoami: {\n host: { type: 'string' },\n },\n status: {\n host: { type: 'string' },\n dir: { type: 'string' },\n findings: { type: 'boolean' },\n all: { type: 'boolean' },\n watch: { type: 'boolean' },\n },\n sources: {\n host: { type: 'string' },\n dir: { type: 'string' },\n },\n catalog: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n },\n agents: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n // Not `--version`: that is global, and prints the CLI's own version.\n to: { type: 'string' },\n 'base-version': { type: 'string' },\n overwrite: { type: 'boolean' },\n out: { type: 'string' },\n yes: { type: 'boolean' },\n force: { type: 'boolean' },\n },\n use: {\n host: { type: 'string' },\n dir: { type: 'string' },\n },\n publish: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n yes: { type: 'boolean' },\n },\n upgrade: {\n dir: { type: 'string' },\n host: { type: 'string' },\n check: { type: 'boolean' },\n yes: { type: 'boolean' },\n // `--no-verify` is the negation of this — parse-argv's `--no-<bool>`\n // convention (same as `--no-json`/`--no-start`), not a flag of its own.\n verify: { type: 'boolean' },\n },\n};\n\n/** Commands that take positional arguments, and what each means, in order. Every other command is positional-free. */\nconst POSITIONAL_COMMANDS: Record<string, readonly string[]> = {\n use: ['source-slug'],\n catalog: ['product-slug'],\n agents: ['subcommand', 'key-or-path'],\n};\n\nconst COMMANDS = Object.keys(COMMAND_SPECS);\n\nconst USAGE = [\n 'Usage: ekanos <command> [options]',\n '',\n 'Commands:',\n ' init Scaffold a new integration project into ./<slug> (--slug <slug> --yes)',\n ' validate Validate ekanos.json + the integration definition (--json)',\n ' dev Scaffold .ekanos/harness and run it with your own Next',\n ' test Run the project test script via its package manager (--json).',\n ' For a vitest test script, also renders a curated failures',\n ' appendix from a JSON reporter report; --raw skips that and',\n ' the reporter injection entirely.',\n ' login Authenticate against an Ekanos host in a browser (--host <url>)',\n ' logout Revoke and delete the stored session (--host <url> | --all)',\n ' whoami Print the identity the stored session authenticates as, plus',\n ' a compact list of the sources you hold a seat on',\n \" status Show login state and this project's submissions on the host\",\n ' (--findings for full gate findings, --all to expand other',\n ' integrations in the source, --watch to block until this',\n \" project's current version reaches a gate verdict)\",\n ' sources List every source you hold a developer/source-admin seat on',\n ' catalog What a source can already use, and how to set it up',\n ' (\"ekanos catalog [<product-slug>] --source <slug>\", --json)',\n \" agents The source's agent templates, held by Ekanos:\",\n ' init [<dir>] (skills + docs MCP for designing agents with Claude)',\n ' list | show <key> | pull <key> [--out <dir>]',\n ' apply <dir|file> [--base-version <n>] [--overwrite]',\n ' publish <key> [--to <n>] --yes | rollback <key> --to <n> --yes',\n ' use Set this project\\'s publish target (\"ekanos use <source-slug>\")',\n ' publish Validate, pack and submit the integration to an Ekanos host',\n ' upgrade Move this toolchain to a coherent target version, with',\n ' verify-and-rollback (--check --yes --no-verify --host <url>)',\n '',\n 'Keeping the toolchain current:',\n ' validate, dev and publish all check for a newer @ekanos/cli in the',\n ' background (never blocking, silenced by EKANOS_NO_UPDATE_CHECK) and warn',\n ' on stderr when one exists. Run \"ekanos upgrade --check\" any time a',\n ' validate finding smells like version skew (an unrecognized-key error you',\n ' are confident is correct) — it is read-only and safe to run freely. A',\n ' bare \"ekanos upgrade\" MUTATES the project (installs the target versions,',\n ' verifies with validate + the test script, rolls back on any failure).',\n '',\n 'Host resolution (logout, whoami, status, sources, catalog, agents, use, publish, upgrade):',\n ' --host, else EKANOS_HOST, else the \"host\" field in ekanos.json, else the',\n ' sole stored login. \"ekanos publish\" saves host and source to ekanos.json.',\n ' \"ekanos login\" never reads ekanos.json for a host (--host, else',\n ' EKANOS_HOST, else the sole stored login) — it is the verb that creates',\n ' credentials, so a committed file must never choose where they go.',\n '',\n 'Publish targeting (see \"ekanos sources\" / \"ekanos use\"):',\n ' publish refuses (FORBIDDEN) a source you hold no seat on. With multiple',\n ' seats and an implicit (ekanos.json) source, a human run asks to confirm',\n ' the target; a scripted/JSON run needs --source or --yes to proceed —',\n ' it never prompts and never guesses.',\n '',\n 'Global options:',\n ' --json Emit a single JSON envelope on stdout (auto-on when piped);',\n ' --no-json forces the human-readable form',\n ' --version Print the CLI version',\n ' --help Show this help',\n].join('\\n');\n\nexport interface RunOptions {\n stdout?: WriteStream;\n stderr?: WriteStream;\n env?: Record<string, string | undefined>;\n cwd?: string;\n /**\n * Test-only override for `publish`'s interactive-confirm gate and `init`\n * / `login`'s clack wizard gate (`canWizard` in `wizard.ts`) — see\n * `PublishArgs` in `commands/publish.ts`. Never set this from real CLI\n * wiring; it exists so a test can exercise the human y/N confirm branch or\n * the wizard flow without a real terminal.\n */\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n /**\n * Test-only override for `status --watch`'s poll delay — see `StatusArgs`\n * in `commands/status.ts`. Never set this from real CLI wiring; it exists\n * so a test can exercise the poll loop without waiting 30s per iteration.\n */\n sleep?: (ms: number) => Promise<void>;\n /**\n * Test-only override for `status`'s AGE column (\"now\") — see `StatusArgs`\n * in `commands/status.ts`. Never set this from real CLI wiring; it exists\n * so a test can assert an exact `relativeTime` string deterministically.\n */\n now?: Date;\n}\n\n/**\n * The single entry point. Resolves the agent-native envelope once, dispatches\n * to a verb, and guarantees exactly one terminal emission (success or error).\n * Returns the process exit code — `bin.ts` is the only place that calls\n * `process.exit`, so this stays fully testable.\n */\nexport async function run(\n argv: readonly string[],\n options: RunOptions = {},\n): Promise<number> {\n const jsonFlag = scanJsonFlag(argv);\n const ctx = new CliContext({\n jsonFlag,\n stdout: options.stdout,\n stderr: options.stderr,\n env: options.env,\n });\n const cwd = options.cwd ?? process.cwd();\n const env = options.env ?? process.env;\n\n try {\n // `--version` is global and verb-independent, so it is answered before the\n // command is even resolved: `ekanos --version` and `ekanos validate\n // --version` both report the tool's version and exit 0.\n if (scanFlagPresence(argv, 'version')) {\n return emitVersion(ctx);\n }\n\n const { command, rest } = splitCommand(argv);\n\n // Top-level help / no command.\n if (!command) {\n if (scanFlagPresence(rest, 'help') || argv.length === 0) {\n return emitHelp(ctx);\n }\n // A leading token that is not a command (e.g. `--nonsense`).\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n error: 'unknown-command',\n commands: COMMANDS,\n usage: USAGE,\n });\n throw usageError(\n `Unknown command or flag \"${argv[0]}\".`,\n `Run one of: ${COMMANDS.join(', ')}. See \"ekanos --help\".`,\n );\n }\n\n if (!COMMANDS.includes(command)) {\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n error: 'unknown-command',\n given: command,\n commands: COMMANDS,\n usage: USAGE,\n });\n throw usageError(\n `Unknown command \"${command}\".`,\n `Run one of: ${COMMANDS.join(', ')}. See \"ekanos --help\".`,\n );\n }\n\n const specs: FlagSpecs = { ...GLOBAL_SPECS, ...COMMAND_SPECS[command] };\n const parsed = parseArgv(rest, specs);\n\n if (parsed.flags.help === true) {\n return emitCommandHelp(ctx, command);\n }\n\n const positionalNames = POSITIONAL_COMMANDS[command] ?? [];\n\n if (positionalNames.length === 0 && parsed.positionals.length > 0) {\n throw usageError(\n `\"${command}\" takes no positional arguments (got \"${parsed.positionals[0]}\").`,\n `Pass options as flags, e.g. \"--dir <path>\". See \"ekanos ${command} --help\".`,\n );\n }\n\n if (parsed.positionals.length > positionalNames.length) {\n const usage = positionalNames.map((name) => `<${name}>`).join(' ');\n throw usageError(\n `\"${command}\" takes at most ${positionalNames.length} positional ` +\n `argument${positionalNames.length === 1 ? '' : 's'} (${usage}), ` +\n `got ${parsed.positionals.length}.`,\n `e.g. \"ekanos ${command} ${usage}\". See \"ekanos ${command} --help\".`,\n );\n }\n\n const dir = (parsed.flags.dir as string | undefined) ?? cwd;\n\n switch (command) {\n case 'init':\n return await runInit(ctx, {\n slug: parsed.flags.slug as string | undefined,\n dir: parsed.flags.dir as string | undefined,\n cwd,\n force: parsed.flags.force === true,\n yes: parsed.flags.yes === true,\n docs: parsed.flags.docs as string[] | undefined,\n stdinIsTTY: options.stdinIsTTY,\n });\n case 'validate':\n return await runValidate(ctx, { dir, env });\n case 'dev':\n return await runDev(ctx, {\n dir,\n port: parsed.flags.port as string | undefined,\n host: parsed.flags.host as string | undefined,\n force: parsed.flags.force === true,\n start: parsed.flags.start as boolean | undefined,\n env,\n });\n case 'test':\n return await runTest(ctx, {\n dir,\n passthrough: parsed.passthrough,\n raw: parsed.flags.raw === true,\n });\n case 'login':\n return await runLogin(ctx, {\n host: parsed.flags.host as string | undefined,\n force: parsed.flags.force === true,\n cwd,\n env,\n stdinIsTTY: options.stdinIsTTY,\n });\n case 'logout':\n return await runLogout(ctx, {\n host: parsed.flags.host as string | undefined,\n all: parsed.flags.all === true,\n cwd,\n env,\n });\n case 'whoami':\n return await runWhoami(ctx, {\n host: parsed.flags.host as string | undefined,\n cwd,\n env,\n });\n case 'status':\n return await runStatus(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n env,\n findings: parsed.flags.findings === true,\n all: parsed.flags.all === true,\n watch: parsed.flags.watch === true,\n sleep: options.sleep,\n now: options.now,\n });\n case 'sources':\n return await runSources(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n env,\n });\n case 'catalog':\n return await runCatalog(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n product: parsed.positionals[0],\n dir,\n env,\n });\n case 'agents':\n return await runAgents(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n subcommand: parsed.positionals[0],\n target: parsed.positionals[1],\n to: parsed.flags.to as string | undefined,\n baseVersion: parsed.flags['base-version'] as string | undefined,\n overwrite: parsed.flags.overwrite === true,\n out: parsed.flags.out as string | undefined,\n yes: parsed.flags.yes === true,\n force: parsed.flags.force === true,\n dir,\n env,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n case 'use':\n return await runUse(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n slug: parsed.positionals[0],\n env,\n });\n case 'publish':\n return await runPublish(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n dir,\n yes: parsed.flags.yes === true,\n env,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n case 'upgrade':\n return await runUpgrade(ctx, {\n dir,\n host: parsed.flags.host as string | undefined,\n env,\n check: parsed.flags.check === true,\n yes: parsed.flags.yes === true,\n noVerify: parsed.flags.verify === false,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n default:\n // Unreachable — COMMANDS gate above — but keeps the switch total.\n throw usageError(\n `Unknown command \"${command}\".`,\n `Run one of: ${COMMANDS.join(', ')}.`,\n );\n }\n } catch (error) {\n return ctx.fail(toCliError(error));\n }\n}\n\n/**\n * Presence of `--json` (or `--no-json`) BEFORE the first `--` passthrough.\n *\n * Tri-state on purpose. `undefined` means \"the user expressed no preference\",\n * which is what lets the context fall back to inferring the mode from a\n * non-TTY stdout or CLAUDECODE. Collapsing `--no-json` to `false` here would\n * make it indistinguishable from absence, and the flag could then never turn\n * JSON mode OFF in exactly the cases it exists for.\n */\nfunction scanJsonFlag(argv: readonly string[]): boolean | undefined {\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 undefined;\n}\n\nfunction scanFlagPresence(argv: readonly string[], name: string): boolean {\n for (const token of argv) {\n if (token === '--') break;\n if (token === `--${name}`) return true;\n }\n return false;\n}\n\n/**\n * Split argv into the command (first bare token before `--`) and the rest\n * (everything else, order preserved, including global flags and the `--`\n * passthrough). Global flags are all booleans, so any bare token is the\n * command — no value-consumption ambiguity.\n */\nfunction splitCommand(argv: readonly string[]): {\n command: string | null;\n rest: string[];\n} {\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i]!;\n if (token === '--') break;\n if (!token.startsWith('-')) {\n return {\n command: token,\n rest: [...argv.slice(0, i), ...argv.slice(i + 1)],\n };\n }\n }\n return { command: null, rest: [...argv] };\n}\n\n/**\n * The CLI's own version, read from the package manifest at runtime rather than\n * baked in by the build — one source of truth, so a release bump cannot leave\n * `--version` reporting a stale number. The path resolves identically from\n * `src/index.ts` and from the emitted `dist/index.js`, both of which sit one\n * directory below the package root.\n */\nfunction readVersion(): string {\n const manifest = new URL('../package.json', import.meta.url);\n const parsed: unknown = JSON.parse(fs.readFileSync(manifest, 'utf8'));\n\n return typeof parsed === 'object' &&\n parsed !== null &&\n 'version' in parsed &&\n typeof parsed.version === 'string'\n ? parsed.version\n : '0.0.0';\n}\n\nfunction emitVersion(ctx: CliContext): number {\n const version = readVersion();\n\n return ctx.succeed({ name: 'ekanos', version }, version);\n}\n\nconst DOCS_FOOTER = `\\nDocs: ${SDK_DOCS_URL} (commands: ${docsPage('cli/commands')})`;\n\nfunction emitHelp(ctx: CliContext): number {\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n commands: COMMANDS,\n usage: USAGE,\n exitCodes: EXIT_CODES,\n });\n return ctx.succeed(\n { usage: USAGE, commands: COMMANDS, docs: SDK_DOCS_URL },\n `${USAGE}${DOCS_FOOTER}`,\n );\n}\n\nfunction emitCommandHelp(ctx: CliContext, command: string): number {\n const specs = COMMAND_SPECS[command] ?? {};\n const flags = Object.keys(specs).map((name) => `--${name}`);\n const help = `Usage: ekanos ${command} [${flags.join('] [')}]`;\n ctx.emitClaudeCodeHint({ tool: 'ekanos', command, flags });\n return ctx.succeed({ command, flags }, help);\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\n\nimport { runAgents } from './commands/agents';\nimport { runApps } from './commands/apps';\nimport { runCatalog } from './commands/catalog';\nimport { runDev } from './commands/dev';\nimport { runInit } from './commands/init';\nimport { runLogin } from './commands/login';\nimport { runLogout } from './commands/logout';\nimport { runPublish } from './commands/publish';\nimport { runSources } from './commands/sources';\nimport { runStatus } from './commands/status';\nimport { runTest } from './commands/test';\nimport { runUpgrade } from './commands/upgrade';\nimport { runUse } from './commands/use';\nimport { runValidate } from './commands/validate';\nimport { runWhoami } from './commands/whoami';\nimport { CliContext, type WriteStream } from './context';\nimport { SDK_DOCS_URL, docsPage } from './docs-links';\nimport { toCliError, usageError } from './errors';\nimport { EXIT_CODES } from './exit-codes';\nimport { type FlagSpecs, parseArgv } from './parse-argv';\n\nexport { CliContext } from './context';\nexport { EXIT_CODES, ERROR_CODES } from './exit-codes';\nexport type { ExitCode, ErrorCode } from './exit-codes';\n\nconst GLOBAL_SPECS: FlagSpecs = {\n json: { type: 'boolean' },\n help: { type: 'boolean' },\n version: { type: 'boolean' },\n};\n\nconst COMMAND_SPECS: Record<string, FlagSpecs> = {\n init: {\n slug: { type: 'string' },\n dir: { type: 'string' },\n force: { type: 'boolean' },\n yes: { type: 'boolean' },\n // Repeatable: each occurrence appends one docs entry (URL or relative\n // path) to the scaffolded ekanos.json.\n docs: { type: 'string', repeatable: true },\n },\n validate: {\n dir: { type: 'string' },\n },\n dev: {\n dir: { type: 'string' },\n port: { type: 'string' },\n host: { type: 'string' },\n force: { type: 'boolean' },\n start: { type: 'boolean' },\n },\n test: {\n dir: { type: 'string' },\n // Skips the vitest JSON-reporter injection and the curated failures\n // appendix, reproducing the pre-appendix raw-passthrough behavior —\n // also the escape hatch if the vitest-detection heuristic ever guesses\n // wrong for a project. See `test-report.ts`.\n raw: { type: 'boolean' },\n },\n login: {\n host: { type: 'string' },\n force: { type: 'boolean' },\n claude: { type: 'boolean' },\n },\n logout: {\n host: { type: 'string' },\n all: { type: 'boolean' },\n },\n whoami: {\n host: { type: 'string' },\n },\n status: {\n host: { type: 'string' },\n dir: { type: 'string' },\n findings: { type: 'boolean' },\n all: { type: 'boolean' },\n watch: { type: 'boolean' },\n },\n sources: {\n host: { type: 'string' },\n dir: { type: 'string' },\n },\n catalog: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n },\n apps: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n },\n agents: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n // Not `--version`: that is global, and prints the CLI's own version.\n to: { type: 'string' },\n 'base-version': { type: 'string' },\n overwrite: { type: 'boolean' },\n out: { type: 'string' },\n yes: { type: 'boolean' },\n force: { type: 'boolean' },\n claude: { type: 'boolean' },\n },\n use: {\n host: { type: 'string' },\n dir: { type: 'string' },\n },\n publish: {\n host: { type: 'string' },\n source: { type: 'string' },\n dir: { type: 'string' },\n yes: { type: 'boolean' },\n },\n upgrade: {\n dir: { type: 'string' },\n host: { type: 'string' },\n check: { type: 'boolean' },\n yes: { type: 'boolean' },\n // `--no-verify` is the negation of this — parse-argv's `--no-<bool>`\n // convention (same as `--no-json`/`--no-start`), not a flag of its own.\n verify: { type: 'boolean' },\n },\n};\n\n/** Commands that take positional arguments, and what each means, in order. Every other command is positional-free. */\nconst POSITIONAL_COMMANDS: Record<string, readonly string[]> = {\n use: ['source-slug'],\n catalog: ['product-slug'],\n apps: ['subcommand', 'product-slug'],\n agents: ['subcommand', 'key-or-path'],\n};\n\nconst COMMANDS = Object.keys(COMMAND_SPECS);\n\nconst USAGE = [\n 'Usage: ekanos <command> [options]',\n '',\n 'Commands:',\n ' init Scaffold a new integration project into ./<slug> (--slug <slug> --yes)',\n ' validate Validate ekanos.json + the integration definition (--json)',\n ' dev Scaffold .ekanos/harness and run it with your own Next',\n ' test Run the project test script via its package manager (--json).',\n ' For a vitest test script, also renders a curated failures',\n ' appendix from a JSON reporter report; --raw skips that and',\n ' the reporter injection entirely.',\n ' login Authenticate against an Ekanos host in a browser (--host <url>;',\n ' offers to add the Ekanos docs to Claude Code: --claude|--no-claude)',\n ' logout Revoke and delete the stored session (--host <url> | --all)',\n ' whoami Print the identity the stored session authenticates as, plus',\n ' a compact list of the sources you hold a seat on',\n \" status Show login state and this project's submissions on the host\",\n ' (--findings for full gate findings, --all to expand other',\n ' integrations in the source, --watch to block until this',\n \" project's current version reaches a gate verdict)\",\n ' sources List every source you hold a developer/source-admin seat on',\n ' catalog What a source can already use, and how to set it up',\n ' (\"ekanos catalog [<product-slug>] --source <slug>\", --json)',\n \" apps The Source's app for an integration teams sign in through:\",\n ' show <product> | set <product> (Source admin; takes the secret',\n ' at your terminal)',\n \" agents The source's agent templates, held by Ekanos:\",\n ' init [<dir>] [--claude|--no-claude] (skills + docs MCP for designing',\n ' agents with Claude; offers to add the docs to Claude Code)',\n ' list | show <key> | pull <key> [--out <dir>]',\n ' apply <dir|file> [--base-version <n>] [--overwrite]',\n ' publish <key> [--to <n>] --yes | rollback <key> --to <n> --yes',\n ' use Set this project\\'s publish target (\"ekanos use <source-slug>\")',\n ' publish Validate, pack and submit the integration to an Ekanos host',\n ' upgrade Move this toolchain to a coherent target version, with',\n ' verify-and-rollback (--check --yes --no-verify --host <url>)',\n '',\n 'Keeping the toolchain current:',\n ' validate, dev and publish all check for a newer @ekanos/cli in the',\n ' background (never blocking, silenced by EKANOS_NO_UPDATE_CHECK) and warn',\n ' on stderr when one exists. Run \"ekanos upgrade --check\" any time a',\n ' validate finding smells like version skew (an unrecognized-key error you',\n ' are confident is correct) — it is read-only and safe to run freely. A',\n ' bare \"ekanos upgrade\" MUTATES the project (installs the target versions,',\n ' verifies with validate + the test script, rolls back on any failure).',\n '',\n 'Host resolution (logout, whoami, status, sources, catalog, apps, agents, use, publish, upgrade):',\n ' --host, else EKANOS_HOST, else the \"host\" field in ekanos.json, else the',\n ' sole stored login. \"ekanos publish\" saves host and source to ekanos.json.',\n ' \"ekanos login\" never reads ekanos.json for a host (--host, else',\n ' EKANOS_HOST, else the sole stored login) — it is the verb that creates',\n ' credentials, so a committed file must never choose where they go.',\n '',\n 'Publish targeting (see \"ekanos sources\" / \"ekanos use\"):',\n ' publish refuses (FORBIDDEN) a source you hold no seat on. With multiple',\n ' seats and an implicit (ekanos.json) source, a human run asks to confirm',\n ' the target; a scripted/JSON run needs --source or --yes to proceed —',\n ' it never prompts and never guesses.',\n '',\n 'Global options:',\n ' --json Emit a single JSON envelope on stdout (auto-on when piped);',\n ' --no-json forces the human-readable form',\n ' --version Print the CLI version',\n ' --help Show this help',\n].join('\\n');\n\nexport interface RunOptions {\n stdout?: WriteStream;\n stderr?: WriteStream;\n env?: Record<string, string | undefined>;\n cwd?: string;\n /**\n * Test-only override for `publish`'s interactive-confirm gate and `init`\n * / `login`'s clack wizard gate (`canWizard` in `wizard.ts`) — see\n * `PublishArgs` in `commands/publish.ts`. Never set this from real CLI\n * wiring; it exists so a test can exercise the human y/N confirm branch or\n * the wizard flow without a real terminal.\n */\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n /** Test-only answers for `apps set`'s questions — never set from real CLI wiring. */\n ask?: (question: string) => Promise<string>;\n askSecret?: (question: string) => Promise<string>;\n /**\n * Test-only override for `status --watch`'s poll delay — see `StatusArgs`\n * in `commands/status.ts`. Never set this from real CLI wiring; it exists\n * so a test can exercise the poll loop without waiting 30s per iteration.\n */\n sleep?: (ms: number) => Promise<void>;\n /**\n * Test-only override for `status`'s AGE column (\"now\") — see `StatusArgs`\n * in `commands/status.ts`. Never set this from real CLI wiring; it exists\n * so a test can assert an exact `relativeTime` string deterministically.\n */\n now?: Date;\n}\n\n/**\n * The single entry point. Resolves the agent-native envelope once, dispatches\n * to a verb, and guarantees exactly one terminal emission (success or error).\n * Returns the process exit code — `bin.ts` is the only place that calls\n * `process.exit`, so this stays fully testable.\n */\nexport async function run(\n argv: readonly string[],\n options: RunOptions = {},\n): Promise<number> {\n const jsonFlag = scanJsonFlag(argv);\n const ctx = new CliContext({\n jsonFlag,\n stdout: options.stdout,\n stderr: options.stderr,\n env: options.env,\n });\n const cwd = options.cwd ?? process.cwd();\n const env = options.env ?? process.env;\n\n try {\n // `--version` is global and verb-independent, so it is answered before the\n // command is even resolved: `ekanos --version` and `ekanos validate\n // --version` both report the tool's version and exit 0.\n if (scanFlagPresence(argv, 'version')) {\n return emitVersion(ctx);\n }\n\n const { command, rest } = splitCommand(argv);\n\n // Top-level help / no command.\n if (!command) {\n if (scanFlagPresence(rest, 'help') || argv.length === 0) {\n return emitHelp(ctx);\n }\n // A leading token that is not a command (e.g. `--nonsense`).\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n error: 'unknown-command',\n commands: COMMANDS,\n usage: USAGE,\n });\n throw usageError(\n `Unknown command or flag \"${argv[0]}\".`,\n `Run one of: ${COMMANDS.join(', ')}. See \"ekanos --help\".`,\n );\n }\n\n if (!COMMANDS.includes(command)) {\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n error: 'unknown-command',\n given: command,\n commands: COMMANDS,\n usage: USAGE,\n });\n throw usageError(\n `Unknown command \"${command}\".`,\n `Run one of: ${COMMANDS.join(', ')}. See \"ekanos --help\".`,\n );\n }\n\n const specs: FlagSpecs = { ...GLOBAL_SPECS, ...COMMAND_SPECS[command] };\n const parsed = parseArgv(rest, specs);\n\n if (parsed.flags.help === true) {\n return emitCommandHelp(ctx, command);\n }\n\n const positionalNames = POSITIONAL_COMMANDS[command] ?? [];\n\n if (positionalNames.length === 0 && parsed.positionals.length > 0) {\n throw usageError(\n `\"${command}\" takes no positional arguments (got \"${parsed.positionals[0]}\").`,\n `Pass options as flags, e.g. \"--dir <path>\". See \"ekanos ${command} --help\".`,\n );\n }\n\n if (parsed.positionals.length > positionalNames.length) {\n const usage = positionalNames.map((name) => `<${name}>`).join(' ');\n throw usageError(\n `\"${command}\" takes at most ${positionalNames.length} positional ` +\n `argument${positionalNames.length === 1 ? '' : 's'} (${usage}), ` +\n `got ${parsed.positionals.length}.`,\n `e.g. \"ekanos ${command} ${usage}\". See \"ekanos ${command} --help\".`,\n );\n }\n\n const dir = (parsed.flags.dir as string | undefined) ?? cwd;\n\n switch (command) {\n case 'init':\n return await runInit(ctx, {\n slug: parsed.flags.slug as string | undefined,\n dir: parsed.flags.dir as string | undefined,\n cwd,\n force: parsed.flags.force === true,\n yes: parsed.flags.yes === true,\n docs: parsed.flags.docs as string[] | undefined,\n stdinIsTTY: options.stdinIsTTY,\n });\n case 'validate':\n return await runValidate(ctx, { dir, env });\n case 'dev':\n return await runDev(ctx, {\n dir,\n port: parsed.flags.port as string | undefined,\n host: parsed.flags.host as string | undefined,\n force: parsed.flags.force === true,\n start: parsed.flags.start as boolean | undefined,\n env,\n });\n case 'test':\n return await runTest(ctx, {\n dir,\n passthrough: parsed.passthrough,\n raw: parsed.flags.raw === true,\n });\n case 'login':\n return await runLogin(ctx, {\n host: parsed.flags.host as string | undefined,\n force: parsed.flags.force === true,\n claude: parsed.flags.claude as boolean | undefined,\n cwd,\n env,\n stdinIsTTY: options.stdinIsTTY,\n });\n case 'logout':\n return await runLogout(ctx, {\n host: parsed.flags.host as string | undefined,\n all: parsed.flags.all === true,\n cwd,\n env,\n });\n case 'whoami':\n return await runWhoami(ctx, {\n host: parsed.flags.host as string | undefined,\n cwd,\n env,\n });\n case 'status':\n return await runStatus(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n env,\n findings: parsed.flags.findings === true,\n all: parsed.flags.all === true,\n watch: parsed.flags.watch === true,\n sleep: options.sleep,\n now: options.now,\n });\n case 'sources':\n return await runSources(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n env,\n });\n case 'catalog':\n return await runCatalog(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n product: parsed.positionals[0],\n dir,\n env,\n });\n case 'apps':\n return await runApps(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n subcommand: parsed.positionals[0],\n product: parsed.positionals[1],\n dir,\n env,\n stdinIsTTY: options.stdinIsTTY,\n ask: options.ask,\n askSecret: options.askSecret,\n confirm: options.confirm,\n });\n case 'agents':\n return await runAgents(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n subcommand: parsed.positionals[0],\n target: parsed.positionals[1],\n to: parsed.flags.to as string | undefined,\n baseVersion: parsed.flags['base-version'] as string | undefined,\n overwrite: parsed.flags.overwrite === true,\n out: parsed.flags.out as string | undefined,\n yes: parsed.flags.yes === true,\n force: parsed.flags.force === true,\n claude: parsed.flags.claude as boolean | undefined,\n dir,\n env,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n case 'use':\n return await runUse(ctx, {\n host: parsed.flags.host as string | undefined,\n dir,\n slug: parsed.positionals[0],\n env,\n });\n case 'publish':\n return await runPublish(ctx, {\n host: parsed.flags.host as string | undefined,\n source: parsed.flags.source as string | undefined,\n dir,\n yes: parsed.flags.yes === true,\n env,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n case 'upgrade':\n return await runUpgrade(ctx, {\n dir,\n host: parsed.flags.host as string | undefined,\n env,\n check: parsed.flags.check === true,\n yes: parsed.flags.yes === true,\n noVerify: parsed.flags.verify === false,\n stdinIsTTY: options.stdinIsTTY,\n confirm: options.confirm,\n });\n default:\n // Unreachable — COMMANDS gate above — but keeps the switch total.\n throw usageError(\n `Unknown command \"${command}\".`,\n `Run one of: ${COMMANDS.join(', ')}.`,\n );\n }\n } catch (error) {\n return ctx.fail(toCliError(error));\n }\n}\n\n/**\n * Presence of `--json` (or `--no-json`) BEFORE the first `--` passthrough.\n *\n * Tri-state on purpose. `undefined` means \"the user expressed no preference\",\n * which is what lets the context fall back to inferring the mode from a\n * non-TTY stdout or CLAUDECODE. Collapsing `--no-json` to `false` here would\n * make it indistinguishable from absence, and the flag could then never turn\n * JSON mode OFF in exactly the cases it exists for.\n */\nfunction scanJsonFlag(argv: readonly string[]): boolean | undefined {\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 undefined;\n}\n\nfunction scanFlagPresence(argv: readonly string[], name: string): boolean {\n for (const token of argv) {\n if (token === '--') break;\n if (token === `--${name}`) return true;\n }\n return false;\n}\n\n/**\n * Split argv into the command (first bare token before `--`) and the rest\n * (everything else, order preserved, including global flags and the `--`\n * passthrough). Global flags are all booleans, so any bare token is the\n * command — no value-consumption ambiguity.\n */\nfunction splitCommand(argv: readonly string[]): {\n command: string | null;\n rest: string[];\n} {\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i]!;\n if (token === '--') break;\n if (!token.startsWith('-')) {\n return {\n command: token,\n rest: [...argv.slice(0, i), ...argv.slice(i + 1)],\n };\n }\n }\n return { command: null, rest: [...argv] };\n}\n\n/**\n * The CLI's own version, read from the package manifest at runtime rather than\n * baked in by the build — one source of truth, so a release bump cannot leave\n * `--version` reporting a stale number. The path resolves identically from\n * `src/index.ts` and from the emitted `dist/index.js`, both of which sit one\n * directory below the package root.\n */\nfunction readVersion(): string {\n const manifest = new URL('../package.json', import.meta.url);\n const parsed: unknown = JSON.parse(fs.readFileSync(manifest, 'utf8'));\n\n return typeof parsed === 'object' &&\n parsed !== null &&\n 'version' in parsed &&\n typeof parsed.version === 'string'\n ? parsed.version\n : '0.0.0';\n}\n\nfunction emitVersion(ctx: CliContext): number {\n const version = readVersion();\n\n return ctx.succeed({ name: 'ekanos', version }, version);\n}\n\nconst DOCS_FOOTER = `\\nDocs: ${SDK_DOCS_URL} (commands: ${docsPage('cli/commands')})`;\n\nfunction emitHelp(ctx: CliContext): number {\n ctx.emitClaudeCodeHint({\n tool: 'ekanos',\n commands: COMMANDS,\n usage: USAGE,\n exitCodes: EXIT_CODES,\n });\n return ctx.succeed(\n { usage: USAGE, commands: COMMANDS, docs: SDK_DOCS_URL },\n `${USAGE}${DOCS_FOOTER}`,\n );\n}\n\nfunction emitCommandHelp(ctx: CliContext, command: string): number {\n const specs = COMMAND_SPECS[command] ?? {};\n const flags = Object.keys(specs).map((name) => `--${name}`);\n const help = `Usage: ekanos ${command} [${flags.join('] [')}]`;\n ctx.emitClaudeCodeHint({ tool: 'ekanos', command, flags });\n return ctx.succeed({ command, flags }, help);\n}\n"]}
@@ -42,3 +42,11 @@ export declare function collectVersionAgreementFindings(integration: {
42
42
  }, definition: {
43
43
  version?: unknown;
44
44
  }, projectDir: string): Finding[];
45
+ /**
46
+ * An OAuth connection with no `setup` steps leaves whoever creates its app —
47
+ * the Source admin (`ekanos apps`) or each team — to work out the provider's
48
+ * console alone. A warning, not an error: the connection works without it.
49
+ */
50
+ export declare function collectOAuthSetupFindings(integration: {
51
+ entryPath: string;
52
+ }, definition: unknown): Finding[];
@@ -36,6 +36,7 @@ export async function collectAllFindings(loaded) {
36
36
  }));
37
37
  findings.push(...collectSlugAgreementFindings(integration, result.definition));
38
38
  findings.push(...collectVersionAgreementFindings(integration, result.definition, loaded.projectDir));
39
+ findings.push(...collectOAuthSetupFindings(integration, result.definition));
39
40
  definitions.push(result.definition);
40
41
  continue;
41
42
  }
@@ -148,4 +149,33 @@ export function collectVersionAgreementFindings(integration, definition, project
148
149
  },
149
150
  ];
150
151
  }
152
+ /**
153
+ * An OAuth connection with no `setup` steps leaves whoever creates its app —
154
+ * the Source admin (`ekanos apps`) or each team — to work out the provider's
155
+ * console alone. A warning, not an error: the connection works without it.
156
+ */
157
+ export function collectOAuthSetupFindings(integration, definition) {
158
+ if (typeof definition !== 'object' || definition === null)
159
+ return [];
160
+ const { oauth, oauthConnections } = definition;
161
+ const connections = [
162
+ ...(oauth ? [['oauth', oauth]] : []),
163
+ ...Object.entries(oauthConnections !== null && oauthConnections !== void 0 ? oauthConnections : {}).map(([id, connection]) => [`oauthConnections.${id}`, connection]),
164
+ ];
165
+ return connections
166
+ .filter(([, connection]) => connection.setup === undefined)
167
+ .map(([where, connection]) => ({
168
+ check: 'oauth.setup-missing',
169
+ severity: 'warn',
170
+ file: integration.entryPath,
171
+ message: `${where} has no setup steps, so ` +
172
+ (connection.teamApp
173
+ ? 'each team creating its app'
174
+ : "the Source admin creating the Source's app (ekanos apps set)") +
175
+ " gets no guidance in the provider's console.",
176
+ hint: `Add \`setup: { consoleUrl, steps: [...] }\` to ${where}: where the app is ` +
177
+ 'created, and the steps in order. Write {callbackUrl} and {scopes} where ' +
178
+ 'Ekanos should fill in the exact redirect URI and scopes.',
179
+ }));
180
+ }
151
181
  //# sourceMappingURL=validate-findings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-findings.js","sourceRoot":"","sources":["../src/validate-findings.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DefinitionCollisionInput,\n Finding,\n} from '@ekanos/integration-schema';\nimport {\n collectCollisionFindings,\n collectDefinitionFindings,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { collectDesignFindings } from './design-findings';\nimport { preconditionError } from './errors';\nimport { collectIconFindings } from './icon-findings';\nimport { loadDefinition } from './load-definition';\nimport type { LoadedProject } from './project';\nimport {\n collectDocsFindings,\n collectHostCompilerRulesFindings,\n collectProjectFindings,\n} from './project-checks';\n\n/**\n * The full findings pass shared by `validate` (which reports them) and\n * `publish` (which refuses to submit on any error-severity finding). One\n * implementation so the publish gate can never drift from what `validate`\n * checks — a project that validates clean is, by construction, a project that\n * publish will accept locally.\n *\n * NOTE on schema skew: an earlier version of this function rewrote the\n * unrecognized-key hint when the project's `@ekanos/integration-schema` was\n * newer than the CLI's (see `schema-skew.ts`). That rewrite was dead code —\n * `assertSchemaNotSkewed` throws PRECONDITION_FAILED before either `validate`\n * or `publish` ever calls this function in that state, so a project-newer\n * finding can never reach here to be rewritten, and the precondition error\n * already names both versions and points at the fix. It was removed rather\n * than kept \"just in case\": if a future caller ever makes validate proceed\n * under skew instead of failing fast, THAT is when a rewrite here becomes\n * necessary again, and it should be reintroduced with a real caller driving\n * it, not tests that fake their own reachability.\n */\nexport async function collectAllFindings(\n loaded: LoadedProject,\n): Promise<Finding[]> {\n const findings: Finding[] = [];\n const definitions: DefinitionCollisionInput[] = [];\n\n for (const integration of loaded.integrations) {\n const result = await loadDefinition(\n integration.entryPath,\n loaded.projectDir,\n );\n\n if (result.ok) {\n findings.push(\n ...collectDefinitionFindings(result.definition, {\n file: integration.entryPath,\n }),\n );\n findings.push(\n ...collectSlugAgreementFindings(\n integration,\n result.definition as { slug?: unknown },\n ),\n );\n findings.push(\n ...collectVersionAgreementFindings(\n integration,\n result.definition as { version?: unknown },\n loaded.projectDir,\n ),\n );\n definitions.push(result.definition as DefinitionCollisionInput);\n continue;\n }\n\n if (result.kind === 'rejected') {\n // The module loaded but the SDK/schema rejected the definition at import\n // time — surface it as a validation finding rather than a crash.\n findings.push({\n check: 'definition.load',\n severity: 'error',\n file: integration.entryPath,\n message: result.message,\n hint:\n 'Fix the integration definition so defineIntegration() accepts it, ' +\n 'then re-run validate.',\n });\n continue;\n }\n\n // A genuine module-load failure is a precondition, not a finding.\n throw preconditionError(\n `Could not load the integration definition for \"${integration.slug}\": ` +\n result.message,\n 'Ensure the entry module and its installed dependencies load under ' +\n 'Node, then re-run validate.',\n );\n }\n\n // Cross-checks only mean something with more than one definition in hand.\n findings.push(...collectCollisionFindings(definitions));\n findings.push(...collectProjectFindings(loaded.projectDir));\n findings.push(...collectDocsFindings(loaded.project, loaded.projectDir));\n findings.push(...collectIconFindings(loaded.projectDir));\n findings.push(...collectDesignFindings(loaded.projectDir));\n findings.push(...collectHostCompilerRulesFindings(loaded.projectDir));\n\n return findings;\n}\n\n/**\n * `ekanos.json` and the definition each carry a slug, and nothing compared\n * them: a project could declare `something-else` while the definition said\n * `repo-activity` and validate would report `{ ok: true, findings: [] }`.\n *\n * That is the identifier every surface addresses the integration by — the\n * harness route, the product slug, the widget id prefix, the MCP server — so\n * two sources of truth disagreeing is not a style question. It is an error,\n * not a warning, for the same reason a silent default is worse than a loud\n * one: the failure it causes shows up somewhere else entirely.\n */\nfunction collectSlugAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { slug?: unknown },\n): Finding[] {\n const declared = definition.slug;\n if (typeof declared !== 'string' || declared === integration.slug) return [];\n\n return [\n {\n check: 'project.slug-agreement',\n severity: 'error',\n file: integration.entryPath,\n message:\n `ekanos.json declares slug \"${integration.slug}\" for this entry, but ` +\n `the definition says \"${declared}\". The slug addresses the ` +\n 'integration everywhere — its harness route, its product record, its ' +\n 'widget ids — so the two must agree.',\n hint:\n `Change one to match the other: either set \"slug\": \"${declared}\" in ` +\n `ekanos.json, or pass slug: '${integration.slug}' to ` +\n 'defineIntegration().',\n },\n ];\n}\n\n/**\n * `package.json`'s `version` field and the `version` `defineIntegration()`\n * declares are two more independent sources of truth for the same fact —\n * this project shipped weather@0.1.1 with a package.json bump, but the\n * declaration itself still said 0.1.0. Generated seeds embed the\n * DECLARATION's version in their header, so a stale declaration produces a\n * seed that looks stale even though the package itself moved on.\n *\n * WARN, not error, unlike slug agreement: a mismatched version is a quality\n * signal a partner should fix, not a broken cross-reference that breaks\n * something else at runtime, so it must not block `publish`. And a project\n * with no package.json, or a package.json with no `version` field, has\n * nothing to compare the declaration against — skip rather than warn on\n * absence.\n */\nexport function collectVersionAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { version?: unknown },\n projectDir: string,\n): Finding[] {\n const declared = definition.version;\n if (typeof declared !== 'string') return [];\n\n const manifestPath = path.join(projectDir, 'package.json');\n if (!fs.existsSync(manifestPath)) return [];\n\n let manifest: unknown;\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n } catch {\n // Malformed package.json is npm's problem to report, not a validate\n // finding — nothing here can compare against an unparseable manifest.\n return [];\n }\n\n const packageVersion =\n typeof manifest === 'object' && manifest !== null\n ? (manifest as { version?: unknown }).version\n : undefined;\n if (typeof packageVersion !== 'string' || packageVersion === declared) {\n return [];\n }\n\n return [\n {\n check: 'project.version-agreement',\n severity: 'warn',\n file: integration.entryPath,\n message:\n `package.json declares version \"${packageVersion}\", but the ` +\n `defineIntegration() declaration for \"${integration.slug}\" still ` +\n `says \"${declared}\". Generated seed headers embed the ` +\n \"declaration's version, so a stale declaration ships stale-looking \" +\n 'metadata even though the package itself moved on.',\n hint:\n `Update the \"version\" passed to defineIntegration() in ` +\n `${integration.entryPath} to match package.json's \"${packageVersion}\".`,\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"validate-findings.js","sourceRoot":"","sources":["../src/validate-findings.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DefinitionCollisionInput,\n Finding,\n} from '@ekanos/integration-schema';\nimport {\n collectCollisionFindings,\n collectDefinitionFindings,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { collectDesignFindings } from './design-findings';\nimport { preconditionError } from './errors';\nimport { collectIconFindings } from './icon-findings';\nimport { loadDefinition } from './load-definition';\nimport type { LoadedProject } from './project';\nimport {\n collectDocsFindings,\n collectHostCompilerRulesFindings,\n collectProjectFindings,\n} from './project-checks';\n\n/**\n * The full findings pass shared by `validate` (which reports them) and\n * `publish` (which refuses to submit on any error-severity finding). One\n * implementation so the publish gate can never drift from what `validate`\n * checks — a project that validates clean is, by construction, a project that\n * publish will accept locally.\n *\n * NOTE on schema skew: an earlier version of this function rewrote the\n * unrecognized-key hint when the project's `@ekanos/integration-schema` was\n * newer than the CLI's (see `schema-skew.ts`). That rewrite was dead code —\n * `assertSchemaNotSkewed` throws PRECONDITION_FAILED before either `validate`\n * or `publish` ever calls this function in that state, so a project-newer\n * finding can never reach here to be rewritten, and the precondition error\n * already names both versions and points at the fix. It was removed rather\n * than kept \"just in case\": if a future caller ever makes validate proceed\n * under skew instead of failing fast, THAT is when a rewrite here becomes\n * necessary again, and it should be reintroduced with a real caller driving\n * it, not tests that fake their own reachability.\n */\nexport async function collectAllFindings(\n loaded: LoadedProject,\n): Promise<Finding[]> {\n const findings: Finding[] = [];\n const definitions: DefinitionCollisionInput[] = [];\n\n for (const integration of loaded.integrations) {\n const result = await loadDefinition(\n integration.entryPath,\n loaded.projectDir,\n );\n\n if (result.ok) {\n findings.push(\n ...collectDefinitionFindings(result.definition, {\n file: integration.entryPath,\n }),\n );\n findings.push(\n ...collectSlugAgreementFindings(\n integration,\n result.definition as { slug?: unknown },\n ),\n );\n findings.push(\n ...collectVersionAgreementFindings(\n integration,\n result.definition as { version?: unknown },\n loaded.projectDir,\n ),\n );\n findings.push(\n ...collectOAuthSetupFindings(integration, result.definition),\n );\n definitions.push(result.definition as DefinitionCollisionInput);\n continue;\n }\n\n if (result.kind === 'rejected') {\n // The module loaded but the SDK/schema rejected the definition at import\n // time — surface it as a validation finding rather than a crash.\n findings.push({\n check: 'definition.load',\n severity: 'error',\n file: integration.entryPath,\n message: result.message,\n hint:\n 'Fix the integration definition so defineIntegration() accepts it, ' +\n 'then re-run validate.',\n });\n continue;\n }\n\n // A genuine module-load failure is a precondition, not a finding.\n throw preconditionError(\n `Could not load the integration definition for \"${integration.slug}\": ` +\n result.message,\n 'Ensure the entry module and its installed dependencies load under ' +\n 'Node, then re-run validate.',\n );\n }\n\n // Cross-checks only mean something with more than one definition in hand.\n findings.push(...collectCollisionFindings(definitions));\n findings.push(...collectProjectFindings(loaded.projectDir));\n findings.push(...collectDocsFindings(loaded.project, loaded.projectDir));\n findings.push(...collectIconFindings(loaded.projectDir));\n findings.push(...collectDesignFindings(loaded.projectDir));\n findings.push(...collectHostCompilerRulesFindings(loaded.projectDir));\n\n return findings;\n}\n\n/**\n * `ekanos.json` and the definition each carry a slug, and nothing compared\n * them: a project could declare `something-else` while the definition said\n * `repo-activity` and validate would report `{ ok: true, findings: [] }`.\n *\n * That is the identifier every surface addresses the integration by — the\n * harness route, the product slug, the widget id prefix, the MCP server — so\n * two sources of truth disagreeing is not a style question. It is an error,\n * not a warning, for the same reason a silent default is worse than a loud\n * one: the failure it causes shows up somewhere else entirely.\n */\nfunction collectSlugAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { slug?: unknown },\n): Finding[] {\n const declared = definition.slug;\n if (typeof declared !== 'string' || declared === integration.slug) return [];\n\n return [\n {\n check: 'project.slug-agreement',\n severity: 'error',\n file: integration.entryPath,\n message:\n `ekanos.json declares slug \"${integration.slug}\" for this entry, but ` +\n `the definition says \"${declared}\". The slug addresses the ` +\n 'integration everywhere — its harness route, its product record, its ' +\n 'widget ids — so the two must agree.',\n hint:\n `Change one to match the other: either set \"slug\": \"${declared}\" in ` +\n `ekanos.json, or pass slug: '${integration.slug}' to ` +\n 'defineIntegration().',\n },\n ];\n}\n\n/**\n * `package.json`'s `version` field and the `version` `defineIntegration()`\n * declares are two more independent sources of truth for the same fact —\n * this project shipped weather@0.1.1 with a package.json bump, but the\n * declaration itself still said 0.1.0. Generated seeds embed the\n * DECLARATION's version in their header, so a stale declaration produces a\n * seed that looks stale even though the package itself moved on.\n *\n * WARN, not error, unlike slug agreement: a mismatched version is a quality\n * signal a partner should fix, not a broken cross-reference that breaks\n * something else at runtime, so it must not block `publish`. And a project\n * with no package.json, or a package.json with no `version` field, has\n * nothing to compare the declaration against — skip rather than warn on\n * absence.\n */\nexport function collectVersionAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { version?: unknown },\n projectDir: string,\n): Finding[] {\n const declared = definition.version;\n if (typeof declared !== 'string') return [];\n\n const manifestPath = path.join(projectDir, 'package.json');\n if (!fs.existsSync(manifestPath)) return [];\n\n let manifest: unknown;\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n } catch {\n // Malformed package.json is npm's problem to report, not a validate\n // finding — nothing here can compare against an unparseable manifest.\n return [];\n }\n\n const packageVersion =\n typeof manifest === 'object' && manifest !== null\n ? (manifest as { version?: unknown }).version\n : undefined;\n if (typeof packageVersion !== 'string' || packageVersion === declared) {\n return [];\n }\n\n return [\n {\n check: 'project.version-agreement',\n severity: 'warn',\n file: integration.entryPath,\n message:\n `package.json declares version \"${packageVersion}\", but the ` +\n `defineIntegration() declaration for \"${integration.slug}\" still ` +\n `says \"${declared}\". Generated seed headers embed the ` +\n \"declaration's version, so a stale declaration ships stale-looking \" +\n 'metadata even though the package itself moved on.',\n hint:\n `Update the \"version\" passed to defineIntegration() in ` +\n `${integration.entryPath} to match package.json's \"${packageVersion}\".`,\n },\n ];\n}\n\n/**\n * An OAuth connection with no `setup` steps leaves whoever creates its app —\n * the Source admin (`ekanos apps`) or each team — to work out the provider's\n * console alone. A warning, not an error: the connection works without it.\n */\nexport function collectOAuthSetupFindings(\n integration: { entryPath: string },\n definition: unknown,\n): Finding[] {\n if (typeof definition !== 'object' || definition === null) return [];\n const { oauth, oauthConnections } = definition as {\n oauth?: { setup?: unknown; teamApp?: unknown };\n oauthConnections?: Record<string, { setup?: unknown; teamApp?: unknown }>;\n };\n\n type Connection = { setup?: unknown; teamApp?: unknown };\n const connections: Array<readonly [string, Connection]> = [\n ...(oauth ? [['oauth', oauth] as const] : []),\n ...Object.entries(oauthConnections ?? {}).map(\n ([id, connection]) => [`oauthConnections.${id}`, connection] as const,\n ),\n ];\n\n return connections\n .filter(([, connection]) => connection.setup === undefined)\n .map(([where, connection]) => ({\n check: 'oauth.setup-missing',\n severity: 'warn' as const,\n file: integration.entryPath,\n message:\n `${where} has no setup steps, so ` +\n (connection.teamApp\n ? 'each team creating its app'\n : \"the Source admin creating the Source's app (ekanos apps set)\") +\n \" gets no guidance in the provider's console.\",\n hint:\n `Add \\`setup: { consoleUrl, steps: [...] }\\` to ${where}: where the app is ` +\n 'created, and the steps in order. Write {callbackUrl} and {scopes} where ' +\n 'Ekanos should fill in the exact redirect URI and scopes.',\n }));\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekanos/cli",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "The Ekanos partner toolchain CLI: scaffold, validate, and test an Ekanos integration against the published @ekanos packages. Agent-native — every verb speaks JSON with a stable exit-code taxonomy.",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@clack/prompts": "1.7.0",
38
- "@ekanos/integration-schema": "0.9.0",
38
+ "@ekanos/integration-schema": "0.11.0",
39
39
  "esbuild": "0.28.1",
40
40
  "picocolors": "1.1.1"
41
41
  },
@@ -1,11 +1,11 @@
1
1
  # Ekanos agents
2
2
 
3
3
  This folder is where we design and change our Ekanos managed agents with the
4
- `ekanos` CLI (`npx ekanos agents …`). The agents themselves live in Ekanos;
4
+ `ekanos` CLI (`npx @ekanos/cli agents …`). The agents themselves live in Ekanos;
5
5
  `agents/<key>/` holds a copy for review (`agent.json` + `AGENT.md`).
6
6
 
7
7
  - To create or change an agent, use the `build-agent` skill: it checks what
8
- the Source already has (`npx ekanos catalog`), interviews the user, then
8
+ the Source already has (`npx @ekanos/cli catalog`), interviews the user, then
9
9
  drafts, applies and — only on the user's yes — publishes.
10
10
  - For how Sources, team accounts, seats, integrations and connections fit
11
11
  together, use the `ekanos-platform` skill.
@@ -12,12 +12,12 @@
12
12
  "prepare": "node scripts/setup-hooks.mjs"
13
13
  },
14
14
  "dependencies": {
15
- "@ekanos/sdk": "^0.9.0",
16
- "@ekanos/ui": "^0.9.0"
15
+ "@ekanos/sdk": "^0.11.0",
16
+ "@ekanos/ui": "^0.11.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@ekanos/cli": "^0.6.0",
20
- "@ekanos/harness": "^0.7.0",
19
+ "@ekanos/cli": "^0.8.0",
20
+ "@ekanos/harness": "^0.7.2",
21
21
  "@hookform/resolvers": "^5.2.2",
22
22
  "@tailwindcss/postcss": "^4.3.3",
23
23
  "@tanstack/react-query": "^5.101.4",
@@ -13,7 +13,7 @@ in plain words, with a recommendation each time — then drafting, applying and
13
13
  have not: Sources vs teams, seats and connections underlie every question
14
14
  here.
15
15
 
16
- Run the CLI as `npx ekanos … --json` and read the envelope
16
+ Run the CLI as `npx @ekanos/cli … --json` and read the envelope
17
17
  (`{ ok, data }` / `{ ok: false, error: { code, message, hint } }`); follow
18
18
  every `hint`. Look things up in the `ekanos-sdk-docs` MCP server
19
19
  (https://sdk.ekanos.dev) rather than guessing.
@@ -31,19 +31,27 @@ every `hint`. Look things up in the `ekanos-sdk-docs` MCP server
31
31
 
32
32
  ## 1. Ground yourself (before asking anything)
33
33
 
34
- 1. `npx ekanos sources --json` — which Sources, which seats. More than one?
34
+ 1. `npx @ekanos/cli sources --json` — which Sources, which seats. More than one?
35
35
  Ask which Source this is for and pass `--source <slug>` on every command
36
36
  after. A `developer` seat can apply drafts but not publish; say so early.
37
- 2. `npx ekanos catalog --source <slug> --json` — every product the Source
37
+ 2. `npx @ekanos/cli catalog --source <slug> --json` — every product the Source
38
38
  has, its tools, its **agent events** (what can start an agent) and its
39
39
  `setupSteps`.
40
- 3. `npx ekanos agents list --source <slug> --json` — an agent that already
40
+ 3. `npx @ekanos/cli agents list --source <slug> --json` — an agent that already
41
41
  does this should be changed, not duplicated.
42
42
  4. Map the request onto the catalog. For each thing the user named, say
43
43
  which of these it is:
44
44
  - **Ready** — the product is `enabled` and has the tools/events needed.
45
- - **Not set up yet** — offered but not enabled, or needing a step from
46
- someone else (`setupSteps` says who: `ekanos` = an Ekanos super admin).
45
+ - **Not set up yet** — offered but not enabled, or a setup step left
46
+ (`setupSteps` says who: `ekanos` = an Ekanos super admin, `source_admin`
47
+ = the user if they hold that seat, `team` = each team). The common one a
48
+ Source admin can clear: an integration's **app for the Source** is not
49
+ set up, so no team can connect. Run
50
+ `npx @ekanos/cli apps show <product> --source <slug> --json` for the
51
+ callback URL to register in the provider, then ask the user to run
52
+ `npx @ekanos/cli apps set <product> --source <slug>` **in their own
53
+ terminal** — it asks for the secret there; never ask for it in chat.
54
+ The agent can be drafted while that is pending.
47
55
  - **Missing** — no product does it. Say so plainly. Options: build the
48
56
  integration (the `build-integration` skill), use a remote MCP server
49
57
  instead if the service offers one (common for docs and knowledge bases:
@@ -90,13 +98,13 @@ in parentheses are the recommendation when the user has no preference.
90
98
  The instructions say: the job, the sources of truth and when to consult
91
99
  each, what to do when unsure (ask, or hand to a person), tone, and what
92
100
  never to do. Show the user both files and walk through them.
93
- 2. On their go: `npx ekanos agents apply agents/<key> --source <slug> --json`.
101
+ 2. On their go: `npx @ekanos/cli agents apply agents/<key> --source <slug> --json`.
94
102
  A refusal (exit 3) lists each problem with its path in the body — explain
95
103
  and fix them together. The stored version is a **draft**: no team sees it.
96
- 3. `npx ekanos agents show <key> --source <slug>` — review the stored draft
104
+ 3. `npx @ekanos/cli agents show <key> --source <slug>` — review the stored draft
97
105
  with the user.
98
106
  4. Ask: publish this version to every team now? Only on yes:
99
- `npx ekanos agents publish <key> --source <slug> --to <n> --yes`.
107
+ `npx @ekanos/cli agents publish <key> --source <slug> --to <n> --yes`.
100
108
  5. Hand over the team-side checklist (`references/triggers.md` has the
101
109
  per-integration parts): find it under Agents → "Provided for your team",
102
110
  Turn on, connect what it needs, confirm access, add triggers. Suggest one
@@ -104,7 +112,7 @@ in parentheses are the recommendation when the user has no preference.
104
112
 
105
113
  ## Changing it later
106
114
 
107
- `npx ekanos agents pull <key> --source <slug>` writes the latest version to
115
+ `npx @ekanos/cli agents pull <key> --source <slug>` writes the latest version to
108
116
  `agents/<key>/`; edit, `apply` (a new draft), `show`, then `publish` on the
109
117
  user's yes. `rollback <key> --to <n> --yes` republishes an earlier version.
110
118
  Teams that pinned a version stay on it and are told a newer one exists.