-
Notifications
You must be signed in to change notification settings - Fork 0
feat(integration): the code-agent picker opens with an opt-in question #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,8 @@ import { | |
| BACK, | ||
| cancel, | ||
| note, | ||
| outro, | ||
| promptConfirmOrBack, | ||
| promptSelectOrBack, | ||
| promptPasswordOrBack, | ||
| } from '../../utils/prompt'; | ||
|
|
@@ -77,6 +79,16 @@ export function typeOptionsForCategory(category: string | undefined): typeof TYP | |
| return TYPE_OPTIONS.filter((o) => o.category === category); | ||
| } | ||
|
|
||
| // The code-agent picker opens with an opt-in question because connecting one | ||
| // changes where autofixes run; --type means the user already decided. | ||
| export function shouldOfferCodeAgent( | ||
| category: string | undefined, | ||
| typeFromFlag: boolean, | ||
| interactive: boolean | ||
| ): boolean { | ||
| return category === 'code-agent' && !typeFromFlag && interactive; | ||
| } | ||
|
|
||
| // The category is validated even when --type wins, so a typo always errors | ||
| // instead of being silently ignored. | ||
| export function resolveTypeOptions(category: string | undefined, typeFromFlag: boolean): typeof TYPE_OPTIONS { | ||
|
|
@@ -602,6 +614,7 @@ export const integrationConnectCommand: Command = { | |
| 'polylane integration connect --type github', | ||
| 'polylane integration connect --type github --reconnect', | ||
| 'polylane integration connect --category observability', | ||
| 'polylane integration connect --category code-agent', | ||
| 'polylane integration connect --type datadog --site us5.datadoghq.com --api-key ... --app-key ...', | ||
| 'polylane integration connect --type honeycomb --region us --api-key ...', | ||
| 'polylane integration connect --type axiom --region us-east-1 --api-token ...', | ||
|
|
@@ -611,12 +624,30 @@ export const integrationConnectCommand: Command = { | |
| 'polylane integration connect --type mcp --url https://mcp.example.com/sse --name "My MCP" --oauth', | ||
| ], | ||
| async execute(config: Config, _flags, args: Record<string, unknown>): Promise<void> { | ||
| const workspaceId = await requireWorkspace(config); | ||
| const noBrowser = getArgBoolean(args, 'noBrowser') === true; | ||
| const api = new PolylaneAPI(config); | ||
| const typeFromFlag = getArgString(args, 'type') !== undefined; | ||
| const category = getArgString(args, 'category'); | ||
| // --type always wins: the category filter only narrows the picker. | ||
| const typeOptions = resolveTypeOptions(getArgString(args, 'category'), typeFromFlag); | ||
| const typeOptions = resolveTypeOptions(category, typeFromFlag); | ||
|
|
||
| if (shouldOfferCodeAgent(category, typeFromFlag, isInteractive(config.nonInteractive))) { | ||
| note( | ||
| 'Optional. Polylane runs autofixes on its own executor; connect your coding agent to run them in your account instead.', | ||
| 'Cloud coding agent' | ||
| ); | ||
| const wants = await promptConfirmOrBack( | ||
| { nonInteractive: config.nonInteractive }, | ||
| 'Connect a cloud coding agent?', | ||
| true | ||
| ); | ||
| if (wants !== true) { | ||
| outro('Skipped. Connect later with `polylane integration connect --category code-agent`.'); | ||
| return; | ||
| } | ||
|
Comment on lines
+643
to
+646
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor (non-blocking): Ctrl+C at the offer prompt is indistinguishable from an explicit "No" — Generated by Claude Code |
||
| } | ||
|
|
||
| const workspaceId = await requireWorkspace(config); | ||
| const api = new PolylaneAPI(config); | ||
|
|
||
| // Type selection restarts whenever the user backs out of the first step of | ||
| // the chosen flow, so nothing is committed until a flow completes. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { describe, it } from 'node:test'; | ||
| import assert from 'node:assert/strict'; | ||
| import { shouldOfferCodeAgent } from '../src/commands/integration/connect'; | ||
|
|
||
| describe('shouldOfferCodeAgent', () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: nice coverage — these four tests exercise the pure gate ( Generated by Claude Code |
||
| it('offers on an interactive code-agent picker', () => { | ||
| assert.equal(shouldOfferCodeAgent('code-agent', false, true), true); | ||
| }); | ||
|
|
||
| it('never offers outside the code-agent category', () => { | ||
| assert.equal(shouldOfferCodeAgent(undefined, false, true), false); | ||
| assert.equal(shouldOfferCodeAgent('observability', false, true), false); | ||
| }); | ||
|
|
||
| it('never offers when --type already decided', () => { | ||
| assert.equal(shouldOfferCodeAgent('code-agent', true, true), false); | ||
| }); | ||
|
|
||
| it('never offers non-interactively', () => { | ||
| assert.equal(shouldOfferCodeAgent('code-agent', false, false), false); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this decline-path
outroprints even with--quiet. Consistent with other clack output in the repo, so cosmetic at most.Generated by Claude Code