Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Embedded Markdown must retain identical bytes on Windows and Unix.
*.md text eol=lf
20 changes: 20 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@
- Update API contracts, OpenAPI documentation and tests together when parameters change.
- Include validation evidence and remaining limitations in PR descriptions.

## Official API rules and Agent usability

- Review the actual official page for each affected endpoint, using the browser when requested. Follow linked request/response models and relevant appendices; an endpoint list or a URL alone does not establish a verified contract.
- Preserve browser-read documentation in `pkg/domain/reference/`, including parameter tables, notes, examples, source paragraph URLs and the review date. Keep the capture process reproducible with `scripts/browser-capture-reference.mjs`; preserve merged table cells so device-specific rules retain their context.
- Expose reviewed documentation through endpoint discovery and `agc <family> <endpoint> --docs --pretty`. Include relevant supplemental models and appendices so an Agent can resolve prerequisites without guessing.
- Encode verified parameter locations, types, requiredness, nested objects, array item types, enums and explicit bounds in domain contracts. Update CLI serialization, REST validation, OpenAPI and independent regression tests together.
- Follow nested model links recursively. Validate child fields with their full paths (for example, `body.languages[0].appDesc`), including conditional child requirements and per-item limits. A valid parent object or array does not establish that its contents satisfy the API contract.
- Preserve the documented wire type when a string contains encoded JSON. Validate its decoded structure locally, but serialize it as a string when the API requires one. Encode form values exactly once, preserve integer precision and reject unsupported repeated scalar parameters.
- When official tables, examples or notes conflict, retain the source evidence and identify the unresolved rule. Do not silently choose an array/object shape, wrapper, required field or mutually exclusive branch. Separate documented requirements from locally verified behavior and implementation limitations.
- Distinguish unconditional requirements from conditional requirements and alternative authentication or application-identification branches. Do not require every authentication header at once. Do not interpret `Integer(32)` as a numeric range, dynamic map examples such as `additionalPropX` as literal required keys, or logical request-model names as JSON wrapper properties without checking the actual request example.
- Preserve transport semantics from the official examples: JSON, form data, multipart files and signed binary uploads require different handling. Respect returned upload methods, signed headers, URL expiry, file length and upload/parse prerequisites.
- Treat `inbound-callback` endpoints as callbacks to the developer's server. Do not automatically load Huawei credentials or forward an AGC Bearer token to that server. Preserve the documented form/JSON encoding and signatures; a simulated callback transport test does not prove Huawei signature verification or a real game transaction succeeded.
- Preserve ordered repeated query keys when the reference shows array query parameters. CLI callers repeat `--query key=value`; REST callers can use `queryValues` arrays alongside scalar `query` entries. Keep paired filters and values aligned, validate documented date formats and interval limits, and keep OpenAPI required-field alternatives consistent with both input forms.
- File rules depend on asset kind, language, device and application kind. Check the official file appendix and linked `LangFileInfo`/`FileInfo` models; a top-level array limit does not replace per-device asset counts, formats, sizes, resolutions or video/poster ordering. Do not guess missing application context or pretend a remote object ID proves local file properties.
- Reject invalid inputs before authentication or network calls when the rule can be checked locally. Return machine-readable CLI/REST errors with a stable code, endpoint, affected field path, source URL, concrete correction suggestion and documentation command. Nested violations must identify the array index and child field. Keep JSON stdout parseable and never include credentials or raw credential responses in feedback.
- Separate input violations, authentication failures, transport failures and upstream business errors. Preserve upstream error codes. Guide the Agent to the documented role, application state or prerequisite instead of suggesting blind retries or silently changing business resources.
- Test meaningful documented examples and failure cases before fixing behavior. Use independent source-based assertions for requiredness, encoding and nested shapes; registry-generated smoke fixtures alone cannot prove the registry is correct. Offline tests must not use the user's Huawei authorization.
- Report documentation review, implemented rules, offline verification and live verification accurately. Do not claim every official rule or real-app operation is supported merely because documentation was captured or generic transport tests passed. Continue toward a usable CLI rather than producing a report in place of the requested implementation.
- Rebuild the CLI after source changes and verify the binary actually invoked by the Agent. Distinguish the workspace binary from an installed package; a successful source test does not prove that an older installed CLI contains the fix.

## Version releases and package managers

- Ordinary branch pushes and PR updates run CI. To publish a stable version, push a new `vMAJOR.MINOR.PATCH` tag on the intended, tested commit from the merged main branch. Check existing tags first; do not move or reuse a published tag.
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

User-visible changes are listed here. Published binaries and versions are available in [GitHub Releases](https://github.com/Createitv/agc-cli/releases).

## [0.3.2] - 2026-10-26

- Add reviewed cloud development management, schema, cache, function resources and create-only SAM deployment.
- Expand local contract validation, offline documentation discovery and regression coverage.
- Preserve account identity, Agent Skills installation and package publication workflows.
- Live Huawei write operations remain unverified; documented unsupported operations remain explicit.

## Unreleased

### Added
Expand Down
22 changes: 15 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,30 @@ test:

# 离线测试:不读取真实华为授权,不调用华为服务器。
test-scripts:
python3 scripts/test_npm_package.py
node --test packaging/npm/test/agc.test.cjs
python3 scripts/test_coverage_isolation.py
python3 scripts/test_ci_report.py
python3 scripts/test_api_suite.py
python3 scripts/test_live_lifecycle.py
python3 scripts/test_npm_package.py
node --test packaging/npm/test/agc.test.cjs
python3 scripts/test_live_package.py
python3 scripts/test_certificate_fingerprint.py
python3 scripts/test_live_multipart.py
python3 scripts/test_goal_progress.py
python3 scripts/test_publishing_audit.py
python3 scripts/test_publishing_models.py

# 每个注册接口验证真实本地 HTTP 收发,8 路并发。
test-api-transport:
$(GO) test ./cmd/agc/command -run TestEveryEndpointHTTPTransport -count=1 -parallel=8

COVERAGE_RUNNER := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))scripts/check-coverage.py

coverage:
$(GO) test ./... -coverprofile=coverage.out
$(GO) tool cover -func=coverage.out
python3 "$(COVERAGE_RUNNER)" --go "$(GO)"

coverage-check: coverage
@total=$$($(GO) tool cover -func=coverage.out | awk '/^total:/ { gsub("%","",$$3); print $$3 }'); \
awk -v total="$$total" -v min="$(COVERAGE_MIN)" 'BEGIN { if (total + 0 < min + 0) { printf("coverage %.1f%% is below %.1f%%\n", total, min); exit 1 } printf("coverage %.1f%% >= %.1f%%\n", total, min) }'
coverage-check:
python3 "$(COVERAGE_RUNNER)" --go "$(GO)" --minimum "$(COVERAGE_MIN)"

lint:
$(GO) vet ./...
Expand All @@ -40,6 +47,7 @@ web-install:

web-test:
$(NPM) --prefix apps/web test -- --run
node --test scripts/test_browser_capture.mjs

web-build:
$(NPM) --prefix apps/web run build
Expand Down
4 changes: 4 additions & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ If agc-cli saves you time in development or automation, you can support ongoing
## License

[MIT](LICENSE).

## Cloud development management

The CLI exposes 102 cloud-development operations, including reviewed management contracts. See [management usage and limitations](docs/SERVERLESS_MANAGEMENT.md). Huawei live write validation remains pending.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ agc publishing app-info-query --invoke --query appId=YOUR_APP_ID --query lang=zh
## 许可证

[MIT](LICENSE)。

## Cloud development management

The CLI exposes 102 cloud-development operations, including reviewed management contracts. See [management usage and limitations](docs/SERVERLESS_MANAGEMENT.md). Huawei live write validation remains pending.
8 changes: 8 additions & 0 deletions apps/web/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,12 @@ describe('App', () => {
expect(document.documentElement).toHaveAttribute('lang', 'en');
expect(document.querySelectorAll('.endpointEntry')).toHaveLength(12);
});

it('selects the bundled cache family when the API is unavailable', () => {
window.history.replaceState({}, '', '/en/reference/cache');
render(<App />);
expect(screen.getAllByText(/Cloud Cache/).length).toBeGreaterThan(0);
expect(screen.getAllByText(/286/).length).toBeGreaterThan(0);
});

});
30 changes: 23 additions & 7 deletions apps/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const skillSourceURL = (skill: string) => `https://github.com/Createitv/agc-cli/
const skillDownloadURL = (skill: string) => `https://raw.githubusercontent.com/Createitv/agc-cli/main/skills/${skill}/SKILL.md`;

const fallbackCapabilities: Capability[] = [
{ id: 'publishing', name: 'Publishing API', description: 'Release metadata, package state, submissions, review withdrawal, and release timing.', command: 'agc publishing', restPath: '/api/v1/publishing', status: 'registered', endpointCount: 14 },
{ id: 'publishing', name: 'Publishing API', description: 'Release metadata, package state, submissions, review withdrawal, and release timing.', command: 'agc publishing', restPath: '/api/v1/publishing', status: 'registered', endpointCount: 42 },
{ id: 'upload', name: 'Upload Management', description: 'APP packages, icons, screenshots, videos, PDFs, and multipart binary uploads.', command: 'agc upload', restPath: '/api/v1/upload', status: 'registered', endpointCount: 6 },
{ id: 'provisioning', name: 'Provisioning', description: 'Certificates, profiles, ACLs, devices, and fingerprints for release workflows.', command: 'agc provisioning', restPath: '/api/v1/provisioning', status: 'registered', endpointCount: 17 },
{ id: 'domains', name: 'Domain Management', description: 'Inspect, precheck, download, and update atomic service domain configuration.', command: 'agc domains', restPath: '/api/v1/domains', status: 'registered', endpointCount: 5 },
Expand All @@ -67,7 +67,15 @@ const fallbackCapabilities: Capability[] = [
{ id: 'game-items', name: 'Game Item Mall', description: 'Inbound role query and order callbacks configured in AGC.', command: 'agc game-items', restPath: '/api/v1/game-items', status: 'registered', endpointCount: 2 },
{ id: 'resources', name: 'Resource Predownload', description: 'Coordinate resource package versions, files, upload confirmation, and publishing.', command: 'agc resources', restPath: '/api/v1/resources', status: 'registered', endpointCount: 8 },
{ id: 'cicd', name: 'CI/CD Platform', description: 'Connect local Hvigor builds to the same command surface.', command: 'agc cicd', restPath: '/api/v1/cicd', status: 'registered', endpointCount: 1 },
];
{ id: 'functions', name: 'Cloud Functions', description: 'Native function creation, code/config updates, publishing and invocation; explicit user OAuth session.', command: 'agc functions', restPath: '/api/v1/functions', status: 'registered', endpointCount: 9 },
{ id: 'cloud-auth', name: 'Cloud Authentication', description: 'Application user sign-in and server user management; separate credential branches.', command: 'agc cloud-auth', restPath: '/api/v1/cloud-auth', status: 'registered', endpointCount: 17 },
{ id: 'clouddb', name: 'Cloud DB for Object', description: 'Object data queries, writes and deletion using existing zones and schemas.', command: 'agc clouddb', restPath: '/api/v1/clouddb', status: 'registered', endpointCount: 5 },
{ id: 'storage', name: 'Cloud Storage', description: 'File upload/download, metadata and listing with server REST.', command: 'agc storage', restPath: '/api/v1/storage', status: 'registered', endpointCount: 6 },
{ id: 'hosting', name: 'Cloud Hosting', description: 'Website sites, environments, signed ZIP uploads, archive and release.', command: 'agc hosting', restPath: '/api/v1/hosting', status: 'registered', endpointCount: 16 },
{ id: 'templates', name: 'Serverless Templates', description: 'Developer-hosted user authentication callbacks; no AGC bearer forwarding.', command: 'agc templates', restPath: '/api/v1/templates', status: 'registered', endpointCount: 2 },
{ id: 'cache', name: 'Cloud Cache', description: 'Manage cache resources using an explicit management session.', command: 'agc cache', restPath: '/api/v1/cache', status: 'registered' },
{ id: 'prefetch', name: 'Prefetch', description: 'Simulate developer callbacks and inspect an explicitly selected device.', command: 'agc prefetch', restPath: '/api/v1/prefetch', status: 'registered' },
].map(capability => ({ ...capability, endpointCount: bundledEndpoints.filter(endpoint => endpoint.familyId === capability.id).length }));

const capabilityTranslations: Record<Language, Record<string, { name: string; description: string }>> = {
en: Object.fromEntries(fallbackCapabilities.map(({ id, name, description }) => [id, { name, description }])),
Expand All @@ -84,6 +92,14 @@ const capabilityTranslations: Record<Language, Record<string, { name: string; de
gameplay: { name: '游戏联运', description: '处理游戏资源同步以及 AppGallery 游戏联运回调。' },
'game-items': { name: '游戏道具商城', description: '处理在 AGC 中配置的角色查询与订单回调。' },
resources: { name: '资源预下载', description: '协调资源包版本、文件上传、上传确认与发布。' },
functions: { name: '云函数', description: '创建、更新、发布、调用及版本查询,显式选择用户 OAuth 会话。' },
'cloud-auth': { name: '认证服务', description: '应用用户认证及服务端用户管理,与开发者登录分开。' },
clouddb: { name: '云数据库', description: '在已有存储区和对象类型中查询、更新和删除数据。' },
storage: { name: '云存储', description: '文件上传下载、元数据与文件列表。' },
hosting: { name: '云托管', description: '网站站点、环境、签名上传和版本归档发布。' },
templates: { name: 'Serverless 模板', description: 'SAM 模板创建部署及开发者认证回调。' },
cache: { name: '云缓存', description: '使用显式管理会话管理缓存资源。' },
prefetch: { name: '预加载', description: '模拟开发者回调并检查显式选择的设备。' },
cicd: { name: 'CI/CD 平台', description: '把本地 Hvigor 构建接入同一套命令控制面。' },
},
};
Expand All @@ -98,7 +114,7 @@ const translations = {
titleAccent: 'one red line.',
body: 'A Go command center for discovering, dry-running, and invoking AppGallery Connect APIs—with stable JSON for people, CI, and coding agents.',
start: 'Get started',
browse: 'Browse 156 interfaces',
browse: `Browse ${bundledEndpoints.length} interfaces`,
families: 'API families',
interfaces: 'registered interfaces',
formats: 'output formats',
Expand Down Expand Up @@ -220,7 +236,7 @@ const translations = {
titleAccent: '同一条红线前进。',
body: '用一套 Go 命令发现、预演并调用 AppGallery Connect API,为开发者、CI 和 Coding Agent 提供稳定 JSON。',
start: '快速开始',
browse: '浏览 156 个接口',
browse: `浏览 ${bundledEndpoints.length} 个接口`,
families: 'API 家族',
interfaces: '已注册接口',
formats: '输出格式',
Expand Down Expand Up @@ -349,7 +365,7 @@ export function App({ renderLanguage, renderFamily }: { renderLanguage?: Languag
const [installOpen, setInstallOpen] = useState(false);
const [installPlatform, setInstallPlatform] = useState<InstallPlatform>('npm');
const [capabilities, setCapabilities] = useState<Capability[]>(fallbackCapabilities);
const [endpointCount, setEndpointCount] = useState(156);
const [endpointCount, setEndpointCount] = useState(bundledEndpoints.length);
const [endpoints, setEndpoints] = useState<Endpoint[]>(bundledEndpoints);
const [mode, setMode] = useState<'demo' | 'live'>('demo');
const [selected, setSelected] = useState(() => renderFamily ?? (typeof window !== 'undefined' ? familyFromPath(window.location.pathname) : undefined) ?? 'publishing');
Expand Down Expand Up @@ -413,7 +429,7 @@ export function App({ renderLanguage, renderFamily }: { renderLanguage?: Languag
setEndpointCount(body.data.length);
}
})
.catch(() => setEndpointCount(156));
.catch(() => setEndpointCount(bundledEndpoints.length));
}, []);

useEffect(() => {
Expand Down Expand Up @@ -531,7 +547,7 @@ export function App({ renderLanguage, renderFamily }: { renderLanguage?: Languag
<a className="secondary" href="#registry"><Layers3 size={18} /> {text.hero.browse}</a>
</div>
<div className="heroFacts" aria-label={text.hero.factsLabel}>
<span><strong>13</strong> {text.hero.families}</span>
<span><strong>{capabilities.length}</strong> {text.hero.families}</span>
<span><strong>{endpointCount}</strong> {text.hero.interfaces}</span>
<span><strong>3</strong> {text.hero.formats}</span>
</div>
Expand Down
Loading
Loading