@fateforge/archery-cli 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +22 -7
- package/README_zh.md +22 -7
- package/docs/LIVE-SMOKE-EVIDENCE.md +54 -0
- package/package.json +7 -7
- package/skills/archery-cli/SKILL.md +2 -2
- package/skills/archery-cli/reference/instance.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.10] - 2026-06-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`instance list` (`--mode jwt`) now returns every instance, not just the first page.** The REST path (`listInstancesREST`) built the request as DRF *LimitOffset* (`?limit=&offset=&search=`) and read only `next != null` as `has_more` while discarding the `next` link, so it could never page past the first result set and silently ignored `--limit` / `--offset` / `--search`. But Archery's REST API is configured as `PageNumberPagination` (param `page`, `PAGE_SIZE` 5 upstream) with `DjangoFilterBackend` only (no `SearchFilter`) — so against more than 5 instances everything past page 1 was unreachable, which also broke any flow that discovers an instance ID before calling `instance resource` / `dict` / etc. The CLI now paginates via `page`, stops when the contract's `next` is null, filters `--search` client-side (DRF exposes no name-search param), and applies `--limit` / `--offset` client-side — mirroring the existing non-DBA session fallback `listUserAllInstancesSession`. When `--search` is unused the server's `count` is used as the true total (early-stopping once the requested window is filled); when it is used the matched count is the total. A page-walk safety cap guards against a misbehaving paginator. Session mode (the default) was never affected — it uses the Django AJAX `POST /instance/list/`, which genuinely honors `limit`/`offset`. Reproduced and verified live against `hhyo/archery:v1.8.5` in `--mode jwt` (8 instances across 2 pages: full enumeration, client-side `--limit`/`--offset` window, and cross-page `--search` all correct). Fixes #12.
|
|
15
|
+
|
|
16
|
+
## [1.0.9] - 2026-06-17
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **`instance list` works for non-DBA users.** It posted to `/instance/list/`, which Archery gates behind the DBA permission `sql.menu_instance_list`, so an ordinary user who can still *query* instances (granted via a resource group) got `403 permission denied` — even though the web SQL-query page lists those instances fine. On 403 the CLI now falls back to the ungated, user-scoped `/group/user_all_instances/` (the endpoint the web query page actually uses), returning the instances the user is authorized to use. That endpoint exposes only `{id, type, db_type, instance_name}` and has no server-side search, so host/port/credentials are omitted (with a stderr note) and `--search`/`--limit` are applied client-side. Verified on a local container with a non-DBA account in a resource group.
|
|
21
|
+
- **`workflow detail` no longer fails to parse executed workflows.** Archery returns `execute_time` (and `sequence`) on a ReviewResult row as a bare JSON number for some workflows and a string for others; the struct hard-typed them as `string`, so a numeric value failed the whole detail parse (`cannot unmarshal number into ... execute_time of type string`) and the SQL content could not be shown. These fields now accept either form. Reproduced and fixed against a real executed workflow.
|
|
22
|
+
- **Response-decode failures are no longer reported as retryable network errors.** A body the CLI received but could not parse (e.g. the `execute_time` mismatch above) surfaced as retryable `E_NETWORK` ("check host URL and network connectivity"); it now maps to non-retryable `E_UNKNOWN`, so an agent fixes the contract mismatch instead of blindly retrying.
|
|
23
|
+
|
|
24
|
+
### Notes
|
|
25
|
+
|
|
26
|
+
- These came out of an endpoint audit cross-referencing every CLI call against the Archery v1.8.5 source (route, permission decorator, request fields, response types). The audit also confirmed that `user list` (`/user/list/`) and `user resource-groups` (`/group/group/`) are `@superuser_required` upstream with no ungated user-scoped session endpoint, so they remain admin-only by Archery's design (the CLI degrades to `E_FORBIDDEN`); and that the workflow list/submit/review gates (`menu_sqlworkflow`, `sql_submit`, `sql_review`, `audit_user`) are legitimate feature permissions.
|
|
27
|
+
|
|
10
28
|
## [1.0.8] - 2026-06-17
|
|
11
29
|
|
|
12
30
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">archery-cli</h1>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Agent-native Archery SQL audit CLI · JSON-first · dry-run guarded</strong>
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="README.md">English</a> · <a href="README_zh.md">中文</a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/fatecannotbealtered/archery-cli/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/fatecannotbealtered/archery-cli/ci.yml?branch=main&style=for-the-badge&logo=githubactions&logoColor=white&label=CI"></a>
|
|
13
|
+
<a href="https://goreportcard.com/report/github.com/fatecannotbealtered/archery-cli"><img alt="Go Report" src="https://img.shields.io/badge/Go%20Report-checked-00ADD8?style=for-the-badge&logo=go&logoColor=white"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@fateforge/archery-cli"><img alt="npm" src="https://img.shields.io/npm/v/@fateforge/archery-cli?style=for-the-badge&logo=npm&logoColor=white&label=npm&color=CB3837"></a>
|
|
15
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-7C3AED?style=for-the-badge"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img alt="Agent native" src="https://img.shields.io/badge/agent-native-111827?style=for-the-badge">
|
|
20
|
+
<img alt="JSON first" src="https://img.shields.io/badge/output-JSON--first-0891B2?style=for-the-badge">
|
|
21
|
+
<img alt="Dry-run guarded" src="https://img.shields.io/badge/writes-dry--run%20guarded-F59E0B?style=for-the-badge">
|
|
22
|
+
</p>
|
|
9
23
|
|
|
10
24
|
> Agent-native CLI for the Archery SQL audit platform. It gives AI Agents deterministic control over SQL workflows, queries, instances, diagnostics, binlog, archive jobs, and data dictionaries.
|
|
11
25
|
|
|
@@ -14,8 +28,9 @@
|
|
|
14
28
|
Paste this block into the AI Agent that will operate Archery SQL audit. It installs the CLI and bundled Skill, provides the minimum runtime context, and runs the self-description preflight.
|
|
15
29
|
|
|
16
30
|
```bash
|
|
17
|
-
# Install CLI
|
|
31
|
+
# Install the CLI (global npm).
|
|
18
32
|
npm install -g @fateforge/archery-cli
|
|
33
|
+
# Install the Agent Skill — copies into your agent-supported skills directory.
|
|
19
34
|
npx skills add fatecannotbealtered/archery-cli -y -g
|
|
20
35
|
|
|
21
36
|
# Provide runtime context. Replace placeholders in the local shell/secret manager.
|
package/README_zh.md
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">archery-cli</h1>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>面向 AI Agent 的 Archery SQL 审核 CLI · JSON 优先 · dry-run 防护</strong>
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="README.md">English</a> · <a href="README_zh.md">中文</a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/fatecannotbealtered/archery-cli/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/fatecannotbealtered/archery-cli/ci.yml?branch=main&style=for-the-badge&logo=githubactions&logoColor=white&label=CI"></a>
|
|
13
|
+
<a href="https://goreportcard.com/report/github.com/fatecannotbealtered/archery-cli"><img alt="Go Report" src="https://img.shields.io/badge/Go%20Report-checked-00ADD8?style=for-the-badge&logo=go&logoColor=white"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@fateforge/archery-cli"><img alt="npm" src="https://img.shields.io/npm/v/@fateforge/archery-cli?style=for-the-badge&logo=npm&logoColor=white&label=npm&color=CB3837"></a>
|
|
15
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-7C3AED?style=for-the-badge"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img alt="Agent native" src="https://img.shields.io/badge/agent-native-111827?style=for-the-badge">
|
|
20
|
+
<img alt="JSON first" src="https://img.shields.io/badge/output-JSON--first-0891B2?style=for-the-badge">
|
|
21
|
+
<img alt="Dry-run guarded" src="https://img.shields.io/badge/writes-dry--run%20guarded-F59E0B?style=for-the-badge">
|
|
22
|
+
</p>
|
|
9
23
|
|
|
10
24
|
> 面向 AI Agent 的 Archery SQL 审核 CLI。它让 Agent 能以确定性的机器契约操作 SQL 工单、查询、实例、诊断、binlog、归档任务和数据字典。
|
|
11
25
|
|
|
@@ -14,8 +28,9 @@
|
|
|
14
28
|
把下面整段交给负责操作 Archery SQL 审核平台 的 AI Agent。它会安装 CLI 和内置 Skill,提供最小运行上下文,并执行自描述预检。
|
|
15
29
|
|
|
16
30
|
```bash
|
|
17
|
-
# 安装 CLI
|
|
31
|
+
# 安装 CLI(全局 npm)。
|
|
18
32
|
npm install -g @fateforge/archery-cli
|
|
33
|
+
# 安装 Agent Skill —— 复制到你 agent 支持的 skills 目录。
|
|
19
34
|
npx skills add fatecannotbealtered/archery-cli -y -g
|
|
20
35
|
|
|
21
36
|
# 提供运行上下文。把占位符替换为本地 shell/密钥管理器里的值。
|
|
@@ -361,6 +361,28 @@ intermittently returned `用户名或密码错误`. Using `http://127.0.0.1:9123
|
|
|
361
361
|
defect; the session login flow itself (GET csrf → POST authenticate → cookie)
|
|
362
362
|
matches the verified curl flow byte-for-byte.
|
|
363
363
|
|
|
364
|
+
## 2026-06-17 — 1.0.9 endpoint audit: instance-list fallback + detail type fixes
|
|
365
|
+
|
|
366
|
+
Triggered by two real-usage reports (a non-DBA account getting 403 on `instance
|
|
367
|
+
list` while the web could list instances, and `workflow detail 42594` failing to
|
|
368
|
+
parse). Method: a **static endpoint audit** cross-referencing every endpoint the
|
|
369
|
+
CLI calls against the `hhyo/archery:v1.8.5` source inside the container (route,
|
|
370
|
+
permission decorator, request fields, response types) — **zero requests to any
|
|
371
|
+
real instance**. Dynamic verification was done **only on the local container**;
|
|
372
|
+
the production instance was never used.
|
|
373
|
+
|
|
374
|
+
| Check | Status | Evidence |
|
|
375
|
+
|-------|--------|----------|
|
|
376
|
+
| `instance list` 403 → user-scoped fallback | live (local container) | PASS — seeded a non-DBA `cliuser` in resource group `pangu_test` granting `pangu_test_redis`; `instance list --db-type redis --search pangu` returned that instance (id 2) via `/group/user_all_instances/` instead of 403, with a stderr note that host/port need DBA permission. |
|
|
377
|
+
| `workflow detail` numeric `execute_time` | unit + earlier real read | PASS — `flexString` accepts number or string; unit test `TestDetail_SessionNumericExecuteTime` encodes the real `0.008516` / numeric `sequence` shape. |
|
|
378
|
+
| Parse failure non-retryable | code review | The decode error now returns a status-less `APIError` → `E_UNKNOWN` (non-retryable), not `E_NETWORK`. |
|
|
379
|
+
| Audit: admin-only endpoints are correct | static | `instance.lists`=`menu_instance_list`, `user.lists`/`resource_group.group`=`@superuser_required`, `data_dictionary.table_list`=`menu_data_dictionary`, workflow gates=`menu_sqlworkflow`/`sql_submit`/`sql_review`/`audit_user`. No ungated user-scoped session alternative for user/group lists, so they stay admin-only by design. |
|
|
380
|
+
|
|
381
|
+
The self-fulfilling test pattern that hid the 2FA and instance-list defects is
|
|
382
|
+
the audit's core lesson: mocks/fixtures were authored from the client's own
|
|
383
|
+
assumptions. New tests encode the **real** Archery contract (numeric field forms,
|
|
384
|
+
403-then-fallback) so a regression flips them red.
|
|
385
|
+
|
|
364
386
|
## 2026-06-17 — 1.0.8 real 2FA login round-trip (closes the prior 2FA gap)
|
|
365
387
|
|
|
366
388
|
The earlier runs could only mock 2FA because the `cli_verify` account had no 2FA
|
|
@@ -410,6 +432,38 @@ leave the container clean.
|
|
|
410
432
|
is fully green, and `golangci-lint run` reports 0 issues.
|
|
411
433
|
- **2FA is mock-verified only** for the reason above.
|
|
412
434
|
|
|
435
|
+
## 2026-06-20 — 1.0.10 `instance list` REST/JWT pagination (issue #12)
|
|
436
|
+
|
|
437
|
+
Live verification of the `instance list` pagination fix against the running
|
|
438
|
+
`tools-e2e-archery` (`hhyo/archery:v1.8.5`) on `localhost:9123`, **`--mode jwt`**,
|
|
439
|
+
superuser `cli_verify` (added to the `api_user_whitelist` SysConfig). The fleet
|
|
440
|
+
was seeded to **8 instances** so it spans more than one REST page (upstream
|
|
441
|
+
`PAGE_SIZE` 5 → 2 pages), then cleaned back down afterward.
|
|
442
|
+
|
|
443
|
+
### Result by scenario
|
|
444
|
+
|
|
445
|
+
| Scenario | Command | Status | Result |
|
|
446
|
+
|---|---|---|---|
|
|
447
|
+
| Full enumeration | `instance list --limit 20` | **live PASS** | all 8 returned (`count:8, total:8, has_more:false`); pre-fix returned only 5 |
|
|
448
|
+
| Client-side window | `instance list --limit 3 --offset 2` | **live PASS** | ids 3,4,5; `total:8`; `has_more:true` |
|
|
449
|
+
| Cross-page search | `instance list --search page-test` | **live PASS** | 6 matches (ids 3–8 span both pages); `total:6` |
|
|
450
|
+
| Exact search | `instance list --search page-test-mysql-5` | **live PASS** | exactly id 7; `total:1` |
|
|
451
|
+
| Server-side filter | `instance list --db-type redis` | **live PASS** | id 2 only; `--db-type` still filtered upstream |
|
|
452
|
+
|
|
453
|
+
Raw `GET /api/v1/instance/?page=1` confirmed the contract: `PageNumberPagination`
|
|
454
|
+
envelope `{count:8, next:"…?page=2", previous:null, results:[…]}` with `id` as a
|
|
455
|
+
bare JSON number (coerced to string by `instanceResult.UnmarshalJSON`).
|
|
456
|
+
|
|
457
|
+
### Honesty notes
|
|
458
|
+
|
|
459
|
+
- **Race detector not run on this host:** `go test -race` needs cgo + gcc, which
|
|
460
|
+
are unavailable on the verifier machine. The non-race suite (`go test ./...`)
|
|
461
|
+
is fully green, `go vet ./...` is clean, and `golangci-lint run` reports 0
|
|
462
|
+
issues. CI runs `-race` on Linux.
|
|
463
|
+
- The new mock-contract test (`TestListInstancesREST_PageNumberPagination`)
|
|
464
|
+
encodes the real `PageNumberPagination` semantics observed above (page walk,
|
|
465
|
+
null `next` terminator, numeric `id`, no server-side search/limit/offset).
|
|
466
|
+
|
|
413
467
|
## Reproduce
|
|
414
468
|
|
|
415
469
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fateforge/archery-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Archery SQL audit CLI for AI Agents - manage SQL workflows, queries, instances, diagnostics, and data dictionaries with a machine-readable contract",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"archery",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"check-version": "node scripts/check-version.js"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"@fateforge/archery-cli-darwin-arm64": "1.0.
|
|
34
|
-
"@fateforge/archery-cli-darwin-x64": "1.0.
|
|
35
|
-
"@fateforge/archery-cli-linux-arm64": "1.0.
|
|
36
|
-
"@fateforge/archery-cli-linux-x64": "1.0.
|
|
37
|
-
"@fateforge/archery-cli-win32-arm64": "1.0.
|
|
38
|
-
"@fateforge/archery-cli-win32-x64": "1.0.
|
|
33
|
+
"@fateforge/archery-cli-darwin-arm64": "1.0.10",
|
|
34
|
+
"@fateforge/archery-cli-darwin-x64": "1.0.10",
|
|
35
|
+
"@fateforge/archery-cli-linux-arm64": "1.0.10",
|
|
36
|
+
"@fateforge/archery-cli-linux-x64": "1.0.10",
|
|
37
|
+
"@fateforge/archery-cli-win32-arm64": "1.0.10",
|
|
38
|
+
"@fateforge/archery-cli-win32-x64": "1.0.10"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"scripts/run.js",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: archery-cli
|
|
3
|
-
version: "1.0.
|
|
3
|
+
version: "1.0.10"
|
|
4
4
|
description: "Archery SQL audit platform CLI for managing SQL workflows, queries, instances, diagnostics. Use when the user asks about SQL审核, database operations, Archery platform management, or needs to submit/review/execute SQL against database instances."
|
|
5
5
|
license: MIT
|
|
6
6
|
user-invocable: true
|
|
7
|
-
metadata: {"requires":{"bins":["archery-cli"],"min_version":"1.0.
|
|
7
|
+
metadata: {"requires":{"bins":["archery-cli"],"min_version":"1.0.10"}}
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# archery-cli
|
|
@@ -224,3 +224,4 @@ archery-cli instance describe --instance prod-mysql --db mydb --table orders
|
|
|
224
224
|
- `instance users` lists database-level users, not Archery platform users
|
|
225
225
|
- `instance table-instances` searches across all registered instances for a given table name
|
|
226
226
|
- JSON output IDs are strings per the CLI contract, even when input flags accept numeric IDs; all instance names are strings
|
|
227
|
+
- `instance list` behaves the same in both transports. In `--mode jwt` the REST API paginates server-side in small pages (Archery's `PageNumberPagination`) and has no name search, so the CLI walks all pages and applies `--search` / `--limit` / `--offset` client-side; `--db-type` is filtered server-side. For a very large fleet, prefer `--db-type` (and `--search`) to narrow results.
|