@ekanos/cli 0.6.0 → 0.7.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.
- package/dist/apps-api.d.ts +27 -0
- package/dist/apps-api.js +80 -0
- package/dist/apps-api.js.map +1 -0
- package/dist/claude-docs.d.ts +39 -0
- package/dist/claude-docs.js +70 -0
- package/dist/claude-docs.js.map +1 -0
- package/dist/commands/agents-init.d.ts +8 -7
- package/dist/commands/agents-init.js +14 -8
- package/dist/commands/agents-init.js.map +1 -1
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +8 -4
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/apps.d.ts +25 -0
- package/dist/commands/apps.js +155 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.js +16 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +32 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/agents-claude.md.tmpl +2 -2
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +18 -10
- package/templates/skills/ekanos-platform/SKILL.md +12 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentTemplateBody,\n AgentTemplateBodySchema,\n type AgentTemplateDetail,\n AgentTemplateKeySchema,\n type AgentTemplateList,\n type AgentTemplateResult,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport {\n type AgentsApiResult,\n applyAgentTemplate,\n listAgentTemplates,\n publishAgentTemplate,\n showAgentTemplate,\n} from '../agents-api';\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport {\n authRequiredError,\n notFoundError,\n usageError,\n validationError,\n} from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { classifyPath } from '../safe-fs';\nimport { resolveSourceTarget } from '../source-target';\nimport { type ResultRow, type Ui, pluralize } from '../ui';\nimport { runAgentsInit, withDocsHint } from './agents-init';\nimport { promptYesNo } from './publish';\n\nexport const AGENTS_SUBCOMMANDS = [\n 'init',\n 'list',\n 'show',\n 'pull',\n 'apply',\n 'publish',\n 'rollback',\n] as const;\n\ntype AgentsSubcommand = (typeof AGENTS_SUBCOMMANDS)[number];\n\n/** The file `pull` writes and `apply` reads, inside an agent's directory. */\nexport const AGENT_FILE = 'agent.json';\n/** Instructions as Markdown, beside it. Used when `agent.json` has none. */\nexport const AGENT_INSTRUCTIONS_FILE = 'AGENT.md';\n\nexport interface AgentsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n /** A template key, or for `apply` a file or directory. */\n target?: string;\n /** `publish` / `rollback`: the version to make the one teams run. */\n to?: string;\n baseVersion?: string;\n overwrite: boolean;\n out?: string;\n yes: boolean;\n /** `init`: replace the skills and CLAUDE.md even when they exist. */\n force?: boolean;\n dir: string;\n env: Record<string, string | undefined>;\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/**\n * `agents` — the Source's agent templates (plan 239.0 / 239.2). Ekanos holds\n * them; nothing here is deployed. `apply` stores a new version (a draft\n * until published), `publish` makes a version the one every team runs,\n * `rollback` publishes an older one. `pull` writes a template out as\n * `agent.json` + `AGENT.md` for review or Git, and `apply` reads the same\n * layout back.\n */\nexport async function runAgents(\n ctx: CliContext,\n args: AgentsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n\n // Local only: no host, no session.\n if (subcommand === 'init') {\n return runAgentsInit(ctx, {\n dir: path.resolve(args.dir, args.target ?? '.'),\n force: args.force === true,\n });\n }\n\n // Read the local input before any network call, so a bad file fails fast.\n const local =\n subcommand === 'apply' ? readAgentInput(args.target, args.dir) : null;\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new AgentsClient(env, resolved.session);\n const source = resolved.source;\n\n switch (subcommand) {\n case 'list': {\n const list = await client.call((token) =>\n listAgentTemplates(env.host, token, source),\n );\n return ctx.succeed(\n { host: env.host, ...list },\n withDocsHint(ctx.ui, args.dir, listSummary(ctx.ui, list)),\n );\n }\n case 'show': {\n const key = requireKey(args.target, 'show');\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n return ctx.succeed(\n { host: env.host, ...shown },\n templateDetail(ctx.ui, shown.template),\n );\n }\n case 'pull': {\n const key = requireKey(args.target, 'pull');\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n const outDir = path.resolve(\n args.dir,\n args.out ?? path.join('agents', key),\n );\n const written = writeAgentFiles(outDir, shown.template);\n return ctx.succeed(\n {\n host: env.host,\n key,\n version: shown.template.latestVersion,\n files: written,\n },\n ctx.ui.result({\n title: `Pulled ${key} v${shown.template.latestVersion}`,\n rows: written.map((file): ResultRow => ['Wrote', file]),\n notes: [\n `Edit, then \"ekanos agents apply ${path.relative(args.dir, outDir) || '.'}\".`,\n ],\n }),\n );\n }\n case 'apply': {\n const input = local!;\n const baseVersion =\n parseVersionFlag(args.baseVersion, '--base-version') ??\n input.baseVersion;\n const result = await client.call((token) =>\n applyAgentTemplate(env.host, token, {\n source,\n key: input.key,\n body: input.body,\n baseVersion,\n overwrite: args.overwrite,\n }),\n );\n if (input.file && result.outcome !== 'unchanged') {\n recordBaseVersion(input.file, result.version);\n }\n return ctx.succeed(\n { host: env.host, ...result },\n resultSummary(ctx.ui, result),\n );\n }\n case 'publish':\n case 'rollback': {\n const key = requireKey(args.target, subcommand);\n let version = parseVersionFlag(args.to, '--to') ?? undefined;\n if (subcommand === 'rollback' && version === undefined) {\n throw usageError(\n 'rollback needs the version to go back to.',\n `Pass \"--to <n>\". \"ekanos agents show ${key}\" lists them.`,\n );\n }\n // Refuse a script with no --yes before reading anything.\n if (!args.yes && !canPrompt(ctx, args)) {\n throw validationError(\n `${subcommand === 'rollback' ? 'Rolling back' : 'Publishing'} ${key} on ${source} needs confirmation.`,\n 'It reaches every team running this agent at once. Pass --yes to confirm.',\n );\n }\n // Publish names the version it confirmed, never \"whatever is latest\n // when the request lands\" — a draft applied in between is not shipped\n // unseen to every team.\n if (version === undefined) {\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n version = shown.template.latestVersion;\n }\n await confirmPublish(ctx, args, {\n key,\n source,\n what:\n subcommand === 'rollback'\n ? `Roll ${key} back to version ${version}`\n : `Publish ${key} version ${version}`,\n });\n const result = await client.call((token) =>\n publishAgentTemplate(env.host, token, subcommand, {\n source,\n key,\n version,\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n resultSummary(ctx.ui, result),\n );\n }\n }\n}\n\n/** Every call refreshes the session once on a 401, then gives up. */\nclass AgentsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<AgentsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the agents call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nfunction parseSubcommand(value: string | undefined): AgentsSubcommand {\n const match = AGENTS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value\n ? `Unknown agents subcommand \"${value}\".`\n : 'agents needs a subcommand.',\n `Run one of: ${AGENTS_SUBCOMMANDS.map((name) => `ekanos agents ${name}`).join(', ')}.`,\n );\n}\n\nfunction requireKey(value: string | undefined, verb: string): string {\n const parsed = AgentTemplateKeySchema.safeParse(value ?? '');\n if (parsed.success) return parsed.data;\n throw usageError(\n value\n ? `\"${value}\" is not an agent key.`\n : `agents ${verb} needs an agent key.`,\n `Pass the key, e.g. \"ekanos agents ${verb} support-triage\". ` +\n `\"ekanos agents list\" shows them.`,\n );\n}\n\nfunction parseVersionFlag(\n value: string | undefined,\n flag: string,\n): number | null {\n if (value === undefined) return null;\n const version = Number(value);\n if (Number.isInteger(version) && version >= 1) return version;\n throw usageError(\n `${flag} must be a version number (got \"${value}\").`,\n `\"ekanos agents show <key>\" lists the versions.`,\n );\n}\n\ninterface AgentInput {\n key: string;\n body: AgentTemplateBody;\n baseVersion: number | null;\n /** The agent.json read, when there was one, so the new version is recorded in it. */\n file: string | null;\n}\n\n/**\n * Read `apply`'s input: a directory holding `agent.json` (and optionally\n * `AGENT.md`), or a `.json` file. The key is the file's `key`, else the\n * directory's name. `baseVersion` in the file is the version it was pulled\n * or last applied at — what the host checks for a concurrent change.\n */\nexport function readAgentInput(\n target: string | undefined,\n cwd: string,\n): AgentInput {\n if (!target) {\n throw usageError(\n 'agents apply needs a file or directory.',\n `Pass an agent directory (\"ekanos agents apply agents/support\") or a ` +\n `JSON file. \"ekanos agents pull <key>\" writes the layout.`,\n );\n }\n const resolved = path.resolve(cwd, target);\n const kind = classifyPath(resolved);\n const dir = kind === 'directory' ? resolved : path.dirname(resolved);\n const file =\n kind === 'directory' ? path.join(resolved, AGENT_FILE) : resolved;\n\n if (classifyPath(file) !== 'file') {\n throw notFoundError(\n `No ${kind === 'directory' ? AGENT_FILE : 'file'} at ${file}.`,\n `\"ekanos agents pull <key>\" writes ${AGENT_FILE} and ${AGENT_INSTRUCTIONS_FILE}.`,\n );\n }\n\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(file, 'utf8'));\n } catch (error) {\n throw validationError(\n `${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the JSON and apply again.',\n );\n }\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw validationError(\n `${file} must hold a JSON object.`,\n 'See \"ekanos agents --help\".',\n );\n }\n\n const {\n key: rawKey,\n baseVersion: rawBase,\n $schema: _schema,\n ...rest\n } = raw as Record<string, unknown>;\n const fields: Record<string, unknown> = { ...rest };\n\n const instructionsFile = path.join(dir, AGENT_INSTRUCTIONS_FILE);\n if (\n fields.instructions === undefined &&\n classifyPath(instructionsFile) === 'file'\n ) {\n fields.instructions = fs.readFileSync(instructionsFile, 'utf8');\n }\n\n const key = AgentTemplateKeySchema.safeParse(\n typeof rawKey === 'string' ? rawKey : path.basename(dir),\n );\n if (!key.success) {\n throw validationError(\n `No usable agent key: set \"key\" in ${file}, or name the directory after it.`,\n key.error.issues[0]?.message ??\n 'Use lowercase letters, digits and hyphens.',\n );\n }\n\n const body = AgentTemplateBodySchema.safeParse(fields);\n if (!body.success) {\n throw validationError(\n [\n `${file} is not a valid agent:`,\n ...body.error.issues.map(\n (issue) => ` ${issue.path.join('.') || '(root)'}: ${issue.message}`,\n ),\n ].join('\\n'),\n `Fields: name, description, instructions (or ${AGENT_INSTRUCTIONS_FILE}), ` +\n `model, maxTurns, tools, policy, skills.`,\n );\n }\n\n const baseVersion =\n typeof rawBase === 'number' && Number.isInteger(rawBase) && rawBase >= 1\n ? rawBase\n : null;\n\n return { key: key.data, body: body.data, baseVersion, file };\n}\n\n/**\n * Write `agent.json` + `AGENT.md`. The instructions live in the Markdown so\n * they read and diff as prose; the JSON holds everything else plus the\n * version they came from.\n */\nfunction writeAgentFiles(\n outDir: string,\n template: AgentTemplateDetail,\n): string[] {\n fs.mkdirSync(outDir, { recursive: true });\n const { instructions, ...rest } = template.body;\n const json = {\n key: template.key,\n baseVersion: template.latestVersion,\n ...rest,\n };\n const jsonPath = path.join(outDir, AGENT_FILE);\n const mdPath = path.join(outDir, AGENT_INSTRUCTIONS_FILE);\n for (const target of [jsonPath, mdPath]) {\n const kind = classifyPath(target);\n if (kind !== 'missing' && kind !== 'file') {\n throw validationError(\n `Refusing to write through ${target} (${kind}).`,\n 'Remove it, or pass --out <dir>.',\n );\n }\n }\n fs.writeFileSync(jsonPath, `${JSON.stringify(json, null, 2)}\\n`);\n fs.writeFileSync(\n mdPath,\n instructions.endsWith('\\n') ? instructions : `${instructions}\\n`,\n );\n return [jsonPath, mdPath];\n}\n\n/** After a stored version, point the file at it, so the next apply is based on it. */\nfunction recordBaseVersion(file: string, version: number) {\n const raw = JSON.parse(fs.readFileSync(file, 'utf8')) as Record<\n string,\n unknown\n >;\n if (raw.baseVersion === version) return;\n const { key, baseVersion: _old, ...rest } = raw;\n const next =\n key === undefined\n ? { baseVersion: version, ...rest }\n : { key, baseVersion: version, ...rest };\n fs.writeFileSync(file, `${JSON.stringify(next, null, 2)}\\n`);\n}\n\nfunction canPrompt(ctx: CliContext, args: AgentsArgs): boolean {\n return !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n\n/**\n * Publishing changes what every team running the agent does, at once. A\n * human run asks first; a scripted or JSON run needs `--yes`.\n */\nasync function confirmPublish(\n ctx: CliContext,\n args: AgentsArgs,\n target: { key: string; source: string; what: string },\n) {\n if (args.yes) return;\n if (!canPrompt(ctx, args)) {\n throw validationError(\n `${target.what} on ${target.source} needs confirmation.`,\n 'It reaches every team running this agent at once. Pass --yes to confirm.',\n );\n }\n ctx.log(\n `${target.what} on ${target.source}. Every team running it follows at once.`,\n );\n const confirmed = await (args.confirm ?? promptYesNo)('Proceed? [y/N]');\n if (!confirmed) {\n throw validationError(\n `${target.what} was not confirmed.`,\n 'Nothing was changed.',\n );\n }\n}\n\nfunction versionLabel(template: {\n latestVersion: number;\n publishedVersion: number | null;\n}): string {\n if (template.publishedVersion === null)\n return `v${template.latestVersion} draft, never published`;\n if (template.publishedVersion === template.latestVersion)\n return `v${template.latestVersion} published`;\n return `v${template.publishedVersion} published, v${template.latestVersion} latest`;\n}\n\nfunction listSummary(ui: Ui, list: AgentTemplateList): string {\n if (list.templates.length === 0) {\n return ui.result({\n title: `No agents on ${list.source.slug} yet`,\n tone: 'warn',\n notes: ['\"ekanos agents apply <dir>\" stores the first one.'],\n });\n }\n return [\n ui.result({\n title: `${pluralize(list.templates.length, 'agent')} on ${list.source.slug}`,\n rows: list.templates.map((template): ResultRow => [\n template.key,\n [\n template.name,\n versionLabel(template),\n template.status === 'archived' ? 'archived' : null,\n template.teams\n ? `${pluralize(template.teams.enabled, 'team')}`\n : null,\n ]\n .filter(Boolean)\n .join(' · '),\n ]),\n }),\n ui.hint('\"ekanos agents show <key>\" shows one, with its versions.'),\n ].join('\\n\\n');\n}\n\nfunction templateDetail(ui: Ui, template: AgentTemplateDetail): string {\n const { body } = template;\n const rows: ResultRow[] = [\n ['Versions', versionLabel(template)],\n ['Model', body.model ?? 'house default'],\n ['Tools', describeTools(body)],\n [\n 'Approval',\n `reads ${body.policy.reads}, writes ${body.policy.writes}` +\n (Object.keys(body.policy.overrides).length > 0\n ? `, ${pluralize(Object.keys(body.policy.overrides).length, 'override')}`\n : ''),\n ],\n ['Skills', body.skills.length > 0 ? body.skills.join(', ') : 'none'],\n ['Connections', describeConnections(body)],\n ['Teams may add', describeCustomization(body)],\n ];\n if (template.teams) {\n rows.push([\n 'Teams',\n `${template.teams.enabled} running` +\n (template.teams.pinned > 0\n ? `, ${template.teams.pinned} pinned to an older version`\n : ''),\n ]);\n }\n rows.push([\n 'History',\n template.versions.map(\n (version) =>\n `v${version.version} ${version.createdAt.slice(0, 10)}` +\n (version.createdBy ? ` by ${version.createdBy}` : '') +\n (version.publishedAt\n ? ` · published ${version.publishedAt.slice(0, 10)}`\n : ''),\n ),\n ]);\n return ui.result({ title: `${body.name} (${template.key})`, rows });\n}\n\nfunction describeConnections(body: AgentTemplateBody): string[] {\n const owner = (connection: AgentTemplateBody['connections'][string]) =>\n connection.owner === 'source'\n ? 'one connection for the source'\n : `each team's own (${connection.team})`;\n const lines = [\n ...Object.entries(body.connections).map(\n ([slug, connection]) => `${slug}: ${owner(connection)}`,\n ),\n ...body.mcpServers.map(\n (server) => `${server.key} (MCP, ${server.url}): ${owner(server)}`,\n ),\n ];\n return lines.length > 0 ? lines : [\"each team's own (optional)\"];\n}\n\nfunction describeCustomization(body: AgentTemplateBody): string {\n const allowed = Object.entries(body.teamCustomization)\n .filter(([, on]) => on)\n .map(([knob]) => CUSTOMIZATION_LABEL[knob] ?? knob);\n return allowed.length > 0 ? allowed.join(', ') : 'nothing (template only)';\n}\n\nconst CUSTOMIZATION_LABEL: Record<string, string> = {\n mcpServers: 'own MCP servers',\n skills: 'own skills',\n integrations: 'more integrations',\n narrow: 'narrower tools',\n};\n\nfunction describeTools(body: AgentTemplateBody): string {\n if (body.tools.mode === 'read_only')\n return 'every read the team has connected';\n if (body.tools.mode === 'all') return 'every tool the team has connected';\n return (\n [...(body.tools.products ?? []), ...(body.tools.tools ?? [])].join(', ') ||\n 'none'\n );\n}\n\nconst OUTCOME_TITLE = {\n created: 'Created',\n updated: 'Stored a new version',\n unchanged: 'Unchanged',\n published: 'Published',\n 'rolled-back': 'Rolled back',\n} as const;\n\nfunction resultSummary(ui: Ui, result: AgentTemplateResult): string {\n const { template } = result;\n const rows: ResultRow[] = [['Versions', versionLabel(template)]];\n if (result.outcome === 'published' || result.outcome === 'rolled-back') {\n rows.push(['Teams updated', String(result.teamsUpdated)]);\n }\n const notes =\n (result.outcome === 'created' || result.outcome === 'updated') &&\n template.publishedVersion !== template.latestVersion\n ? [\n `Teams still run the published version. \"ekanos agents publish ${template.key}\" moves them.`,\n ]\n : [];\n return ui.result({\n title: `${OUTCOME_TITLE[result.outcome]}: ${template.key}`,\n tone: result.outcome === 'unchanged' ? 'warn' : 'ok',\n rows,\n notes,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentTemplateBody,\n AgentTemplateBodySchema,\n type AgentTemplateDetail,\n AgentTemplateKeySchema,\n type AgentTemplateList,\n type AgentTemplateResult,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport {\n type AgentsApiResult,\n applyAgentTemplate,\n listAgentTemplates,\n publishAgentTemplate,\n showAgentTemplate,\n} from '../agents-api';\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport {\n authRequiredError,\n notFoundError,\n usageError,\n validationError,\n} from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { classifyPath } from '../safe-fs';\nimport { resolveSourceTarget } from '../source-target';\nimport { type ResultRow, type Ui, pluralize } from '../ui';\nimport { runAgentsInit, withDocsHint } from './agents-init';\nimport { promptYesNo } from './publish';\n\nexport const AGENTS_SUBCOMMANDS = [\n 'init',\n 'list',\n 'show',\n 'pull',\n 'apply',\n 'publish',\n 'rollback',\n] as const;\n\ntype AgentsSubcommand = (typeof AGENTS_SUBCOMMANDS)[number];\n\n/** The file `pull` writes and `apply` reads, inside an agent's directory. */\nexport const AGENT_FILE = 'agent.json';\n/** Instructions as Markdown, beside it. Used when `agent.json` has none. */\nexport const AGENT_INSTRUCTIONS_FILE = 'AGENT.md';\n\nexport interface AgentsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n /** A template key, or for `apply` a file or directory. */\n target?: string;\n /** `publish` / `rollback`: the version to make the one teams run. */\n to?: string;\n baseVersion?: string;\n overwrite: boolean;\n out?: string;\n yes: boolean;\n /** `init`: replace the skills and CLAUDE.md even when they exist. */\n force?: boolean;\n /** `init`: `--claude` adds the docs to Claude Code without asking; `--no-claude` skips it. */\n claude?: boolean;\n dir: string;\n env: Record<string, string | undefined>;\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/**\n * `agents` — the Source's agent templates (plan 239.0 / 239.2). Ekanos holds\n * them; nothing here is deployed. `apply` stores a new version (a draft\n * until published), `publish` makes a version the one every team runs,\n * `rollback` publishes an older one. `pull` writes a template out as\n * `agent.json` + `AGENT.md` for review or Git, and `apply` reads the same\n * layout back.\n */\nexport async function runAgents(\n ctx: CliContext,\n args: AgentsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n\n // Local only: no host, no session.\n if (subcommand === 'init') {\n return runAgentsInit(ctx, {\n dir: path.resolve(args.dir, args.target ?? '.'),\n force: args.force === true,\n claude: args.claude,\n canPrompt: canPrompt(ctx, args),\n confirm: args.confirm ?? promptYesNo,\n env: args.env,\n });\n }\n\n // Read the local input before any network call, so a bad file fails fast.\n const local =\n subcommand === 'apply' ? readAgentInput(args.target, args.dir) : null;\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new AgentsClient(env, resolved.session);\n const source = resolved.source;\n\n switch (subcommand) {\n case 'list': {\n const list = await client.call((token) =>\n listAgentTemplates(env.host, token, source),\n );\n return ctx.succeed(\n { host: env.host, ...list },\n withDocsHint(ctx.ui, args.dir, listSummary(ctx.ui, list)),\n );\n }\n case 'show': {\n const key = requireKey(args.target, 'show');\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n return ctx.succeed(\n { host: env.host, ...shown },\n templateDetail(ctx.ui, shown.template),\n );\n }\n case 'pull': {\n const key = requireKey(args.target, 'pull');\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n const outDir = path.resolve(\n args.dir,\n args.out ?? path.join('agents', key),\n );\n const written = writeAgentFiles(outDir, shown.template);\n return ctx.succeed(\n {\n host: env.host,\n key,\n version: shown.template.latestVersion,\n files: written,\n },\n ctx.ui.result({\n title: `Pulled ${key} v${shown.template.latestVersion}`,\n rows: written.map((file): ResultRow => ['Wrote', file]),\n notes: [\n `Edit, then \"ekanos agents apply ${path.relative(args.dir, outDir) || '.'}\".`,\n ],\n }),\n );\n }\n case 'apply': {\n const input = local!;\n const baseVersion =\n parseVersionFlag(args.baseVersion, '--base-version') ??\n input.baseVersion;\n const result = await client.call((token) =>\n applyAgentTemplate(env.host, token, {\n source,\n key: input.key,\n body: input.body,\n baseVersion,\n overwrite: args.overwrite,\n }),\n );\n if (input.file && result.outcome !== 'unchanged') {\n recordBaseVersion(input.file, result.version);\n }\n return ctx.succeed(\n { host: env.host, ...result },\n resultSummary(ctx.ui, result),\n );\n }\n case 'publish':\n case 'rollback': {\n const key = requireKey(args.target, subcommand);\n let version = parseVersionFlag(args.to, '--to') ?? undefined;\n if (subcommand === 'rollback' && version === undefined) {\n throw usageError(\n 'rollback needs the version to go back to.',\n `Pass \"--to <n>\". \"ekanos agents show ${key}\" lists them.`,\n );\n }\n // Refuse a script with no --yes before reading anything.\n if (!args.yes && !canPrompt(ctx, args)) {\n throw validationError(\n `${subcommand === 'rollback' ? 'Rolling back' : 'Publishing'} ${key} on ${source} needs confirmation.`,\n 'It reaches every team running this agent at once. Pass --yes to confirm.',\n );\n }\n // Publish names the version it confirmed, never \"whatever is latest\n // when the request lands\" — a draft applied in between is not shipped\n // unseen to every team.\n if (version === undefined) {\n const shown = await client.call((token) =>\n showAgentTemplate(env.host, token, source, key),\n );\n version = shown.template.latestVersion;\n }\n await confirmPublish(ctx, args, {\n key,\n source,\n what:\n subcommand === 'rollback'\n ? `Roll ${key} back to version ${version}`\n : `Publish ${key} version ${version}`,\n });\n const result = await client.call((token) =>\n publishAgentTemplate(env.host, token, subcommand, {\n source,\n key,\n version,\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n resultSummary(ctx.ui, result),\n );\n }\n }\n}\n\n/** Every call refreshes the session once on a 401, then gives up. */\nclass AgentsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<AgentsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the agents call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nfunction parseSubcommand(value: string | undefined): AgentsSubcommand {\n const match = AGENTS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value\n ? `Unknown agents subcommand \"${value}\".`\n : 'agents needs a subcommand.',\n `Run one of: ${AGENTS_SUBCOMMANDS.map((name) => `ekanos agents ${name}`).join(', ')}.`,\n );\n}\n\nfunction requireKey(value: string | undefined, verb: string): string {\n const parsed = AgentTemplateKeySchema.safeParse(value ?? '');\n if (parsed.success) return parsed.data;\n throw usageError(\n value\n ? `\"${value}\" is not an agent key.`\n : `agents ${verb} needs an agent key.`,\n `Pass the key, e.g. \"ekanos agents ${verb} support-triage\". ` +\n `\"ekanos agents list\" shows them.`,\n );\n}\n\nfunction parseVersionFlag(\n value: string | undefined,\n flag: string,\n): number | null {\n if (value === undefined) return null;\n const version = Number(value);\n if (Number.isInteger(version) && version >= 1) return version;\n throw usageError(\n `${flag} must be a version number (got \"${value}\").`,\n `\"ekanos agents show <key>\" lists the versions.`,\n );\n}\n\ninterface AgentInput {\n key: string;\n body: AgentTemplateBody;\n baseVersion: number | null;\n /** The agent.json read, when there was one, so the new version is recorded in it. */\n file: string | null;\n}\n\n/**\n * Read `apply`'s input: a directory holding `agent.json` (and optionally\n * `AGENT.md`), or a `.json` file. The key is the file's `key`, else the\n * directory's name. `baseVersion` in the file is the version it was pulled\n * or last applied at — what the host checks for a concurrent change.\n */\nexport function readAgentInput(\n target: string | undefined,\n cwd: string,\n): AgentInput {\n if (!target) {\n throw usageError(\n 'agents apply needs a file or directory.',\n `Pass an agent directory (\"ekanos agents apply agents/support\") or a ` +\n `JSON file. \"ekanos agents pull <key>\" writes the layout.`,\n );\n }\n const resolved = path.resolve(cwd, target);\n const kind = classifyPath(resolved);\n const dir = kind === 'directory' ? resolved : path.dirname(resolved);\n const file =\n kind === 'directory' ? path.join(resolved, AGENT_FILE) : resolved;\n\n if (classifyPath(file) !== 'file') {\n throw notFoundError(\n `No ${kind === 'directory' ? AGENT_FILE : 'file'} at ${file}.`,\n `\"ekanos agents pull <key>\" writes ${AGENT_FILE} and ${AGENT_INSTRUCTIONS_FILE}.`,\n );\n }\n\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(file, 'utf8'));\n } catch (error) {\n throw validationError(\n `${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n 'Fix the JSON and apply again.',\n );\n }\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw validationError(\n `${file} must hold a JSON object.`,\n 'See \"ekanos agents --help\".',\n );\n }\n\n const {\n key: rawKey,\n baseVersion: rawBase,\n $schema: _schema,\n ...rest\n } = raw as Record<string, unknown>;\n const fields: Record<string, unknown> = { ...rest };\n\n const instructionsFile = path.join(dir, AGENT_INSTRUCTIONS_FILE);\n if (\n fields.instructions === undefined &&\n classifyPath(instructionsFile) === 'file'\n ) {\n fields.instructions = fs.readFileSync(instructionsFile, 'utf8');\n }\n\n const key = AgentTemplateKeySchema.safeParse(\n typeof rawKey === 'string' ? rawKey : path.basename(dir),\n );\n if (!key.success) {\n throw validationError(\n `No usable agent key: set \"key\" in ${file}, or name the directory after it.`,\n key.error.issues[0]?.message ??\n 'Use lowercase letters, digits and hyphens.',\n );\n }\n\n const body = AgentTemplateBodySchema.safeParse(fields);\n if (!body.success) {\n throw validationError(\n [\n `${file} is not a valid agent:`,\n ...body.error.issues.map(\n (issue) => ` ${issue.path.join('.') || '(root)'}: ${issue.message}`,\n ),\n ].join('\\n'),\n `Fields: name, description, instructions (or ${AGENT_INSTRUCTIONS_FILE}), ` +\n `model, maxTurns, tools, policy, skills.`,\n );\n }\n\n const baseVersion =\n typeof rawBase === 'number' && Number.isInteger(rawBase) && rawBase >= 1\n ? rawBase\n : null;\n\n return { key: key.data, body: body.data, baseVersion, file };\n}\n\n/**\n * Write `agent.json` + `AGENT.md`. The instructions live in the Markdown so\n * they read and diff as prose; the JSON holds everything else plus the\n * version they came from.\n */\nfunction writeAgentFiles(\n outDir: string,\n template: AgentTemplateDetail,\n): string[] {\n fs.mkdirSync(outDir, { recursive: true });\n const { instructions, ...rest } = template.body;\n const json = {\n key: template.key,\n baseVersion: template.latestVersion,\n ...rest,\n };\n const jsonPath = path.join(outDir, AGENT_FILE);\n const mdPath = path.join(outDir, AGENT_INSTRUCTIONS_FILE);\n for (const target of [jsonPath, mdPath]) {\n const kind = classifyPath(target);\n if (kind !== 'missing' && kind !== 'file') {\n throw validationError(\n `Refusing to write through ${target} (${kind}).`,\n 'Remove it, or pass --out <dir>.',\n );\n }\n }\n fs.writeFileSync(jsonPath, `${JSON.stringify(json, null, 2)}\\n`);\n fs.writeFileSync(\n mdPath,\n instructions.endsWith('\\n') ? instructions : `${instructions}\\n`,\n );\n return [jsonPath, mdPath];\n}\n\n/** After a stored version, point the file at it, so the next apply is based on it. */\nfunction recordBaseVersion(file: string, version: number) {\n const raw = JSON.parse(fs.readFileSync(file, 'utf8')) as Record<\n string,\n unknown\n >;\n if (raw.baseVersion === version) return;\n const { key, baseVersion: _old, ...rest } = raw;\n const next =\n key === undefined\n ? { baseVersion: version, ...rest }\n : { key, baseVersion: version, ...rest };\n fs.writeFileSync(file, `${JSON.stringify(next, null, 2)}\\n`);\n}\n\nfunction canPrompt(ctx: CliContext, args: AgentsArgs): boolean {\n return !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n\n/**\n * Publishing changes what every team running the agent does, at once. A\n * human run asks first; a scripted or JSON run needs `--yes`.\n */\nasync function confirmPublish(\n ctx: CliContext,\n args: AgentsArgs,\n target: { key: string; source: string; what: string },\n) {\n if (args.yes) return;\n if (!canPrompt(ctx, args)) {\n throw validationError(\n `${target.what} on ${target.source} needs confirmation.`,\n 'It reaches every team running this agent at once. Pass --yes to confirm.',\n );\n }\n ctx.log(\n `${target.what} on ${target.source}. Every team running it follows at once.`,\n );\n const confirmed = await (args.confirm ?? promptYesNo)('Proceed? [y/N]');\n if (!confirmed) {\n throw validationError(\n `${target.what} was not confirmed.`,\n 'Nothing was changed.',\n );\n }\n}\n\nfunction versionLabel(template: {\n latestVersion: number;\n publishedVersion: number | null;\n}): string {\n if (template.publishedVersion === null)\n return `v${template.latestVersion} draft, never published`;\n if (template.publishedVersion === template.latestVersion)\n return `v${template.latestVersion} published`;\n return `v${template.publishedVersion} published, v${template.latestVersion} latest`;\n}\n\nfunction listSummary(ui: Ui, list: AgentTemplateList): string {\n if (list.templates.length === 0) {\n return ui.result({\n title: `No agents on ${list.source.slug} yet`,\n tone: 'warn',\n notes: ['\"ekanos agents apply <dir>\" stores the first one.'],\n });\n }\n return [\n ui.result({\n title: `${pluralize(list.templates.length, 'agent')} on ${list.source.slug}`,\n rows: list.templates.map((template): ResultRow => [\n template.key,\n [\n template.name,\n versionLabel(template),\n template.status === 'archived' ? 'archived' : null,\n template.teams\n ? `${pluralize(template.teams.enabled, 'team')}`\n : null,\n ]\n .filter(Boolean)\n .join(' · '),\n ]),\n }),\n ui.hint('\"ekanos agents show <key>\" shows one, with its versions.'),\n ].join('\\n\\n');\n}\n\nfunction templateDetail(ui: Ui, template: AgentTemplateDetail): string {\n const { body } = template;\n const rows: ResultRow[] = [\n ['Versions', versionLabel(template)],\n ['Model', body.model ?? 'house default'],\n ['Tools', describeTools(body)],\n [\n 'Approval',\n `reads ${body.policy.reads}, writes ${body.policy.writes}` +\n (Object.keys(body.policy.overrides).length > 0\n ? `, ${pluralize(Object.keys(body.policy.overrides).length, 'override')}`\n : ''),\n ],\n ['Skills', body.skills.length > 0 ? body.skills.join(', ') : 'none'],\n ['Connections', describeConnections(body)],\n ['Teams may add', describeCustomization(body)],\n ];\n if (template.teams) {\n rows.push([\n 'Teams',\n `${template.teams.enabled} running` +\n (template.teams.pinned > 0\n ? `, ${template.teams.pinned} pinned to an older version`\n : ''),\n ]);\n }\n rows.push([\n 'History',\n template.versions.map(\n (version) =>\n `v${version.version} ${version.createdAt.slice(0, 10)}` +\n (version.createdBy ? ` by ${version.createdBy}` : '') +\n (version.publishedAt\n ? ` · published ${version.publishedAt.slice(0, 10)}`\n : ''),\n ),\n ]);\n return ui.result({ title: `${body.name} (${template.key})`, rows });\n}\n\nfunction describeConnections(body: AgentTemplateBody): string[] {\n const owner = (connection: AgentTemplateBody['connections'][string]) =>\n connection.owner === 'source'\n ? 'one connection for the source'\n : `each team's own (${connection.team})`;\n const lines = [\n ...Object.entries(body.connections).map(\n ([slug, connection]) => `${slug}: ${owner(connection)}`,\n ),\n ...body.mcpServers.map(\n (server) => `${server.key} (MCP, ${server.url}): ${owner(server)}`,\n ),\n ];\n return lines.length > 0 ? lines : [\"each team's own (optional)\"];\n}\n\nfunction describeCustomization(body: AgentTemplateBody): string {\n const allowed = Object.entries(body.teamCustomization)\n .filter(([, on]) => on)\n .map(([knob]) => CUSTOMIZATION_LABEL[knob] ?? knob);\n return allowed.length > 0 ? allowed.join(', ') : 'nothing (template only)';\n}\n\nconst CUSTOMIZATION_LABEL: Record<string, string> = {\n mcpServers: 'own MCP servers',\n skills: 'own skills',\n integrations: 'more integrations',\n narrow: 'narrower tools',\n};\n\nfunction describeTools(body: AgentTemplateBody): string {\n if (body.tools.mode === 'read_only')\n return 'every read the team has connected';\n if (body.tools.mode === 'all') return 'every tool the team has connected';\n return (\n [...(body.tools.products ?? []), ...(body.tools.tools ?? [])].join(', ') ||\n 'none'\n );\n}\n\nconst OUTCOME_TITLE = {\n created: 'Created',\n updated: 'Stored a new version',\n unchanged: 'Unchanged',\n published: 'Published',\n 'rolled-back': 'Rolled back',\n} as const;\n\nfunction resultSummary(ui: Ui, result: AgentTemplateResult): string {\n const { template } = result;\n const rows: ResultRow[] = [['Versions', versionLabel(template)]];\n if (result.outcome === 'published' || result.outcome === 'rolled-back') {\n rows.push(['Teams updated', String(result.teamsUpdated)]);\n }\n const notes =\n (result.outcome === 'created' || result.outcome === 'updated') &&\n template.publishedVersion !== template.latestVersion\n ? [\n `Teams still run the published version. \"ekanos agents publish ${template.key}\" moves them.`,\n ]\n : [];\n return ui.result({\n title: `${OUTCOME_TITLE[result.outcome]}: ${template.key}`,\n tone: result.outcome === 'unchanged' ? 'warn' : 'ok',\n rows,\n notes,\n });\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CliContext } from '../context.js';
|
|
2
|
+
import type { ExitCode } from '../exit-codes.js';
|
|
3
|
+
export declare const APPS_SUBCOMMANDS: readonly ['show', 'set'];
|
|
4
|
+
export interface AppsArgs {
|
|
5
|
+
host?: string;
|
|
6
|
+
source?: string;
|
|
7
|
+
subcommand?: string;
|
|
8
|
+
product?: string;
|
|
9
|
+
dir: string;
|
|
10
|
+
env: Record<string, string | undefined>;
|
|
11
|
+
stdinIsTTY?: boolean;
|
|
12
|
+
/** Test seams for the questions `set` asks. */
|
|
13
|
+
ask?: (question: string) => Promise<string>;
|
|
14
|
+
askSecret?: (question: string) => Promise<string>;
|
|
15
|
+
confirm?: (question: string) => Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `apps` — a Source's provider apps: the OAuth client an integration signs
|
|
19
|
+
* every team in through (Linear's, say). `show` says whether the Source has
|
|
20
|
+
* one and which callback URL to register; `set` takes the client id and
|
|
21
|
+
* secret from the Source admin at the terminal — never from a flag, a file
|
|
22
|
+
* or a non-interactive run, so an agent driving the CLI never handles the
|
|
23
|
+
* secret.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runApps(ctx: CliContext, args: AppsArgs): Promise<ExitCode>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { setProviderApp, showProviderApp, } from '../apps-api.js';
|
|
2
|
+
import { refreshStoredSession, requireSession, resolveAuthEnvironment, } from '../auth/session.js';
|
|
3
|
+
import { authRequiredError, usageError, validationError } from '../errors.js';
|
|
4
|
+
import { resolveSourceTarget } from '../source-target.js';
|
|
5
|
+
import { promptYesNo } from './publish.js';
|
|
6
|
+
export const APPS_SUBCOMMANDS = ['show', 'set'];
|
|
7
|
+
/**
|
|
8
|
+
* `apps` — a Source's provider apps: the OAuth client an integration signs
|
|
9
|
+
* every team in through (Linear's, say). `show` says whether the Source has
|
|
10
|
+
* one and which callback URL to register; `set` takes the client id and
|
|
11
|
+
* secret from the Source admin at the terminal — never from a flag, a file
|
|
12
|
+
* or a non-interactive run, so an agent driving the CLI never handles the
|
|
13
|
+
* secret.
|
|
14
|
+
*/
|
|
15
|
+
export async function runApps(ctx, args) {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
const subcommand = parseSubcommand(args.subcommand);
|
|
18
|
+
const product = requireProduct(args.product, subcommand);
|
|
19
|
+
if (subcommand === 'set' && !canPrompt(ctx, args)) {
|
|
20
|
+
throw usageError('apps set takes the client secret at a terminal, never in a script or an agent run.', `Run it yourself in your terminal: npx @ekanos/cli apps set ${product}${args.source ? ` --source ${args.source}` : ''}`);
|
|
21
|
+
}
|
|
22
|
+
const env = resolveAuthEnvironment(ctx, args.host, args.env, {
|
|
23
|
+
projectDir: args.dir,
|
|
24
|
+
});
|
|
25
|
+
const resolved = await resolveSourceTarget(env, requireSession(env.store, env.host), args);
|
|
26
|
+
const client = new AppsClient(env, resolved.session);
|
|
27
|
+
const source = resolved.source;
|
|
28
|
+
const status = await client.call((token) => showProviderApp(env.host, token, source, product));
|
|
29
|
+
if (subcommand === 'show') {
|
|
30
|
+
return ctx.succeed(Object.assign({ host: env.host }, status), summary(ctx, status));
|
|
31
|
+
}
|
|
32
|
+
ctx.log([
|
|
33
|
+
`${status.product.name} app for ${status.source.slug}`,
|
|
34
|
+
` 1. In ${status.product.name}, create an OAuth app (or open the one you use).`,
|
|
35
|
+
` 2. Register this callback URL exactly: ${status.callbackUrl}`,
|
|
36
|
+
` 3. Enter its client ID and secret below. The secret is stored in Ekanos's vault and never shown again.`,
|
|
37
|
+
].join('\n'));
|
|
38
|
+
if (status.configured) {
|
|
39
|
+
const replace = await ((_a = args.confirm) !== null && _a !== void 0 ? _a : promptYesNo)(`${status.source.slug} already has ${status.product.name} credentials. Replace them? [y/N]`);
|
|
40
|
+
if (!replace) {
|
|
41
|
+
throw validationError('Nothing was changed.', `Run "ekanos apps show ${product}" to see the current state.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const clientId = (await ((_b = args.ask) !== null && _b !== void 0 ? _b : promptLine)('Client ID: ')).trim();
|
|
45
|
+
const clientSecret = (await ((_c = args.askSecret) !== null && _c !== void 0 ? _c : promptHidden)('Client secret (hidden): ')).trim();
|
|
46
|
+
if (!clientId || !clientSecret) {
|
|
47
|
+
throw validationError('Both the client ID and the client secret are needed.', `Run "ekanos apps set ${product}" again.`);
|
|
48
|
+
}
|
|
49
|
+
const result = await client.call((token) => setProviderApp(env.host, token, {
|
|
50
|
+
source,
|
|
51
|
+
product,
|
|
52
|
+
clientId,
|
|
53
|
+
clientSecret,
|
|
54
|
+
}));
|
|
55
|
+
return ctx.succeed(Object.assign({ host: env.host }, result), ctx.ui.result({
|
|
56
|
+
title: result.replaced
|
|
57
|
+
? `Replaced the ${result.product.name} app`
|
|
58
|
+
: `Set up the ${result.product.name} app`,
|
|
59
|
+
rows: [
|
|
60
|
+
['Source', result.source.slug],
|
|
61
|
+
['Teams can connect', result.configured ? 'yes' : 'not yet'],
|
|
62
|
+
['Callback URL', result.callbackUrl],
|
|
63
|
+
],
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
function summary(ctx, status) {
|
|
67
|
+
const rows = [
|
|
68
|
+
['Source', status.source.slug],
|
|
69
|
+
[
|
|
70
|
+
'Set up',
|
|
71
|
+
status.configured
|
|
72
|
+
? 'yes — teams can connect'
|
|
73
|
+
: 'no — no team can connect yet',
|
|
74
|
+
],
|
|
75
|
+
['Callback URL', status.callbackUrl],
|
|
76
|
+
];
|
|
77
|
+
return [
|
|
78
|
+
ctx.ui.result({ title: `${status.product.name} app`, rows }),
|
|
79
|
+
...(status.configured
|
|
80
|
+
? []
|
|
81
|
+
: [
|
|
82
|
+
ctx.ui.hint(`Run "ekanos apps set ${status.product.slug}" in your terminal to enter its credentials.`),
|
|
83
|
+
]),
|
|
84
|
+
].join('\n');
|
|
85
|
+
}
|
|
86
|
+
class AppsClient {
|
|
87
|
+
constructor(env, session) {
|
|
88
|
+
this.env = env;
|
|
89
|
+
this.session = session;
|
|
90
|
+
}
|
|
91
|
+
async call(send) {
|
|
92
|
+
let result = await send(this.session.accessToken);
|
|
93
|
+
if (result.status === 'unauthorized') {
|
|
94
|
+
this.session = await refreshStoredSession(this.env, this.session);
|
|
95
|
+
result = await send(this.session.accessToken);
|
|
96
|
+
}
|
|
97
|
+
if (result.status === 'ok')
|
|
98
|
+
return result.data;
|
|
99
|
+
throw authRequiredError(`The session for ${this.env.host} could not authorize the apps call.`, `Run "ekanos login --host ${this.env.host}" and retry.`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function canPrompt(ctx, args) {
|
|
103
|
+
var _a;
|
|
104
|
+
return !ctx.jsonMode && ((_a = args.stdinIsTTY) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true);
|
|
105
|
+
}
|
|
106
|
+
function parseSubcommand(value) {
|
|
107
|
+
const match = APPS_SUBCOMMANDS.find((name) => name === value);
|
|
108
|
+
if (match)
|
|
109
|
+
return match;
|
|
110
|
+
throw usageError(value ? `Unknown apps subcommand "${value}".` : 'apps needs a subcommand.', `Run one of: ${APPS_SUBCOMMANDS.map((name) => `ekanos apps ${name} <product>`).join(', ')}.`);
|
|
111
|
+
}
|
|
112
|
+
function requireProduct(value, verb) {
|
|
113
|
+
const slug = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
|
|
114
|
+
if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug))
|
|
115
|
+
return slug;
|
|
116
|
+
throw usageError(value
|
|
117
|
+
? `"${value}" is not a product slug.`
|
|
118
|
+
: `apps ${verb} needs a product.`, `Pass the product's slug, e.g. "ekanos apps ${verb} linear". "ekanos catalog" lists them.`);
|
|
119
|
+
}
|
|
120
|
+
async function promptLine(question) {
|
|
121
|
+
const readline = await import('node:readline/promises');
|
|
122
|
+
const rl = readline.createInterface({
|
|
123
|
+
input: process.stdin,
|
|
124
|
+
output: process.stderr,
|
|
125
|
+
});
|
|
126
|
+
try {
|
|
127
|
+
return await rl.question(question);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
rl.close();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Read a line without echoing it: the secret never appears on screen or in scrollback. */
|
|
134
|
+
async function promptHidden(question) {
|
|
135
|
+
const readline = await import('node:readline');
|
|
136
|
+
process.stderr.write(question);
|
|
137
|
+
const rl = readline.createInterface({
|
|
138
|
+
input: process.stdin,
|
|
139
|
+
output: process.stderr,
|
|
140
|
+
terminal: true,
|
|
141
|
+
});
|
|
142
|
+
// Swallow readline's echo of each keystroke; the question is already written.
|
|
143
|
+
rl._writeToOutput =
|
|
144
|
+
() => { };
|
|
145
|
+
try {
|
|
146
|
+
return await new Promise((resolve) => {
|
|
147
|
+
rl.question('', resolve);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
rl.close();
|
|
152
|
+
process.stderr.write('\n');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=apps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderAppStatus } from '@ekanos/integration-schema';\n\nimport {\n type AppsApiResult,\n setProviderApp,\n showProviderApp,\n} from '../apps-api';\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport { authRequiredError, usageError, validationError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport type { ResultRow } from '../ui';\nimport { promptYesNo } from './publish';\n\nexport const APPS_SUBCOMMANDS = ['show', 'set'] as const;\ntype AppsSubcommand = (typeof APPS_SUBCOMMANDS)[number];\n\nexport interface AppsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n stdinIsTTY?: boolean;\n /** Test seams for the questions `set` asks. */\n ask?: (question: string) => Promise<string>;\n askSecret?: (question: string) => Promise<string>;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/**\n * `apps` — a Source's provider apps: the OAuth client an integration signs\n * every team in through (Linear's, say). `show` says whether the Source has\n * one and which callback URL to register; `set` takes the client id and\n * secret from the Source admin at the terminal — never from a flag, a file\n * or a non-interactive run, so an agent driving the CLI never handles the\n * secret.\n */\nexport async function runApps(\n ctx: CliContext,\n args: AppsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n const product = requireProduct(args.product, subcommand);\n\n if (subcommand === 'set' && !canPrompt(ctx, args)) {\n throw usageError(\n 'apps set takes the client secret at a terminal, never in a script or an agent run.',\n `Run it yourself in your terminal: npx @ekanos/cli apps set ${product}${args.source ? ` --source ${args.source}` : ''}`,\n );\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new AppsClient(env, resolved.session);\n const source = resolved.source;\n\n const status = await client.call((token) =>\n showProviderApp(env.host, token, source, product),\n );\n\n if (subcommand === 'show') {\n return ctx.succeed({ host: env.host, ...status }, summary(ctx, status));\n }\n\n ctx.log(\n [\n `${status.product.name} app for ${status.source.slug}`,\n ` 1. In ${status.product.name}, create an OAuth app (or open the one you use).`,\n ` 2. Register this callback URL exactly: ${status.callbackUrl}`,\n ` 3. Enter its client ID and secret below. The secret is stored in Ekanos's vault and never shown again.`,\n ].join('\\n'),\n );\n if (status.configured) {\n const replace = await (args.confirm ?? promptYesNo)(\n `${status.source.slug} already has ${status.product.name} credentials. Replace them? [y/N]`,\n );\n if (!replace) {\n throw validationError(\n 'Nothing was changed.',\n `Run \"ekanos apps show ${product}\" to see the current state.`,\n );\n }\n }\n\n const clientId = (await (args.ask ?? promptLine)('Client ID: ')).trim();\n const clientSecret = (\n await (args.askSecret ?? promptHidden)('Client secret (hidden): ')\n ).trim();\n if (!clientId || !clientSecret) {\n throw validationError(\n 'Both the client ID and the client secret are needed.',\n `Run \"ekanos apps set ${product}\" again.`,\n );\n }\n\n const result = await client.call((token) =>\n setProviderApp(env.host, token, {\n source,\n product,\n clientId,\n clientSecret,\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n ctx.ui.result({\n title: result.replaced\n ? `Replaced the ${result.product.name} app`\n : `Set up the ${result.product.name} app`,\n rows: [\n ['Source', result.source.slug],\n ['Teams can connect', result.configured ? 'yes' : 'not yet'],\n ['Callback URL', result.callbackUrl],\n ],\n }),\n );\n}\n\nfunction summary(ctx: CliContext, status: ProviderAppStatus): string {\n const rows: ResultRow[] = [\n ['Source', status.source.slug],\n [\n 'Set up',\n status.configured\n ? 'yes — teams can connect'\n : 'no — no team can connect yet',\n ],\n ['Callback URL', status.callbackUrl],\n ];\n return [\n ctx.ui.result({ title: `${status.product.name} app`, rows }),\n ...(status.configured\n ? []\n : [\n ctx.ui.hint(\n `Run \"ekanos apps set ${status.product.slug}\" in your terminal to enter its credentials.`,\n ),\n ]),\n ].join('\\n');\n}\n\nclass AppsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<AppsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the apps call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nfunction canPrompt(ctx: CliContext, args: AppsArgs): boolean {\n return !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n\nfunction parseSubcommand(value: string | undefined): AppsSubcommand {\n const match = APPS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value ? `Unknown apps subcommand \"${value}\".` : 'apps needs a subcommand.',\n `Run one of: ${APPS_SUBCOMMANDS.map((name) => `ekanos apps ${name} <product>`).join(', ')}.`,\n );\n}\n\nfunction requireProduct(value: string | undefined, verb: string): string {\n const slug = value?.trim().toLowerCase();\n if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug)) return slug;\n throw usageError(\n value\n ? `\"${value}\" is not a product slug.`\n : `apps ${verb} needs a product.`,\n `Pass the product's slug, e.g. \"ekanos apps ${verb} linear\". \"ekanos catalog\" lists them.`,\n );\n}\n\nasync function promptLine(question: string): Promise<string> {\n const readline = await import('node:readline/promises');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n try {\n return await rl.question(question);\n } finally {\n rl.close();\n }\n}\n\n/** Read a line without echoing it: the secret never appears on screen or in scrollback. */\nasync function promptHidden(question: string): Promise<string> {\n const readline = await import('node:readline');\n process.stderr.write(question);\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n terminal: true,\n });\n // Swallow readline's echo of each keystroke; the question is already written.\n (rl as unknown as { _writeToOutput: (text: string) => void })._writeToOutput =\n () => {};\n try {\n return await new Promise<string>((resolve) => {\n rl.question('', resolve);\n });\n } finally {\n rl.close();\n process.stderr.write('\\n');\n }\n}\n"]}
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface LoginArgs {
|
|
|
13
13
|
* `index.ts`.
|
|
14
14
|
*/
|
|
15
15
|
stdinIsTTY?: boolean;
|
|
16
|
+
/** `--claude` adds the Ekanos docs to Claude Code without asking; `--no-claude` skips the offer. */
|
|
17
|
+
claude?: boolean;
|
|
18
|
+
/** Test seam for the Claude Code offer's question. */
|
|
19
|
+
confirm?: (question: string) => Promise<boolean>;
|
|
16
20
|
}
|
|
17
21
|
/**
|
|
18
22
|
* `login` — authenticate this machine against an Ekanos deployment via the
|
package/dist/commands/login.js
CHANGED
|
@@ -2,10 +2,12 @@ import { pollForDeviceTokens, startDeviceAuthorization, } from '../auth/device-f
|
|
|
2
2
|
import { createEkanosSession, fetchCliAuthConfig } from '../auth/ekanos-api.js';
|
|
3
3
|
import { resolveAuthEnvironment, resolveIdentity } from '../auth/session.js';
|
|
4
4
|
import { printBanner } from '../banner.js';
|
|
5
|
+
import { claudeDocsRow, offerDocsToClaude } from '../claude-docs.js';
|
|
5
6
|
import { CliError } from '../errors.js';
|
|
6
7
|
import { ERROR_CODES } from '../exit-codes.js';
|
|
7
8
|
import { shortHost } from '../ui.js';
|
|
8
9
|
import { canWizard, wizard } from '../wizard.js';
|
|
10
|
+
import { promptYesNo } from './publish.js';
|
|
9
11
|
/**
|
|
10
12
|
* `login` — authenticate this machine against an Ekanos deployment via the
|
|
11
13
|
* Auth0 device authorization flow.
|
|
@@ -25,7 +27,7 @@ import { canWizard, wizard } from '../wizard.js';
|
|
|
25
27
|
* non-TTY mode are byte-for-byte what they were before this existed.
|
|
26
28
|
*/
|
|
27
29
|
export async function runLogin(ctx, args) {
|
|
28
|
-
var _a, _b, _c, _d, _e;
|
|
30
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
29
31
|
// No `projectDir`: login is the one verb that CREATES credentials, so its
|
|
30
32
|
// host must come from something the developer chose (--host, EKANOS_HOST)
|
|
31
33
|
// or already trusts (the sole stored login) — never from a committed
|
|
@@ -100,9 +102,18 @@ export async function runLogin(ctx, args) {
|
|
|
100
102
|
updatedAt: new Date().toISOString(),
|
|
101
103
|
};
|
|
102
104
|
env.store.write(env.host, stored);
|
|
105
|
+
// A first sign-in is when a developer is setting up: offer the docs to
|
|
106
|
+
// Claude Code once, so it can look Ekanos up instead of guessing.
|
|
107
|
+
const claudeDocs = await offerDocsToClaude({
|
|
108
|
+
choice: args.claude,
|
|
109
|
+
canPrompt: !ctx.jsonMode && ((_d = args.stdinIsTTY) !== null && _d !== void 0 ? _d : process.stdin.isTTY === true),
|
|
110
|
+
confirm: (_e = args.confirm) !== null && _e !== void 0 ? _e : promptYesNo,
|
|
111
|
+
env: args.env,
|
|
112
|
+
});
|
|
113
|
+
const claudeRow = claudeDocsRow(claudeDocs);
|
|
103
114
|
printBanner(ctx);
|
|
104
115
|
if (useWizard) {
|
|
105
|
-
wizard.outro(`Signed in as ${(
|
|
116
|
+
wizard.outro(`Signed in as ${(_f = session.email) !== null && _f !== void 0 ? _f : session.userId} on ${shortHost(env.host)}.`);
|
|
106
117
|
}
|
|
107
118
|
return ctx.succeed({
|
|
108
119
|
host: env.host,
|
|
@@ -110,13 +121,15 @@ export async function runLogin(ctx, args) {
|
|
|
110
121
|
user: { id: session.userId, email: session.email },
|
|
111
122
|
expiresAt: session.expiresAt,
|
|
112
123
|
credentialsPath: env.store.filePath,
|
|
124
|
+
claudeDocs,
|
|
113
125
|
}, useWizard
|
|
114
126
|
? ''
|
|
115
127
|
: ctx.ui.result({
|
|
116
128
|
title: 'Signed in',
|
|
117
129
|
rows: [
|
|
118
|
-
['Account', (
|
|
130
|
+
['Account', (_g = session.email) !== null && _g !== void 0 ? _g : session.userId],
|
|
119
131
|
['Host', shortHost(env.host)],
|
|
132
|
+
...(claudeRow ? [claudeRow] : []),
|
|
120
133
|
],
|
|
121
134
|
}));
|
|
122
135
|
}
|
|
@@ -1 +1 @@
|
|
|
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 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":"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;AACxC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAElE,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;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAqBxC;;;;;;;;;;;;;;;;;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,uEAAuE;IACvE,kEAAkE;IAClE,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC;QACzC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EACP,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAC,IAAI,CAAC,UAAU,mCAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;QACpE,OAAO,QAAE,IAAI,CAAC,OAAO,mCAAI,WAAW;QACpC,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAE5C,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;QACnC,UAAU;KACX,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;gBAC7B,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aAClC;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 { 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
|