@ekanos/cli 0.14.0 → 0.16.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/README.md +41 -4
- package/dist/auth/ekanos-api.d.ts +23 -0
- package/dist/auth/ekanos-api.js +33 -6
- package/dist/auth/ekanos-api.js.map +1 -1
- package/dist/commands/agents.d.ts +2 -2
- package/dist/commands/agents.js +14 -20
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/apps.d.ts +11 -3
- package/dist/commands/apps.js +86 -28
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/catalog.d.ts +4 -2
- package/dist/commands/catalog.js +166 -35
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +17 -0
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/runs.d.ts +7 -3
- package/dist/commands/runs.js +24 -6
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +7 -0
- package/dist/commands/scope-notice.js +4 -11
- package/dist/commands/scope-notice.js.map +1 -1
- package/dist/commands/sources-roles.d.ts +5 -0
- package/dist/commands/sources-roles.js +235 -0
- package/dist/commands/sources-roles.js.map +1 -0
- package/dist/commands/sources.d.ts +5 -0
- package/dist/commands/sources.js +6 -1
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/team-agent-readiness.d.ts +23 -17
- package/dist/commands/team-agent-readiness.js +57 -90
- package/dist/commands/team-agent-readiness.js.map +1 -1
- package/dist/commands/team-agents-agents.d.ts +8 -5
- package/dist/commands/team-agents-agents.js +173 -58
- package/dist/commands/team-agents-agents.js.map +1 -1
- package/dist/commands/team-agents-define.d.ts +31 -0
- package/dist/commands/team-agents-define.js +176 -0
- package/dist/commands/team-agents-define.js.map +1 -0
- package/dist/commands/team-agents-mcp.js +112 -10
- package/dist/commands/team-agents-mcp.js.map +1 -1
- package/dist/commands/team-agents-triggers.d.ts +1 -1
- package/dist/commands/team-agents-triggers.js +137 -5
- package/dist/commands/team-agents-triggers.js.map +1 -1
- package/dist/commands/team-agents.d.ts +4 -1
- package/dist/commands/team-agents.js +17 -4
- package/dist/commands/team-agents.js.map +1 -1
- package/dist/commands/team-llm-key.d.ts +14 -0
- package/dist/commands/team-llm-key.js +122 -0
- package/dist/commands/team-llm-key.js.map +1 -0
- package/dist/commands/teams-connect.js +123 -31
- package/dist/commands/teams-connect.js.map +1 -1
- package/dist/commands/teams-lifecycle.d.ts +90 -0
- package/dist/commands/teams-lifecycle.js +457 -0
- package/dist/commands/teams-lifecycle.js.map +1 -0
- package/dist/commands/teams-onboard.d.ts +14 -0
- package/dist/commands/teams-onboard.js +62 -13
- package/dist/commands/teams-onboard.js.map +1 -1
- package/dist/commands/teams-overview.js +7 -3
- package/dist/commands/teams-overview.js.map +1 -1
- package/dist/commands/teams.d.ts +25 -5
- package/dist/commands/teams.js +101 -39
- package/dist/commands/teams.js.map +1 -1
- package/dist/commands/workflows.d.ts +37 -0
- package/dist/commands/workflows.js +589 -0
- package/dist/commands/workflows.js.map +1 -0
- package/dist/connect-fields.d.ts +22 -0
- package/dist/connect-fields.js +115 -0
- package/dist/connect-fields.js.map +1 -0
- package/dist/context.d.ts +12 -0
- package/dist/context.js +32 -9
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +367 -133
- package/dist/index.js.map +1 -1
- package/dist/invocation.d.ts +31 -0
- package/dist/invocation.js +58 -0
- package/dist/invocation.js.map +1 -0
- package/dist/runs-api.js +8 -3
- package/dist/runs-api.js.map +1 -1
- package/dist/safe-fs.d.ts +18 -0
- package/dist/safe-fs.js +57 -0
- package/dist/safe-fs.js.map +1 -1
- package/dist/secret-form.d.ts +48 -0
- package/dist/secret-form.js +212 -0
- package/dist/secret-form.js.map +1 -0
- package/dist/secret-input.d.ts +96 -0
- package/dist/secret-input.js +299 -0
- package/dist/secret-input.js.map +1 -0
- package/dist/team-connect-api.d.ts +78 -3
- package/dist/team-connect-api.js +17 -2
- package/dist/team-connect-api.js.map +1 -1
- package/dist/team-lifecycle-api.d.ts +435 -0
- package/dist/team-lifecycle-api.js +301 -0
- package/dist/team-lifecycle-api.js.map +1 -0
- package/dist/teams-api.d.ts +13 -1
- package/dist/teams-api.js +90 -31
- package/dist/teams-api.js.map +1 -1
- package/dist/unknown-command.d.ts +18 -0
- package/dist/unknown-command.js +50 -0
- package/dist/unknown-command.js.map +1 -0
- package/dist/workflows-api.d.ts +69 -0
- package/dist/workflows-api.js +182 -0
- package/dist/workflows-api.js.map +1 -0
- package/package.json +3 -3
- package/templates/AGENTS.md.tmpl +6 -4
- package/templates/claude-skill.md.tmpl +4 -1
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +56 -22
- package/templates/skills/build-agent/references/agent-json.md +4 -1
- package/templates/skills/build-agent/references/app-setup.md +14 -7
- package/templates/skills/build-agent/references/rollout.md +40 -20
- package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
- package/templates/skills/build-agent/references/triggers.md +4 -3
- package/templates/skills/build-integration/references/widget-design.md +1 -1
- package/templates/skills/ekanos-platform/SKILL.md +77 -23
- package/templates/skills/polish-widgets/references/patterns.md +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../src/commands/workflows.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type TeamWorkflowApproval,\n type TeamWorkflowRunDetail,\n TeamWorkflowRunStatusSchema,\n type TeamWorkflowRunSummary,\n type TeamWorkflowSummary,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { StoredSession } from '../auth/credential-store';\nimport { loginHint } from '../auth/host-trust';\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 { writePulledFiles } from '../pull-write';\nimport { resolveSourceTarget } from '../source-target';\nimport type { ResultRow, Ui } from '../ui';\nimport {\n type CodeAccess,\n type WorkflowsApiResult,\n applyWorkflow,\n cancelWorkflowRun,\n decideWorkflowApproval,\n listWorkflowApprovals,\n listWorkflowRuns,\n listWorkflows,\n setWorkflowStatus,\n showWorkflow,\n showWorkflowRun,\n startWorkflowRun,\n} from '../workflows-api';\nimport { promptYesNo } from './publish';\n\nexport const WORKFLOWS_SUBCOMMANDS = [\n 'list',\n 'show',\n 'pull',\n 'apply',\n 'enable',\n 'disable',\n 'run',\n 'runs',\n 'approvals',\n] as const;\n\nconst RUNS_VERBS = ['list', 'show', 'cancel'] as const;\nconst APPROVALS_VERBS = ['list', 'approve', 'reject'] as const;\n\n/** The file `pull` writes and a directory given to `apply` is read from. */\nexport const WORKFLOW_FILE = 'workflow.json';\n\nconst FOLLOW_INTERVAL_MS = 2000;\nconst FOLLOW_TIMEOUT_MS = 15 * 60 * 1000;\n\nexport interface WorkflowsArgs {\n host?: string;\n source?: string;\n positionals: readonly string[];\n team?: string;\n all: boolean;\n out?: string;\n force: boolean;\n update?: string;\n confirmAccess: boolean;\n dryRun: boolean;\n input?: string;\n follow: boolean;\n workflow?: string;\n status?: string;\n reason?: string;\n yes: boolean;\n dir: string;\n env: Record<string, string | undefined>;\n /** Test seams: the `--follow` poll delay, and the confirmations. */\n sleep?: (ms: number) => Promise<void>;\n stdinIsTTY?: boolean;\n confirm?: (question: string) => Promise<boolean>;\n}\n\n/**\n * `workflows` — a team's workflows, for its Source admin: the same\n * definitions the visual editor saves, saved through the same checks\n * (shape, effect pinning, Custom Code review, write-behind-gate), activated\n * through the same gate, run and approved through the same paths. A\n * member's personal workflow is theirs alone and never reachable here.\n */\nexport async function runWorkflows(\n ctx: CliContext,\n args: WorkflowsArgs,\n): Promise<ExitCode> {\n const [rawSubcommand, operand, third, ...extra] = args.positionals;\n const subcommand = WORKFLOWS_SUBCOMMANDS.find(\n (name) => name === rawSubcommand,\n );\n if (!subcommand) {\n throw usageError(\n rawSubcommand\n ? `Unknown workflows subcommand \"${rawSubcommand}\".`\n : 'workflows needs a subcommand.',\n `Run one of: ${WORKFLOWS_SUBCOMMANDS.map((name) => `ekanos workflows ${name}`).join(', ')} — each with --team <slug>.`,\n );\n }\n rejectExtra(extra);\n const team = requireTeam(args.team);\n\n switch (subcommand) {\n case 'list':\n rejectExtra([operand, third]);\n return list(ctx, args, team);\n case 'show':\n case 'pull':\n case 'enable':\n case 'disable':\n case 'run': {\n rejectExtra([third]);\n const workflow = requireOperand(\n operand,\n 'workflow (its id or name)',\n subcommand,\n );\n if (subcommand === 'show') return show(ctx, args, team, workflow);\n if (subcommand === 'pull') return pull(ctx, args, team, workflow);\n if (subcommand === 'run') return run(ctx, args, team, workflow);\n return setStatus(\n ctx,\n args,\n team,\n workflow,\n subcommand === 'enable' ? 'active' : 'paused',\n );\n }\n case 'apply': {\n rejectExtra([third]);\n const file = requireOperand(operand, 'file or folder', 'apply');\n return apply(ctx, args, team, file);\n }\n case 'runs':\n return runs(ctx, args, team, operand, third);\n case 'approvals':\n return approvals(ctx, args, team, operand, third);\n }\n}\n\nasync function list(ctx: CliContext, args: WorkflowsArgs, team: string) {\n const { env, client, source } = await connect(ctx, args);\n const listed = await client.call((token) =>\n listWorkflows(env.host, token, { source, team, all: args.all }),\n );\n return ctx.succeed(\n { host: env.host, ...listed },\n listed.workflows.length === 0\n ? ctx.ui.result({\n title: `No workflows on ${listed.team.slug}`,\n tone: 'warn',\n notes: [\n 'Write one as JSON (the editor\\'s format) and \"ekanos workflows apply <file> --team <slug>\".',\n ],\n })\n : ctx.ui.table(\n ['ID', 'NAME', 'STATUS', 'TRIGGER', 'LAST RUN'],\n listed.workflows.map((workflow) => [\n workflow.id,\n workflow.name,\n workflow.status,\n workflow.trigger ?? '?',\n lastRunLabel(workflow),\n ]),\n ),\n );\n}\n\nasync function show(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n workflow: string,\n) {\n const { env, client, source } = await connect(ctx, args);\n const detail = await client.call((token) =>\n showWorkflow(env.host, token, { source, team, workflow }),\n );\n const { workflow: shown } = detail;\n const rows: ResultRow[] = [\n ['Id', shown.id],\n ['Status', shown.status],\n ['Trigger', shown.trigger ?? 'unreadable definition'],\n ['Updated', shown.updatedAt],\n ...(detail.codeSteps.length > 0\n ? [\n [\n 'Custom Code',\n detail.codeSteps.map((step) =>\n [\n `${step.stepId}: ${CODE_STATUS_WORDS[step.reviewStatus]}`,\n step.reviewSummary ? ` — ${step.reviewSummary}` : '',\n ].join(''),\n ),\n ] as ResultRow,\n ]\n : []),\n [\n 'Recent runs',\n detail.recentRuns.length === 0\n ? 'none'\n : detail.recentRuns.map((run) => runLine(run)),\n ],\n ];\n return ctx.succeed(\n { host: env.host, ...detail },\n ctx.ui.result({\n title: shown.name,\n tone: detail.codeSteps.length > 0 ? 'warn' : 'ok',\n rows,\n notes: [\n `The definition: --json, or \"ekanos workflows pull ${shown.id} --team ${team}\".`,\n ],\n }),\n );\n}\n\nconst CODE_STATUS_WORDS = {\n pending: 'security review not finished',\n rejected: 'rejected by security review',\n missing: 'not reviewed yet (save it again)',\n needs_approval: 'reviewed; needs your approval of what it reaches',\n} as const;\n\nasync function pull(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n workflow: string,\n) {\n const { env, client, source } = await connect(ctx, args);\n const detail = await client.call((token) =>\n showWorkflow(env.host, token, { source, team, workflow }),\n );\n const outDir = path.resolve(\n args.dir,\n args.out ?? path.join('workflows', folderName(detail.workflow.name)),\n );\n const written = writePulledFiles({\n projectDir: args.dir,\n outDir,\n files: [\n {\n path: WORKFLOW_FILE,\n contents: `${JSON.stringify(detail.workflow.dsl, null, 2)}\\n`,\n },\n ],\n force: args.force,\n rerun: `ekanos workflows pull ${workflow} --team ${team}`,\n });\n const relative = path.relative(args.dir, outDir) || '.';\n return ctx.succeed(\n {\n host: env.host,\n team: detail.team,\n workflow: { id: detail.workflow.id, name: detail.workflow.name },\n files: written,\n },\n ctx.ui.result({\n title: `Pulled ${detail.workflow.name}`,\n rows: written.map((file): ResultRow => ['Wrote', file]),\n notes: [\n `Edit, then \"ekanos workflows apply ${relative} --team ${team} --update ${detail.workflow.id}\".`,\n ],\n }),\n );\n}\n\nasync function apply(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n target: string,\n) {\n const dsl = readDefinition(args.dir, target);\n const { env, client, source } = await connect(ctx, args);\n const applied = await client.call((token) =>\n applyWorkflow(\n env.host,\n token,\n { source, team },\n { dsl, ...(args.update ? { update: args.update } : {}) },\n ),\n );\n const { workflow } = applied;\n const blocking = applied.codeReviews.filter(\n (review) => review.reviewStatus !== 'approved',\n );\n return ctx.succeed(\n { host: env.host, ...applied },\n ctx.ui.result({\n title: `${applied.created ? 'Created' : 'Updated'} ${workflow.name} on ${applied.team.slug}`,\n tone: applied.warnings.length > 0 || blocking.length > 0 ? 'warn' : 'ok',\n rows: [\n ['Id', workflow.id],\n ['Status', workflow.status],\n ...(applied.codeReviews.length > 0\n ? [\n [\n 'Custom Code',\n applied.codeReviews.map(\n (review) =>\n `${review.stepId}: review ${review.reviewStatus}${review.reviewSummary ? ` — ${review.reviewSummary}` : ''}`,\n ),\n ] as ResultRow,\n ]\n : []),\n ...(applied.warnings.length > 0\n ? [['Warnings', applied.warnings] as ResultRow]\n : []),\n ],\n notes: [\n applied.warnings.length > 0\n ? 'Saved, but activation refuses until the warnings are fixed.'\n : workflow.status === 'draft'\n ? `A draft until you turn it on: \"ekanos workflows enable ${workflow.id} --team ${team}\" (\"workflows run ${workflow.id} --dry-run\" rehearses it first).`\n : `It stays ${workflow.status}.`,\n ],\n }),\n );\n}\n\nasync function setStatus(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n workflow: string,\n status: 'active' | 'paused',\n) {\n const { env, client, source } = await connect(ctx, args);\n const send = (confirmAccess: boolean) =>\n client.call(\n (token) =>\n setWorkflowStatus(\n env.host,\n token,\n { source, team, workflow },\n { status, confirmAccess },\n ),\n { allowNeedsAccess: true },\n );\n\n let changed = await send(args.confirmAccess);\n if ('needsAccess' in changed) {\n const lines = changed.needsAccess.map(accessLine);\n if (ctx.jsonMode || !(args.stdinIsTTY ?? process.stdin.isTTY === true)) {\n throw validationError(\n [\n `Turning on ${workflow} needs your approval of what its Custom Code reaches:`,\n ...lines.map((line) => ` ${line}`),\n ].join('\\n'),\n `Nothing changed. If you approve it, as yourself: ekanos workflows enable ${workflow} --team ${team} --confirm-access`,\n );\n }\n for (const line of lines) ctx.log(` ${line}`);\n const confirmed = await (args.confirm ?? promptYesNo)(\n 'Approve this access, as yourself, and turn the workflow on? [y/N]',\n );\n if (!confirmed) {\n throw validationError(\n 'The Custom Code access was not approved.',\n 'Nothing changed.',\n );\n }\n changed = await send(true);\n if ('needsAccess' in changed) {\n throw validationError(\n 'The host still asks for approval of the Custom Code access.',\n 'Nothing changed. Run \"ekanos workflows show\" for what it reaches.',\n );\n }\n }\n\n return ctx.succeed(\n { host: env.host, ...changed },\n ctx.ui.result({\n title: `${status === 'active' ? 'Turned on' : 'Paused'} ${changed.workflow.name} on ${changed.team.slug}`,\n tone: status === 'active' ? 'ok' : 'warn',\n rows: [\n ['Status', `${changed.from} → ${changed.workflow.status}`],\n ['Trigger', changed.workflow.trigger ?? '?'],\n ],\n notes:\n status === 'active'\n ? [\n 'Its trigger now starts it; every write still waits on its approval gate.',\n ]\n : ['Its trigger no longer starts it. Runs already going continue.'],\n }),\n );\n}\n\nfunction accessLine(access: CodeAccess): string {\n const parts = [\n access.effect === 'write' ? 'writes' : 'reads',\n ...(access.egressHosts.length > 0\n ? [`reaches ${access.egressHosts.join(', ')}`]\n : []),\n ...(access.tools.length > 0 ? [`calls ${access.tools.join(', ')}`] : []),\n ];\n return `${access.stepId}: ${parts.join('; ')}${access.reviewSummary ? ` — review: ${access.reviewSummary}` : ''}`;\n}\n\nasync function run(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n workflow: string,\n) {\n if (args.input && !args.dryRun) {\n throw usageError(\n '--input is a sample trigger payload for a dry run.',\n `A live run takes what its trigger gives it. Rehearse with it: ekanos workflows run ${workflow} --team ${team} --dry-run --input ${args.input}`,\n );\n }\n const input = args.input ? readSample(args.dir, args.input) : undefined;\n const { env, client, source } = await connect(ctx, args);\n const started = await client.call((token) =>\n startWorkflowRun(\n env.host,\n token,\n { source, team, workflow },\n { dryRun: args.dryRun, ...(input ? { input } : {}) },\n ),\n );\n const note = `${started.dryRun ? 'Rehearsing' : 'Started'} ${started.workflow.name} on ${started.team.slug}: run ${started.runId}`;\n\n if (!args.follow) {\n return ctx.succeed(\n { host: env.host, ...started },\n ctx.ui.result({\n title: note,\n notes: [\n ...(started.dryRun\n ? ['A dry run: writes are recorded, not sent, and gates pass.']\n : []),\n `Watch it: \"ekanos workflows runs show ${started.runId} --team ${team}\".`,\n ],\n }),\n );\n }\n\n ctx.log(note);\n const detail = await follow(ctx, args, () =>\n client.call((token) =>\n showWorkflowRun(env.host, token, {\n source,\n team,\n runId: started.runId,\n }),\n ),\n );\n return ctx.succeed(\n { host: env.host, started, ...detail },\n runDetail(ctx.ui, detail),\n );\n}\n\n/** Poll until the run ends or parks on a gate, logging each step it finishes. */\nasync function follow(\n ctx: CliContext,\n args: WorkflowsArgs,\n read: () => Promise<TeamWorkflowRunDetail>,\n): Promise<TeamWorkflowRunDetail> {\n const sleep =\n args.sleep ??\n ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const seen = new Set<string>();\n let lastStatus = '';\n const deadline = Date.now() + FOLLOW_TIMEOUT_MS;\n\n for (;;) {\n const detail = await read();\n for (const step of detail.run.stepsExecuted) {\n if (seen.has(step)) continue;\n seen.add(step);\n ctx.log(` ✓ ${step}`);\n }\n if (detail.run.status !== lastStatus) {\n lastStatus = detail.run.status;\n ctx.log(` status: ${lastStatus}`);\n }\n if (detail.run.status !== 'running' || Date.now() > deadline) {\n return detail;\n }\n await sleep(FOLLOW_INTERVAL_MS);\n }\n}\n\nasync function runs(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n rawVerb: string | undefined,\n operand: string | undefined,\n) {\n const verb = RUNS_VERBS.find((name) => name === rawVerb);\n if (!verb) {\n throw usageError(\n rawVerb\n ? `Unknown workflows runs verb \"${rawVerb}\".`\n : 'workflows runs needs a verb.',\n 'Run one of: ekanos workflows runs list --team <slug> [--workflow <id>] [--status <status>], ekanos workflows runs show <run-id> --team <slug>, ekanos workflows runs cancel <run-id> --team <slug> [--yes].',\n );\n }\n\n if (verb === 'list') {\n rejectExtra([operand]);\n const status = parseStatus(args.status);\n const { env, client, source } = await connect(ctx, args);\n const listed = await client.call((token) =>\n listWorkflowRuns(env.host, token, {\n source,\n team,\n workflow: args.workflow,\n status,\n }),\n );\n return ctx.succeed(\n { host: env.host, ...listed },\n listed.runs.length === 0\n ? ctx.ui.result({\n title: `No workflow runs on ${listed.team.slug}`,\n tone: 'warn',\n })\n : ctx.ui.table(\n ['RUN', 'WORKFLOW', 'STATUS', 'STARTED'],\n listed.runs.map((run) => [\n run.id,\n run.workflow.name,\n `${run.status}${run.dryRun ? ' (dry run)' : ''}`,\n run.startedAt.slice(0, 19).replace('T', ' '),\n ]),\n ),\n );\n }\n\n const runId = requireOperand(operand, 'run id', `runs ${verb}`);\n if (verb === 'cancel') await confirmCancel(ctx, args, runId, team);\n const { env, client, source } = await connect(ctx, args);\n\n if (verb === 'show') {\n const detail = await client.call((token) =>\n showWorkflowRun(env.host, token, { source, team, runId }),\n );\n return ctx.succeed(\n { host: env.host, ...detail },\n runDetail(ctx.ui, detail),\n );\n }\n\n const cancelled = await client.call((token) =>\n cancelWorkflowRun(env.host, token, { source, team, runId }),\n );\n return ctx.succeed(\n { host: env.host, ...cancelled },\n ctx.ui.result({\n title: `Cancelled run ${cancelled.run.id} on ${cancelled.team.slug}`,\n tone: 'warn',\n rows: [\n ['Workflow', cancelled.run.workflow.name],\n ['Status', cancelled.run.status],\n ],\n notes: ['Its pending approvals expired.'],\n }),\n );\n}\n\nasync function confirmCancel(\n ctx: CliContext,\n args: WorkflowsArgs,\n runId: string,\n team: string,\n) {\n if (args.yes) return;\n if (ctx.jsonMode || !(args.stdinIsTTY ?? process.stdin.isTTY === true)) {\n throw validationError(\n `Cancelling run ${runId} on ${team} needs confirmation.`,\n `It stops the run for good and expires its pending approvals. Pass --yes to confirm: ekanos workflows runs cancel ${runId} --team ${team} --yes`,\n );\n }\n const confirmed = await (args.confirm ?? promptYesNo)(\n `Stop run ${runId} on ${team} for good? [y/N]`,\n );\n if (!confirmed) {\n throw validationError(\n `Cancelling run ${runId} was not confirmed.`,\n 'Nothing was changed.',\n );\n }\n}\n\nasync function approvals(\n ctx: CliContext,\n args: WorkflowsArgs,\n team: string,\n rawVerb: string | undefined,\n operand: string | undefined,\n) {\n const verb = APPROVALS_VERBS.find((name) => name === rawVerb);\n if (!verb) {\n throw usageError(\n rawVerb\n ? `Unknown workflows approvals verb \"${rawVerb}\".`\n : 'workflows approvals needs a verb.',\n 'Run one of: ekanos workflows approvals list --team <slug>, ekanos workflows approvals approve|reject <id> --team <slug> [--reason \"…\"].',\n );\n }\n\n if (verb === 'list') {\n rejectExtra([operand]);\n const { env, client, source } = await connect(ctx, args);\n const listed = await client.call((token) =>\n listWorkflowApprovals(env.host, token, { source, team }),\n );\n return ctx.succeed(\n { host: env.host, ...listed },\n listed.approvals.length === 0\n ? ctx.ui.result({ title: `Nothing waiting on ${listed.team.slug}` })\n : ctx.ui.result({\n title: `${listed.approvals.length} waiting on ${listed.team.slug}`,\n tone: 'warn',\n rows: listed.approvals.map((approval): ResultRow => [\n approval.id,\n approvalLines(approval),\n ]),\n notes: [\n '\"ekanos workflows approvals approve|reject <id> --team <slug>\" decides one.',\n ],\n }),\n );\n }\n\n const approvalId = requireOperand(\n operand,\n 'approval id',\n `approvals ${verb}`,\n );\n const { env, client, source } = await connect(ctx, args);\n const decided = await client.call((token) =>\n decideWorkflowApproval(\n env.host,\n token,\n { source, team, approvalId },\n {\n decision: verb === 'reject' ? 'rejected' : 'approved',\n ...(args.reason ? { reason: args.reason } : {}),\n },\n ),\n );\n const { approval } = decided;\n return ctx.succeed(\n { host: env.host, ...decided },\n ctx.ui.result({\n title: `${approval.status === 'rejected' ? 'Rejected' : 'Approved'} ${approval.stepId} in ${approval.workflow.name}`,\n tone: approval.status === 'rejected' ? 'warn' : 'ok',\n rows: [['Run', approval.runId]],\n notes: [\n `The run picks it up now: \"ekanos workflows runs show ${approval.runId} --team ${team}\".`,\n ],\n }),\n );\n}\n\nfunction runDetail(ui: Ui, detail: TeamWorkflowRunDetail): string {\n const { run } = detail;\n const pending = detail.approvals.filter(\n (approval) => approval.status === 'pending',\n );\n const decisions = Object.entries(run.gateDecisions);\n return ui.result({\n title: `Run ${run.id}`,\n tone:\n run.status === 'failed' || run.status === 'rejected'\n ? 'err'\n : run.status === 'completed'\n ? 'ok'\n : 'warn',\n rows: [\n ['Workflow', run.workflow.name],\n ['Status', `${run.status}${run.dryRun ? ' (dry run)' : ''}`],\n ['Started', run.startedAt],\n ...(run.finishedAt ? [['Finished', run.finishedAt] as ResultRow] : []),\n ...(run.error ? [['Error', run.error] as ResultRow] : []),\n [\n 'Steps',\n run.stepsExecuted.length === 0 ? 'none yet' : run.stepsExecuted,\n ],\n ...(decisions.length > 0\n ? [\n [\n 'Gates',\n decisions.map(([step, decision]) => `${step}: ${decision}`),\n ] as ResultRow,\n ]\n : []),\n ...(pending.length > 0\n ? [\n [\n 'Waiting on',\n pending.map((approval) => `${approval.id} ${approval.stepId}`),\n ] as ResultRow,\n ]\n : []),\n ],\n notes:\n pending.length > 0\n ? [\n `Decide: \"ekanos workflows approvals approve|reject <id> --team ${detail.team.slug}\".`,\n ]\n : ['The full record: --json.'],\n });\n}\n\nfunction approvalLines(approval: TeamWorkflowApproval): string[] {\n return [\n `${approval.stepId} · ${approval.workflow.name}`,\n `run ${approval.runId}${approval.expiresAt ? ` · expires ${approval.expiresAt}` : ''}`,\n clip(approval.summary),\n ];\n}\n\nfunction runLine(run: TeamWorkflowRunSummary): string {\n return `${run.id} ${run.status}${run.dryRun ? ' (dry run)' : ''} ${run.startedAt.slice(0, 19).replace('T', ' ')}`;\n}\n\nfunction lastRunLabel(workflow: TeamWorkflowSummary): string {\n const run = workflow.lastRun;\n if (!run) return 'never';\n return `${run.status}${run.dryRun ? ' (dry)' : ''} ${run.startedAt.slice(0, 16).replace('T', ' ')}`;\n}\n\nfunction clip(text: string, max = 200): string {\n const flat = text.replace(/\\s+/g, ' ').trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\n/** A folder name for `pull`'s default `workflows/<name>`. */\nfunction folderName(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60);\n return slug || 'workflow';\n}\n\n/** `apply <file|dir>`: the JSON the editor saves, from a file or `<dir>/workflow.json`. */\nfunction readDefinition(dir: string, target: string): unknown {\n const resolved = path.resolve(dir, target);\n let file = resolved;\n try {\n if (fs.statSync(resolved).isDirectory()) {\n file = path.join(resolved, WORKFLOW_FILE);\n }\n } catch {\n throw usageError(\n `Cannot read ${resolved}.`,\n `Pass a workflow JSON file, or a folder holding ${WORKFLOW_FILE}.`,\n );\n }\n let raw: string;\n try {\n raw = fs.readFileSync(file, 'utf8');\n } catch {\n throw usageError(\n `Cannot read ${file}.`,\n `Pass a workflow JSON file, or a folder holding ${WORKFLOW_FILE}.`,\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw validationError(\n `${file} is not valid JSON.`,\n 'A workflow is the JSON the editor saves: { version, name, scope, trigger, steps, edges }.',\n );\n }\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n Array.isArray(parsed) ||\n typeof (parsed as { name?: unknown }).name !== 'string'\n ) {\n throw validationError(\n `${file} is not a workflow definition.`,\n 'A workflow is the JSON the editor saves: { version, name, scope, trigger, steps, edges }. \"ekanos workflows pull <id>\" writes one.',\n );\n }\n return parsed;\n}\n\n/** `--input`: a JSON object, the dry run's sample `trigger.*`. */\nfunction readSample(dir: string, file: string): Record<string, unknown> {\n const resolved = path.resolve(dir, file);\n let raw: string;\n try {\n raw = fs.readFileSync(resolved, 'utf8');\n } catch {\n throw usageError(`Cannot read ${resolved}.`, 'Pass --input <file.json>.');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw validationError(`${resolved} is not valid JSON.`, 'Fix the file.');\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw validationError(\n `${resolved} is not a JSON object.`,\n 'The sample payload is read as trigger.*, so it is an object of fields.',\n );\n }\n return parsed as Record<string, unknown>;\n}\n\nfunction parseStatus(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined;\n const parsed = TeamWorkflowRunStatusSchema.safeParse(raw.trim());\n if (parsed.success) return parsed.data;\n throw usageError(\n `--status \"${raw}\" is not a workflow run status.`,\n `Use one of: ${TeamWorkflowRunStatusSchema.options.join(', ')}.`,\n );\n}\n\nfunction requireTeam(value: string | undefined): 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 team slug.`\n : 'Name the team with --team <slug>.',\n '\"ekanos teams list\" lists the teams on this Source.',\n );\n}\n\nfunction requireOperand(\n value: string | undefined,\n what: string,\n command: string,\n): string {\n const trimmed = value?.trim();\n if (trimmed) return trimmed;\n throw usageError(\n `Name the ${what}.`,\n `e.g. \"ekanos workflows ${command} <…> --team <slug>\". See \"ekanos workflows --help\".`,\n );\n}\n\nfunction rejectExtra(extra: ReadonlyArray<string | undefined>) {\n const first = extra.find((value) => value !== undefined);\n if (first !== undefined) {\n throw usageError(\n `Unexpected argument \"${first}\".`,\n 'See \"ekanos workflows --help\".',\n );\n }\n}\n\nasync function connect(ctx: CliContext, args: WorkflowsArgs) {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n return {\n env,\n client: new WorkflowsClient(env, resolved.session),\n source: resolved.source,\n };\n}\n\nclass WorkflowsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n call<T>(\n send: (accessToken: string) => Promise<WorkflowsApiResult<T>>,\n ): Promise<T>;\n call<T>(\n send: (accessToken: string) => Promise<WorkflowsApiResult<T>>,\n options: { allowNeedsAccess: true },\n ): Promise<T | { needsAccess: CodeAccess[] }>;\n async call<T>(\n send: (accessToken: string) => Promise<WorkflowsApiResult<T>>,\n options?: { allowNeedsAccess: true },\n ): Promise<T | { needsAccess: CodeAccess[] }> {\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 if (result.status === 'needs-access') {\n if (options?.allowNeedsAccess) return { needsAccess: result.codeAccess };\n throw validationError(\n result.error,\n 'Run \"ekanos workflows enable <id> --team <slug>\" to review and approve it.',\n );\n }\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the call.`,\n loginHint(this.env),\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FieldValue, TeamConnectField } from './team-connect-api.js';
|
|
2
|
+
/**
|
|
3
|
+
* The activation fields `ekanos teams connect` enters, by the type the host
|
|
4
|
+
* reads off the integration's own schema: text, a number, yes/no, one of a
|
|
5
|
+
* set (`select`), a comma-separated list, or a JSON value for anything
|
|
6
|
+
* structured. The text comes from the shared secret input
|
|
7
|
+
* (`secret-input.ts`): `--set <name>=<value>`, a secret flag, `--browser` or
|
|
8
|
+
* a prompt; every source parses the same way here, so what works typed at
|
|
9
|
+
* the terminal works in a script.
|
|
10
|
+
*
|
|
11
|
+
* A secret (`sensitive`, which the host also sets on a JSON field) is never
|
|
12
|
+
* taken from `--set`, and its value is never echoed in an error.
|
|
13
|
+
*/
|
|
14
|
+
/** How a field reads in a prompt: its type, and that Enter skips an optional one. */
|
|
15
|
+
export declare function fieldPrompt(field: TeamConnectField): string;
|
|
16
|
+
/**
|
|
17
|
+
* One field's value from what was typed or passed. Empty is "not given"
|
|
18
|
+
* (`undefined`), which the caller skips for an optional field. Anything that
|
|
19
|
+
* does not parse as the field's type is a usage error naming the field and
|
|
20
|
+
* what it takes.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseFieldValue(field: TeamConnectField, raw: string): FieldValue | undefined;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { usageError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* The activation fields `ekanos teams connect` enters, by the type the host
|
|
4
|
+
* reads off the integration's own schema: text, a number, yes/no, one of a
|
|
5
|
+
* set (`select`), a comma-separated list, or a JSON value for anything
|
|
6
|
+
* structured. The text comes from the shared secret input
|
|
7
|
+
* (`secret-input.ts`): `--set <name>=<value>`, a secret flag, `--browser` or
|
|
8
|
+
* a prompt; every source parses the same way here, so what works typed at
|
|
9
|
+
* the terminal works in a script.
|
|
10
|
+
*
|
|
11
|
+
* A secret (`sensitive`, which the host also sets on a JSON field) is never
|
|
12
|
+
* taken from `--set`, and its value is never echoed in an error.
|
|
13
|
+
*/
|
|
14
|
+
/** How a field reads in a prompt: its type, and that Enter skips an optional one. */
|
|
15
|
+
export function fieldPrompt(field) {
|
|
16
|
+
const kind = describeType(field);
|
|
17
|
+
const parts = [
|
|
18
|
+
...(kind ? [kind] : []),
|
|
19
|
+
...(field.required ? [] : ['optional — Enter skips']),
|
|
20
|
+
...(field.sensitive ? ['hidden'] : []),
|
|
21
|
+
];
|
|
22
|
+
return `${field.label} [${field.name}]${parts.length > 0 ? ` (${parts.join('; ')})` : ''}: `;
|
|
23
|
+
}
|
|
24
|
+
function describeType(field) {
|
|
25
|
+
var _a;
|
|
26
|
+
switch (field.type) {
|
|
27
|
+
case 'text':
|
|
28
|
+
return null;
|
|
29
|
+
case 'number':
|
|
30
|
+
return 'a number';
|
|
31
|
+
case 'boolean':
|
|
32
|
+
return 'yes or no';
|
|
33
|
+
case 'select':
|
|
34
|
+
return `one of: ${((_a = field.options) !== null && _a !== void 0 ? _a : []).join(', ')}`;
|
|
35
|
+
case 'list':
|
|
36
|
+
return field.options
|
|
37
|
+
? `comma-separated, each one of: ${field.options.join(', ')}`
|
|
38
|
+
: `comma-separated${field.itemType === 'number' ? ' numbers' : ''}`;
|
|
39
|
+
case 'json':
|
|
40
|
+
return 'JSON';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One field's value from what was typed or passed. Empty is "not given"
|
|
45
|
+
* (`undefined`), which the caller skips for an optional field. Anything that
|
|
46
|
+
* does not parse as the field's type is a usage error naming the field and
|
|
47
|
+
* what it takes.
|
|
48
|
+
*/
|
|
49
|
+
export function parseFieldValue(field, raw) {
|
|
50
|
+
var _a;
|
|
51
|
+
const text = raw.trim();
|
|
52
|
+
if (text === '')
|
|
53
|
+
return undefined;
|
|
54
|
+
// A secret's value is never echoed, not even in an error.
|
|
55
|
+
const wrong = (takes) => usageError(`${field.sensitive ? 'That' : `"${text}"`} is not a value for ${field.label} (${field.name}): it takes ${takes}.`, `Pass it as --set ${field.name}=<value>, or enter it at the prompt.`);
|
|
56
|
+
switch (field.type) {
|
|
57
|
+
case 'text':
|
|
58
|
+
return text;
|
|
59
|
+
case 'number': {
|
|
60
|
+
const value = Number(text);
|
|
61
|
+
if (!Number.isFinite(value))
|
|
62
|
+
throw wrong('a number');
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
case 'boolean': {
|
|
66
|
+
const value = text.toLowerCase();
|
|
67
|
+
if (['y', 'yes', 'true', 'on', '1'].includes(value))
|
|
68
|
+
return true;
|
|
69
|
+
if (['n', 'no', 'false', 'off', '0'].includes(value))
|
|
70
|
+
return false;
|
|
71
|
+
throw wrong('yes or no');
|
|
72
|
+
}
|
|
73
|
+
case 'select': {
|
|
74
|
+
const options = (_a = field.options) !== null && _a !== void 0 ? _a : [];
|
|
75
|
+
if (!options.includes(text))
|
|
76
|
+
throw wrong(`one of ${options.join(', ')}`);
|
|
77
|
+
return text;
|
|
78
|
+
}
|
|
79
|
+
case 'list': {
|
|
80
|
+
// A JSON array is accepted too, for an entry that holds a comma.
|
|
81
|
+
const items = text.startsWith('[')
|
|
82
|
+
? parseJson(text, field, wrong)
|
|
83
|
+
: text
|
|
84
|
+
.split(',')
|
|
85
|
+
.map((item) => item.trim())
|
|
86
|
+
.filter((item) => item.length > 0);
|
|
87
|
+
if (!Array.isArray(items))
|
|
88
|
+
throw wrong('a comma-separated list');
|
|
89
|
+
return items.map((item) => {
|
|
90
|
+
const entry = typeof item === 'string' ? item : String(item);
|
|
91
|
+
if (field.itemType === 'number') {
|
|
92
|
+
const value = Number(entry);
|
|
93
|
+
if (!Number.isFinite(value))
|
|
94
|
+
throw wrong('a list of numbers');
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
if (field.options && !field.options.includes(entry)) {
|
|
98
|
+
throw wrong(`a list of ${field.options.join(', ')}`);
|
|
99
|
+
}
|
|
100
|
+
return entry;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
case 'json':
|
|
104
|
+
return parseJson(text, field, wrong);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function parseJson(text, field, wrong) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(text);
|
|
110
|
+
}
|
|
111
|
+
catch (_a) {
|
|
112
|
+
throw wrong(`JSON (for example ${field.type === 'list' ? '["a","b"]' : '{"key":"value"}'})`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=connect-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-fields.js","sourceRoot":"","sources":["../src/connect-fields.ts"],"names":[],"mappings":"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","sourcesContent":["import { usageError } from './errors';\nimport type { FieldValue, TeamConnectField } from './team-connect-api';\n\n/**\n * The activation fields `ekanos teams connect` enters, by the type the host\n * reads off the integration's own schema: text, a number, yes/no, one of a\n * set (`select`), a comma-separated list, or a JSON value for anything\n * structured. The text comes from the shared secret input\n * (`secret-input.ts`): `--set <name>=<value>`, a secret flag, `--browser` or\n * a prompt; every source parses the same way here, so what works typed at\n * the terminal works in a script.\n *\n * A secret (`sensitive`, which the host also sets on a JSON field) is never\n * taken from `--set`, and its value is never echoed in an error.\n */\n\n/** How a field reads in a prompt: its type, and that Enter skips an optional one. */\nexport function fieldPrompt(field: TeamConnectField): string {\n const kind = describeType(field);\n const parts = [\n ...(kind ? [kind] : []),\n ...(field.required ? [] : ['optional — Enter skips']),\n ...(field.sensitive ? ['hidden'] : []),\n ];\n return `${field.label} [${field.name}]${parts.length > 0 ? ` (${parts.join('; ')})` : ''}: `;\n}\n\nfunction describeType(field: TeamConnectField): string | null {\n switch (field.type) {\n case 'text':\n return null;\n case 'number':\n return 'a number';\n case 'boolean':\n return 'yes or no';\n case 'select':\n return `one of: ${(field.options ?? []).join(', ')}`;\n case 'list':\n return field.options\n ? `comma-separated, each one of: ${field.options.join(', ')}`\n : `comma-separated${field.itemType === 'number' ? ' numbers' : ''}`;\n case 'json':\n return 'JSON';\n }\n}\n\n/**\n * One field's value from what was typed or passed. Empty is \"not given\"\n * (`undefined`), which the caller skips for an optional field. Anything that\n * does not parse as the field's type is a usage error naming the field and\n * what it takes.\n */\nexport function parseFieldValue(\n field: TeamConnectField,\n raw: string,\n): FieldValue | undefined {\n const text = raw.trim();\n if (text === '') return undefined;\n // A secret's value is never echoed, not even in an error.\n const wrong = (takes: string) =>\n usageError(\n `${field.sensitive ? 'That' : `\"${text}\"`} is not a value for ${field.label} (${field.name}): it takes ${takes}.`,\n `Pass it as --set ${field.name}=<value>, or enter it at the prompt.`,\n );\n\n switch (field.type) {\n case 'text':\n return text;\n case 'number': {\n const value = Number(text);\n if (!Number.isFinite(value)) throw wrong('a number');\n return value;\n }\n case 'boolean': {\n const value = text.toLowerCase();\n if (['y', 'yes', 'true', 'on', '1'].includes(value)) return true;\n if (['n', 'no', 'false', 'off', '0'].includes(value)) return false;\n throw wrong('yes or no');\n }\n case 'select': {\n const options = field.options ?? [];\n if (!options.includes(text)) throw wrong(`one of ${options.join(', ')}`);\n return text;\n }\n case 'list': {\n // A JSON array is accepted too, for an entry that holds a comma.\n const items = text.startsWith('[')\n ? parseJson(text, field, wrong)\n : text\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n if (!Array.isArray(items)) throw wrong('a comma-separated list');\n return items.map((item) => {\n const entry = typeof item === 'string' ? item : String(item);\n if (field.itemType === 'number') {\n const value = Number(entry);\n if (!Number.isFinite(value)) throw wrong('a list of numbers');\n return value;\n }\n if (field.options && !field.options.includes(entry)) {\n throw wrong(`a list of ${field.options.join(', ')}`);\n }\n return entry;\n });\n }\n case 'json':\n return parseJson(text, field, wrong);\n }\n}\n\nfunction parseJson(\n text: string,\n field: TeamConnectField,\n wrong: (takes: string) => Error,\n): FieldValue {\n try {\n return JSON.parse(text) as FieldValue;\n } catch {\n throw wrong(\n `JSON (for example ${field.type === 'list' ? '[\"a\",\"b\"]' : '{\"key\":\"value\"}'})`,\n );\n }\n}\n"]}
|
package/dist/context.d.ts
CHANGED
|
@@ -66,6 +66,10 @@ export declare class CliContext {
|
|
|
66
66
|
* components this carries.
|
|
67
67
|
*/
|
|
68
68
|
readonly ui: Ui;
|
|
69
|
+
/** A coding agent's marker is in the environment (`isAgentEnvironment`). */
|
|
70
|
+
readonly agentDetected: boolean;
|
|
71
|
+
/** `--json` was passed — not inferred from a pipe. */
|
|
72
|
+
private readonly explicitJson;
|
|
69
73
|
private readonly stdout;
|
|
70
74
|
private readonly stderr;
|
|
71
75
|
private settled;
|
|
@@ -133,4 +137,12 @@ export declare class CliContext {
|
|
|
133
137
|
}): number;
|
|
134
138
|
private settle;
|
|
135
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The environment markers coding agents set in the shells they run:
|
|
142
|
+
* Claude Code (`CLAUDECODE=1`), Codex (`CODEX_SANDBOX`), Cursor's agent
|
|
143
|
+
* (`CURSOR_AGENT=1`), Gemini CLI (`GEMINI_CLI=1`), and the generic
|
|
144
|
+
* `AI_AGENT`. A pipe alone is not one — a person piping into `grep` is not
|
|
145
|
+
* an agent.
|
|
146
|
+
*/
|
|
147
|
+
export declare function isAgentEnvironment(env: Readonly<Record<string, string | undefined>>): boolean;
|
|
136
148
|
export {};
|
package/dist/context.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EXIT_CODES } from './exit-codes.js';
|
|
2
|
+
import { echoInvocation } from './invocation.js';
|
|
2
3
|
import { createUi } from './ui.js';
|
|
3
4
|
/**
|
|
4
5
|
* `data` is deliberately `unknown` above — each verb owns its own shape — but
|
|
@@ -39,6 +40,8 @@ export class CliContext {
|
|
|
39
40
|
// or the CLAUDECODE marker.
|
|
40
41
|
const nonTty = stdout.isTTY !== true;
|
|
41
42
|
this.jsonMode = (_d = input.jsonFlag) !== null && _d !== void 0 ? _d : (nonTty || env.CLAUDECODE === '1');
|
|
43
|
+
this.explicitJson = input.jsonFlag === true;
|
|
44
|
+
this.agentDetected = isAgentEnvironment(env);
|
|
42
45
|
}
|
|
43
46
|
/** Whether stderr is a real terminal — decoration (the banner) gates on this. */
|
|
44
47
|
get stderrIsTTY() {
|
|
@@ -55,11 +58,11 @@ export class CliContext {
|
|
|
55
58
|
}
|
|
56
59
|
/** Human/progress output — ALWAYS stderr, so stdout stays pure in JSON mode. */
|
|
57
60
|
log(message) {
|
|
58
|
-
this.stderr.write(`${message}\n`);
|
|
61
|
+
this.stderr.write(`${echoInvocation(message)}\n`);
|
|
59
62
|
}
|
|
60
63
|
/** A warning — stderr, no ANSI. */
|
|
61
64
|
warn(message) {
|
|
62
|
-
this.stderr.write(`${message}\n`);
|
|
65
|
+
this.stderr.write(`${echoInvocation(message)}\n`);
|
|
63
66
|
}
|
|
64
67
|
/**
|
|
65
68
|
* Emit the `claude-code-hint` protocol line to STDERR. Used on --help and on
|
|
@@ -68,9 +71,11 @@ export class CliContext {
|
|
|
68
71
|
*/
|
|
69
72
|
emitClaudeCodeHint(payload) {
|
|
70
73
|
// The protocol line is machine-readable JSON for an agent reading
|
|
71
|
-
// stderr.
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
+
// stderr. It is written only when an agent is known to be reading: one
|
|
75
|
+
// was detected in the environment, or `--json` was asked for. A person —
|
|
76
|
+
// at a terminal, or piping into `less` or `grep` — gets the readable
|
|
77
|
+
// error or help text, never a line of JSON above it.
|
|
78
|
+
if (!this.explicitJson && !this.agentDetected)
|
|
74
79
|
return;
|
|
75
80
|
this.stderr.write(`claude-code-hint: ${JSON.stringify(payload)}\n`);
|
|
76
81
|
}
|
|
@@ -88,7 +93,7 @@ export class CliContext {
|
|
|
88
93
|
else if (humanSummary !== '') {
|
|
89
94
|
// An explicit empty summary means "already said it" — a wizard flow's
|
|
90
95
|
// outro is the result, and a trailing line would just repeat it.
|
|
91
|
-
this.stdout.write(`${humanSummary !== null && humanSummary !== void 0 ? humanSummary : 'OK'}\n`);
|
|
96
|
+
this.stdout.write(`${echoInvocation(humanSummary !== null && humanSummary !== void 0 ? humanSummary : 'OK')}\n`);
|
|
92
97
|
}
|
|
93
98
|
return EXIT_CODES.OK;
|
|
94
99
|
}
|
|
@@ -135,8 +140,12 @@ export class CliContext {
|
|
|
135
140
|
throw new Error(`failWith for "${params.message}" was given an empty hint. Every CLI ` +
|
|
136
141
|
'error must carry an imperative remediation.');
|
|
137
142
|
}
|
|
143
|
+
// The commands a hint names, as this run was invoked (`invocation.ts`).
|
|
144
|
+
const message = echoInvocation(params.message);
|
|
145
|
+
const hint = echoInvocation(params.hint);
|
|
138
146
|
if (this.jsonMode) {
|
|
139
|
-
const envelope = Object.assign(Object.assign({ ok: false }, (params.data !== undefined ? { data: params.data } : {})), { error: Object.assign({ code: params.code, message
|
|
147
|
+
const envelope = Object.assign(Object.assign({ ok: false }, (params.data !== undefined ? { data: params.data } : {})), { error: Object.assign({ code: params.code, message,
|
|
148
|
+
hint }, (params.docs ? { docs: params.docs } : {})) });
|
|
140
149
|
this.stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
141
150
|
}
|
|
142
151
|
else if (params.findingsSummary) {
|
|
@@ -144,8 +153,8 @@ export class CliContext {
|
|
|
144
153
|
this.stderr.write(`${this.ui.err(`${this.ui.glyphs.err} ${command} failed: ${errorCount} error${errorCount === 1 ? '' : 's'}`)}\n`);
|
|
145
154
|
}
|
|
146
155
|
else {
|
|
147
|
-
this.stderr.write(`${this.ui.err('Error:')} ${
|
|
148
|
-
this.stderr.write(`${this.ui.dim('Hint:')} ${
|
|
156
|
+
this.stderr.write(`${this.ui.err('Error:')} ${message}\n`);
|
|
157
|
+
this.stderr.write(`${this.ui.dim('Hint:')} ${hint}\n`);
|
|
149
158
|
if (params.docs) {
|
|
150
159
|
this.stderr.write(`${this.ui.dim('Docs:')} ${params.docs}\n`);
|
|
151
160
|
}
|
|
@@ -161,6 +170,20 @@ export class CliContext {
|
|
|
161
170
|
this.settled = true;
|
|
162
171
|
}
|
|
163
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* The environment markers coding agents set in the shells they run:
|
|
175
|
+
* Claude Code (`CLAUDECODE=1`), Codex (`CODEX_SANDBOX`), Cursor's agent
|
|
176
|
+
* (`CURSOR_AGENT=1`), Gemini CLI (`GEMINI_CLI=1`), and the generic
|
|
177
|
+
* `AI_AGENT`. A pipe alone is not one — a person piping into `grep` is not
|
|
178
|
+
* an agent.
|
|
179
|
+
*/
|
|
180
|
+
export function isAgentEnvironment(env) {
|
|
181
|
+
return (env.CLAUDECODE === '1' ||
|
|
182
|
+
Boolean(env.CODEX_SANDBOX) ||
|
|
183
|
+
env.CURSOR_AGENT === '1' ||
|
|
184
|
+
env.GEMINI_CLI === '1' ||
|
|
185
|
+
Boolean(env.AI_AGENT));
|
|
186
|
+
}
|
|
164
187
|
function defaultStream(stream) {
|
|
165
188
|
return {
|
|
166
189
|
write: (chunk) => {
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors';\nimport { EXIT_CODES, type ExitCode } from './exit-codes';\nimport { type Ui, createUi } from './ui';\n\n/**\n * A single writable sink. Real streams satisfy this; tests pass a capturing\n * buffer so the stdout-purity invariant can be asserted byte-for-byte.\n */\nexport interface WriteStream {\n write(chunk: string): void;\n isTTY?: boolean;\n}\n\nexport interface ContextInput {\n /**\n * The user's EXPLICIT preference, already parsed: `true` for `--json`,\n * `false` for `--no-json`, `undefined` when neither was passed. The\n * undefined case is what allows the mode to be inferred instead.\n */\n jsonFlag?: boolean;\n stdout?: WriteStream;\n stderr?: WriteStream;\n /** Overrides process.env for CLAUDECODE detection (tests). */\n env?: Record<string, string | undefined>;\n}\n\n/** The success envelope. */\ninterface OkEnvelope {\n ok: true;\n data: unknown;\n}\n\n/** The error envelope. `data` is optional — validate carries its findings here. */\ninterface ErrEnvelope {\n ok: false;\n data?: unknown;\n error: { code: string; message: string; hint: string; docs?: string };\n}\n\n/** See `fail`'s doc comment — the human-mode epilogue seam for a command that already rendered a findings block. */\ninterface FindingsSummary {\n /** The command name to name in the summary line, e.g. \"ekanos validate\". */\n command: string;\n errorCount: number;\n}\n\nexport interface FailOptions {\n findingsSummary?: FindingsSummary;\n}\n\n/**\n * `data` is deliberately `unknown` above — each verb owns its own shape — but\n * one convention spans several of them: `validate`, `dev`, `publish` and\n * `status` all add an OPTIONAL `toolchain` field to `data` (never to the\n * envelope's top level) when the proactive update check in `update-notice.ts`\n * finds this CLI is behind. See that file's `ToolchainNoticeData` for the\n * shape, and `README.md`'s \"Keeping the toolchain current\" section for the\n * full contract. It is absent, not `null`, when there is nothing to report.\n */\n\n/**\n * The agent-native output envelope, resolved ONCE at startup and threaded\n * through every command.\n *\n * The load-bearing invariant: in JSON mode, stdout receives EXACTLY ONE JSON\n * object for the whole process — nothing else, ever. Every progress line, warn,\n * and scrap of human prose goes to stderr. This is the single most common way\n * an agent's tool call breaks (a stray log line on stdout makes the JSON\n * unparseable), so the context enforces it structurally: `succeed`/`fail` are\n * the only writers of stdout, and a `settled` latch makes a second call throw\n * rather than emit a second object.\n */\nexport class CliContext {\n readonly jsonMode: boolean;\n /**\n * The environment the context resolved against — exposed so decoration\n * (the gradient banner) can honour `NO_COLOR` / `EKANOS_NO_BANNER` without\n * every call site threading `process.env` through by hand.\n */\n readonly env: Readonly<Record<string, string | undefined>>;\n /**\n * The style layer (`ui.ts`), resolved once against stderr — the stream\n * every human-mode render target uses — so every command shares one color\n * decision instead of each re-deriving it. See `ui.ts` for the tokens and\n * components this carries.\n */\n readonly ui: Ui;\n private readonly stdout: WriteStream;\n private readonly stderr: WriteStream;\n private settled = false;\n\n constructor(input: ContextInput = {}) {\n const stdout = input.stdout ?? defaultStream(process.stdout);\n const stderr = input.stderr ?? defaultStream(process.stderr);\n const env = input.env ?? process.env;\n\n this.stdout = stdout;\n this.stderr = stderr;\n this.env = env;\n this.ui = createUi({ isTTY: stderr.isTTY === true, env });\n\n // Resolve JSON mode once. An EXPLICIT flag always wins: `--json` forces the\n // envelope on even at a terminal, `--no-json` forces the human form even\n // when piped. Only when the user expressed no preference is the mode\n // inferred — from a non-TTY stdout (piped into another program or an agent)\n // or the CLAUDECODE marker.\n const nonTty = stdout.isTTY !== true;\n this.jsonMode = input.jsonFlag ?? (nonTty || env.CLAUDECODE === '1');\n }\n\n /** Whether stderr is a real terminal — decoration (the banner) gates on this. */\n get stderrIsTTY(): boolean {\n return this.stderr.isTTY === true;\n }\n\n /**\n * Whether stdout is a real terminal — `wizard.ts`'s `canWizard` gates on\n * this (clack renders to stdout, unlike the rest of this CLI's human\n * output). `ctx.jsonMode` being false does not by itself guarantee this:\n * `--no-json` forces human mode even against a piped stdout.\n */\n get stdoutIsTTY(): boolean {\n return this.stdout.isTTY === true;\n }\n\n /** Human/progress output — ALWAYS stderr, so stdout stays pure in JSON mode. */\n log(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /** A warning — stderr, no ANSI. */\n warn(message: string): void {\n this.stderr.write(`${message}\\n`);\n }\n\n /**\n * Emit the `claude-code-hint` protocol line to STDERR. Used on --help and on\n * an unknown command so an agent reading stderr is told what to do next\n * without the line ever touching stdout.\n */\n emitClaudeCodeHint(payload: Record<string, unknown>): void {\n // The protocol line is machine-readable JSON for an agent reading\n // stderr. A person at a terminal (human mode on a real stderr TTY) gets\n // the readable error or help text instead of a wall of JSON above it.\n if (!this.jsonMode && this.stderrIsTTY) return;\n\n this.stderr.write(`claude-code-hint: ${JSON.stringify(payload)}\\n`);\n }\n\n /**\n * Terminal success. Writes the single stdout object (JSON mode) or a concise\n * human line (human mode). Returns the OK exit code so the caller can end the\n * process with it. Idempotent-by-latch: a second settle throws.\n */\n succeed(data: unknown, humanSummary?: string): ExitCode {\n this.settle();\n if (this.jsonMode) {\n const envelope: OkEnvelope = { ok: true, data };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (humanSummary !== '') {\n // An explicit empty summary means \"already said it\" — a wizard flow's\n // outro is the result, and a trailing line would just repeat it.\n this.stdout.write(`${humanSummary ?? 'OK'}\\n`);\n }\n return EXIT_CODES.OK;\n }\n\n /**\n * Terminal failure. Writes the single stdout error object (JSON mode) or the\n * message + hint to stderr (human mode). Returns the error's exit code.\n *\n * `error.hint` is guaranteed non-empty by CliError's constructor, so the\n * envelope's \"every error carries a hint\" invariant holds for every path\n * that reaches here.\n *\n * `options.findingsSummary` is the seam for a command that has ALREADY\n * rendered the shared findings block to stderr (human mode) before calling\n * this — `validate`'s and `publish`'s gate-refusal paths. Passing it swaps\n * the default two-line `Error: … / Hint: …` epilogue (whose hint always\n * points at the JSON-only `data.findings`) for one short summary line,\n * `✖ <command> failed: <n> error(s)`, so a partner never reads the same\n * finding jargon twice. JSON mode is completely unaffected either way —\n * `error.hint` always carries the original, JSON-only-appropriate text in\n * the envelope.\n */\n fail(error: CliError, data?: unknown, options?: FailOptions): ExitCode {\n this.failWith({\n code: error.code,\n message: error.message,\n hint: error.hint,\n docs: error.docs,\n exitCode: error.exitCode,\n data,\n findingsSummary: options?.findingsSummary,\n });\n return error.exitCode;\n }\n\n /**\n * The low-level failure emitter. Used directly by `test`, whose exit code is\n * a TRANSPARENT passthrough of the delegated runner's exit code (which is not\n * one of the CLI's own frozen numeric conditions) and whose error `code` is\n * an out-of-taxonomy string. Enforces the same non-empty-hint invariant as\n * CliError so no failure path can emit an empty hint.\n */\n failWith(params: {\n code: string;\n message: string;\n hint: string;\n /** A docs URL for this error; JSON gets a `docs` field, human mode a line. */\n docs?: string;\n exitCode: number;\n data?: unknown;\n findingsSummary?: FindingsSummary;\n }): number {\n this.settle();\n if (!params.hint || params.hint.trim().length === 0) {\n throw new Error(\n `failWith for \"${params.message}\" was given an empty hint. Every CLI ` +\n 'error must carry an imperative remediation.',\n );\n }\n if (this.jsonMode) {\n const envelope: ErrEnvelope = {\n ok: false,\n ...(params.data !== undefined ? { data: params.data } : {}),\n error: {\n code: params.code,\n message: params.message,\n hint: params.hint,\n ...(params.docs ? { docs: params.docs } : {}),\n },\n };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (params.findingsSummary) {\n const { command, errorCount } = params.findingsSummary;\n this.stderr.write(\n `${this.ui.err(\n `${this.ui.glyphs.err} ${command} failed: ${errorCount} error${\n errorCount === 1 ? '' : 's'\n }`,\n )}\\n`,\n );\n } else {\n this.stderr.write(`${this.ui.err('Error:')} ${params.message}\\n`);\n this.stderr.write(`${this.ui.dim('Hint:')} ${params.hint}\\n`);\n if (params.docs) {\n this.stderr.write(`${this.ui.dim('Docs:')} ${params.docs}\\n`);\n }\n }\n return params.exitCode;\n }\n\n private settle(): void {\n if (this.settled) {\n throw new Error(\n 'CliContext settled twice — a command tried to emit a second ' +\n 'terminal result. In JSON mode this would corrupt stdout with two ' +\n 'objects. This is a bug in the command.',\n );\n }\n this.settled = true;\n }\n}\n\nfunction defaultStream(stream: NodeJS.WriteStream): WriteStream {\n return {\n write: (chunk: string) => {\n stream.write(chunk);\n },\n isTTY: stream.isTTY,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors';\nimport { EXIT_CODES, type ExitCode } from './exit-codes';\nimport { echoInvocation } from './invocation';\nimport { type Ui, createUi } from './ui';\n\n/**\n * A single writable sink. Real streams satisfy this; tests pass a capturing\n * buffer so the stdout-purity invariant can be asserted byte-for-byte.\n */\nexport interface WriteStream {\n write(chunk: string): void;\n isTTY?: boolean;\n}\n\nexport interface ContextInput {\n /**\n * The user's EXPLICIT preference, already parsed: `true` for `--json`,\n * `false` for `--no-json`, `undefined` when neither was passed. The\n * undefined case is what allows the mode to be inferred instead.\n */\n jsonFlag?: boolean;\n stdout?: WriteStream;\n stderr?: WriteStream;\n /** Overrides process.env for CLAUDECODE detection (tests). */\n env?: Record<string, string | undefined>;\n}\n\n/** The success envelope. */\ninterface OkEnvelope {\n ok: true;\n data: unknown;\n}\n\n/** The error envelope. `data` is optional — validate carries its findings here. */\ninterface ErrEnvelope {\n ok: false;\n data?: unknown;\n error: { code: string; message: string; hint: string; docs?: string };\n}\n\n/** See `fail`'s doc comment — the human-mode epilogue seam for a command that already rendered a findings block. */\ninterface FindingsSummary {\n /** The command name to name in the summary line, e.g. \"ekanos validate\". */\n command: string;\n errorCount: number;\n}\n\nexport interface FailOptions {\n findingsSummary?: FindingsSummary;\n}\n\n/**\n * `data` is deliberately `unknown` above — each verb owns its own shape — but\n * one convention spans several of them: `validate`, `dev`, `publish` and\n * `status` all add an OPTIONAL `toolchain` field to `data` (never to the\n * envelope's top level) when the proactive update check in `update-notice.ts`\n * finds this CLI is behind. See that file's `ToolchainNoticeData` for the\n * shape, and `README.md`'s \"Keeping the toolchain current\" section for the\n * full contract. It is absent, not `null`, when there is nothing to report.\n */\n\n/**\n * The agent-native output envelope, resolved ONCE at startup and threaded\n * through every command.\n *\n * The load-bearing invariant: in JSON mode, stdout receives EXACTLY ONE JSON\n * object for the whole process — nothing else, ever. Every progress line, warn,\n * and scrap of human prose goes to stderr. This is the single most common way\n * an agent's tool call breaks (a stray log line on stdout makes the JSON\n * unparseable), so the context enforces it structurally: `succeed`/`fail` are\n * the only writers of stdout, and a `settled` latch makes a second call throw\n * rather than emit a second object.\n */\nexport class CliContext {\n readonly jsonMode: boolean;\n /**\n * The environment the context resolved against — exposed so decoration\n * (the gradient banner) can honour `NO_COLOR` / `EKANOS_NO_BANNER` without\n * every call site threading `process.env` through by hand.\n */\n readonly env: Readonly<Record<string, string | undefined>>;\n /**\n * The style layer (`ui.ts`), resolved once against stderr — the stream\n * every human-mode render target uses — so every command shares one color\n * decision instead of each re-deriving it. See `ui.ts` for the tokens and\n * components this carries.\n */\n readonly ui: Ui;\n /** A coding agent's marker is in the environment (`isAgentEnvironment`). */\n readonly agentDetected: boolean;\n /** `--json` was passed — not inferred from a pipe. */\n private readonly explicitJson: boolean;\n private readonly stdout: WriteStream;\n private readonly stderr: WriteStream;\n private settled = false;\n\n constructor(input: ContextInput = {}) {\n const stdout = input.stdout ?? defaultStream(process.stdout);\n const stderr = input.stderr ?? defaultStream(process.stderr);\n const env = input.env ?? process.env;\n\n this.stdout = stdout;\n this.stderr = stderr;\n this.env = env;\n this.ui = createUi({ isTTY: stderr.isTTY === true, env });\n\n // Resolve JSON mode once. An EXPLICIT flag always wins: `--json` forces the\n // envelope on even at a terminal, `--no-json` forces the human form even\n // when piped. Only when the user expressed no preference is the mode\n // inferred — from a non-TTY stdout (piped into another program or an agent)\n // or the CLAUDECODE marker.\n const nonTty = stdout.isTTY !== true;\n this.jsonMode = input.jsonFlag ?? (nonTty || env.CLAUDECODE === '1');\n this.explicitJson = input.jsonFlag === true;\n this.agentDetected = isAgentEnvironment(env);\n }\n\n /** Whether stderr is a real terminal — decoration (the banner) gates on this. */\n get stderrIsTTY(): boolean {\n return this.stderr.isTTY === true;\n }\n\n /**\n * Whether stdout is a real terminal — `wizard.ts`'s `canWizard` gates on\n * this (clack renders to stdout, unlike the rest of this CLI's human\n * output). `ctx.jsonMode` being false does not by itself guarantee this:\n * `--no-json` forces human mode even against a piped stdout.\n */\n get stdoutIsTTY(): boolean {\n return this.stdout.isTTY === true;\n }\n\n /** Human/progress output — ALWAYS stderr, so stdout stays pure in JSON mode. */\n log(message: string): void {\n this.stderr.write(`${echoInvocation(message)}\\n`);\n }\n\n /** A warning — stderr, no ANSI. */\n warn(message: string): void {\n this.stderr.write(`${echoInvocation(message)}\\n`);\n }\n\n /**\n * Emit the `claude-code-hint` protocol line to STDERR. Used on --help and on\n * an unknown command so an agent reading stderr is told what to do next\n * without the line ever touching stdout.\n */\n emitClaudeCodeHint(payload: Record<string, unknown>): void {\n // The protocol line is machine-readable JSON for an agent reading\n // stderr. It is written only when an agent is known to be reading: one\n // was detected in the environment, or `--json` was asked for. A person —\n // at a terminal, or piping into `less` or `grep` — gets the readable\n // error or help text, never a line of JSON above it.\n if (!this.explicitJson && !this.agentDetected) return;\n\n this.stderr.write(`claude-code-hint: ${JSON.stringify(payload)}\\n`);\n }\n\n /**\n * Terminal success. Writes the single stdout object (JSON mode) or a concise\n * human line (human mode). Returns the OK exit code so the caller can end the\n * process with it. Idempotent-by-latch: a second settle throws.\n */\n succeed(data: unknown, humanSummary?: string): ExitCode {\n this.settle();\n if (this.jsonMode) {\n const envelope: OkEnvelope = { ok: true, data };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (humanSummary !== '') {\n // An explicit empty summary means \"already said it\" — a wizard flow's\n // outro is the result, and a trailing line would just repeat it.\n this.stdout.write(`${echoInvocation(humanSummary ?? 'OK')}\\n`);\n }\n return EXIT_CODES.OK;\n }\n\n /**\n * Terminal failure. Writes the single stdout error object (JSON mode) or the\n * message + hint to stderr (human mode). Returns the error's exit code.\n *\n * `error.hint` is guaranteed non-empty by CliError's constructor, so the\n * envelope's \"every error carries a hint\" invariant holds for every path\n * that reaches here.\n *\n * `options.findingsSummary` is the seam for a command that has ALREADY\n * rendered the shared findings block to stderr (human mode) before calling\n * this — `validate`'s and `publish`'s gate-refusal paths. Passing it swaps\n * the default two-line `Error: … / Hint: …` epilogue (whose hint always\n * points at the JSON-only `data.findings`) for one short summary line,\n * `✖ <command> failed: <n> error(s)`, so a partner never reads the same\n * finding jargon twice. JSON mode is completely unaffected either way —\n * `error.hint` always carries the original, JSON-only-appropriate text in\n * the envelope.\n */\n fail(error: CliError, data?: unknown, options?: FailOptions): ExitCode {\n this.failWith({\n code: error.code,\n message: error.message,\n hint: error.hint,\n docs: error.docs,\n exitCode: error.exitCode,\n data,\n findingsSummary: options?.findingsSummary,\n });\n return error.exitCode;\n }\n\n /**\n * The low-level failure emitter. Used directly by `test`, whose exit code is\n * a TRANSPARENT passthrough of the delegated runner's exit code (which is not\n * one of the CLI's own frozen numeric conditions) and whose error `code` is\n * an out-of-taxonomy string. Enforces the same non-empty-hint invariant as\n * CliError so no failure path can emit an empty hint.\n */\n failWith(params: {\n code: string;\n message: string;\n hint: string;\n /** A docs URL for this error; JSON gets a `docs` field, human mode a line. */\n docs?: string;\n exitCode: number;\n data?: unknown;\n findingsSummary?: FindingsSummary;\n }): number {\n this.settle();\n if (!params.hint || params.hint.trim().length === 0) {\n throw new Error(\n `failWith for \"${params.message}\" was given an empty hint. Every CLI ` +\n 'error must carry an imperative remediation.',\n );\n }\n // The commands a hint names, as this run was invoked (`invocation.ts`).\n const message = echoInvocation(params.message);\n const hint = echoInvocation(params.hint);\n if (this.jsonMode) {\n const envelope: ErrEnvelope = {\n ok: false,\n ...(params.data !== undefined ? { data: params.data } : {}),\n error: {\n code: params.code,\n message,\n hint,\n ...(params.docs ? { docs: params.docs } : {}),\n },\n };\n this.stdout.write(`${JSON.stringify(envelope)}\\n`);\n } else if (params.findingsSummary) {\n const { command, errorCount } = params.findingsSummary;\n this.stderr.write(\n `${this.ui.err(\n `${this.ui.glyphs.err} ${command} failed: ${errorCount} error${\n errorCount === 1 ? '' : 's'\n }`,\n )}\\n`,\n );\n } else {\n this.stderr.write(`${this.ui.err('Error:')} ${message}\\n`);\n this.stderr.write(`${this.ui.dim('Hint:')} ${hint}\\n`);\n if (params.docs) {\n this.stderr.write(`${this.ui.dim('Docs:')} ${params.docs}\\n`);\n }\n }\n return params.exitCode;\n }\n\n private settle(): void {\n if (this.settled) {\n throw new Error(\n 'CliContext settled twice — a command tried to emit a second ' +\n 'terminal result. In JSON mode this would corrupt stdout with two ' +\n 'objects. This is a bug in the command.',\n );\n }\n this.settled = true;\n }\n}\n\n/**\n * The environment markers coding agents set in the shells they run:\n * Claude Code (`CLAUDECODE=1`), Codex (`CODEX_SANDBOX`), Cursor's agent\n * (`CURSOR_AGENT=1`), Gemini CLI (`GEMINI_CLI=1`), and the generic\n * `AI_AGENT`. A pipe alone is not one — a person piping into `grep` is not\n * an agent.\n */\nexport function isAgentEnvironment(\n env: Readonly<Record<string, string | undefined>>,\n): boolean {\n return (\n env.CLAUDECODE === '1' ||\n Boolean(env.CODEX_SANDBOX) ||\n env.CURSOR_AGENT === '1' ||\n env.GEMINI_CLI === '1' ||\n Boolean(env.AI_AGENT)\n );\n}\n\nfunction defaultStream(stream: NodeJS.WriteStream): WriteStream {\n return {\n write: (chunk: string) => {\n stream.write(chunk);\n },\n isTTY: stream.isTTY,\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type WriteStream } from './context.js';
|
|
2
|
+
import { type Invocation } from './invocation.js';
|
|
2
3
|
export { CliContext } from './context.js';
|
|
3
4
|
export { EXIT_CODES, ERROR_CODES } from './exit-codes.js';
|
|
4
5
|
export type { ExitCode, ErrorCode } from './exit-codes.js';
|
|
@@ -7,6 +8,11 @@ export interface RunOptions {
|
|
|
7
8
|
stderr?: WriteStream;
|
|
8
9
|
env?: Record<string, string | undefined>;
|
|
9
10
|
cwd?: string;
|
|
11
|
+
/**
|
|
12
|
+
* How this run was invoked, for the commands hints name (`invocation.ts`).
|
|
13
|
+
* Detected from `env` and the script path when absent.
|
|
14
|
+
*/
|
|
15
|
+
invocation?: Invocation;
|
|
10
16
|
/**
|
|
11
17
|
* Test-only override for `publish`'s interactive-confirm gate and `init`
|
|
12
18
|
* / `login`'s clack wizard gate (`canWizard` in `wizard.ts`) — see
|
|
@@ -25,6 +31,13 @@ export interface RunOptions {
|
|
|
25
31
|
*/
|
|
26
32
|
openUrl?: (url: string) => void;
|
|
27
33
|
pollDelayMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Test-only seams for the secret-input flags (`secret-input.ts`): what
|
|
36
|
+
* `--secret-stdin` reads, and how long a `--browser` form waits. The
|
|
37
|
+
* opener above also opens the form. Never set from real CLI wiring.
|
|
38
|
+
*/
|
|
39
|
+
readStdin?: () => Promise<string>;
|
|
40
|
+
secretFormTimeoutMs?: number;
|
|
28
41
|
/**
|
|
29
42
|
* Test-only override for `status --watch`'s poll delay — see `StatusArgs`
|
|
30
43
|
* in `commands/status.ts`. Never set this from real CLI wiring; it exists
|