Introduce CICD CLI Commands for AI-Workspace#2278
Conversation
📝 WalkthroughWalkthroughThis PR adds AI-workspace CLI support, migrates DevPortal request paths to org-scoped routes, introduces a new ChangesAI Workspace CLI Feature
DevPortal API Path Restructuring
Project Package and DevPortal Build/Gen Revamp
Gateway LLM Support and CLI Utilities
sync-cli-with-openapi Skill Documentation
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
8752145 to
f8ecdf2
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/cli/devportal/README.md (1)
666-748: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUpdate stale endpoint references in the Subscription Plan section.
The new
sub-plan listnote correctly documentsGET /o/<org-id>/devportal/v1/subscription-policies, but the section intro (line 668) and thesub-plan publishnote (line 728) still describe the old/devportal/organizations/{orgId}/subscription-policiespath. Update those to the org-scoped/o/{orgId}/devportal/v1/...format for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/cli/devportal/README.md` around lines 666 - 748, Update the stale subscription plan endpoint references so they consistently use the org-scoped `/o/{orgId}/devportal/v1/subscription-policies` format. In the Subscription Plan section intro and the `ap devportal sub-plan publish` notes, replace the old `/devportal/organizations/{orgId}/subscription-policies` wording to match the `ap devportal sub-plan list` documentation and keep the `sub-plan publish`/`sub-plan list` command descriptions aligned.
🧹 Nitpick comments (8)
cli/src/cmd/aiws/llmproxy/list.go (1)
66-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMark
--project-idas a required Cobra flag for consistency.The flag description states "(required)" and is validated manually in
runListCommand, butMarkFlagRequiredis never called, unlike other commands in this PR (e.g.,llmprovider/delete.go) that mark their key identifier flag as required. This means--helpwon't surface the requirement and errors surface only after manual parsing.♻️ Proposed fix
utils.AddStringFlag(listCmd, utils.FlagPlatform, &listPlatform, "", "Platform name") listCmd.Flags().BoolVar(&listInsecure, "insecure", false, "Skip TLS certificate verification") + _ = listCmd.MarkFlagRequired(utils.FlagProjectID) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiws/llmproxy/list.go` around lines 66 - 73, The list command currently treats `--project-id` as required only in the flag description and manual validation, but it is not declared as required by Cobra. Update the flag setup in init for listCmd to mark the project ID flag as required, following the same pattern used by other commands such as llmprovider/delete.go, so help output and command validation reflect the requirement consistently.cli/src/cmd/aiws/llmproxy/get.go (1)
44-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse the shared
utils.FlagInsecureconstant/helper for consistency.
getInsecureis registered via a rawgetCmd.Flags().BoolVar(&getInsecure, "insecure", false, ...)(Line 74) instead ofutils.AddBoolFlag(getCmd, utils.FlagInsecure, ...), which is the pattern used incli/src/cmd/devportal/subplan/list.go. This duplicates the flag-name literal and diverges from the established helper pattern.♻️ Suggested consistency fix
- getCmd.Flags().BoolVar(&getInsecure, "insecure", false, "Skip TLS certificate verification") + utils.AddBoolFlag(getCmd, utils.FlagInsecure, &getInsecure, false, "Skip TLS certificate verification")Also applies to: 74-74
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiws/llmproxy/get.go` around lines 44 - 52, The getCmd insecure flag registration in getCmd should use the shared utils.FlagInsecure helper pattern instead of a raw BoolVar call. Update the flag setup in the get command to call utils.AddBoolFlag with utils.FlagInsecure, and keep the getInsecure variable as the target so the behavior stays the same while matching the existing convention used elsewhere such as the list command.cli/src/cmd/aiws/add.go (1)
217-241: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider consolidating the duplicate auth-type switches.
The two
switch addAuthblocks (credential-stored note and missing-credentials hint) repeat the same case structure. Extracting the env-var name(s) per auth type into a small helper would reduce duplication.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiws/add.go` around lines 217 - 241, The two addAuth switch blocks in add.go duplicate the same auth-type mapping, so consolidate them into a single helper that returns the relevant env var name(s) for utils.AuthTypeBasic, utils.AuthTypeOAuth, and utils.AuthTypeAPIKey. Update the credential-stored note and the no-credentials boxed message to call that helper instead of repeating the case structure, keeping the existing behavior and messages in place.cli/src/cmd/aiws/list.go (1)
68-77: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winSort rows for deterministic table output.
platform.AIWorkspacesis a map, so iteration order is randomized in Go; each invocation ofap ai-workspace listmay print rows in a different order.♻️ Suggested fix: sort by name
+ names := make([]string, 0, len(platform.AIWorkspaces)) + for name := range platform.AIWorkspaces { + names = append(names, name) + } + sort.Strings(names) + headers := []string{"PLATFORM", "NAME", "URL", "AUTH", "CURRENT"} rows := make([][]string, 0, len(platform.AIWorkspaces)) - for name, ws := range platform.AIWorkspaces { + for _, name := range names { + ws := platform.AIWorkspaces[name] current := "" if name == platform.ActiveAIWorkspace { current = "*" } rows = append(rows, []string{resolvedPlatform, name, ws.URL, ws.Auth.Type, current}) }(add
"sort"to imports)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiws/list.go` around lines 68 - 77, The ai-workspace list output is nondeterministic because ListAIWorkspaces iterates over the platform.AIWorkspaces map directly. Update the row-building logic in list.go to collect the workspace names from platform.AIWorkspaces, sort them with the sort package, and then append rows in that sorted order so utils.PrintTable always prints a stable table. Keep the current workspace marker logic using platform.ActiveAIWorkspace unchanged.docs/cli/ai-workspace/README.md (1)
261-261: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFix trailing space inside code span.
The
`export `code span has a trailing space, flagged by markdownlint (MD038).✏️ Proposed fix
-an `export ` prefix is allowed +an `export` prefix is allowed🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/cli/ai-workspace/README.md` at line 261, The README text in the env file format description has a markdownlint MD038 issue caused by a trailing space inside the inline code span for export. Update the affected prose in the README so the inline code formatting around export has no trailing whitespace, and verify the surrounding sentence still reads naturally with the same env parsing rules description.Source: Linters/SAST tools
cli/src/cmd/project/init.go (2)
91-106: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant artifact-type validation.
runInitCommandalready validatesprojectTypeviaproject.IsValidArtifactTypebefore callingbuildDirectoryStructure, which re-runs the identical check. Consider dropping the duplicate check inbuildDirectoryStructuresince it is always invoked with an already-validated type.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/project/init.go` around lines 91 - 106, runInitCommand already validates projectType with project.IsValidArtifactType before calling buildDirectoryStructure, so the identical check inside buildDirectoryStructure is redundant. Remove the duplicate artifact-type validation from buildDirectoryStructure and keep the validation only in runInitCommand, leaving buildDirectoryStructure focused on creating the directory structure for the already-validated artifact type.
64-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueLowercase error message strings.
Per Go convention, error strings should not be capitalized.
♻️ Proposed fix
- return fmt.Errorf("Failed to read display name: %w", err) + return fmt.Errorf("failed to read display name: %w", err)- return fmt.Errorf("Failed to read artifact type: %w", err) + return fmt.Errorf("failed to read artifact type: %w", err)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/project/init.go` around lines 64 - 101, The error messages returned from runInitCommand are capitalized and should follow Go convention by starting lowercase. Update the fmt.Errorf strings in runInitCommand, including the PromptInput and PromptSelect failures, so they begin with lowercase text while keeping the same error context and wrapping behavior. Also check any other returned errors in this flow, such as validation failures for displayName and projectType, to ensure all user-facing error strings in this command are consistently lowercase.cli/src/utils/input.go (1)
152-224: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate credential-prompt logic.
PromptAIWorkspaceCredentialsmirrorsPromptDevPortalCredentialsalmost exactly, differing only in prompt labels and env var constants. Consider extracting a shared helper parameterized by service name and env var names to avoid maintaining two near-identical implementations.♻️ Example consolidation approach
func promptCredentials(service, authType string, envUser, envPass, envToken, envKey string) (username, password, token, apiKey string, err error) { switch authType { case AuthTypeBasic: username, err = PromptInput(fmt.Sprintf("Enter %s username (leave empty to use %s env var): ", service, envUser)) if err != nil { return "", "", "", "", err } password, err = PromptPassword(fmt.Sprintf("Enter %s password (leave empty to use %s env var): ", service, envPass)) if err != nil { return "", "", "", "", err } return username, password, "", "", nil case AuthTypeOAuth: token, err = PromptPassword(fmt.Sprintf("Enter %s OAuth token (leave empty to use %s env var): ", service, envToken)) if err != nil { return "", "", "", "", err } return "", "", token, "", nil case AuthTypeAPIKey: apiKey, err = PromptPassword(fmt.Sprintf("Enter %s API key (leave empty to use %s env var): ", service, envKey)) if err != nil { return "", "", "", "", err } return "", "", "", apiKey, nil default: return "", "", "", "", fmt.Errorf("unsupported %s auth type '%s'", service, authType) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/utils/input.go` around lines 152 - 224, PromptDevPortalCredentials and PromptAIWorkspaceCredentials are near-duplicate credential flows; extract the shared prompting logic into a helper like promptCredentials and parameterize it with the service label plus the env var names. Keep the existing public functions as thin wrappers that pass the appropriate constants (for DevPortal and AI workspace) into the helper, and preserve the current AuthTypeBasic, AuthTypeOAuth, AuthTypeAPIKey, and default error handling behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.agents/skills/sync-cli-with-openapi/references/cli-command-anatomy.md:
- Line 243: The CLI literal in this section is outdated and should use the
current `ap ai-workspace` family instead of `ap ai-ws`. Update the referenced
command name in the `cli-command-anatomy.md` content so it matches the existing
CLI grouping and examples, and keep the surrounding references to the
`llmprovider`, `llmproxy`, and `mcpproxy` groups aligned with that command
family.
In @.vscode/launch.json:
- Line 48: The shared launch configuration currently hardcodes
PLATFORM_SECRET_ENCRYPTION_KEY, which should not be committed as reusable secret
material. Update the launch.json entry to use an environment placeholder or a
local override mechanism instead, keeping the secret out of the shared config
while preserving the same variable name for launch-time resolution.
In `@cli/src/cmd/aiws/llmproxy/get.go`:
- Around line 44-52: The GET command flow is printing error responses as if they
were successful because PrintJSONResponse only formats the body. Update the
llmproxy get/list handling around the
getID/getProjectID/getLimit/getOffset/getName/getPlatform options to check
resp.StatusCode before calling PrintJSONResponse, and return an error for any
4xx/5xx response so failed proxy lookups/listings are surfaced properly. Use the
existing response handling in the get command path to keep the success path
unchanged while routing non-2xx statuses to error handling.
In `@cli/src/cmd/devportal/build.go`:
- Around line 268-341: `applyManifestOverrides` is mutating the source devportal
manifest instead of the staged copy, which can leave build flags behind in the
workspace. Update the build flow in `build.go` so
`createDevPortalArchiveStagingDir` (or the staging path it returns) is the place
where `applyManifestOverrides` is applied before `utils.ZipDirectory`, and keep
the project file untouched. Adjust the related build test to verify the manifest
contents from the generated archive/staging output rather than the original
`devportal.yaml`.
In `@cli/src/cmd/devportal/gen.go`:
- Around line 255-256: The generated devportal manifest is currently built by
interpolating raw values in renderGeneratedDevPortalManifest, which can break
YAML when name, displayName, or version contain special characters. Update
renderGeneratedDevPortalManifest to construct the manifest from a structured Go
value (struct or map) and marshal it to YAML instead of using fmt.Sprintf with
the template. Keep the existing function signature and ensure the generated
devportal.yaml content stays valid for all input values.
- Around line 108-121: Ensure the devportal generation flow does not leave
behind a partially created portalRoot when later validation or copy steps fail.
In gen.go, adjust the sequence around resolveProjectPath, os.Stat, and copyFile
so inputs are verified before os.MkdirAll creates the devportal directory, or
add cleanup logic that removes the directory on any error after creation. Keep
the existing behavior in the devportal generation path, but make sure the
directory creation in the main generation function is not the first irreversible
step.
---
Outside diff comments:
In `@docs/cli/devportal/README.md`:
- Around line 666-748: Update the stale subscription plan endpoint references so
they consistently use the org-scoped
`/o/{orgId}/devportal/v1/subscription-policies` format. In the Subscription Plan
section intro and the `ap devportal sub-plan publish` notes, replace the old
`/devportal/organizations/{orgId}/subscription-policies` wording to match the
`ap devportal sub-plan list` documentation and keep the `sub-plan
publish`/`sub-plan list` command descriptions aligned.
---
Nitpick comments:
In `@cli/src/cmd/aiws/add.go`:
- Around line 217-241: The two addAuth switch blocks in add.go duplicate the
same auth-type mapping, so consolidate them into a single helper that returns
the relevant env var name(s) for utils.AuthTypeBasic, utils.AuthTypeOAuth, and
utils.AuthTypeAPIKey. Update the credential-stored note and the no-credentials
boxed message to call that helper instead of repeating the case structure,
keeping the existing behavior and messages in place.
In `@cli/src/cmd/aiws/list.go`:
- Around line 68-77: The ai-workspace list output is nondeterministic because
ListAIWorkspaces iterates over the platform.AIWorkspaces map directly. Update
the row-building logic in list.go to collect the workspace names from
platform.AIWorkspaces, sort them with the sort package, and then append rows in
that sorted order so utils.PrintTable always prints a stable table. Keep the
current workspace marker logic using platform.ActiveAIWorkspace unchanged.
In `@cli/src/cmd/aiws/llmproxy/get.go`:
- Around line 44-52: The getCmd insecure flag registration in getCmd should use
the shared utils.FlagInsecure helper pattern instead of a raw BoolVar call.
Update the flag setup in the get command to call utils.AddBoolFlag with
utils.FlagInsecure, and keep the getInsecure variable as the target so the
behavior stays the same while matching the existing convention used elsewhere
such as the list command.
In `@cli/src/cmd/aiws/llmproxy/list.go`:
- Around line 66-73: The list command currently treats `--project-id` as
required only in the flag description and manual validation, but it is not
declared as required by Cobra. Update the flag setup in init for listCmd to mark
the project ID flag as required, following the same pattern used by other
commands such as llmprovider/delete.go, so help output and command validation
reflect the requirement consistently.
In `@cli/src/cmd/project/init.go`:
- Around line 91-106: runInitCommand already validates projectType with
project.IsValidArtifactType before calling buildDirectoryStructure, so the
identical check inside buildDirectoryStructure is redundant. Remove the
duplicate artifact-type validation from buildDirectoryStructure and keep the
validation only in runInitCommand, leaving buildDirectoryStructure focused on
creating the directory structure for the already-validated artifact type.
- Around line 64-101: The error messages returned from runInitCommand are
capitalized and should follow Go convention by starting lowercase. Update the
fmt.Errorf strings in runInitCommand, including the PromptInput and PromptSelect
failures, so they begin with lowercase text while keeping the same error context
and wrapping behavior. Also check any other returned errors in this flow, such
as validation failures for displayName and projectType, to ensure all
user-facing error strings in this command are consistently lowercase.
In `@cli/src/utils/input.go`:
- Around line 152-224: PromptDevPortalCredentials and
PromptAIWorkspaceCredentials are near-duplicate credential flows; extract the
shared prompting logic into a helper like promptCredentials and parameterize it
with the service label plus the env var names. Keep the existing public
functions as thin wrappers that pass the appropriate constants (for DevPortal
and AI workspace) into the helper, and preserve the current AuthTypeBasic,
AuthTypeOAuth, AuthTypeAPIKey, and default error handling behavior.
In `@docs/cli/ai-workspace/README.md`:
- Line 261: The README text in the env file format description has a
markdownlint MD038 issue caused by a trailing space inside the inline code span
for export. Update the affected prose in the README so the inline code
formatting around export has no trailing whitespace, and verify the surrounding
sentence still reads naturally with the same env parsing rules description.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d3fee44f-c733-4a14-9b0e-144e4e29e820
📒 Files selected for processing (90)
.agents/skills/sync-cli-with-openapi/references/cli-command-anatomy.md.gitignore.vscode/launch.jsoncli/src/cmd/aiws/add.gocli/src/cmd/aiws/build.gocli/src/cmd/aiws/build_test.gocli/src/cmd/aiws/current.gocli/src/cmd/aiws/edit.gocli/src/cmd/aiws/list.gocli/src/cmd/aiws/llmprovider/delete.gocli/src/cmd/aiws/llmprovider/get.gocli/src/cmd/aiws/llmprovider/list.gocli/src/cmd/aiws/llmprovider/root.gocli/src/cmd/aiws/llmproxy/delete.gocli/src/cmd/aiws/llmproxy/get.gocli/src/cmd/aiws/llmproxy/list.gocli/src/cmd/aiws/llmproxy/root.gocli/src/cmd/aiws/mcpproxy/delete.gocli/src/cmd/aiws/mcpproxy/get.gocli/src/cmd/aiws/mcpproxy/list.gocli/src/cmd/aiws/mcpproxy/root.gocli/src/cmd/aiws/push.gocli/src/cmd/aiws/remove.gocli/src/cmd/aiws/root.gocli/src/cmd/aiws/use.gocli/src/cmd/apiproject/init.gocli/src/cmd/apiproject/init_test.gocli/src/cmd/devportal/apikey/commands_test.gocli/src/cmd/devportal/apikey/generate.gocli/src/cmd/devportal/apikey/get.gocli/src/cmd/devportal/apikey/regenerate.gocli/src/cmd/devportal/apikey/revoke.gocli/src/cmd/devportal/application/commands_test.gocli/src/cmd/devportal/application/create.gocli/src/cmd/devportal/application/delete.gocli/src/cmd/devportal/application/get.gocli/src/cmd/devportal/application/update.gocli/src/cmd/devportal/build.gocli/src/cmd/devportal/build_test.gocli/src/cmd/devportal/gen.gocli/src/cmd/devportal/gen_test.gocli/src/cmd/devportal/org/add.gocli/src/cmd/devportal/org/commands_test.gocli/src/cmd/devportal/org/delete.gocli/src/cmd/devportal/org/edit.gocli/src/cmd/devportal/org/get.gocli/src/cmd/devportal/org/list.gocli/src/cmd/devportal/restapi/commands_test.gocli/src/cmd/devportal/restapi/delete.gocli/src/cmd/devportal/restapi/edit.gocli/src/cmd/devportal/restapi/get.gocli/src/cmd/devportal/restapi/list.gocli/src/cmd/devportal/restapi/publish.gocli/src/cmd/devportal/root.gocli/src/cmd/devportal/subplan/commands_test.gocli/src/cmd/devportal/subplan/delete.gocli/src/cmd/devportal/subplan/get.gocli/src/cmd/devportal/subplan/list.gocli/src/cmd/devportal/subplan/publish.gocli/src/cmd/devportal/subplan/root.gocli/src/cmd/devportal/subscription/commands_test.gocli/src/cmd/devportal/subscription/create.gocli/src/cmd/devportal/subscription/delete.gocli/src/cmd/devportal/subscription/edit.gocli/src/cmd/devportal/subscription/get.gocli/src/cmd/gateway/apply.gocli/src/cmd/platform/remove.gocli/src/cmd/platform/root.gocli/src/cmd/project/init.gocli/src/cmd/project/init_test.gocli/src/cmd/project/root.gocli/src/cmd/root.gocli/src/internal/aiworkspace/client.gocli/src/internal/aiworkspace/helpers.gocli/src/internal/aiworkspace/paths_test.gocli/src/internal/aiworkspace/print_test.gocli/src/internal/config/config.gocli/src/internal/config/remove_platform_test.gocli/src/internal/devportal/helpers.gocli/src/internal/gateway/resources.gocli/src/internal/project/artifact.gocli/src/internal/project/config.gocli/src/internal/project/scaffold.gocli/src/utils/constants.gocli/src/utils/flags.gocli/src/utils/input.godocs/cli/README.mddocs/cli/ai-workspace/README.mddocs/cli/devportal/README.mddocs/cli/end-to-end-workflow.md
💤 Files with no reviewable changes (2)
- cli/src/cmd/apiproject/init_test.go
- cli/src/cmd/apiproject/init.go
13ba760 to
08e6106
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (5)
cli/src/cmd/devportal/gen_test.go (2)
38-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMissing test coverage for kind-default fallback.
Per context snippet 3,
buildGeneratedDevPortalManifestdefaultskindto"RestApi"whenmetadata.Kindis blank. This file only exercises the explicitkind: RestApipath; there's no case wheremetadata.yamlomitskindto verify the fallback actually takes effect.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/devportal/gen_test.go` around lines 38 - 92, Add test coverage for the kind-default fallback in runGenCommand by updating TestRunGenCommand_GeneratesDefaultArtifact or adding a sibling test that writes a metadata.yaml without kind. Verify buildGeneratedDevPortalManifest still produces the expected devportal.yaml using the default "RestApi" kind and that the generated manifest matches the existing REST artifact assertions.
29-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReset
genProjectDirbetween tests.Each test sets the package-level
genProjectDirvariable directly but never restores it afterward. If a later test in this package (or file, under-shuffle) relies on the zero-value""default, stale state from an earlier test will leak in. Addt.Cleanupto restore the prior value.♻️ Proposed fix (apply to each test setting genProjectDir)
func TestRunGenCommand_RequiresProjectDirectory(t *testing.T) { - genProjectDir = t.TempDir() + genProjectDir = t.TempDir() + t.Cleanup(func() { genProjectDir = "" }) err := runGenCommand()Also applies to: 38-46, 94-99, 145-152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/devportal/gen_test.go` around lines 29 - 36, The package-level genProjectDir state is leaking across tests because each test mutates it without restoring the prior value. In the gen_test.go tests that set genProjectDir (including TestRunGenCommand_RequiresProjectDirectory and the other affected test cases), capture the existing value before assignment and register t.Cleanup to restore it after the test. This keeps runGenCommand and related tests isolated and prevents stale state from affecting later cases.cli/src/cmd/aiworkspace/list.go (1)
68-77: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNon-deterministic output ordering from map iteration.
Iterating
platform.AIWorkspaces(a Go map) directly means row order varies across runs, which works against the PR's stated goal of "consistent CLI output."♻️ Proposed fix
+ names := make([]string, 0, len(platform.AIWorkspaces)) + for name := range platform.AIWorkspaces { + names = append(names, name) + } + sort.Strings(names) + headers := []string{"PLATFORM", "NAME", "URL", "AUTH", "CURRENT"} rows := make([][]string, 0, len(platform.AIWorkspaces)) - for name, ws := range platform.AIWorkspaces { + for _, name := range names { + ws := platform.AIWorkspaces[name] current := "" if name == platform.ActiveAIWorkspace { current = "*" } rows = append(rows, []string{resolvedPlatform, name, ws.URL, ws.Auth.Type, current}) }(add
"sort"to imports)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/list.go` around lines 68 - 77, The AI workspace table output is non-deterministic because ListAIWorkspaces iterates platform.AIWorkspaces directly, so the row order changes between runs. Update the list-building logic in the list command to collect the workspace names, sort them with the sort package, and then append rows in that sorted order while preserving the current marker for platform.ActiveAIWorkspace. Use the existing ListAIWorkspaces flow and utils.PrintTable output path as the place to make this change.cli/src/cmd/aiworkspace/mcpproxy/get.go (1)
90-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winListing branch duplicates
list.gowholesale.The
elsebranch here (project-ID validation +MCPProxyListPath(projectID, aiworkspace.ListQuery{Limit: getLimit, Offset: getOffset})) reimplements exactly whatlist.go'srunListCommandalready does. Keeping two independently-maintained copies of the same listing logic (flags, validation message, path construction) risks drift — e.g. if pagination validation or the path builder call changes in one, it's easy to forget the other.Consider having
get(without--id) delegate to the same helperlistuses, or drop the listing capability fromgetsincemcp-proxy listalready covers it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/mcpproxy/get.go` around lines 90 - 102, The `get` command’s non-`--id` branch duplicates the listing flow already implemented in `runListCommand`, including project-ID validation and `MCPProxyListPath` construction. Refactor `get.go` so `runGetCommand` delegates to the same shared helper used by `list.go` (or remove the list fallback from `get` entirely) to avoid keeping two copies of the same proxy-listing logic in sync.cli/src/cmd/aiworkspace/build_test.go (1)
320-335: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winBare-word env substitution risks accidental value corruption.
TestResolveEnvPlaceholders_BareFormRequiresWordBoundaryconfirmsresolveEnvPlaceholdersrewrites any bare, word-boundary-delimited occurrence of a known env var name anywhere in the JSON payload text — not just fields explicitly intended as placeholders. If a payload legitimately contains a literal string identical to a set env var name (e.g. a display name, description, or example value), it will be silently replaced with that variable's value. Unlike the${VAR}/$VARforms, bare-word matching has no syntactic marker signaling "this is a placeholder," which is unusual compared to conventional env-substitution implementations and increases the chance of an unintended, hard-to-diagnose substitution in a generated payload.Consider requiring an explicit sigil for all supported forms (drop bare-word support, or restrict it to specific known fields) to remove this ambiguity.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/build_test.go` around lines 320 - 335, The bare-word matching in resolveEnvPlaceholders is too permissive and can rewrite legitimate literal strings anywhere in the JSON payload. Update the placeholder resolution logic to require an explicit sigil form (such as the existing ${VAR} or $VAR forms) and remove or tightly scope bare-word substitution so only intentional placeholders are replaced. Adjust TestResolveEnvPlaceholders_BareFormRequiresWordBoundary and related tests to reflect the new behavior, using resolveEnvPlaceholders as the main entry point to verify literals remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.agents/skills/sync-cli-with-openapi/references/cli-command-anatomy.md:
- Around line 44-52: The AI-workspace command examples still reference the old
aiws package path, so update the template guidance to use
cli/src/cmd/aiworkspace/... and the matching root file under that tree. Fix the
path references in this markdown section and any related examples/comments in
the same template so copy/paste instructions point to the current command
family, using the aiworkspace symbols and layout consistently.
In @.agents/skills/sync-cli-with-openapi/SKILL.md:
- Around line 3-5: Update the skill metadata to use the new AI-workspace naming
and CLI root so future syncs target the right command tree. In the description,
replace the old `ap ai-ws` family and `cli/src/cmd/aiws/` references with `ap
ai-workspace` and `cli/src/cmd/aiworkspace/`, and make the same rename anywhere
else in this SKILL.md that still points to the old family or path. Keep the rest
of the sync guidance unchanged.
In `@cli/src/cmd/aiworkspace/add.go`:
- Around line 157-192: Trim the credential inputs before they are validated and
stored in aiWorkspace, since username, password, token, and apiKey can carry
trailing whitespace from prompts or flags. Update the add flow in add.go where
username/password/token/apiKey are assigned and used so the values are
normalized before the auth checks and before constructing config.AIWorkspace,
similar to how addName and addServer are handled.
In `@cli/src/cmd/aiworkspace/build.go`:
- Around line 618-655: The MCP proxy payload builder is dropping the runtime
description by hardcoding an empty value in buildMCPProxyPayload. Update that
function to read and trim runtime.Spec.Description, matching the behavior in
buildLLMProxyPayload, and apply the same default/fallback handling
(defaultProxyDescription) when the field is unset so user-authored descriptions
are preserved in the generated payload.
In `@cli/src/internal/aiworkspace/client.go`:
- Around line 135-157: The non-2xx error paths in Client.sendNoBody and
Client.sendJSON leak the response body because resp.Body is never closed before
returning c.formatHTTPError. Update both helpers to always close resp.Body on
error status, matching the pattern used by Client.Exists, and keep the success
path unchanged so the transport can reuse connections properly.
In `@docs/cli/ai-workspace/README.md`:
- Around line 3-10: The README still points readers to the old aiws command
location, so update the guide text to reference the current aiworkspace CLI tree
instead. In the ai-workspace README content, replace the stale cli/src/cmd/aiws
path with cli/src/cmd/aiworkspace and make sure the command group description
still matches the implemented ai-workspace commands.
- Around line 204-240: The ai-workspace apply docs currently describe
conflicting command behavior by mentioning both apply/edit semantics and then
stating there is no separate edit command. Update the prose around ap
ai-workspace apply to use one consistent model only, and adjust the surrounding
references in this section so it clearly explains that apply generates and
creates/updates the artifact without implying a separate edit command.
---
Nitpick comments:
In `@cli/src/cmd/aiworkspace/build_test.go`:
- Around line 320-335: The bare-word matching in resolveEnvPlaceholders is too
permissive and can rewrite legitimate literal strings anywhere in the JSON
payload. Update the placeholder resolution logic to require an explicit sigil
form (such as the existing ${VAR} or $VAR forms) and remove or tightly scope
bare-word substitution so only intentional placeholders are replaced. Adjust
TestResolveEnvPlaceholders_BareFormRequiresWordBoundary and related tests to
reflect the new behavior, using resolveEnvPlaceholders as the main entry point
to verify literals remain unchanged.
In `@cli/src/cmd/aiworkspace/list.go`:
- Around line 68-77: The AI workspace table output is non-deterministic because
ListAIWorkspaces iterates platform.AIWorkspaces directly, so the row order
changes between runs. Update the list-building logic in the list command to
collect the workspace names, sort them with the sort package, and then append
rows in that sorted order while preserving the current marker for
platform.ActiveAIWorkspace. Use the existing ListAIWorkspaces flow and
utils.PrintTable output path as the place to make this change.
In `@cli/src/cmd/aiworkspace/mcpproxy/get.go`:
- Around line 90-102: The `get` command’s non-`--id` branch duplicates the
listing flow already implemented in `runListCommand`, including project-ID
validation and `MCPProxyListPath` construction. Refactor `get.go` so
`runGetCommand` delegates to the same shared helper used by `list.go` (or remove
the list fallback from `get` entirely) to avoid keeping two copies of the same
proxy-listing logic in sync.
In `@cli/src/cmd/devportal/gen_test.go`:
- Around line 38-92: Add test coverage for the kind-default fallback in
runGenCommand by updating TestRunGenCommand_GeneratesDefaultArtifact or adding a
sibling test that writes a metadata.yaml without kind. Verify
buildGeneratedDevPortalManifest still produces the expected devportal.yaml using
the default "RestApi" kind and that the generated manifest matches the existing
REST artifact assertions.
- Around line 29-36: The package-level genProjectDir state is leaking across
tests because each test mutates it without restoring the prior value. In the
gen_test.go tests that set genProjectDir (including
TestRunGenCommand_RequiresProjectDirectory and the other affected test cases),
capture the existing value before assignment and register t.Cleanup to restore
it after the test. This keeps runGenCommand and related tests isolated and
prevents stale state from affecting later cases.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6ab2990f-42be-49d4-aa47-fd40e661055d
📒 Files selected for processing (91)
.agents/skills/sync-cli-with-openapi/SKILL.md.agents/skills/sync-cli-with-openapi/references/cli-command-anatomy.md.gitignorecli/src/cmd/aiworkspace/add.gocli/src/cmd/aiworkspace/apply.gocli/src/cmd/aiworkspace/build.gocli/src/cmd/aiworkspace/build_test.gocli/src/cmd/aiworkspace/current.gocli/src/cmd/aiworkspace/list.gocli/src/cmd/aiworkspace/llmprovider/delete.gocli/src/cmd/aiworkspace/llmprovider/get.gocli/src/cmd/aiworkspace/llmprovider/list.gocli/src/cmd/aiworkspace/llmprovider/root.gocli/src/cmd/aiworkspace/llmproxy/delete.gocli/src/cmd/aiworkspace/llmproxy/get.gocli/src/cmd/aiworkspace/llmproxy/list.gocli/src/cmd/aiworkspace/llmproxy/root.gocli/src/cmd/aiworkspace/mcpproxy/delete.gocli/src/cmd/aiworkspace/mcpproxy/get.gocli/src/cmd/aiworkspace/mcpproxy/list.gocli/src/cmd/aiworkspace/mcpproxy/root.gocli/src/cmd/aiworkspace/remove.gocli/src/cmd/aiworkspace/root.gocli/src/cmd/aiworkspace/use.gocli/src/cmd/apiproject/init.gocli/src/cmd/apiproject/init_test.gocli/src/cmd/devportal/apikey/commands_test.gocli/src/cmd/devportal/apikey/generate.gocli/src/cmd/devportal/apikey/get.gocli/src/cmd/devportal/apikey/regenerate.gocli/src/cmd/devportal/apikey/revoke.gocli/src/cmd/devportal/application/commands_test.gocli/src/cmd/devportal/application/create.gocli/src/cmd/devportal/application/delete.gocli/src/cmd/devportal/application/get.gocli/src/cmd/devportal/application/update.gocli/src/cmd/devportal/build.gocli/src/cmd/devportal/build_test.gocli/src/cmd/devportal/commands_test.gocli/src/cmd/devportal/gen.gocli/src/cmd/devportal/gen_test.gocli/src/cmd/devportal/org/add.gocli/src/cmd/devportal/org/commands_test.gocli/src/cmd/devportal/org/delete.gocli/src/cmd/devportal/org/edit.gocli/src/cmd/devportal/org/get.gocli/src/cmd/devportal/org/list.gocli/src/cmd/devportal/restapi/commands_test.gocli/src/cmd/devportal/restapi/delete.gocli/src/cmd/devportal/restapi/edit.gocli/src/cmd/devportal/restapi/get.gocli/src/cmd/devportal/restapi/list.gocli/src/cmd/devportal/restapi/publish.gocli/src/cmd/devportal/root.gocli/src/cmd/devportal/subplan/commands_test.gocli/src/cmd/devportal/subplan/delete.gocli/src/cmd/devportal/subplan/get.gocli/src/cmd/devportal/subplan/list.gocli/src/cmd/devportal/subplan/publish.gocli/src/cmd/devportal/subplan/root.gocli/src/cmd/devportal/subscription/commands_test.gocli/src/cmd/devportal/subscription/create.gocli/src/cmd/devportal/subscription/delete.gocli/src/cmd/devportal/subscription/edit.gocli/src/cmd/devportal/subscription/get.gocli/src/cmd/gateway/apply.gocli/src/cmd/platform/remove.gocli/src/cmd/platform/root.gocli/src/cmd/project/init.gocli/src/cmd/project/init_test.gocli/src/cmd/project/root.gocli/src/cmd/root.gocli/src/internal/aiworkspace/client.gocli/src/internal/aiworkspace/client_test.gocli/src/internal/aiworkspace/helpers.gocli/src/internal/aiworkspace/paths_test.gocli/src/internal/aiworkspace/print_test.gocli/src/internal/config/config.gocli/src/internal/config/remove_platform_test.gocli/src/internal/devportal/helpers.gocli/src/internal/gateway/resources.gocli/src/internal/project/artifact.gocli/src/internal/project/config.gocli/src/internal/project/scaffold.gocli/src/utils/constants.gocli/src/utils/flags.gocli/src/utils/input.godocs/cli/README.mddocs/cli/ai-workspace/README.mddocs/cli/devportal/README.mddocs/cli/end-to-end-workflow.md
💤 Files with no reviewable changes (3)
- cli/src/cmd/devportal/commands_test.go
- cli/src/cmd/apiproject/init_test.go
- cli/src/cmd/apiproject/init.go
✅ Files skipped from review due to trivial changes (6)
- .gitignore
- docs/cli/devportal/README.md
- cli/src/cmd/devportal/org/add.go
- cli/src/cmd/gateway/apply.go
- docs/cli/end-to-end-workflow.md
- docs/cli/README.md
🚧 Files skipped from review as they are similar to previous changes (54)
- cli/src/cmd/devportal/org/edit.go
- cli/src/cmd/devportal/org/get.go
- cli/src/cmd/devportal/restapi/edit.go
- cli/src/cmd/devportal/subplan/root.go
- cli/src/cmd/devportal/apikey/revoke.go
- cli/src/cmd/devportal/subplan/get.go
- cli/src/cmd/devportal/apikey/commands_test.go
- cli/src/cmd/devportal/apikey/generate.go
- cli/src/cmd/devportal/subscription/edit.go
- cli/src/cmd/devportal/apikey/regenerate.go
- cli/src/cmd/devportal/application/delete.go
- cli/src/cmd/devportal/subscription/commands_test.go
- cli/src/cmd/devportal/application/commands_test.go
- cli/src/cmd/devportal/org/commands_test.go
- cli/src/cmd/devportal/subscription/delete.go
- cli/src/cmd/devportal/subscription/create.go
- cli/src/internal/aiworkspace/paths_test.go
- cli/src/cmd/platform/root.go
- cli/src/internal/config/remove_platform_test.go
- cli/src/cmd/devportal/application/update.go
- cli/src/cmd/devportal/subplan/delete.go
- cli/src/cmd/devportal/subplan/list.go
- cli/src/cmd/devportal/restapi/publish.go
- cli/src/cmd/devportal/org/delete.go
- cli/src/cmd/devportal/subplan/publish.go
- cli/src/internal/project/artifact.go
- cli/src/internal/project/config.go
- cli/src/cmd/project/root.go
- cli/src/internal/aiworkspace/print_test.go
- cli/src/cmd/devportal/root.go
- cli/src/cmd/devportal/application/create.go
- cli/src/cmd/devportal/restapi/list.go
- cli/src/cmd/devportal/apikey/get.go
- cli/src/cmd/devportal/application/get.go
- cli/src/cmd/root.go
- cli/src/cmd/devportal/restapi/get.go
- cli/src/cmd/devportal/org/list.go
- cli/src/cmd/devportal/subscription/get.go
- cli/src/cmd/project/init_test.go
- cli/src/internal/aiworkspace/helpers.go
- cli/src/cmd/devportal/restapi/delete.go
- cli/src/cmd/platform/remove.go
- cli/src/utils/flags.go
- cli/src/internal/gateway/resources.go
- cli/src/cmd/devportal/subplan/commands_test.go
- cli/src/internal/devportal/helpers.go
- cli/src/internal/project/scaffold.go
- cli/src/cmd/devportal/restapi/commands_test.go
- cli/src/cmd/devportal/gen.go
- cli/src/cmd/project/init.go
- cli/src/internal/config/config.go
- cli/src/utils/input.go
- cli/src/cmd/devportal/build_test.go
- cli/src/cmd/devportal/build.go
a86b5c3 to
5596d0c
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (3)
cli/src/cmd/aiworkspace/llmproxy/list.go (3)
68-69: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueNo validation that
limit/offsetare numeric before sending to the API.
listLimit/listOffsetare plain strings passed straight intoProxyListPath/ListQuery(Line 92). If a user passes a non-numeric value, the failure will surface as an opaque API/server error rather than a clear client-side validation message.Also applies to: 92-92
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/llmproxy/list.go` around lines 68 - 69, The list command is passing the raw string flags listLimit and listOffset straight into ProxyListPath/ListQuery without client-side numeric validation. Update listCmd handling in list.go to validate both values before building the request, returning a clear validation error if either flag is non-numeric. Use the existing listLimit/listOffset variables and the ProxyListPath/ListQuery call site to locate the fix.
44-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueInconsistent flag registration pattern for
--insecure.Other flags go through
utils.AddStringFlag, butinsecureis registered directly vialistCmd.Flags().BoolVar. If this pattern repeats across the other AI-workspace subcommands (read/delete for llm-provider, app-llm-proxy, mcp-proxy), it's worth adding a sharedutils.AddBoolFlag/utils.AddInsecureFlaghelper to avoid the duplicated description string and boilerplate.♻️ Suggested helper usage
- listCmd.Flags().BoolVar(&listInsecure, "insecure", false, "Skip TLS certificate verification") + utils.AddBoolFlag(listCmd, utils.FlagInsecure, &listInsecure, false, "Skip TLS certificate verification")Also applies to: 66-73
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/llmproxy/list.go` around lines 44 - 51, The `--insecure` flag registration in `listCmd` is inconsistent with the existing `utils.AddStringFlag` pattern and duplicates the same description/boilerplate across AI-workspace commands. Introduce or reuse a shared helper such as `utils.AddBoolFlag` or `utils.AddInsecureFlag`, then update `listCmd` and the related llm-provider/app-llm-proxy/mcp-proxy commands to register `listInsecure` through that helper instead of calling `Flags().BoolVar` directly.
67-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
project-iddocumented as required but not enforced via Cobra.The help text says "(required)" but the flag isn't marked with
MarkFlagRequired; enforcement instead happens manually later inrunListCommand(Lines 82-84). This works functionally but means--helpand Cobra's own usage/validation won't reflect the requirement.🔧 Suggested fix
func init() { utils.AddStringFlag(listCmd, utils.FlagProjectID, &listProjectID, "", "Project ID (required)") + listCmd.MarkFlagRequired(utils.FlagProjectID)Also applies to: 81-84
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/cmd/aiworkspace/llmproxy/list.go` at line 67, The project-id flag in listCmd is only documented as required, but Cobra is not enforcing it. Update the command setup around utils.AddStringFlag and runListCommand so the requirement is registered with Cobra via MarkFlagRequired on the list command, and remove or simplify the later manual validation in runListCommand to avoid duplicating the check. Make sure the help/usage for listCmd now reflects the required flag behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cli/src/cmd/aiworkspace/llmproxy/list.go`:
- Around line 68-69: The list command is passing the raw string flags listLimit
and listOffset straight into ProxyListPath/ListQuery without client-side numeric
validation. Update listCmd handling in list.go to validate both values before
building the request, returning a clear validation error if either flag is
non-numeric. Use the existing listLimit/listOffset variables and the
ProxyListPath/ListQuery call site to locate the fix.
- Around line 44-51: The `--insecure` flag registration in `listCmd` is
inconsistent with the existing `utils.AddStringFlag` pattern and duplicates the
same description/boilerplate across AI-workspace commands. Introduce or reuse a
shared helper such as `utils.AddBoolFlag` or `utils.AddInsecureFlag`, then
update `listCmd` and the related llm-provider/app-llm-proxy/mcp-proxy commands
to register `listInsecure` through that helper instead of calling
`Flags().BoolVar` directly.
- Line 67: The project-id flag in listCmd is only documented as required, but
Cobra is not enforcing it. Update the command setup around utils.AddStringFlag
and runListCommand so the requirement is registered with Cobra via
MarkFlagRequired on the list command, and remove or simplify the later manual
validation in runListCommand to avoid duplicating the check. Make sure the
help/usage for listCmd now reflects the required flag behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ce5cd92f-71fd-4b57-9309-d765e778b938
📒 Files selected for processing (91)
.agents/skills/sync-cli-with-openapi/SKILL.md.agents/skills/sync-cli-with-openapi/references/cli-command-anatomy.md.gitignorecli/src/cmd/aiworkspace/add.gocli/src/cmd/aiworkspace/apply.gocli/src/cmd/aiworkspace/build.gocli/src/cmd/aiworkspace/build_test.gocli/src/cmd/aiworkspace/current.gocli/src/cmd/aiworkspace/list.gocli/src/cmd/aiworkspace/llmprovider/delete.gocli/src/cmd/aiworkspace/llmprovider/get.gocli/src/cmd/aiworkspace/llmprovider/list.gocli/src/cmd/aiworkspace/llmprovider/root.gocli/src/cmd/aiworkspace/llmproxy/delete.gocli/src/cmd/aiworkspace/llmproxy/get.gocli/src/cmd/aiworkspace/llmproxy/list.gocli/src/cmd/aiworkspace/llmproxy/root.gocli/src/cmd/aiworkspace/mcpproxy/delete.gocli/src/cmd/aiworkspace/mcpproxy/get.gocli/src/cmd/aiworkspace/mcpproxy/list.gocli/src/cmd/aiworkspace/mcpproxy/root.gocli/src/cmd/aiworkspace/remove.gocli/src/cmd/aiworkspace/root.gocli/src/cmd/aiworkspace/use.gocli/src/cmd/apiproject/init.gocli/src/cmd/apiproject/init_test.gocli/src/cmd/devportal/apikey/commands_test.gocli/src/cmd/devportal/apikey/generate.gocli/src/cmd/devportal/apikey/get.gocli/src/cmd/devportal/apikey/regenerate.gocli/src/cmd/devportal/apikey/revoke.gocli/src/cmd/devportal/application/commands_test.gocli/src/cmd/devportal/application/create.gocli/src/cmd/devportal/application/delete.gocli/src/cmd/devportal/application/get.gocli/src/cmd/devportal/application/update.gocli/src/cmd/devportal/build.gocli/src/cmd/devportal/build_test.gocli/src/cmd/devportal/commands_test.gocli/src/cmd/devportal/gen.gocli/src/cmd/devportal/gen_test.gocli/src/cmd/devportal/org/add.gocli/src/cmd/devportal/org/commands_test.gocli/src/cmd/devportal/org/delete.gocli/src/cmd/devportal/org/edit.gocli/src/cmd/devportal/org/get.gocli/src/cmd/devportal/org/list.gocli/src/cmd/devportal/restapi/commands_test.gocli/src/cmd/devportal/restapi/delete.gocli/src/cmd/devportal/restapi/edit.gocli/src/cmd/devportal/restapi/get.gocli/src/cmd/devportal/restapi/list.gocli/src/cmd/devportal/restapi/publish.gocli/src/cmd/devportal/root.gocli/src/cmd/devportal/subplan/commands_test.gocli/src/cmd/devportal/subplan/delete.gocli/src/cmd/devportal/subplan/get.gocli/src/cmd/devportal/subplan/list.gocli/src/cmd/devportal/subplan/publish.gocli/src/cmd/devportal/subplan/root.gocli/src/cmd/devportal/subscription/commands_test.gocli/src/cmd/devportal/subscription/create.gocli/src/cmd/devportal/subscription/delete.gocli/src/cmd/devportal/subscription/edit.gocli/src/cmd/devportal/subscription/get.gocli/src/cmd/gateway/apply.gocli/src/cmd/platform/remove.gocli/src/cmd/platform/root.gocli/src/cmd/project/init.gocli/src/cmd/project/init_test.gocli/src/cmd/project/root.gocli/src/cmd/root.gocli/src/internal/aiworkspace/client.gocli/src/internal/aiworkspace/client_test.gocli/src/internal/aiworkspace/helpers.gocli/src/internal/aiworkspace/paths_test.gocli/src/internal/aiworkspace/print_test.gocli/src/internal/config/config.gocli/src/internal/config/remove_platform_test.gocli/src/internal/devportal/helpers.gocli/src/internal/gateway/resources.gocli/src/internal/project/artifact.gocli/src/internal/project/config.gocli/src/internal/project/scaffold.gocli/src/utils/constants.gocli/src/utils/flags.gocli/src/utils/input.godocs/cli/README.mddocs/cli/ai-workspace/README.mddocs/cli/devportal/README.mddocs/cli/end-to-end-workflow.md
💤 Files with no reviewable changes (3)
- cli/src/cmd/devportal/commands_test.go
- cli/src/cmd/apiproject/init_test.go
- cli/src/cmd/apiproject/init.go
✅ Files skipped from review due to trivial changes (8)
- cli/src/cmd/gateway/apply.go
- .gitignore
- cli/src/internal/config/remove_platform_test.go
- cli/src/cmd/devportal/application/commands_test.go
- cli/src/cmd/devportal/subscription/commands_test.go
- docs/cli/README.md
- cli/src/cmd/devportal/org/commands_test.go
- docs/cli/devportal/README.md
🚧 Files skipped from review as they are similar to previous changes (75)
- cli/src/cmd/devportal/root.go
- cli/src/cmd/aiworkspace/llmprovider/root.go
- cli/src/cmd/devportal/application/delete.go
- cli/src/internal/aiworkspace/client_test.go
- cli/src/cmd/devportal/apikey/get.go
- cli/src/cmd/devportal/org/add.go
- cli/src/cmd/devportal/subplan/delete.go
- cli/src/cmd/devportal/apikey/commands_test.go
- cli/src/cmd/devportal/apikey/generate.go
- cli/src/cmd/devportal/apikey/revoke.go
- cli/src/cmd/devportal/subplan/get.go
- cli/src/cmd/devportal/apikey/regenerate.go
- cli/src/cmd/aiworkspace/root.go
- cli/src/cmd/aiworkspace/mcpproxy/get.go
- cli/src/internal/aiworkspace/paths_test.go
- cli/src/cmd/devportal/application/create.go
- cli/src/cmd/devportal/org/edit.go
- cli/src/cmd/devportal/application/get.go
- cli/src/cmd/devportal/org/list.go
- cli/src/cmd/devportal/restapi/edit.go
- cli/src/cmd/aiworkspace/remove.go
- cli/src/cmd/devportal/subplan/commands_test.go
- cli/src/cmd/aiworkspace/current.go
- cli/src/cmd/aiworkspace/mcpproxy/list.go
- cli/src/cmd/aiworkspace/build_test.go
- cli/src/cmd/devportal/subplan/publish.go
- cli/src/cmd/devportal/restapi/get.go
- cli/src/cmd/devportal/restapi/list.go
- cli/src/cmd/aiworkspace/llmprovider/get.go
- cli/src/cmd/aiworkspace/use.go
- cli/src/cmd/root.go
- cli/src/cmd/devportal/restapi/delete.go
- cli/src/cmd/devportal/subscription/edit.go
- cli/src/cmd/aiworkspace/llmproxy/root.go
- cli/src/cmd/devportal/subscription/get.go
- cli/src/cmd/aiworkspace/llmprovider/delete.go
- cli/src/internal/project/config.go
- cli/src/cmd/aiworkspace/mcpproxy/delete.go
- docs/cli/end-to-end-workflow.md
- cli/src/cmd/devportal/org/get.go
- cli/src/internal/gateway/resources.go
- cli/src/internal/devportal/helpers.go
- cli/src/cmd/devportal/subplan/root.go
- cli/src/cmd/devportal/gen_test.go
- cli/src/utils/input.go
- cli/src/cmd/aiworkspace/mcpproxy/root.go
- cli/src/cmd/aiworkspace/llmprovider/list.go
- cli/src/cmd/aiworkspace/llmproxy/get.go
- cli/src/cmd/aiworkspace/llmproxy/delete.go
- cli/src/cmd/project/root.go
- cli/src/cmd/platform/root.go
- cli/src/cmd/platform/remove.go
- cli/src/internal/aiworkspace/print_test.go
- cli/src/utils/flags.go
- cli/src/cmd/project/init_test.go
- cli/src/cmd/project/init.go
- cli/src/cmd/devportal/subscription/delete.go
- cli/src/internal/project/artifact.go
- cli/src/cmd/devportal/restapi/commands_test.go
- cli/src/cmd/devportal/restapi/publish.go
- cli/src/cmd/devportal/gen.go
- cli/src/cmd/devportal/application/update.go
- cli/src/cmd/devportal/subplan/list.go
- cli/src/cmd/aiworkspace/list.go
- cli/src/cmd/devportal/subscription/create.go
- cli/src/internal/aiworkspace/client.go
- cli/src/internal/aiworkspace/helpers.go
- cli/src/cmd/devportal/org/delete.go
- cli/src/cmd/aiworkspace/add.go
- cli/src/cmd/aiworkspace/apply.go
- cli/src/internal/project/scaffold.go
- cli/src/cmd/devportal/build_test.go
- cli/src/internal/config/config.go
- cli/src/cmd/aiworkspace/build.go
- cli/src/cmd/devportal/build.go
Purpose
Summary
metadata.yaml/runtime.yaml/definition.yaml, validate them, then generate the creation payload and push it to the target — with the endpoint selected automatically from the artifact kind.Implementation Details
New Command Family
Connection management (per-platform, stored in the CLI config like
ap gateway/ap devportal):ap ai-workspace add— register an AI-Workspace connection (basic/oauth/api-key)ap ai-workspace list/use/current/removeArtifact lifecycle (operate inside an API project):
ap ai-workspace build— validates the project artifact (files present, metadata/runtime kinds align, name matches). Generates/sends nothing.ap ai-workspace apply— runs the same validation, generates the creation payload from the project artifacts, and creates the artifact (POST) or update an exiting artifact (PUT /{resource}/{id}). Here the both create & edit will be handled through apply command to make consistent with Gateway CICD flow.applylive at the root and pick the endpoint from the declared kind:LlmProvider/llm-providersLlmProxy/llm-proxiesMcp/mcp-proxiesRead/delete per kind:
ap ai-workspace llm-provider list | get | deleteap ai-workspace app-llm-proxy list | get | deleteap ai-workspace mcp-proxy list | get | deleteOther CLI Changes
ap project init— scaffolds an API project (renamed fromapiproject). Artifact types:REST,LLM-Proxy,App-LLM-Provider,MCP-Proxy; generatesmetadata.yaml,runtime.yaml,definition.yaml,docs/,tests/, and.api-platform/config.yaml.ap devportal gen(new) + reworkedap devportal build— two-stage flow:genproduces the editable devportal artifact source (./devportal) and registers it in the project config;buildpackages it intobuild/devportal.zip.--reference-id/--gateway-typeare stamped into the archived manifest only (the workspace source is left untouched).ap devportalresource commands synced to the current spec (org,application,apikey,subscription,sub-planincl. newlist,restapi).ap platform remove(new).Key Behaviours
metadata.yaml/runtime.yamlmay referenceENV_CLI_*placeholders for environment-specific field values (not secrets).push/editresolve them at publish time from--env-file, else the project.env, else the process environment; an unresolved variable fails the command and names it. (Secrets remain server-side via{{ secret "name" }}.)metadata.yamlcarries a…Metadatakind (e.g.LlmProxyMetadata) distinct from the runtime kind (LlmProxy); the suffix is stripped when matching.associatedGateways— read fromspec.associatedGatewaysinmetadata.yamland folded into the payload for every kind.ai-workspaceconfig — the project config models it as one object (a project has at most one AI-Workspace), unlike thedevportalslist.applyprint anap gateway apply-style summary (Status,Message,ID,Organization,Project,Created At,Updated At,State), or full JSON with-o json.--orgflag).