{skill}{text.skills.descriptions[skill]}
+{command}
+
+ {text.skills.eyebrow}
+{text.skills.body}
+ + {text.skills.contribute}$ {installAllSkillsCommand}
+
+ {skill}{text.skills.descriptions[skill]}
+{command}
+
+ {text.workflow.eyebrow}
diff --git a/apps/web/src/siteContent.ts b/apps/web/src/siteContent.ts index 27cd8b6..a670348 100644 --- a/apps/web/src/siteContent.ts +++ b/apps/web/src/siteContent.ts @@ -16,6 +16,7 @@ export const content = { { q: '156 个接口是否都完成了生产验证?', a: '156 表示注册表中的接口条目数量,分属 13 个 API 家族,不代表每个接口都已完成生产验证。注册表展示已登记参数和调用入口;完整请求、响应、权限与业务前置条件以每个接口链接的参考文档为准。' }, { q: '默认 dry-run 会修改我的应用吗?', a: '不会。带 --invoke 的接口命令默认构建并预览请求,不发送远程请求。真实调用需显式设置 --dry-run=false;调用前应检查目标应用、所选凭据和参数。' }, { q: '可以把 agc-cli 用在脚本或 AI Agent 中吗?', a: '可以。默认 JSON 输出适合脚本处理,agc capabilities 和 agc endpoints 提供能力发现;agc web-server 提供本地 REST 接口,agc openapi 导出接口契约。命令模板帮助导航,但不能替代业务状态检查或审核判断。' }, + { q: '如何安装 agc-cli 的 Codex 或 Claude Agent Skills?', a: '先安装 agc-cli,再运行 agc skills list 查看 6 个任务型 Skills。使用 agc skills install --agent codex --global 安装全部 Skills,或增加 --name agc-publishing 只安装发布 Skill。也可以从官网直接下载对应的 SKILL.md。' }, { q: '项目 Profile 会自动填入所有接口参数吗?', a: '项目配置可以绑定默认凭据 Profile,临时切换时使用 --profile。应用 ID、语言、请求头和请求体等接口参数仍需按接口要求显式提供。不要将 Service Account 私钥或凭据文件提交到 Git。' }, ], }, @@ -33,6 +34,7 @@ export const content = { { q: 'Are all 156 endpoints production-verified?', a: 'No. The registry contains 156 entries across 13 API families; this is registry coverage, not production verification of every endpoint. Registered parameters and command surfaces are shown here. Consult each endpoint reference for full request and response schemas, permissions, and business prerequisites.' }, { q: 'Does the default dry run change my app?', a: 'No. Endpoint commands with --invoke preview the request without sending it by default. Real invocation requires --dry-run=false. Check the target app, credential profile, and parameters before executing.' }, { q: 'Can I use agc-cli with scripts or AI agents?', a: 'Yes. JSON output supports script processing. agc capabilities and agc endpoints expose discovery; agc web-server provides local REST routes, and agc openapi exports the contract. Command templates support navigation but do not replace business-state checks or review decisions.' }, + { q: 'How do I install the agc-cli Skills for Codex or Claude?', a: 'Install agc-cli, then run agc skills list to browse the six task-oriented Skills. Run agc skills install --agent codex --global for all Skills, or add --name agc-publishing for only the publishing Skill. Individual SKILL.md files are also downloadable from the website.' }, { q: 'Does a project profile fill all endpoint parameters automatically?', a: 'A project configuration can select its default credential profile, with --profile for explicit overrides. App IDs, languages, headers, and request bodies still need to be supplied according to each endpoint. Keep Service Account private keys and credential files out of Git.' }, ], }, diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 8ab39ab..65a6658 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -349,6 +349,49 @@ main { min-height: 100vh; overflow: hidden; } background: rgba(126, 226, 168, 0.055); } +.skillsSection { padding-top: 92px; padding-bottom: 132px; border-top: 1px solid var(--line); } +.skillsIntro { max-width: none; display: grid; grid-template-columns: 1.05fr 0.75fr; gap: 72px; align-items: end; } +.skillsIntro h2 { max-width: 760px; } +.skillsIntroCopy > p { margin: 0; color: var(--muted); font-size: 15px; line-height: 1.75; } +.skillsIntroCopy > a { margin-top: 18px; display: inline-flex; align-items: center; gap: 7px; color: var(--red); font-family: var(--mono); font-size: 10px; font-weight: 600; } +.skillsInstallAll { + min-height: 78px; + margin-top: 48px; + padding: 16px 18px; + display: grid; + grid-template-columns: auto minmax(0, 1fr) 38px; + align-items: center; + gap: 18px; + border: 1px solid rgba(240, 68, 68, 0.34); + border-radius: 10px; + background: linear-gradient(100deg, rgba(240, 68, 68, 0.12), #111114 48%, #0d0d0f); +} +.skillsInstallAll > span { display: inline-flex; align-items: center; gap: 9px; color: var(--paper); font-size: 12px; font-weight: 700; } +.skillsInstallAll > span svg { color: var(--red); } +.skillsInstallAll > code { color: #d5d0cd; font-size: 11px; overflow-wrap: anywhere; } +.skillsInstallAll > code span { color: var(--red); margin-right: 7px; } +.skillsInstallAll > button, .skillCommand button { + width: 36px; + height: 36px; + display: grid; + place-items: center; + color: var(--muted); + border: 1px solid var(--line-strong); + border-radius: 7px; + background: #0a0a0c; + cursor: pointer; +} +.skillsGrid { margin-top: 18px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; } +.skillCard { min-width: 0; padding: 22px; display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 10px; background: linear-gradient(155deg, #111114, #0d0d0f); } +.skillCardHeader { display: flex; align-items: center; gap: 9px; color: var(--red); } +.skillCardHeader code { color: var(--paper); font-size: 12px; font-weight: 600; } +.skillCard > p { min-height: 66px; margin: 18px 0; color: var(--muted); font-size: 12px; line-height: 1.7; } +.skillCommand { min-height: 64px; padding: 12px; display: grid; grid-template-columns: minmax(0, 1fr) 36px; align-items: center; gap: 10px; border: 1px solid var(--line); border-radius: 8px; background: #09090b; } +.skillCommand code { color: #c9c5c2; font-size: 9px; line-height: 1.55; overflow-wrap: anywhere; } +.skillLinks { margin-top: 17px; padding-top: 15px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border-top: 1px solid var(--line); } +.skillLinks a { display: inline-flex; align-items: center; gap: 6px; color: var(--quiet); font-family: var(--mono); font-size: 9px; } +.skillLinks a:hover { color: var(--paper); } + .workflowSection { padding-bottom: 152px; } .workflowGrid { margin-top: 64px; display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--line); } .workflowCard { min-height: 280px; padding: 27px; position: relative; border-right: 1px solid var(--line); background: linear-gradient(155deg, #111114, #0d0d0f); overflow: hidden; } @@ -627,6 +670,7 @@ footer { max-width: var(--max); min-height: 160px; margin: 0 auto; padding: 38px .profileSection, .consoleSection { grid-template-columns: 1fr; } .profileConfig { max-width: 720px; } .installGuideGrid { grid-template-columns: 1fr; } + .skillsGrid { grid-template-columns: repeat(2, 1fr); } .quickStep { grid-template-columns: 50px 1fr; } .quickStep .commandBox { grid-column: 2; } } @@ -701,3 +745,7 @@ footer { max-width: var(--max); min-height: 160px; margin: 0 auto; padding: 38px } :focus-visible { outline: 2px solid var(--red); outline-offset: 3px; } + .skillsIntro { grid-template-columns: 1fr; gap: 24px; } + .skillsInstallAll { grid-template-columns: 1fr 38px; } + .skillsInstallAll > span { grid-column: 1 / -1; } + .skillsGrid { grid-template-columns: 1fr; } diff --git a/cmd/agc/command/root.go b/cmd/agc/command/root.go index eba0f13..38b3b36 100644 --- a/cmd/agc/command/root.go +++ b/cmd/agc/command/root.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "fmt" + "io" "net" "net/http" "os" + "os/exec" "strings" "time" @@ -68,12 +70,67 @@ func NewRootCommand() *cobra.Command { cmd.AddCommand(initCommand(opts)) cmd.AddCommand(webServerCommand()) cmd.AddCommand(docsCommand(opts)) + cmd.AddCommand(skillsCommand()) for _, capability := range domain.DecoratedCapabilities() { cmd.AddCommand(moduleCommand(opts, capability)) } return cmd } +var runSkillsCLI = func(ctx context.Context, stdout, stderr io.Writer, args ...string) error { + command := exec.CommandContext(ctx, "npx", args...) + command.Stdout = stdout + command.Stderr = stderr + command.Stdin = os.Stdin + if err := command.Run(); err != nil { + if execError, ok := err.(*exec.Error); ok && execError.Err == exec.ErrNotFound { + return fmt.Errorf("npx is required to manage Agent Skills; install Node.js and try again") + } + return fmt.Errorf("run Agent Skills installer: %w", err) + } + return nil +} + +func skillsCommand() *cobra.Command { + const repository = "Createitv/agc-cli" + cmd := &cobra.Command{ + Use: "skills", + Short: "Browse and install agc-cli Agent Skills", + } + list := &cobra.Command{ + Use: "list", + Short: "List Agent Skills published by agc-cli", + RunE: func(cmd *cobra.Command, args []string) error { + return runSkillsCLI(cmd.Context(), cmd.OutOrStdout(), cmd.ErrOrStderr(), "--yes", "skills", "add", repository, "--list") + }, + } + var name string + var agent string + var global bool + install := &cobra.Command{ + Use: "install", + Short: "Install one or all agc-cli Agent Skills", + RunE: func(cmd *cobra.Command, args []string) error { + installerArgs := []string{"--yes", "skills", "add", repository} + if name != "" { + installerArgs = append(installerArgs, "--skill", name) + } + if agent != "" { + installerArgs = append(installerArgs, "--agent", agent) + } + if global { + installerArgs = append(installerArgs, "--global") + } + return runSkillsCLI(cmd.Context(), cmd.OutOrStdout(), cmd.ErrOrStderr(), installerArgs...) + }, + } + install.Flags().StringVar(&name, "name", "", "Install only the named skill; omit to install all skills") + install.Flags().StringVar(&agent, "agent", "", "Target agent supported by the skills installer, for example codex or claude-code") + install.Flags().BoolVar(&global, "global", false, "Install into the selected agent's global skill directory") + cmd.AddCommand(list, install) + return cmd +} + func versionCommand(opts *options) *cobra.Command { return &cobra.Command{ Use: "version", diff --git a/cmd/agc/command/root_test.go b/cmd/agc/command/root_test.go index 566eba2..c342ac0 100644 --- a/cmd/agc/command/root_test.go +++ b/cmd/agc/command/root_test.go @@ -8,6 +8,7 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" + "io" "net/http" "net/http/httptest" "os" @@ -117,6 +118,45 @@ func TestVersionCommand(t *testing.T) { } } +func TestSkillsListDelegatesToSkillsInstaller(t *testing.T) { + original := runSkillsCLI + t.Cleanup(func() { runSkillsCLI = original }) + var got []string + runSkillsCLI = func(_ context.Context, stdout, _ io.Writer, args ...string) error { + got = append([]string(nil), args...) + _, _ = io.WriteString(stdout, "agc-cli-usage\n") + return nil + } + out, err := execute("skills", "list") + if err != nil { + t.Fatal(err) + } + if strings.Join(got, " ") != "--yes skills add Createitv/agc-cli --list" { + t.Fatalf("installer args = %q", got) + } + if out != "agc-cli-usage\n" { + t.Fatalf("output = %q", out) + } +} + +func TestSkillsInstallSelectsSkillAgentAndScope(t *testing.T) { + original := runSkillsCLI + t.Cleanup(func() { runSkillsCLI = original }) + var got []string + runSkillsCLI = func(_ context.Context, _, _ io.Writer, args ...string) error { + got = append([]string(nil), args...) + return nil + } + _, err := execute("skills", "install", "--name", "agc-auth", "--agent", "codex", "--global") + if err != nil { + t.Fatal(err) + } + want := "--yes skills add Createitv/agc-cli --skill agc-auth --agent codex --global" + if strings.Join(got, " ") != want { + t.Fatalf("installer args = %q, want %q", got, want) + } +} + func TestEveryRegisteredCommandHasHelp(t *testing.T) { root := NewRootCommand() for _, cmd := range root.Commands() { diff --git a/docs/AGENT_SKILLS.md b/docs/AGENT_SKILLS.md index ad87cd5..2276a8e 100644 --- a/docs/AGENT_SKILLS.md +++ b/docs/AGENT_SKILLS.md @@ -1,8 +1,17 @@ -# Agent Skill / Agent 技能 +# Agent Skills / Agent 技能 -仓库提供可移植的 [`agc-cli-usage`](../skills/agc-cli-usage/SKILL.md) Agent Skill,帮助 Codex、Claude Code 及其他支持 `SKILL.md` 的 Agent 安全地发现命令、选择凭据与项目、预览请求、执行已授权的 AppGallery Connect 操作并验证远程结果。 +仓库按照 ASC Skills 的任务分层模式提供一组可移植 Agent Skills,帮助 Codex、Claude Code 及其他支持 `SKILL.md` 的 Agent 使用 agc-cli。 -This repository ships the portable [`agc-cli-usage`](../skills/agc-cli-usage/SKILL.md) skill for Codex, Claude Code, and other agents that support `SKILL.md`. It teaches command discovery, credential and project selection, dry-run review, authorized AppGallery Connect invocation, and remote-state verification. +This repository follows the task-oriented ASC Skills pattern and ships a portable collection for Codex, Claude Code, and other agents that support `SKILL.md`. + +| Skill | 用途 / Purpose | +| --- | --- | +| [`agc-cli-usage`](../skills/agc-cli-usage/SKILL.md) | 通用命令发现、dry-run、授权执行和验证 / General discovery, dry-run, authorized execution, and verification | +| [`agc-auth`](../skills/agc-auth/SKILL.md) | 凭据、profile、`whoami` 和授权诊断 / Credentials, profiles, `whoami`, and authorization diagnosis | +| [`agc-publishing`](../skills/agc-publishing/SKILL.md) | 应用资料、软件包、审核提交和发布状态 / Metadata, packages, review submission, and release state | +| [`agc-testing`](../skills/agc-testing/SKILL.md) | 测试版本、群组、用户、邀请码和反馈 / Test releases, groups, users, invitation codes, and feedback | +| [`agc-reports`](../skills/agc-reports/SKILL.md) | 分发、付费、留存和元服务报表 / Distribution, revenue, retention, and HarmonyOS service reports | +| [`agc-cicd`](../skills/agc-cicd/SKILL.md) | 跨平台无人值守安装与发布流水线 / Cross-platform unattended installation and release pipelines | ## 安装 / Install @@ -13,22 +22,36 @@ npm install --global @createitv/agc-cli agc version ``` -通过 Agent Skills 安装器全局安装仓库中的技能: +通过 agc-cli 浏览并安装全部技能: + +```bash +agc skills list +agc skills install --agent codex --global +``` + +也可以只安装一个技能: + +```bash +agc skills install --name agc-publishing --agent codex --global +``` + +CLI delegates installation to the open Agent Skills installer, so Node.js and `npx` must be available. The equivalent direct commands are: ```bash npx --yes skills add Createitv/agc-cli --global --agent codex +npx --yes skills add Createitv/agc-cli --skill agc-publishing --global --agent codex ``` -不使用安装器时,可以将 `skills/agc-cli-usage` 目录复制到 Agent 的技能目录,例如 Codex 的 `~/.codex/skills/` 或 Claude Code 的 `~/.claude/skills/`。保留整个目录,以便 `agents/openai.yaml` 等客户端元数据随技能一起安装。 +不使用安装器时,可以把所需的完整 Skill 目录复制到 Agent 的技能目录,例如 Codex 的 `~/.codex/skills/` 或 Claude Code 的 `~/.claude/skills/`。保留整个目录,以便 `agents/openai.yaml` 等客户端元数据随技能一起安装。 -Without the installer, copy the complete `skills/agc-cli-usage` directory into the agent's skill directory, such as `~/.codex/skills/` for Codex or `~/.claude/skills/` for Claude Code. +Without the installer, copy each complete skill directory into the agent's skill directory. ## 使用 / Use Codex 中可显式调用: ```text -Use $agc-cli-usage to inspect the publishing operation, preview the request, and execute only the authorized change. +Use $agc-publishing to inspect the app release, preview the request, and execute only the authorized change. ``` 支持自动发现的 Agent 也可以根据 `SKILL.md` 的 description 自动选择该技能。技能不会扩大用户授权:查看、预览、提交、删除、发布和审核状态仍是不同操作。 @@ -37,6 +60,6 @@ Agents that support automatic discovery can select the skill from its descriptio ## 设计原则 / Design -本技能对标 ASC Skills 的分层方式:入口技能只保存会改变 Agent 决策的稳定规则,具体命令优先从当前二进制的 `--help`、endpoint definition、`sourceUrl` 和 OpenAPI 动态发现。随着高频工作流成熟,可以再增加独立技能,例如发布编排、元数据同步或审核诊断,而不是让一个技能变成完整手册。 +这些技能对标 `tddworks/asc-cli-skills` 的分层方式:通用入口保持精简,高频工作流按任务拆分;具体命令优先从当前二进制的 `--help`、endpoint definition、`sourceUrl` 和 OpenAPI 动态发现。技能内容不会扩大用户对远程写入、提交、删除或发布的授权。 -The skill follows the layered ASC Skills pattern: the entry skill keeps stable decision rules, while exact commands are discovered from the installed binary's `--help`, endpoint definitions, `sourceUrl`, and OpenAPI contract. Mature workflows can later become separate release, metadata, or review-diagnosis skills instead of turning one skill into a copied manual. +The collection follows the layered `tddworks/asc-cli-skills` pattern: a small general entry skill plus task-specific workflow skills. Exact commands come from the installed binary's `--help`, endpoint definitions, `sourceUrl`, and OpenAPI contract. A skill never expands authorization for remote writes, submission, deletion, or publication. diff --git a/skills/agc-auth/SKILL.md b/skills/agc-auth/SKILL.md new file mode 100644 index 0000000..371b277 --- /dev/null +++ b/skills/agc-auth/SKILL.md @@ -0,0 +1,51 @@ +--- +name: agc-auth +description: Authenticate agc-cli, manage credential profiles, identify the active Huawei AppGallery Connect account, and diagnose authorization failures. Use for login, profile switching, auth checks, whoami, OAuth team lookup, or CI credential setup. +--- + +# agc auth + +Use `agc auth` for local credential profiles and identity inspection. Never ask for or expose client keys, service-account private keys, access tokens, credential files, or raw authentication responses. + +## Inspect before changing credentials + +```bash +agc auth list --output table +agc auth check +agc auth whoami --pretty +agc --profile production auth check +``` + +`auth check` validates local configuration unless `--remote` is explicitly supplied. `auth whoami` reports the selected profile, non-secret client or service-account identity, and project context. It does not invent a personal developer name from credentials that do not contain one. + +With a user-authorized Huawei OAuth token, query official team accounts without saving the token: + +```bash +AGC_OAUTH2_TOKEN="$AGC_OAUTH2_TOKEN" agc auth whoami --teams --pretty +``` + +Treat the token as a secret. Do not echo it, put it in command examples with a literal value, persist it in project files, or include it in logs. + +## Login and profile selection + +Inspect the installed command first: + +```bash +agc auth login --help +``` + +Then use a credential file or protected environment values already available on the machine: + +```bash +agc auth login --service-account-file /protected/agc-service-account.json --name production +agc auth login --api-client-file /protected/agc-api-client.json --name staging +agc auth login --client-id "$AGC_CLIENT_ID" --client-key "$AGC_CLIENT_KEY" --name ci +``` + +Use `--profile NAME` on unattended commands. Project context may provide a default profile, but an explicit profile is easier to audit in multi-environment CI. + +## Remote checks + +`agc auth check --remote` contacts Huawei and may perform an app or project read. Run it only when the user has authorized the remote check and the intended profile/project is explicit. Token creation is not proof that the profile can access a particular app. + +For 401/403 failures, report the selected profile and redacted command, then check credential mode, project/app ownership, required Huawei roles, and endpoint-specific headers. Never include secrets in the report. diff --git a/skills/agc-auth/agents/openai.yaml b/skills/agc-auth/agents/openai.yaml new file mode 100644 index 0000000..56b70c9 --- /dev/null +++ b/skills/agc-auth/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "AGC Authentication" + short_description: "Authenticate and inspect agc-cli profiles safely" + default_prompt: "Use $agc-auth to inspect the selected agc-cli identity and configure or diagnose authentication without exposing secrets." diff --git a/skills/agc-cicd/SKILL.md b/skills/agc-cicd/SKILL.md new file mode 100644 index 0000000..deed5d3 --- /dev/null +++ b/skills/agc-cicd/SKILL.md @@ -0,0 +1,42 @@ +--- +name: agc-cicd +description: Build unattended multi-platform CI/CD workflows around agc-cli. Use for Windows, macOS, or Linux installation, protected credential setup, dry-run gates, HarmonyOS Hvigor builds, release automation, and post-action verification. +--- + +# agc-cli CI/CD + +Install the pinned version needed by the pipeline and verify it before work: + +```bash +npm install --global @createitv/agc-cli@VERSION +agc version +``` + +Use an explicit profile and project directory in unattended jobs. Supply credentials through the CI provider's protected secret/file mechanism; never write secrets into the repository, workflow output, cache keys, or artifacts. + +## Pipeline shape + +1. Install and verify the pinned CLI version. +2. Materialize protected credentials with the narrowest permissions and delete ephemeral files in the runner cleanup phase. +3. Run `agc auth check` locally; use `--remote` only when an authorized live check is intended. +4. Resolve app/project/profile explicitly. +5. Discover the operation contract from the installed CLI. +6. Produce and retain a redacted dry-run artifact for review or policy gates. +7. Execute only approved live operations with `--dry-run=false`. +8. Query the remote state until the required terminal state, and preserve redacted evidence. + +For HarmonyOS local builds, inspect the current local CI/CD operation first: + +```bash +agc cicd endpoints --output table +agc cicd build-hvigor --pretty +``` + +## Reliability rules + +- Pin stable versions; do not let production jobs float on an unverified latest release. +- Keep Windows, macOS, and Linux path/quoting differences inside shell-specific steps. +- Use JSON output for automation and parse it structurally. +- Do not treat a queued job, successful build, accepted upload, review submission, approval, and public availability as the same state. +- Do not blindly retry mutations after timeouts. Query remote state and make retries idempotent where Huawei provides a stable identifier. +- Make test resources and production resources distinct. A smoke test must not publish an app or alter an existing production resource. diff --git a/skills/agc-cicd/agents/openai.yaml b/skills/agc-cicd/agents/openai.yaml new file mode 100644 index 0000000..c765e83 --- /dev/null +++ b/skills/agc-cicd/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "AGC CI/CD" + short_description: "Automate agc-cli across CI runners" + default_prompt: "Use $agc-cicd to design or operate a pinned, secret-safe agc-cli pipeline with dry-run gates and verified remote outcomes." diff --git a/skills/agc-publishing/SKILL.md b/skills/agc-publishing/SKILL.md new file mode 100644 index 0000000..dea17f8 --- /dev/null +++ b/skills/agc-publishing/SKILL.md @@ -0,0 +1,54 @@ +--- +name: agc-publishing +description: Manage AppGallery Connect application metadata, packages, staged rollout, and review submission with agc-cli. Use when preparing, previewing, submitting, or checking a Huawei or HarmonyOS app release. +--- + +# AppGallery Connect publishing + +Use the installed endpoint registry as the source of truth: + +```bash +agc publishing endpoints --output table +agc publishing