diff --git a/skill/SKILL.md b/skill/SKILL.md index 5aed199..54aabbe 100644 --- a/skill/SKILL.md +++ b/skill/SKILL.md @@ -262,7 +262,7 @@ Run `polylane automation create --help` for every flag. Common trigger types: `a `{cloudflare,vercel,render,fly}.deployment`, `slack.message`, `polylane.*` (issue.triaged, cloud_account.synced, codebase.synced, …). Actions include `openIssue`, `rollback{Cloudflare,Vercel,Render,Fly}Deployment`, `submitPr`, `commentPr`, `mergePr`, -`commentGithubIssue`, `createGithubIssue`, `autofix`, `handoffTo{Devin,Cursor,Factory}`. The +`commentGithubIssue`, `createGithubIssue`, `autofix`, `handoffTo{Devin,Cursor,Factory,Conductor}`. The authoritative, always-current list of types and filters is in the docs and in `polylane api describe automations.post`. diff --git a/src/commands/integration/connect.ts b/src/commands/integration/connect.ts index acf84f1..1d8c30b 100644 --- a/src/commands/integration/connect.ts +++ b/src/commands/integration/connect.ts @@ -43,6 +43,7 @@ type ConnectableType = | 'devin' | 'cursor' | 'factory' + | 'conductor' | 'mcp'; // Mirrors each type's subcategory in the integrations catalog @@ -62,6 +63,7 @@ const TYPE_OPTIONS: Array<{ value: ConnectableType; label: string; hint: string; { value: 'devin', label: 'Devin', hint: 'API key · coding agent', category: 'code-agent' }, { value: 'cursor', label: 'Cursor', hint: 'API key · coding agent', category: 'code-agent' }, { value: 'factory', label: 'Factory', hint: 'API key · coding agent', category: 'code-agent' }, + { value: 'conductor', label: 'Conductor', hint: 'API key · coding agent', category: 'code-agent' }, { value: 'mcp', label: 'MCP server', hint: 'any MCP server by URL', category: 'protocol' }, ]; @@ -125,6 +127,13 @@ const CODE_AGENTS = { link: 'https://app.factory.ai/settings/api-keys', linkLabel: 'Create API key', }, + conductor: { + name: 'Conductor', + instructions: + 'Create an API key in Conductor under Users > API keys. The key starts with sk_. Handed-off autofixes run as agents in Conductor Cloud workspaces on your account.', + link: 'https://app.conductor.build/users/api-keys', + linkLabel: 'Create API key', + }, } as const; function isCodeAgentType(value: Integration['type']): value is keyof typeof CODE_AGENTS { @@ -567,7 +576,7 @@ async function connectType( export const integrationConnectCommand: Command = { name: 'integration connect', - description: 'Connect an integration (GitHub, Slack, Sentry, Datadog, Honeycomb, Axiom, Better Stack, Devin, Cursor, Factory, MCP)', + description: 'Connect an integration (GitHub, Slack, Sentry, Datadog, Honeycomb, Axiom, Better Stack, Devin, Cursor, Factory, Conductor, MCP)', operationId: 'integrations.connect', options: [ { @@ -582,7 +591,7 @@ export const integrationConnectCommand: Command = { }, { flag: '--site ', description: 'Datadog site (e.g. us5.datadoghq.com)', type: 'string' }, { flag: '--region ', description: 'Honeycomb (us|eu) or Axiom (us-east-1|eu-central-1)', type: 'string' }, - { flag: '--api-key ', description: 'API key (Datadog / Honeycomb / Devin / Cursor / Factory)', type: 'string' }, + { flag: '--api-key ', description: 'API key (Datadog / Honeycomb / Devin / Cursor / Factory / Conductor)', type: 'string' }, { flag: '--app-key ', description: 'App key (Datadog only)', type: 'string' }, { flag: '--api-token ', description: 'API token (Axiom / Better Stack global token)', type: 'string' }, { flag: '--uptime-api-token ', description: 'Uptime API token (Better Stack only)', type: 'string' }, diff --git a/test/integration-connect-category.test.ts b/test/integration-connect-category.test.ts index 9e6e4d6..7616622 100644 --- a/test/integration-connect-category.test.ts +++ b/test/integration-connect-category.test.ts @@ -10,7 +10,7 @@ import { isCLIError } from '../src/errors/base'; describe('typeOptionsForCategory', () => { it('returns every option when no category is given', () => { const all = typeOptionsForCategory(undefined); - assert.equal(all.length, 11); + assert.equal(all.length, 12); }); it('narrows to exactly the observability integrations', () => { @@ -18,6 +18,11 @@ describe('typeOptionsForCategory', () => { assert.deepEqual(types.sort(), ['axiom', 'betterstack', 'datadog', 'honeycomb', 'sentry']); }); + it('narrows to exactly the code agents', () => { + const types = typeOptionsForCategory('code-agent').map((o) => o.value); + assert.deepEqual(types.sort(), ['conductor', 'cursor', 'devin', 'factory']); + }); + it('covers every option with a known category', () => { for (const category of CONNECT_CATEGORIES) { assert.ok(typeOptionsForCategory(category).length > 0, `empty category: ${category}`); @@ -42,9 +47,9 @@ describe('typeOptionsForCategory', () => { describe('resolveTypeOptions', () => { it('lets --type win over the filter', () => { - assert.equal(resolveTypeOptions('observability', true).length, 11); + assert.equal(resolveTypeOptions('observability', true).length, 12); assert.equal(resolveTypeOptions('observability', false).length, 5); - assert.equal(resolveTypeOptions(undefined, false).length, 11); + assert.equal(resolveTypeOptions(undefined, false).length, 12); }); it('rejects an unknown category even when --type is present', () => {