Introduce CICD CLI Commands for AI-Workspace#2278
Conversation
|
Caution Review failedAn error occurred during the review process. Please try again later. 📝 WalkthroughWalkthroughThis PR introduces a new Sequence Diagram(s)sequenceDiagram
participant User
participant BuildCmd as ai-workspace build
participant PushCmd as ai-workspace push/edit
participant Config as CLI config
participant Client as aiworkspace.Client
participant API as AI Workspace API
User->>BuildCmd: ap ai-workspace build
BuildCmd->>BuildCmd: load & validate project artifact
BuildCmd-->>User: validation result
User->>PushCmd: ap ai-workspace push/edit
PushCmd->>PushCmd: marshal payload, resolve ENV_CLI_* placeholders
PushCmd->>Config: load config, resolve workspace/platform
PushCmd->>Client: create client (insecure option)
Client->>API: POST/PUT payload
API-->>Client: HTTP response
Client-->>PushCmd: response or wrapped error
PushCmd-->>User: apply result output
sequenceDiagram
participant CLI as devportal command
participant Helper as OrgScopedPath
participant Client as devportal HTTP client
participant API as DevPortal API
CLI->>Helper: OrgScopedPath(orgID, resource)
Helper-->>CLI: /o/{org}/devportal/v1/{resource}
CLI->>Client: GET/POST/PUT/DELETE(path)
Client->>API: HTTP request
API-->>Client: response
Client-->>CLI: parsed result
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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
82d7241 to
13ba760
Compare
13ba760 to
08e6106
Compare
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).ap ai-workspace edit— same generation, then updates an existing artifact (PUT /{resource}/{id}).push/editlive 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.apply/editprint anap gateway apply-style summary (Status,Message,ID,Organization,Project,Created At,Updated At,State), or full JSON with-o json.--orgflag).