Skip to content

feat: close the eight essential CLI feature gaps - #2146

Merged
jariy17 merged 14 commits into
refactorfrom
feat/essential-gaps
Aug 31, 2026
Merged

feat: close the eight essential CLI feature gaps#2146
jariy17 merged 14 commits into
refactorfrom
feat/essential-gaps

Conversation

@AlexanderRichey

@AlexanderRichey AlexanderRichey commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Closes the eight essential feature gaps between the original CLI and the refactor, one commit per gap, each verified live against AWS account 501930284170 (us-east-1) where the gap has a deployable surface.

Gaps closed

1. Harness-first project creation — feat(create): harness-first project creation

Bare project create --name X (and --defaults) now creates a harness project, matching the original's default quick start. Harness-only flags (--model-id, --api-key-arn, --api-base, --additional-params, --no-harness-memory, --max-iterations, --max-tokens, --timeout, --truncation-strategy, --container) flow into the harness spec; the create-time harness scaffolds through the same addResource path as project add harness; mixing harness and runtime-scaffolding flags is a validation error mirroring the original's dispatch.
Live e2e: project create --name GapE2eHarness0830 --model-id us.amazon.nova-lite-v1:0 → zero-config project deploy → stack AgentCore-GapE2eHarness0830-default CREATE_COMPLETE (us-east-1) → harness invoke returned a real Nova Lite response. Stack destroyed after (DELETE_COMPLETE).

2. Bedrock Agent import — feat(create): import a Bedrock Agent as a runtime

project create --type import --agent-id --agent-alias-id (and project add runtime --type import) describes the agent/alias via @aws-sdk/client-bedrock-agent (new dependency), validates the region against the supported list, and scaffolds a proxy runtime from the new bedrock-agent-proxy-python template (InvokeAgent + streamed reply; vended bedrock-agent-policy.json grants bedrock:InvokeAgent via additionalPolicies). Deliberate shape difference: the original translated the agent definition to framework code; this ships the proxy form per the parity spec.
Live e2e: created throwaway Bedrock Agent 6AHPCYGV7S (Nova Lite) + alias JJUMUT2PCQ + service role; imported; deployed AgentCore-GapE2eImport0830-default CREATE_COMPLETE; runtime invokedata: "The capital of France is Paris."; then destroyed the stack and deleted the agent, alias, and role.

3. Export harness → Strands runtime — feat(project): export a harness to a Strands runtime agent

New project export harness (--name for an in-project harness, --arn for any service harness — region-aware from the ARN; --target-agent-name, --build CodeZip|Container, --json). Renders editable Strands code under app/<target>/ through the stock strands template's export context (model config for all four harness providers, system prompt, remote-MCP tools with credential env wiring, inline functions, skills, in-project memory, truncation, execution limits via a vendored hooks/execution_limits.py), registers the runtime in agentcore.json (the harness entry is kept, mirroring the original), writes EXPORT_NOTES.md for anything unmappable, refuses overwrites, and validates the project before any service fetch (the 0.28.1 fix). 73 new unit tests.
Live e2e: GapE2eExport0830 — deploy #1 CREATE_COMPLETE with harness GapE2eExport0830_exportme-ZFg6mVuUYn READY → export → project build → deploy #2 UPDATE_COMPLETE → runtime invoke on the exported runtime streamed a live Nova Lite reply ("Exported agent reporting for duty."); the --arn path was exercised against the deployed harness and built. Stack destroyed (DELETE_COMPLETE).

4. Complete project remove + remove allfeat(remove): cover all addable resources and add remove all

The remove enum now covers every addable type (adds credential, config-bundle, online-eval, online-insight, memory) with .env.local cleanup for credentials; removing a nonexistent resource raises ResourceNotFoundError instead of warn-and-rewrite; project remove all resets every spec collection behind a y/N confirmation with --yes.
Live e2e: GapE2eRemove0830 — added all five newly-removable types, removed them (spec + .env.local verified), deployed CREATE_COMPLETE, remove all --yes, then deploy --yes teardown path → DELETE_COMPLETE.

5. runtime logsfeat(runtime): logs streaming and search (+ refactor(core): extract shared observability helpers)

The precursor commit extracts the runtime log-group derivation and the multi-log-group, fully-paginated Logs Insights runner out of core/eval into src/core/observability.ts (zero behavior change; eval re-pointed) and adds the time-string parser (now, 30s/5m/1h/2d, epoch ms, ISO 8601). runtime logs then ships follow mode by default (StartLiveTail with auto-reconnect over the 3-hour session cap; Ctrl-C exits 130 cleanly) and search mode on --since/--until (FilterLogEvents, paginated, oldest→newest), with --level, --query (composed into a CloudWatch filter pattern), --limit, and --json JSON-Lines. --id works anywhere; inside a project the runtime id resolves live from the target stack's outputs via DescribeStacks (single runtime auto-selects; several → error listing candidates), with the deployment target's region taking precedence.
Live e2e: GapE2eObs0830 deployed CREATE_COMPLETE; 4 invokes; search returned real events; --level/--query/--limit/--json verified; follow mode captured a mid-stream invocation marker and exited 130 on SIGINT; auto-resolve without --id (even with a wrong ambient --region) found the events. Stack destroyed after.

6. runtime tracesfeat(runtime): traces list and get

runtime traces list (--id/project auto-resolve, --limit default 20, --since default 12h, --until, --json) aggregates recent traceIds with timestamps and session ids via the shared Insights runner (filtering empty-traceId infra records before aggregation — fixes an off-by-one the original had). runtime traces get <traceId> validates the id format and downloads every record to --output or agentcore/.cli/traces/<runtime>-<traceId>.json. No hardcoded console URLs (deep link deliberately skipped).
Live e2e: all four invocations' traces listed with matching session ids ~3 minutes after invoking; traces get wrote 10 records to the default project path; invalid/missing trace ids and missing log group produce guided errors.

7. --versionfeat(cli): add --version

Bare agentcore --version/-V prints the build-time version (verified under bun run and in the bundled dist/index.js). Implemented as a root-only pre-parse intercept so leaf --version <value> flags (harness version get, etc.) are not shadowed.

8. project create TUI wizard — feat(tui): project create wizard

Bare agentcore project create in a terminal now opens a wizard instead of exiting with NotImplementedError: name (validated live against ProjectNameSchema, schema messages shown inline) → project type (harness — the default, per gap 1 — or scaffolded agent) → harness model id or agent template with the strands memory choice (hello-world skips the memory question) → confirmation summary → live ProjectManager progress → success screen with cd/deploy next steps. No forked creation logic: the wizard builds the same CreateProjectInput as the flag-driven handler (resolveScaffoldHarnessInput, now exported, for the harness path; resolveRuntimeTemplateShortcut for templates) and iterates core.projectManager.create in the cwd, npm install and git init included; a create() failure renders and exits nonzero via useApp().exit(error). Dispatch is conservative: only a bare, flagless invocation on a TTY opens the wizard (withTuiOnEmptyFlagsAndArgs, TTY-gated at registration) — any user-supplied flag, --json, or a non-TTY session behaves exactly as before, enforced by making --name optional at the Commander layer and re-validated in the handler with the identical error wording. The other six project subcommands keep their not-implemented stubs. 16 ink-testing-library tests cover the flows, validation, esc navigation, error teardown, and all four dispatch cases.
Live check: wizard driven end-to-end in a real pty — name typed, harness type and default model accepted, review confirmed, creation ran (npm install + git init), success screen, exit 0 — producing a project spec-identical to the flag path's. Doing so surfaced a pre-existing UI-kit bug: Ink hands coalesced keystrokes (and every terminal paste) to useInput as one chunk whose key.return is false, so TextInput stored a trailing \r as an invisible character that failed name validation with a message the user couldn't act on. Fixed in fix(ui): strip control bytes from coalesced text-input chunks (C0/DEL stripped from appended text, matching ink-text-input's \r/\n handling; stripped newlines deliberately don't submit), with a paste regression test.

Verification

  • Full gate green on the merged result: bun test (2513 pass, 0 fail, 184 files), bun run typecheck, bun run lint:check.
  • Final live smoke on the merged build: project create --name GapE2eSmoke0831 (bare → harness project) → zero-config project deploy (target auto-provisioned: account 501930284170, us-east-1) → stack AgentCore-GapE2eSmoke0831-default CREATE_COMPLETE (verified via DescribeStacks) with harness READY → harness invoke returned the requested reply verbatim ("smoke test ok") → runtime logs --id harness_GapE2eSmoke0831_GapE2eSmoke0831-H1UyMN5OLm --since 15m returned real CloudWatch events from the runtime log group; bare runtime logs without --id in this harness-only project fails with the intended actionable error ("stack exports no runtime ids … pass --id" — harness stacks export an AgentRuntimeArn but no RuntimeId output, and the auto-resolver's contract is runtime outputs). Stack destroyed after (confirmed gone via DescribeStacks).
  • Post-lockfile e2e recheck: after regenerating bun.lock, node_modules was deleted and rebuilt solely from the committed lockfile under bun 1.4.0 (CI's toolchain) — the nested override resolves (@aws-cdk/toolkit-lib gets yaml@1.10.3), all 2513 tests pass on the fresh tree, and the live loop was re-run end-to-end: bare project create --name GapE2eLock0831 → zero-config project deployAgentCore-GapE2eLock0831-default CREATE_COMPLETE with harness READY → harness invoke returned the requested reply verbatim ("lockfile e2e ok") → runtime logs --since 10m returned real events. Also exercised on the fresh tree: project create --template strands-pythonproject build synthesized the template (runtime + memory) cleanly, and add runtime --type import loaded @aws-sdk/client-bedrock-agent and made a live signed GetAgent call (the account role currently lacks bedrock:GetAgent, so it surfaced the service's AccessDenied cleanly and left the spec untouched — the SDK/dependency path the lockfile governs is proven). Stack destroyed after.
  • All e2e stacks/agents/roles created for this work were destroyed; CDKToolkit bootstrap stacks remain in us-east-1, us-west-2, eu-west-1 (pre-existing).

Also included: a leading chore commit that scopes bun test/tsc to the source tree (generated out/ scaffolds and stale dist/ output were failing the gate) and fixes two react(set-state-in-effect) findings newer oxlint raises.

Stacked on #2145 (feat(deploy): auto-provision the default deployment target from STS): its commit is the base of this branch because every live e2e here rides the zero-config deploy. The diff reduces to just this work once #2145 merges.

CI fixes: fix(deps): record the nested toolkit-lib yaml override in bun.lock, and a follow-up fix(test) making the trace output-path tests platform-agnostic (the Windows unit-test job — which this branch is the first to reach past the install step — exposed hardcoded POSIX path expectations). On the lockfile: CI installs the latest bun (unpinned setup-bun@v2); bun 1.4.0 records nested package.json overrides in the lockfile and fails --frozen-lockfile when they're absent — which also breaks the base refactor branch's own CI as of 2026-08-31 (green on 2026-08-28 under the previous bun). The regenerated lockfile changes only lockfileVersion 1→3 plus the recorded @aws-cdk/toolkit-lib yaml override from #2122, with zero resolution changes; the full gate passes under bun 1.4.0. Heads-up for local dev: lockfileVersion 3 needs bun ≥ 1.4.0 (older bun ignores the lockfile — it can't represent the nested override in either format, so no lockfile satisfies both versions).

🤖 Generated with Claude Code

https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P

AlexanderRichey and others added 12 commits August 30, 2026 23:01
`project deploy` now synthesizes the `default` target when
aws-targets.json is missing, empty, or lacks a `default` entry: the
account comes from STS GetCallerIdentity and the region from the CLI's
already-resolved effective region, validated against
AgentCoreRegionSchema before anything is written. Existing entries are
preserved byte-for-byte, the synthesized entry is reported on stderr,
and the deploy proceeds in the same invocation. Named targets still
require explicit configuration, and unsupported regions or
unresolvable credentials fail with actionable errors before the file
is touched.

Also restores the vended CDK app (bin/cdk.ts, lib/cdk-stack.ts,
test/cdk.test.ts, package.json) to its last publishable state: it
referenced an AgentCorePayments L3 that no released @aws/agentcore-cdk
exports, so every fresh scaffold failed `cdk synth` at tsc before
reaching AWS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
…eck gate

Leftover e2e scaffolds under out/ (and stale dist/ build output) were being
swept up by bun test and tsc, failing the gate on files that are not part of
the source tree. Scope both to the repo source, and fix the two
react(set-state-in-effect) findings oxlint 1.80 raises in usePagedList and
DataTable by deriving/adjusting state during render instead of in effects.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Bare `project create --name X` (and --defaults) now creates a harness
project — a managed agent configured by spec — matching the original CLI's
default quick start. The harness-only flags (--model-id, --api-key-arn,
--api-base, --additional-params, --no-harness-memory, --max-iterations,
--max-tokens, --timeout, --truncation-strategy, --container) flow into the
harness spec, which is validated up front against the same schema
`project add harness` uses and scaffolded through the same addResource
path, so the two entry points cannot drift. Runtime scaffolding is selected
by --template or the runtime flags exactly as before; mixing the two flag
families is a validation error, mirroring the original's dispatch.

Tests that relied on the previous hello-world default now scaffold it
explicitly via --template.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
`project create --type import --agent-id <id> --agent-alias-id <id>` (and
the same on `project add runtime`) wraps an existing Amazon Bedrock Agent
as an AgentCore runtime: the agent and alias are described through
@aws-sdk/client-bedrock-agent to validate they exist (with the global
--region naming the agent's region, validated against the supported list),
and a proxy runtime is scaffolded from a new bedrock-agent-proxy-python
template that forwards prompts via InvokeAgent and streams the reply. The
vended bedrock-agent-policy.json grants the execution role
bedrock:InvokeAgent on the alias through the runtime's additionalPolicies,
so the project deploys and invokes like any other.

The original CLI translated the Bedrock Agent's definition into native
framework code; this ships the proxy shape instead — the agent stays the
brain, the runtime is the AgentCore front door.

bun.lock: adds the @aws-sdk/client-bedrock-agent entry; the surrounding
churn is bun regenerating the lock format on install.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
project remove now accepts credential, config-bundle, online-eval,
online-insight, and memory; removing a credential also deletes the
.env.local keys it reserved (EnvLocalFile gains removeKeys with
snapshot/rollback). Removing a resource that does not exist now throws
ResourceNotFoundError instead of warn-and-rewrite. New `project remove
all` empties every resource collection in agentcore.json (spec-level;
app/ code and aws-targets.json are kept) behind a y/N prompt with
--yes for non-interactive use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Bare `agentcore --version` (and -V) prints the package version embedded at
build time and exits 0, in dev, bundled, and compiled forms. Handled as a
pre-parse intercept on the root router rather than a Commander version
option: a root-level --version option would shadow subcommands that declare
their own `--version <value>` flag (harness version get, runtime version
get, dataset --version, …). Root-only, matching the original CLI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
`agentcore project export harness` converts a harness into an editable
Python Strands runtime agent: it renders the strands-http-python template
under app/<target-agent-name>/ with a context mapped from the harness spec
(model incl. Bedrock Mantle/OpenAI/Gemini/LiteLLM, system prompt, remote
MCP + inline-function tools, path/s3/git skills, in-project memory,
truncation, and execution limits via a vendored hooks/execution_limits.py),
registers the runtime in agentcore.json (the harness entry stays), installs
its deps with uv sync, and writes an EXPORT_NOTES.md in the agent directory
listing precise manual follow-ups for everything that cannot be mapped
mechanically (gateway/browser/code-interpreter tools, external/managed
memory, aws skills, custom Dockerfiles, ...).

The harness comes from `--name` (in-project files) or `--arn` (fetched from
the service via GetHarness, using the region embedded in the ARN); exactly
one is required, and the project is resolved and validated by withProject
before any service fetch. `--target-agent-name` defaults to
<harnessName>Agent, `--build` overrides the CodeZip default (containerUri /
dockerfile harnesses auto-select Container), and `--json` emits a
machine-readable summary on stdout while progress and notes stay on stderr.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Move the runtime log-group derivation, the Insights query-value sanitizer,
and the paginating CloudWatch Logs Insights query runner out of the private
scope of src/core/eval.tsx into src/core/observability.ts so the upcoming
runtime logs/traces commands can share them. The runner's row-ceiling error
becomes an injectable policy (InsightsRowLimit); eval passes its existing
message, so behavior is unchanged. Also adds parseTimeString, porting the
old CLI's time-parser semantics (now / relative 5m-1h-2d / epoch ms / ISO
8601) with a typed InputValidationError on invalid input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Adds `agentcore runtime logs`: by default it live-tails the runtime's
CloudWatch log group via StartLiveTail (reconnecting transparently over the
~3h session cap; Ctrl+C exits 130), and with --since/--until it switches to
a bounded FilterLogEvents search, paginated to completion oldest-to-newest.
--level/--query compose into a server-side filter pattern (ported from the
old CLI's filter-pattern.ts), --limit caps search results, and --json emits
JSON Lines. A missing log group maps to "has the runtime been invoked yet?"
guidance.

Addressing follows `runtime invoke --id`; without --id inside a project the
deployed runtime is resolved live from the target stack's CloudFormation
outputs (default target, one runtime auto-selects, several list candidates),
through a new ObservabilityClient wired into CoreClient and the Core
contract. The runtime router's TUI dispatch is limited to its existing
children so a bare `runtime logs` streams instead of opening the TUI. The
gitignore's blanket `logs` entry is scoped to the repo root so the handler
directory is trackable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Adds `agentcore runtime traces list` and `agentcore runtime traces get
<traceId>`. list aggregates the runtime's telemetry with a Logs Insights
`stats ... by traceId` query (newest first, default 12h window, --limit
default 20) and renders a traceId/timestamp/sessionId table, or a single
JSON document with --json; an empty result prints a stderr notice that
traces take 2-3 minutes to appear. get validates the trace-id format,
downloads every log record of the trace (@message JSON-parsed when
possible), writes them to --output or agentcore/.cli/traces/
<runtime>-<traceId>.json inside a project (./<traceId>.json outside), and
prints the written path on stdout.

Both leaves share `runtime logs`' addressing: --id anywhere, or automatic
resolution of the project's deployed runtime from its stack outputs. The
queries run through the shared Insights runner extracted in the earlier
observability refactor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
A bare `agentcore project create` in a terminal now opens an interactive
wizard: name (validated live against ProjectNameSchema, schema messages
inline) → project type → harness model id or agent template (with the
strands memory choice; hello-world skips it) → confirmation summary →
live ProjectManager progress → success screen with next steps. The
wizard builds the same CreateProjectInput as the flag-driven handler —
resolveScaffoldHarnessInput (now exported) for the harness path,
resolveRuntimeTemplateShortcut for templates — and iterates
core.projectManager.create in the cwd, npm install and git init
included. A create() failure renders and tears the TUI down via
useApp().exit(error), so the process exits nonzero.

Dispatch: only a bare, flagless invocation on a TTY opens the wizard
(withTuiOnEmptyFlagsAndArgs, TTY-gated at registration). Any
user-supplied flag, --json, or a non-TTY session stays headless. To make
the middleware reachable, --name is optional at the Commander layer and
enforced inside handle with the same "required option '--name <name>'
not specified" wording — so `project create --defaults` and bare
non-TTY invocations fail exactly as before. The other six project
subcommands keep their not-implemented stubs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
Ink delivers rapidly typed keystrokes and every terminal paste as one
multi-character useInput event whose key.return is false even when the
chunk ends in "\r" — so TextInput appended the control byte into the
value as an invisible character. In the create wizard's name step that
left a visually valid name failing ProjectNameSchema with a message the
user couldn't act on ("must ... contain only alphanumeric characters")
and enter refusing to advance. Found by driving the wizard end-to-end
in a real pty during the final live smoke.

A single-line input must never store control bytes: strip C0 controls
and DEL from appended text (the official ink-text-input strips \r/\n
for the same reason). A stripped chunk's newline is deliberately not a
submit — matching readline and browser single-line paste semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
@github-actions github-actions Bot added the size/xl PR size: XL label Aug 31, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added claude-security-reviewing Claude Code /security-review in progress agentcore-harness-reviewing AgentCore Harness review in progress labels Aug 31, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed claude-security-reviewing Claude Code /security-review in progress agentcore-harness-reviewing AgentCore Harness review in progress labels Aug 31, 2026
bun 1.4.0 — which CI installs via the unpinned setup-bun@v2 — records
nested package.json overrides in the lockfile and refuses frozen
installs when they are missing, so every CI job fails with "lockfile
had changes, but lockfile is frozen" (the base refactor branch's own
CI run on 2026-08-31 fails the same way; runs from 2026-08-28 under
the previous bun were green). The bun that last saved this lockfile
predated nested-override recording and silently dropped the
@aws-cdk/toolkit-lib yaml pin from #2122.

Regenerated with bun 1.4.0. The only changes are lockfileVersion
1 -> 3 and the recorded override block — zero resolution changes
("Checked 766 installs across 703 packages (no changes)"). The full
CI gate passes under bun 1.4.0: frozen install, 2513 tests, tsc,
oxlint, prettier.

Note: lockfileVersion 3 requires bun >= 1.4.0 for lockfile-honoring
installs; older bun prints "Ignoring lockfile" (it cannot represent
the nested override either way, so there is no lockfile both versions
accept).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 31, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 31, 2026
@codecov-commenter

codecov-commenter commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.61118% with 135 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.14%. Comparing base (3d449c5) to head (8c39667).

Files with missing lines Patch % Lines
src/core/project/bedrockAgent.ts 22.72% 51 Missing ⚠️
src/handlers/project/export/serviceHarness.ts 89.36% 20 Missing ⚠️
src/core/project/templates/export.ts 97.87% 15 Missing ⚠️
src/core/observability.ts 95.73% 14 Missing ⚠️
src/core/project/manager.tsx 96.59% 12 Missing ⚠️
src/handlers/project/create/screen.tsx 97.28% 11 Missing ⚠️
src/handlers/runtime/traces/get/index.tsx 93.15% 5 Missing ⚠️
src/core/project/backends/cdk/environment.ts 0.00% 4 Missing ⚠️
src/core/eval.tsx 92.00% 2 Missing ⚠️
src/handlers/project/export/harness.ts 98.95% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #2146      +/-   ##
============================================
- Coverage     97.29%   97.14%   -0.15%     
============================================
  Files           479      494      +15     
  Lines         29673    32550    +2877     
============================================
+ Hits          28871    31622    +2751     
- Misses          802      928     +126     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

The resolveTraceOutputPath tests hardcoded POSIX strings, so on Windows
— where resolve() produces drive-letter backslash paths — all three
failed. Build the expected values with the same join/resolve primitives
the resolver uses: the tests pin down which branch wins (--output >
project > cwd), not the platform separator. First surfaced by CI's
Windows unit-test job, which this branch is the first to reach past
the install step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfADH54TZn2SSGUUixft8P
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 31, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@github-actions github-actions Bot added the size/xl PR size: XL label Aug 31, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added claude-security-reviewing Claude Code /security-review in progress and removed claude-security-reviewing Claude Code /security-review in progress labels Aug 31, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 31, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 31, 2026
@jariy17
jariy17 merged commit f2b73d6 into refactor Aug 31, 2026
29 checks passed
@jariy17
jariy17 deleted the feat/essential-gaps branch August 31, 2026 16:11
aidandaly24 added a commit to aidandaly24/agentcore-cli that referenced this pull request Sep 2, 2026
Export rendered `templates/strands-http-python`, the same template
`project create` scaffolds from, so every export fix landed in a file whose
primary consumer is the regular Strands runtime. That coupling is why this PR
was touching provider loading, MCP client construction and memory retrieval in
a shared template to fix bugs only export could reach.

Export now renders `templates/export-harness-python`, and
`strands-http-python` is restored to its pre-aws#2146 state: the
hooks/execution_limits.py that aws#2146 added is gone, and the Bedrock model line
it extended with temperature/top_p is back to its original form. `project
create` output is byte-identical to refactor, verified by rendering a scaffold
on both commits and diffing.

The export template also drops what export can never produce: the container
Dockerfile and .dockerignore (export is always CodeZip) and the Anthropic
provider block (export emits Bedrock, OpenAI, Gemini or LiteLLM).
Hweinstock pushed a commit that referenced this pull request Sep 2, 2026
* feat(core): add cached EC2 client support

* fix(export): preserve harness configuration fidelity

* fix(export): validate service ARNs and restore VPC IDs

* fix(templates): align generated provider dependencies

* fix(templates): enforce harness limits per invocation

* refactor(export): remove EC2 VPC lookup

* fix(schemas): restore the lite_llm-only additionalParams guard

The pinned @aws/agentcore-cdk rejects additionalParams on every provider but
lite_llm, and re-parses harness.json at synth. Dropping the CLI refinement moved
that failure from `project add harness` to `project build`, where it surfaces as
a raw zod dump — reachable via `project create --additional-params`, whose
provider defaults to bedrock.

Restore the refinement, and drop the field with an export note on the --arn path
instead of hard-failing, since a harness authored outside this CLI can carry it.

* fix(export): require --vpc-id for container exports in VPC mode

Export layers the generated agent into the harness's image by writing a
`FROM <containerUri>` Dockerfile, which turns a no-build harness into a CodeBuild
build. CodeBuild's CreateProject needs an explicit vpcId and cannot infer one
from subnets, so the exported project failed at `project build` with a raw zod
dump from CDK synth.

Neither source of a harness carries a vpcId — the service's VpcConfig has no such
field, and a local containerUri harness is never built so its schema rightly does
not demand one. Export is what creates the requirement, so add --vpc-id and fail
before writing anything when it is needed and absent.

No AWS lookup is involved: getHarness remains the only request on the --arn path.

* refactor: drop formatting residue from the reverted EC2 client

Commit 8570ab2 added an `ec2:` stub key and a fake client, which pushed one
object past prettier's width and shifted a blank line. b3fbb3d removed the EC2
code but left the reflowed formatting, so the PR still showed two core test files
as changed with no bug behind them. Both files now match the base byte for byte.

* fix(export): align --vpc-id with repo conventions

Three follow-ups from auditing the new commits against surrounding code:

- reuse NetworkConfigSchema.shape.vpcId for the flag instead of restating its
  regex, matching how every other validated flag reuses a projectSchemas schema
  (BuildTypeSchema, ProtocolModeSchema, NetworkModeSchema); the inline regex was
  the only one in src/handlers
- the remedy said `--vpc-id vpc-xxxxxxxx`, which VPC_ID_PATTERN rejects because
  x is not a hex digit, so copy-pasting it produced a second error; use the
  <placeholder> form the other free-form remedies use
- document the flag in README, which enumerates this command's flags in prose
- cover both new mapper branches in export.test.ts, which owns
  mapHarnessToExportPlan branch coverage and already tests the sibling throw

* test(export): trim a redundant assertion and close two coverage gaps

Mutation-tested every test this PR adds by breaking the behaviour each one
claims to cover and re-running it. Three results worth acting on:

- the lite_llm half of "notes additionalParams..." asserted what the
  pre-existing "maps openai and litellm model configs" already asserts with the
  same fixture value; both fail on the same mutation, so it was pure duplication
- "requires --vpc-id..." claimed in its comment to fail before writing anything
  but only asserted rejection, so relocating the throw after the write would have
  kept it green; now snapshots agentcore.json and checks the agent dir is absent
- the ARN test never pinned the 12-digit account group; loosening \d{12} to \d+
  passed. It now fails, verified by applying that mutation.

Everything else detected its mutation and stays as is.

* fix(export): note unsupported system prompt blocks

* refactor(export): keep additional params LiteLLM-only

* refactor(templates): remove unreachable provider params

* fix(schemas): require vpcId for container builds in VPC mode

ProjectRuntimeSchema already mirrors the CDK's CodeBuild security-group cap
but not its vpcId requirement, so any writer of agentcore.json could emit a
Container/VPC runtime that fails at synth. Adds the missing clause beside its
sibling, using the CDK's `build === "Container"` predicate.

The security-group cap test only asserted failure, which the new clause would
satisfy on its own; it now pins the issue path so it still isolates the cap.

* refactor(export): always export a CodeZip runtime

The exported agent is a self-contained Strands application: its dependencies
come from its own pyproject.toml and it defines its own entrypoint, so nothing
in it comes from the source harness's image. Deriving a Container build from
containerUri/dockerfile therefore bought a CodeBuild project, an ECR pull
grant, and a VPC id the Runtime API cannot supply, for a base layer the agent
never used. Export now always emits CodeZip and reports a source image or
Dockerfile as an export note.

Removes --vpc-id and --build from `project export harness`, along with
resolveBuildType, resolveDockerfilePlan and buildDockerfileStub.

Path-based skills are now rejected rather than noted: they name directories on
the harness image's filesystem, which the exported agent does not have, so the
files were simply absent at invocation. Republishing them from s3 or git is the
supported path. Container-based export can return additively if a real need for
it appears.

ProjectRuntimeSchema's vpcId rule is kept — it guards `project add runtime` and
hand-edited specs, which can still declare a Container build.

* fix(templates): keep the Bedrock model block well formed

The optional provider params were rendered with inline conditionals whose
leading indentation survived when every param was absent, so a plain
`project create` scaffold — which sets none of them — emitted a stray
closing paren at twelve spaces. Uses the standalone-conditional form the
rest of the template already relies on.

* refactor(export): give harness export its own template

Export rendered `templates/strands-http-python`, the same template
`project create` scaffolds from, so every export fix landed in a file whose
primary consumer is the regular Strands runtime. That coupling is why this PR
was touching provider loading, MCP client construction and memory retrieval in
a shared template to fix bugs only export could reach.

Export now renders `templates/export-harness-python`, and
`strands-http-python` is restored to its pre-#2146 state: the
hooks/execution_limits.py that #2146 added is gone, and the Bedrock model line
it extended with temperature/top_p is back to its original form. `project
create` output is byte-identical to refactor, verified by rendering a scaffold
on both commits and diffing.

The export template also drops what export can never produce: the container
Dockerfile and .dockerignore (export is always CodeZip) and the Anthropic
provider block (export emits Bedrock, OpenAI, Gemini or LiteLLM).

* refactor(export): drop template branches export cannot reach

The export template started as a copy of strands-http-python, so it carried
branches for capabilities the export mapper hardcodes off: gateway, browser and
code-interpreter tools (all reported as manual follow-ups rather than
generated), payment and config-bundle (no harness concept), and path skills
(now rejected outright). Removes those blocks and the render-context keys that
fed them.

Verified by generating exports for four harness shapes — default Bedrock,
execution limits with sliding-window truncation, LiteLLM, and remote MCP with
colliding header names plus s3/git skills — before and after: byte-identical
output, so only unreachable branches were removed. The generated agent still
resolves strands-agents 1.54 via uv sync and imports.
aidandaly24 added a commit that referenced this pull request Sep 3, 2026
… construct

The generated CDK app has been carrying its own Payment orchestration since
#2146 restored a pre-Quick-Create adapter to unblock scaffolding while
AgentCorePayments was unpublished. That construct now ships in
@aws/agentcore-cdk 0.1.0-alpha.51, so the vendored loops are obsolete.

Quick Create is broken on refactor today: bin/cdk.ts requires every connector
to resolve a credentialName to a deployed ARN, and a Quick Create connector
deliberately has neither, so it throws before synthesis. The restored adapter
also concatenates underscore-stripped manager and connector names into
construct IDs, so foo_bar/foobar and A/BC versus AB/C collide, and the tests
covering both behaviors were deleted alongside it.

bin/cdk.ts now passes the raw spec and the target's deployed credentials
straight through, and cdk-stack.ts hands them to AgentCorePayments, which owns
connector variant mapping, credential resolution, runtime wiring and outputs
inside the upgradeable package. Payment orchestration leaves the frozen
scaffold, so future Payment changes reach existing projects through a
dependency bump rather than a regenerated app.

The generated-CDK tests for manual and Quick Create synthesis and for
collision-safe identities are restored.
This was referenced Sep 3, 2026
aidandaly24 added a commit that referenced this pull request Sep 4, 2026
… construct (#2186)

* fix(project): deploy payments through the published AgentCorePayments construct

The generated CDK app has been carrying its own Payment orchestration since
#2146 restored a pre-Quick-Create adapter to unblock scaffolding while
AgentCorePayments was unpublished. That construct now ships in
@aws/agentcore-cdk 0.1.0-alpha.51, so the vendored loops are obsolete.

Quick Create is broken on refactor today: bin/cdk.ts requires every connector
to resolve a credentialName to a deployed ARN, and a Quick Create connector
deliberately has neither, so it throws before synthesis. The restored adapter
also concatenates underscore-stripped manager and connector names into
construct IDs, so foo_bar/foobar and A/BC versus AB/C collide, and the tests
covering both behaviors were deleted alongside it.

bin/cdk.ts now passes the raw spec and the target's deployed credentials
straight through, and cdk-stack.ts hands them to AgentCorePayments, which owns
connector variant mapping, credential resolution, runtime wiring and outputs
inside the upgradeable package. Payment orchestration leaves the frozen
scaffold, so future Payment changes reach existing projects through a
dependency bump rather than a regenerated app.

The generated-CDK tests for manual and Quick Create synthesis and for
collision-safe identities are restored.

* feat(project): report Quick Create connectors awaiting authorization

A Quick Create connector is deployed but unusable until someone follows its
authorization link, and deploy said nothing about it. The link had to be dug out
of the stack's CloudFormation outputs to be found at all, and it expires about
ten minutes after the connector is created, so by the time anyone thought to
look the window was usually gone. The project reported a successful deploy
either way.

Deploy now names each Quick Create connector the spec declares, with its live
status and, while one exists, the link and how long it lasts. An expired
connector says how to get a new link, which is to recreate it: neither
UpdatePaymentConnector nor redeploying an unchanged connector mints another one.

The status and the link are read from the Payments service rather than the
outputs of the same name. Those outputs are Fn::GetAtt values resolved when the
connector was created, so they keep serving a dead link and a stale
PENDING_AUTHENTICATION long after the service has moved on to
AUTHENTICATION_EXPIRED.

Managers are found by their CloudFormation resource type in the project's own
stack. Manager names are account-scoped, so matching the spec against the
account would confuse two projects that both declare `payments`, and reading the
L3's output keys would tie the CLI to names the L3 owns. Connectors then come
from the manager, so connector names cannot collide across managers.

Reads run after the stack is up and never fail the deploy: a status that cannot
be retrieved is reported as such. A project without Quick Create connectors
makes no calls at all.

* fix(project): take the manager id out of the ARN CloudFormation reports

The authorization report asked the Payments service about a manager using the
physical resource id CloudFormation gives for it, which is the manager's ARN.
`paymentManagerId` accepts only the bare identifier and rejects an ARN against
its own pattern, so every deploy of a project with a Quick Create connector
reported that the connector's status could not be retrieved instead of handing
over its authorization link.

Only reachable against CloudFormation, so the unit tests could not see it: they
fake the service boundary, and the boundary was the defect.

* test(project): drop the assertion on the Quick Create authorization output

The generated app does not read this output, and neither does the CLI: the
authorization URL is read from the Payments service because it expires. The L3
is removing the output for that reason, since an output holding an attribute
that disappears fails every later stack update.

Asserting it here only pins a value nothing consumes to whichever L3 version is
pinned, so the pin bump can stand alone.

* test(project): drop the connector identity test the L3 already owns

The generated app hands the whole spec to AgentCorePayments, which derives every
connector's construct identity. Feeding it colliding names asserted that
derivation, not anything this package decides, and the L3 covers the same
foo_bar/foobar case in its own suite.

Seventy lines of fixture for one resource count, over code owned elsewhere.

The manual and Quick Create synthesis test stays: it is the only check that the
generated app passes the spec and the target's deployed credentials to the
construct at all, which is exactly what regressed when the vendored Payment loops
were restored.

* refactor(project): simplify payment authorization URL reporting

* fix(project): continue after payment connector lookup failures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants