') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); feat: add API Gateway target TUI wizard and address review feedback by aidandaly24 · Pull Request #511 · aws/agentcore-cli · GitHub
Skip to content

feat: add API Gateway target TUI wizard and address review feedback - #511

Merged
tejaskash merged 4 commits into
mainfrom
feat/api-gateway-tui
Mar 9, 2026
Merged

feat: add API Gateway target TUI wizard and address review feedback#511
tejaskash merged 4 commits into
mainfrom
feat/api-gateway-tui

Conversation

@aidandaly24

@aidandaly24aidandaly24 commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Description

Adds the TUI wizard flow for API Gateway targets, along with review feedback fixes and polish from CLI #509.

TUI Wizard:

  • New target type option: "API Gateway REST API" in the target type picker
  • Three new wizard steps: REST API ID, Deployment Stage, Tool Filters (split into two prompts: path pattern + HTTP methods)
  • apiGateway step sequence: name → target-type → rest-api-id → stage → tool-filters → gateway → confirm
  • Wizard navigation refactored from hardcoded setStep() to dynamic goToNextStep() for all setters except setTargetType (closure issue documented)
  • ConfirmReview shows apiGateway-specific fields (REST API ID, Stage, Tool Filters) instead of Endpoint/Outbound Auth
  • Flow dispatches to createApiGatewayTarget() for apiGateway targets

ResourceGraph:

  • Shows restApiId/stage and [apiGateway] badge for API Gateway targets

Review Feedback Fixes (from CLI #2 review):

  • Made sourcePath, host, toolDefinition, description, language optional on AddGatewayTargetConfig — apiGateway targets don't use these
  • Removed dummy field values from apiGateway CLI dispatch config
  • Removed unused targetType from dispatch config (method hardcodes it)
  • Added outboundAuth rejection to schema superRefine for apiGateway targets
  • Moved apiGateway validation block before outbound auth validation to prevent misleading errors
  • Fixed success screen: no "Project created at " for apiGateway, showDevOption={false} for gateway targets

Related Issue

Closes #

Documentation PR

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

Additionally:

  • Manually tested TUI wizard end-to-end: selected API Gateway REST API, entered REST API ID, stage, tool filters, gateway, confirmed — correct mcp.json written
  • Verified remove + re-add via TUI works correctly
  • 1978 unit tests pass, zero regressions

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.

@aidandaly24
aidandaly24 requested a review from a teamMarch 6, 2026 21:25
@github-actionsgithub-actionsBot added the size/m PR size: M label Mar 6, 2026
@github-actions

github-actionsBot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

StatusCategoryPercentageCovered / Total
🔵Lines42.74%3722 / 8707
🔵Statements42.34%3927 / 9274
🔵Functions44.39%737 / 1660
🔵Branches44.76%2426 / 5420
Generated in workflow #899 for commit 512eec3 by the Vitest Coverage Report Action

@tejaskashtejaskash left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

1. Non-null assertion (!) proliferation — 8 new instances (Medium)

Making fields optional on AddGatewayTargetConfig and then using ! at every call site trades one problem (dummy values) for another (suppressed type safety). There are 8 new ! assertions across GatewayTargetPrimitive.ts (config.toolDefinition! ×2, config.sourcePath! ×4, config.language! ×1) and useCreateMcp.ts (config.language! ×1).

If a code path ever reaches these without the field set (e.g., a new target type that doesn't set sourcePath), it'll be a silent undefined runtime error. A discriminated union would be the proper fix:

typeAddGatewayTargetConfig=|{targetType: 'apiGateway';name: string;restApiId: string;stage: string; ... }|{targetType: 'mcpServer';name: string;sourcePath: string;language: TargetLanguage;host: ComputeHost;toolDefinition: ToolDefinition; ... }

Worth tracking before adding more target types.


2. Tool filter HTTP methods are not validated in the TUI (Medium)

In AddGatewayTargetScreen.tsx (lines ~233-238), user input is split, trimmed, and uppercased, but never validated against the allowed set (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS). If a user types GET,TRACE, the value TRACE will be written to the config and only fail at deploy time when the Zod schema (ApiGatewayHttpMethodSchema) rejects it. Consider validating in the wizard or using a multi-select instead of free-text input.


3. outboundAuth schema check allows type: 'NONE' (Low)

In mcp.ts line 360, the check is data.outboundAuth && data.outboundAuth.type !== 'NONE'. This means { outboundAuth: { type: 'NONE' } } is technically valid on an apiGateway target. If outbound auth is "not applicable" for apiGateway, all values should be rejected, not just non-NONE. Consider simplifying to if (data.outboundAuth).


4. Two-phase tool-filters step uses component-local state (Low)

In AddGatewayTargetScreen.tsx, the tool-filters step is split into two prompts (path pattern → HTTP methods) managed by a local filterPath state variable, creating a sub-step outside the wizard's step tracking. The wizard's step value stays at 'tool-filters' throughout both sub-prompts. This works but is fragile — if more sub-steps are needed later, this pattern doesn't scale. Consider promoting these to separate wizard steps (tool-filter-path, tool-filter-methods).


5. Triple-nested ternary in ResourceGraph (Nit)

In ResourceGraph.tsx (lines ~247-252), the displayText computation is now a three-level ternary, duplicated at line ~292. Consider extracting a helper:

functiongetTargetDisplayText(target: AgentCoreGatewayTarget): string{if(target.targetType==='mcpServer'&&target.endpoint)returntarget.endpoint;if(target.targetType==='apiGateway'&&target.apiGateway)return`${target.apiGateway.restApiId}/${target.apiGateway.stage}`;returntarget.name;}

tejaskash
tejaskash previously requested changes Mar 6, 2026
Introduce McpServerTargetConfig and ApiGatewayTargetConfig as a
discriminated union, replacing the single bag-of-optionals interface.
The wizard uses GatewayTargetWizardState internally and narrows to
the union at the confirm step boundary.
- Remove all 8 non-null assertions (!) from GatewayTargetPrimitive
and useCreateMcp by narrowing method signatures
- Add HTTP method validation to tool-filters TUI input
- Add explanatory comment on two-phase tool-filters local state
- Remove dead code-scaffolding branch from handleCreateComplete
@github-actionsgithub-actionsBot added size/l PR size: L and removed size/m PR size: M labels Mar 7, 2026
@aidandaly24

Copy link
Copy Markdown
ContributorAuthor

@tejaskash I will fix #3 in the next PR for auth

@aidandaly24
aidandaly24 dismissed tejaskash’s stale reviewMarch 9, 2026 14:08

updated the PR covering the comments

@tejaskash
tejaskash merged commit 9ecf0fa into mainMar 9, 2026
19 checks passed
@tejaskash
tejaskash deleted the feat/api-gateway-tui branch March 9, 2026 14:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lPR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aidandaly24@tejaskash