@luckypiggy/zhihu-ai-cli 0.1.0-test.1 → 0.2.1-test.4
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/README.md +32 -20
- package/assets/codex-skills/zhihu-aiops/SKILL.md +32 -16
- package/assets/codex-skills/zhihu-aiops/references/commands.md +28 -14
- package/assets/codex-skills/zhihu-aiops/references/errors.md +1 -1
- package/assets/codex-skills/zhihu-aiops/references/safety.md +6 -4
- package/dist/auth-service.js +71 -83
- package/dist/cli.js +226 -22
- package/dist/codex-skill.js +3 -3
- package/dist/config.js +14 -3
- package/dist/contracts.js +3 -1
- package/dist/credentials.js +152 -29
- package/dist/http.js +413 -67
- package/dist/install.js +310 -59
- package/dist/profile-lock.js +32 -3
- package/dist/release.js +24 -0
- package/dist/terminal-prompt.js +191 -0
- package/dist/token-manager.js +36 -15
- package/package.json +4 -2
- package/dist/browser.js +0 -49
- package/dist/pkce.js +0 -15
package/README.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 智护 Pilot CLI — P1 Authentication, Employees, Assets, Metrics, Alarms, Incident Diagnosis, and Inspection Read-only CLI
|
|
2
2
|
|
|
3
3
|
智护 Pilot CLI P1 只读能力切片提供安全的本机认证闭环:
|
|
4
4
|
|
|
5
|
-
- `zhihu auth login
|
|
5
|
+
- `zhihu auth login`:在当前终端依次输入用户名、可选租户、可选验证码和隐藏密码,调用 Pilot 终端登录接口,并把仅有的 Pilot Refresh Credential 写入 macOS Keychain 或 Linux Secret Service;不打开浏览器,也不支持 `--password` 或 `ZHIHU_PASSWORD`;
|
|
6
6
|
- `zhihu auth status`:使用本机凭据安全轮换一次,显示 profile、用户/租户、Scope 和 Access Token 到期时间;
|
|
7
7
|
- `zhihu auth logout`:先请求 Pilot 撤销会话,再删除本机凭据;网络失败时保留凭据供重试;
|
|
8
8
|
- `zhihu capabilities list`:通过固定只读网关列出当前登录用户的 canonical Scope 和能力;遇到一次 401 只在 profile 锁内刷新并重试一次;
|
|
9
|
+
- `zhihu a2a capabilities`:通过固定 integrations v1 网关发现四类只读 A2A capability;目标员工仍由 Pilot 服务端 registry 选择,CLI 不保存或提交员工映射;
|
|
10
|
+
- `zhihu a2a delegate --capability <resource_query|incident_analysis|inspection_summary|knowledge_qa> --message <text>`:把一次用户原始问题提交给既有 A2A 总控,由服务端安全委派专业数字员工;请求体仅含 capability 和 question,写能力始终拒绝;
|
|
11
|
+
- `zhihu a2a task get --id <opaque-task-id>`:查询当前签名 CLI 用户、租户和 namespace 可见的 A2A 任务投影;不返回他人的身份、root、run key 或会话字段;
|
|
9
12
|
- `zhihu employees list`:通过固定只读网关列出当前用户可见的安全数字员工字段;只读请求同样复用 profile 锁内一次 401 重试;
|
|
10
13
|
- `zhihu employees chat <employee-id> --message <text> [--conversation <id>]`:调用 manifest 中允许的只读数字员工并流式输出安全回答;首次请求返回的 opaque `conversation_id` 会在人工模式写到 stderr,后续用 `--conversation` 续接;`--json` 只输出一个最终 envelope;Ctrl+C/断连会尽力取消下游生成;
|
|
11
14
|
- `zhihu assets list [--keyword <text>] [--model <name|code|id>] [--page N] [--page-size N]`:通过固定资产只读网关查询安全投影;模型文本只做名称/编码精确匹配,页码和响应字段严格校验,401 最多刷新并重试一次;
|
|
@@ -13,37 +16,39 @@
|
|
|
13
16
|
- `zhihu metrics query --asset <id|ip> --metric <online|cpu|memory|load|disk|io|snmp> [--window 5m..24h] [--max-points N]`:通过固定指标定义查询 VictoriaMetrics;资产 ID 先解析为受控监控 IP,PromQL、VM URL 和标签选择均由 Pilot 服务端固定,响应只返回有限统计和采样点;
|
|
14
17
|
- `zhihu alarms list [--status all|firing|resolved] [--page N] [--page-size N]`:通过固定告警只读网关分页查询安全投影;状态、分页和响应字段严格校验,401 最多刷新并重试一次;
|
|
15
18
|
- `zhihu alarms get --id <id>`:通过固定告警详情只读网关读取单条安全投影;告警 ID、详情 envelope 和响应身份严格校验,401 最多刷新并重试一次;
|
|
16
|
-
- `zhihu incidents diagnose --alarm-id <id>`:通过固定指定告警诊断网关生成结构化证据、确定性分类、稳定结论/置信度/发现/动作 code;仅接受 active signed session 与 `incidents:analyze`、`alarms:read`、`assets:read`、`metrics:read`,固定读取告警详情、精确资产 ID/明确告警 IP 和 allowlist 指标的有界告警事件窗口与最近窗口;客户端不能提供 URL、PromQL
|
|
19
|
+
- `zhihu incidents diagnose --alarm-id <id>`:通过固定指定告警诊断网关生成结构化证据、确定性分类、稳定结论/置信度/发现/动作 code;仅接受 active signed session 与 `incidents:analyze`、`alarms:read`、`assets:read`、`metrics:read`,固定读取告警详情、精确资产 ID/明确告警 IP 和 allowlist 指标的有界告警事件窗口与最近窗口;客户端不能提供 URL、PromQL、时间窗口、模型提示或远程终端,服务端不调用 LLM、不写数据,30 秒总超时且 401 最多刷新一次;
|
|
17
20
|
- `zhihu inspections run [--model <name|code|id>] [--window 5m..24h]`:通过固定 `/api/zhihu/integrations/v1/inspections/run` 生成结构化 `grade`/`findings`/`actions` 巡检摘要;仅接受 active signed session 与 `inspections:run-readonly`、`assets:read`、`metrics:read`、`alarms:read`,资产和告警各最多 100 条,VM 仅使用 `host_ip`、`instance`、`monitorIp`、`ip`、`agent_hostname` 五类标签并最多解析 10,000 个身份,告警仅按精确资产 ID/IP 关联;客户端不能提供 query 参数、URL、PromQL、任意标签或写操作,30 秒总超时且 401 最多刷新一次;
|
|
18
|
-
- `zhihu install [--base-url <https-url>] [--profile <name>] [--timeout N] [--language zh-CN|en] [--ca-file <absolute-file>] [--codex-skill-dir <absolute-path>] [--skip-login] [--skip-codex] [--force]`:交互 TTY
|
|
21
|
+
- `zhihu install [--base-url <https-url>] [--profile <name>] [--timeout N] [--language zh-CN|en] [--ca-file <absolute-file>] [--codex-skill-dir <absolute-path>] [--skip-login] [--skip-codex] [--force]`:交互 TTY 或显式参数安装向导;交互顺序为 Skill → 语言 → 智护地址 → Profile → `/info` 预检 → 用户名 → 可选租户 → 隐藏密码 → 登录;失败时恢复本地 Profile;非交互/JSON 模式必须显式使用 `--skip-login`;CA 文件只保存绝对路径,不保存证书内容;
|
|
19
22
|
- `zhihu doctor`:结构化检查 Profile/base URL/TLS/CA、OS 凭据存储、Pilot `/api/zhihu/integrations/v1/info` 兼容性、登录状态、能力和 Codex Skill 状态,不会触发登录;
|
|
20
23
|
- `zhihu install codex` / `zhihu uninstall codex`:在临时或用户指定的 Codex Skill 目录原子安装、升级和卸载无密钥的 `zhihu-aiops` Skill;受管文件被修改或目标目录不是本 CLI 创建的安装时默认拒绝,`--force` 仅用于受管安装;
|
|
21
24
|
- `zhihu version`、`zhihu config init`、`zhihu config show --redact` 继续可用。
|
|
22
25
|
|
|
23
|
-
需要访问已配置环境的命令支持 `--profile`,各命令按帮助说明使用 `--json`。JSON stdout 始终只有一个 success/error envelope;Access/Refresh Token
|
|
26
|
+
需要访问已配置环境的命令支持 `--profile`,各命令按帮助说明使用 `--json`。JSON stdout 始终只有一个 success/error envelope;Access/Refresh Token、密码、授权码和上游正文不会写入 stdout、stderr、日志或 Profile。Profile 只保存非敏感的用户名和租户提示,Refresh Credential 只保存到系统凭据库。
|
|
24
27
|
|
|
25
28
|
当前客户端只访问当前 Profile 的固定 `/api/zhihu/integrations/v1` 路径,拒绝任意 HTTP 重定向和非回环明文 HTTP;Profile 的 CA bundle 用于严格 TLS 校验。macOS 使用 `/usr/bin/security`,Linux 使用固定路径 `/usr/bin/secret-tool`,不提供明文文件 fallback。Refresh rotation 通过 profile 锁和进程内 single-flight 合并,并在 Keychain 写入失败时尝试撤销新会话和清理本机旧值。
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
本切片提供数字员工、资产、指标、告警、指定告警诊断、巡检和 A2A 四类只读委派的 `list`/`get`/`query`/`chat`/`diagnose`/`run` 能力,并在包内实现无密钥的外部 `zhihu-aiops` Codex Skill 及其受管安装/卸载,以及公网测试版 `zhihu install` 安装向导。自然语言任务默认通过 `zhihu a2a delegate` 进入 A2A;底层命令仍保留为显式结构化查询和受控诊断入口。CLI/Skill 不提交或猜测 target、source、root、turn、tool、user、tenant 或员工映射。canonical 与离线包的 Skill 使用当前构建提供的本地 `zhihu` runner,不读取本机认证材料,不提供写操作或 MCP;公网测试构建会在隔离 staging 中把 Skill runner 固定为指定 npx 版本。测试版支持客户 URL 和离线交付,正式 GA 与真实客户联调遵循各自发布门禁。安装向导严格验证 `/info` 的服务、协议、版本、能力顺序和终端登录契约,拒绝非回环明文 HTTP、重定向、userinfo、query/fragment、符号链接 CA;Profile 与 root current_profile 采用快照恢复,Skill 安装遵守 foreign/modified/force 语义。指定告警诊断只允许 `cpu`/`memory`/`load`/`io`/`disk`/`online`/`unknown` 确定性分类,巡检只允许固定模型/窗口、四个 Scope、资产/告警各 100 条和五类 VM IP 标签,证据不足时保守返回;两条链路均不会接受客户端 URL、PromQL、任意标签或写操作,不调用 LLM,均为 30 秒总超时且 401 最多刷新一次。CLI 只解析签名 JWT 的非敏感展示字段,不以本地解析结果作为授权决策。Chat conversation 映射当前是服务端单 worker 的有界 TTL 内存状态,同进程并发有锁保护;多 worker/多副本部署需要共享状态存储。
|
|
28
31
|
|
|
29
|
-
##
|
|
32
|
+
## 公网测试版安装
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
当前公网测试版命令为:
|
|
32
35
|
|
|
33
36
|
```bash
|
|
34
|
-
npx @luckypiggy/zhihu-ai-cli@test install
|
|
37
|
+
npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 install
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
这是智护 Pilot 的公网测试版(不是正式 GA);`npx` 只临时运行 CLI,安装向导会写入非敏感 Profile 并安装无密钥 Codex Skill,后续 Skill 调用继续使用上面的精确 npx runner。服务地址、权限和凭据仍由用户在安装向导中配置。客户 URL 和离线 `.tgz` 适用于受控网络或隔离环境。
|
|
41
|
+
|
|
42
|
+
AI/Codex Skill 调用必须继续使用上面的精确 npx runner;一次 `npx ... install` 只运行临时包,不会把 `zhihu` 命令永久写入 PATH。若用户要手动直接输入 `zhihu`,必须先全局安装同一精确版本:`npm install --global --ignore-scripts @luckypiggy/zhihu-ai-cli@0.2.1-test.4`。离线包则应使用其自身的 `zhihu` 安装方式,不要为了绕过离线约束改用公网 runner。
|
|
38
43
|
|
|
39
44
|
`install` 的固定顺序是:
|
|
40
45
|
|
|
41
|
-
1. 先安装或确认包内 bundled `zhihu-aiops` Skill;Skill 失败时不发起网络请求、不提示环境配置,也不写 Profile。
|
|
42
|
-
2.
|
|
43
|
-
3. 对客户地址执行严格 `/info` 预检,确认服务、协议、版本、能力和 OAuth
|
|
44
|
-
4.
|
|
45
|
-
5.
|
|
46
|
-
6. 登录流程结束后运行 `doctor`,输出配置、服务契约、凭据状态和 Skill
|
|
46
|
+
1. 先安装或确认包内 bundled `zhihu-aiops` Skill;Skill 失败时不发起网络请求、不提示环境配置,也不写 Profile。Skill 已存在时可安全地再次运行同一条安装命令。
|
|
47
|
+
2. 引导语言、地址、Profile、CA 和超时配置;支持非敏感环境变量默认值。
|
|
48
|
+
3. 对客户地址执行严格 `/info` 预检,确认服务、协议、版本、能力和 `pilot_terminal_password` 登录契约;旧版 browser OAuth 会明确返回 `TERMINAL_LOGIN_REQUIRED`,绝不回退。
|
|
49
|
+
4. 预检通过后依次询问用户名、可选租户和隐藏密码;密码只存在于当前请求内,不写配置、环境、日志或命令行。
|
|
50
|
+
5. 调用固定 `/api/zhihu/integrations/v1/auth/login`,只保存返回的 Refresh Credential 到 macOS Keychain 或 Linux Secret Service,Access Token 只在进程内存中短期缓存。
|
|
51
|
+
6. 登录流程结束后运行 `doctor`,输出配置、服务契约、凭据状态和 Skill 状态;失败会恢复本地 Profile。
|
|
47
52
|
|
|
48
53
|
安装向导只支持以下非敏感环境变量,且空值或全空白值按未设置处理:
|
|
49
54
|
|
|
@@ -51,20 +56,27 @@ npx @luckypiggy/zhihu-ai-cli@test install
|
|
|
51
56
|
| --- | --- |
|
|
52
57
|
| `ZHIHU_PROFILE` | Profile 名称 |
|
|
53
58
|
| `ZHIHU_BASE_URL` | 客户智护 HTTPS 地址 |
|
|
54
|
-
| `
|
|
59
|
+
| `ZHIHU_USERNAME` | 非敏感用户名默认值 |
|
|
60
|
+
| `ZHIHU_TENANT_ID` | 非敏感租户 ID 默认值 |
|
|
55
61
|
| `ZHIHU_CA_BUNDLE` | 客户 CA bundle 绝对路径 |
|
|
56
62
|
| `ZHIHU_TIMEOUT` | 请求超时秒数(1~300) |
|
|
57
63
|
|
|
58
|
-
配置优先级固定为“CLI 参数 > 非空 env > 交互/default”。不支持也不建议 `ZHIHU_ACCESS_TOKEN`、`ZHIHU_USER` 或 `ZHIHU_PASSWORD
|
|
64
|
+
配置优先级固定为“CLI 参数 > 非空 env > 交互/default”。不支持也不建议 `ZHIHU_ACCESS_TOKEN`、`ZHIHU_USER` 或 `ZHIHU_PASSWORD`;密码和可选验证码只能通过隐藏/终端提示本次传入,令牌只由终端登录接口获得并由系统凭据库保存 Refresh Credential。安装失败或服务尚未配置时可再次运行相同的 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 install` 命令,向导会保留/恢复一致的本地 Profile。npm `install` 没有交互钩子,不会在依赖安装阶段启动向导、读取密码或打开浏览器。
|
|
65
|
+
|
|
66
|
+
安装完成后请新开一个 Codex 会话,让它重新发现 Skill;可以直接用自然语言尝试“列出当前活动告警”“查看资产 123 最近一小时 CPU 趋势”或“分析告警 456 的根因”。需要排查安装时运行 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 doctor`,该命令只输出脱敏检查结果。
|
|
59
67
|
|
|
60
68
|
开发和发布需要 Node.js 22 或更新版本:
|
|
61
69
|
|
|
62
70
|
```bash
|
|
63
71
|
npm test
|
|
64
72
|
npm pack --dry-run
|
|
73
|
+
|
|
74
|
+
# 从 canonical package source 生成不改工作树的公网测试 tgz
|
|
75
|
+
mkdir -p /tmp/zhihu-cli-public-test
|
|
76
|
+
node scripts/build-public-test-package.mjs --output /tmp/zhihu-cli-public-test
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
发布包只包含 `bin/`、编译后的 `dist/*.js`、无密钥的 `assets/codex-skills/`、README 和 package manifest,不包含源码、测试、凭据或 `postinstall` 脚本。正式联调需要 HTTPS 客户地址、真实客户契约(`/info`、
|
|
79
|
+
发布包只包含 `bin/`、编译后的 `dist/*.js`、无密钥的 `assets/codex-skills/`、README 和 package manifest,不包含源码、测试、凭据或 `postinstall` 脚本。正式联调需要 HTTPS 客户地址、真实客户契约(`/info`、terminal auth/login、employees chat、assets、metrics、alarms、incidents diagnose、inspections run)和客户 OS 凭据服务;本地测试覆盖 parser、取消、错误、终端隐藏输入、安装向导非交互校验、Profile 回滚、Skill 安装/卸载和 npm 白名单。客户 URL、npm 发布和跨平台凭据验收按独立门禁执行。
|
|
68
80
|
|
|
69
81
|
## 完全离线交付(Stage 6A)
|
|
70
82
|
|
|
@@ -89,4 +101,4 @@ npm install --global --prefix /your/prefix --ignore-scripts --offline ./zhihu-ai
|
|
|
89
101
|
/your/prefix/bin/zhihu --version
|
|
90
102
|
```
|
|
91
103
|
|
|
92
|
-
离线制品与本地校验覆盖 Linux x86_64 禁网场景;真实
|
|
104
|
+
离线制品与本地校验覆盖 Linux x86_64 禁网场景;真实 terminal login、客户智护 URL、npm 发布、跨平台凭据和客户环境联调需要对应环境与发布门禁。
|
|
@@ -1,39 +1,55 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: zhihu-aiops
|
|
3
|
-
description: 通过智护 Pilot CLI
|
|
3
|
+
description: 通过智护 Pilot CLI 将自然语言运维问题路由到智护 A2A 四类只读能力,并对登录状态、能力、数字员工、资产、指标、告警、事件诊断和巡检执行安全分析。当用户需要查询智护运行状态或解释告警时使用;目标不明确时先询问,不猜测身份或资源。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 智护 AI 运维
|
|
7
7
|
|
|
8
|
-
本 Skill
|
|
8
|
+
本 Skill 只把明确的自然语言问题交给当前构建的本地 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4` runner,并依据单一 JSON 结果给出分析。默认路径是一次 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate`,由 Pilot 服务端的 A2A 注册中心选择专业数字员工;Skill 只提交 capability_id 和用户原始问题,不提交或猜测 employee_id、target、root、turn、tool、user 或 tenant。离线包不会访问公网;公网测试包会在 staging 时将该 runner 固定为指定 npx 版本。先确认用户要看的租户、资产、告警或时间范围,再选择一个最小查询;多个查询之间保留用户给出的精确 ID。
|
|
9
9
|
|
|
10
10
|
## 工作流程
|
|
11
11
|
|
|
12
|
-
1. 确认目标和范围。缺少资产 ID、告警 ID
|
|
13
|
-
2. 只调用 `zhihu ... --json`,每次调用都等待完整 JSON envelope。不要把诊断参数改写成 URL、查询表达式或任意参数。
|
|
14
|
-
3.
|
|
12
|
+
1. 确认目标和范围。缺少资产 ID、告警 ID、模型或时间窗时提问;不要用名称猜测唯一对象。只有用户明确指定可信员工 ID 并要求直接对话时,才使用 `employees chat`。
|
|
13
|
+
2. 只调用 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 ... --json`,每次调用都等待完整 JSON envelope。不要把诊断参数改写成 URL、查询表达式或任意参数。
|
|
14
|
+
3. 先查认证/能力,再按意图映射到一个只读 capability;认证失败时仅提示用户运行 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 auth login`,不要要求用户粘贴任何凭据。
|
|
15
15
|
4. 只依据 `ok`、稳定错误码和 `data` 字段回答。字段缺失、对象不唯一或结果过期时明确说明并停止推断。
|
|
16
16
|
5. 对告警或巡检结论引用返回的证据、范围和时间窗;建议动作必须保持在只读排查范围内。
|
|
17
17
|
6. 回复语言跟随当前用户语言;命令和稳定错误码保持原样,解释、确认和结论使用用户选择的中文或英文。
|
|
18
18
|
|
|
19
|
+
## A2A 默认路由
|
|
20
|
+
|
|
21
|
+
自然语言任务默认只使用以下四个 capability,一次任务只委派一次:
|
|
22
|
+
|
|
23
|
+
| 用户意图 | capability_id | 默认命令 |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| 资产、指标、采集状态 | `resource_query` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability resource_query --message <原始问题> --json` |
|
|
26
|
+
| 告警、故障、根因和恢复验证建议 | `incident_analysis` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability incident_analysis --message <原始问题> --json` |
|
|
27
|
+
| 巡检、健康检查和状态摘要 | `inspection_summary` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability inspection_summary --message <原始问题> --json` |
|
|
28
|
+
| 知识、案例、手册和 SOP | `knowledge_qa` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability knowledge_qa --message <原始问题> --json` |
|
|
29
|
+
|
|
30
|
+
先调用 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a capabilities --json` 检查 Pilot 是否声明 A2A;A2A 关闭、能力不可用、歧义或下游失败时报告稳定错误并停止,不静默绕过治理。`asset_onboarding`、`asset_discovery` 等写能力始终禁用。
|
|
31
|
+
|
|
19
32
|
## 可用查询
|
|
20
33
|
|
|
21
|
-
- `zhihu auth status --json`
|
|
22
|
-
- `zhihu capabilities list --json`
|
|
23
|
-
- `zhihu
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
27
|
-
- `zhihu
|
|
28
|
-
- `zhihu
|
|
34
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 auth status --json`
|
|
35
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 capabilities list --json`
|
|
36
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a capabilities --json`
|
|
37
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability <resource_query|incident_analysis|inspection_summary|knowledge_qa> --message <用户原始问题> --json`
|
|
38
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a task get --id <opaque-task-id> --json`
|
|
39
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 employees list --json`
|
|
40
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 assets list --json` 或 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 assets get --id <id> --json`
|
|
41
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 metrics query --asset <id|ip> --metric <online|cpu|memory|load|disk|io|snmp> --window <5m..24h> --json`
|
|
42
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 alarms list --status <all|firing|resolved> --json` 或 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 alarms get --id <id> --json`
|
|
43
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 incidents diagnose --alarm-id <id> --json`
|
|
44
|
+
- `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 inspections run [--model <name|code|id>] [--window <5m..24h>] --json`
|
|
29
45
|
|
|
30
|
-
筛选、分页、模型和时间窗必须使用 CLI
|
|
46
|
+
筛选、分页、模型和时间窗必须使用 CLI 已声明的取值;不要自行拼接未列出的选项。底层资产、指标、告警、诊断和巡检命令只在用户明确要求原始结构化数据、排查 CLI 本身或 A2A 明确不可用且用户同意受控降级时使用;A2A 错误不得自动降级。员工对话只有在用户明确给出可信员工 ID 和问题时才可使用 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 employees chat <employee-id> --message <text> --json`,不得把对话当作默认路由或执行变更的入口。
|
|
31
47
|
|
|
32
48
|
## 输出和安全边界
|
|
33
49
|
|
|
34
50
|
- 只展示 CLI envelope 中必要的非敏感字段;不要复述认证材料、配置内容、环境变量或本机凭据。
|
|
35
|
-
- 只读命令不等于服务端一定有数据。遇到 `AUTH_RELOGIN_REQUIRED`、`FORBIDDEN`、`CAPABILITY_NOT_AVAILABLE`、`ASSET_NOT_FOUND`、`ALARM_NOT_FOUND`、`DATA_SOURCE_UNAVAILABLE`、`TIMEOUT` 或 `PROTOCOL_ERROR`,说明稳定错误码和下一步,不编造结果。
|
|
51
|
+
- 只读命令不等于服务端一定有数据。遇到 `AUTH_RELOGIN_REQUIRED`、`FORBIDDEN`、`CAPABILITY_NOT_AVAILABLE`、`A2A_DISABLED`、`A2A_CAPABILITY_NOT_FOUND`、`A2A_CAPABILITY_DISABLED`、`A2A_TASK_NOT_FOUND`、`A2A_FORBIDDEN`、`A2A_TIMEOUT`、`A2A_EXECUTION_INDETERMINATE`、`ASSET_NOT_FOUND`、`ALARM_NOT_FOUND`、`DATA_SOURCE_UNAVAILABLE`、`TIMEOUT` 或 `PROTOCOL_ERROR`,说明稳定错误码和下一步,不编造结果。
|
|
36
52
|
- 不直接访问智护服务、监控服务或容器;不执行额外命令,不访问本机配置/凭据存储,不联系外部地址。
|
|
37
|
-
- 本 Skill 不提供 MCP、变更、部署或公网包发布能力;`zhihu install codex` 只安装本地 Skill 文件。
|
|
53
|
+
- 本 Skill 不提供 MCP、变更、部署或公网包发布能力;`npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 install codex` 只安装本地 Skill 文件。
|
|
38
54
|
|
|
39
55
|
详细命令字段见 [references/commands.md](references/commands.md),错误处理见 [references/errors.md](references/errors.md),边界规则见 [references/safety.md](references/safety.md)。
|
|
@@ -1,33 +1,47 @@
|
|
|
1
1
|
# CLI 命令参考
|
|
2
2
|
|
|
3
|
-
所有调用都必须以 `--json` 结束或等价地启用 JSON
|
|
3
|
+
所有调用都必须以 `--json` 结束或等价地启用 JSON 模式;命令使用当前构建提供的本地 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4` runner。离线包不访问公网;公网测试包会在 staging 时替换为精确固定版本。只解析一个完整 envelope:成功看 `ok: true` 与 `data`,失败看 `ok: false`、`error.code`、`error.retryable`。
|
|
4
4
|
|
|
5
5
|
## 会话与能力
|
|
6
6
|
|
|
7
7
|
| 目的 | 命令 |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| 查看当前登录状态 | `zhihu auth status --json` |
|
|
10
|
-
| 查看能力范围 | `zhihu capabilities list --json` |
|
|
11
|
-
|
|
|
12
|
-
|
|
|
9
|
+
| 查看当前登录状态 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 auth status --json` |
|
|
10
|
+
| 查看能力范围 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 capabilities list --json` |
|
|
11
|
+
| 查看 A2A 只读能力 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a capabilities --json` |
|
|
12
|
+
| 查看可用数字员工 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 employees list --json` |
|
|
13
|
+
| 发起只读员工问答 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 employees chat <employee-id> --message <text> --json` |
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
## 自然语言默认路由
|
|
16
|
+
|
|
17
|
+
普通运维问题不要求用户先知道员工 ID。将原始问题映射到一个 capability,并只提交以下两个参数:
|
|
18
|
+
|
|
19
|
+
| 用户意图 | capability_id | 命令 |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| 资产、指标、采集状态 | `resource_query` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability resource_query --message <原始问题> --json` |
|
|
22
|
+
| 告警、故障、根因和恢复验证建议 | `incident_analysis` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability incident_analysis --message <原始问题> --json` |
|
|
23
|
+
| 巡检、健康检查和状态摘要 | `inspection_summary` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability inspection_summary --message <原始问题> --json` |
|
|
24
|
+
| 知识、案例、手册和 SOP | `knowledge_qa` | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a delegate --capability knowledge_qa --message <原始问题> --json` |
|
|
25
|
+
|
|
26
|
+
委派返回 opaque `task`、目标员工、状态、追踪字段和只读结论;需要复查时使用 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 a2a task get --id <opaque-task-id> --json`。不添加 `--employee`、`--target-agent`、`--source-agent`、`--tool`、`--root-session`、`--tenant` 或 `--user`。
|
|
27
|
+
|
|
28
|
+
普通 A2A 问答不要求用户知道员工 ID;只有用户明确要求直接与数字员工对话时,才确认可信员工 ID。`--message` 只描述查询,不描述变更。
|
|
15
29
|
|
|
16
30
|
## 资产、指标与告警
|
|
17
31
|
|
|
18
32
|
| 目的 | 命令 |
|
|
19
33
|
| --- | --- |
|
|
20
|
-
| 查资产 | `zhihu assets list [--keyword <text>] [--model <name|code|id>] --json` |
|
|
21
|
-
| 取资产 | `zhihu assets get --id <id> --json` |
|
|
22
|
-
| 查指标 | `zhihu metrics query --asset <id|ip> --metric <allowed-name> --window <5m..24h> --json` |
|
|
23
|
-
| 列告警 | `zhihu alarms list --status <all|firing|resolved> --json` |
|
|
24
|
-
| 取告警 | `zhihu alarms get --id <id> --json` |
|
|
34
|
+
| 查资产 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 assets list [--keyword <text>] [--model <name|code|id>] --json` |
|
|
35
|
+
| 取资产 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 assets get --id <id> --json` |
|
|
36
|
+
| 查指标 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 metrics query --asset <id|ip> --metric <allowed-name> --window <5m..24h> --json` |
|
|
37
|
+
| 列告警 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 alarms list --status <all|firing|resolved> --json` |
|
|
38
|
+
| 取告警 | `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 alarms get --id <id> --json` |
|
|
25
39
|
|
|
26
|
-
资产和告警 ID 必须来自用户或此前 CLI 返回;IP、指标和窗口必须满足 CLI
|
|
40
|
+
资产和告警 ID 必须来自用户或此前 CLI 返回;IP、指标和窗口必须满足 CLI 的白名单与上限。底层查询命令是显式结构化数据入口,不是自然语言任务的默认路径。
|
|
27
41
|
|
|
28
42
|
## 诊断与巡检
|
|
29
43
|
|
|
30
|
-
- 指定告警分析:`zhihu incidents diagnose --alarm-id <id> --json`
|
|
31
|
-
- 只读巡检摘要:`zhihu inspections run [--model <name|code|id>] [--window <5m..24h>] --json`
|
|
44
|
+
- 指定告警分析:`npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 incidents diagnose --alarm-id <id> --json`
|
|
45
|
+
- 只读巡检摘要:`npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 inspections run [--model <name|code|id>] [--window <5m..24h>] --json`
|
|
32
46
|
|
|
33
47
|
诊断和巡检结果是保守的结构化摘要。证据不足时报告不足,不补全设备、租户、权限或因果关系。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
常见处理:
|
|
6
6
|
|
|
7
|
-
- `AUTH_RELOGIN_REQUIRED`:提示用户运行 `zhihu auth login`,然后重试原查询。
|
|
7
|
+
- `AUTH_RELOGIN_REQUIRED`:提示用户运行 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4 auth login`,然后重试原查询。
|
|
8
8
|
- `FORBIDDEN`、`CAPABILITY_NOT_AVAILABLE`:说明当前账号没有所需范围,请用户联系管理员;不要尝试其他身份。
|
|
9
9
|
- `EMPLOYEE_NOT_FOUND`、`ASSET_NOT_FOUND`、`ALARM_NOT_FOUND`:让用户确认精确 ID;不要从相似名称猜测。
|
|
10
10
|
- `INCIDENT_ASSET_IDENTITY_UNAVAILABLE`、`ASSET_METRIC_IDENTITY_UNAVAILABLE`、`METRIC_DATA_NOT_FOUND`:报告目标无法安全关联或没有数据。
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# 安全边界
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- 唯一入口是当前构建提供的本地 `npx --yes @luckypiggy/zhihu-ai-cli@0.2.1-test.4` runner 的 JSON 命令。离线包不会访问公网;公网测试包会在 staging 时固定 runner。不要从本机配置、环境变量、凭据服务或日志读取认证材料。
|
|
4
4
|
- 不要直接访问智护 API、监控后端、容器地址或任意网络地址;不要改写请求地址、查询表达式、标签、租户或权限。
|
|
5
5
|
- 不执行额外系统命令,不操作主机、文件、进程、网络设备或部署;不要把 CLI 结果发送给外部服务。
|
|
6
|
-
-
|
|
7
|
-
-
|
|
6
|
+
- 只读范围包括认证状态、能力、A2A 四类只读委派、数字员工、资产、指标、告警、指定告警诊断和巡检。任何创建、删除、更新、重启、发布或变更请求都应拒绝并说明当前能力限制;`asset_onboarding`、`asset_discovery` 等写 capability 不可调用。
|
|
7
|
+
- A2A 默认路由只提交 `capability_id` 和用户原始问题,由 Pilot 服务端注册中心选择目标员工。不得生成或接受 `employee_id`、`target_agent_id`、`source_agent_id`、`requested_tools`、`root_session_id`、`turn_id`、`user_id`、`tenant_id` 或任意客户端身份字段。
|
|
8
|
+
- 用户意图映射固定为 `resource_query`(资产/指标/采集)、`incident_analysis`(告警/故障/根因)、`inspection_summary`(巡检/健康摘要)和 `knowledge_qa`(知识/案例/SOP)。命中多个意图、缺少必要对象或包含“查询并处理”等写/歧义请求时先澄清。
|
|
9
|
+
- 用户没有给出唯一目标时先询问:资产 ID、告警 ID、模型、指标、窗口和语言都不能凭空补全;只有用户明确要求直接员工对话时才询问员工 ID。
|
|
8
10
|
- 结果只保留回答所需的字段。不要输出本机路径、内部地址、完整请求、会话材料或未脱敏正文。
|
|
9
|
-
-
|
|
11
|
+
- 这是只读 Skill,不宣称 MCP、变更能力或公网包发布能力;离线构建使用本地 runner,公网测试构建使用固定版本 runner。
|
package/dist/auth-service.js
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
|
-
import { openSystemBrowser, validAuthorizationUrl } from "./browser.js";
|
|
2
1
|
import { HttpError } from "./http.js";
|
|
3
|
-
import {
|
|
4
|
-
import { withProfileLock } from "./profile-lock.js";
|
|
2
|
+
import { ProfileLockCancelledError, withProfileLock } from "./profile-lock.js";
|
|
5
3
|
import { CliAuthError, TokenManager, decodeClaims, mapFailure } from "./token-manager.js";
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { cliCommand } from "./release.js";
|
|
5
|
+
function cancellationError() {
|
|
6
|
+
return new CliAuthError("USER_CANCELLED", "Installation cancelled / 安装已取消", { exitCode: 2 });
|
|
7
|
+
}
|
|
8
|
+
function throwIfAborted(signal) {
|
|
9
|
+
if (signal?.aborted)
|
|
10
|
+
throw cancellationError();
|
|
11
|
+
}
|
|
12
|
+
const TERMINAL_AUTH_MESSAGES = {
|
|
13
|
+
AUTH_LOGIN_FAILED: "Zhihu login was rejected. Check the username and password and try again.",
|
|
14
|
+
AUTH_ACCOUNT_LOCKED: "Zhihu login is temporarily locked. Try again later or contact an administrator.",
|
|
15
|
+
AUTH_CAPTCHA_REQUIRED: "Zhihu login requires captcha verification. Complete the challenge and try again.",
|
|
16
|
+
NETWORK_ERROR: "Unable to reach the Zhihu service",
|
|
17
|
+
RATE_LIMITED: "The server is rate limiting requests; try again later.",
|
|
18
|
+
};
|
|
19
|
+
function mapTerminalFailure(error) {
|
|
20
|
+
if (error instanceof HttpError && TERMINAL_AUTH_MESSAGES[error.code]) {
|
|
21
|
+
return mapFailure(new HttpError(error.code, TERMINAL_AUTH_MESSAGES[error.code], {
|
|
22
|
+
retryable: error.retryable,
|
|
23
|
+
status: error.status,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
return mapFailure(error);
|
|
8
27
|
}
|
|
9
28
|
// ECMAScript Date values are only representable within this inclusive range.
|
|
10
29
|
// JWT NumericDate values outside it must not be allowed to make presentation
|
|
@@ -37,7 +56,7 @@ function safeExpiresAt(now, expiresIn, claims) {
|
|
|
37
56
|
return new Date(0).toISOString();
|
|
38
57
|
}
|
|
39
58
|
}
|
|
40
|
-
function displayFromToken(profile, token, expiresIn, now
|
|
59
|
+
function displayFromToken(profile, token, expiresIn, now) {
|
|
41
60
|
if (typeof token !== "string" || token.length === 0) {
|
|
42
61
|
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login token", { exitCode: 8 });
|
|
43
62
|
}
|
|
@@ -62,7 +81,6 @@ function displayFromToken(profile, token, expiresIn, now, browserOpened) {
|
|
|
62
81
|
...(tenant !== undefined ? { tenant_id: tenant } : {}),
|
|
63
82
|
scopes,
|
|
64
83
|
access_expires_at: safeExpiresAt(now, expiresIn, claims),
|
|
65
|
-
...(browserOpened === undefined ? {} : { browser_opened: browserOpened }),
|
|
66
84
|
};
|
|
67
85
|
}
|
|
68
86
|
export class AuthService {
|
|
@@ -70,27 +88,22 @@ export class AuthService {
|
|
|
70
88
|
client;
|
|
71
89
|
credentials;
|
|
72
90
|
profile;
|
|
73
|
-
browser;
|
|
74
|
-
onBrowserFailure;
|
|
75
|
-
wait;
|
|
76
91
|
now;
|
|
77
|
-
|
|
78
|
-
maxDelay;
|
|
92
|
+
environment;
|
|
79
93
|
constructor(client, credentials, profile, options = {}) {
|
|
80
94
|
this.client = client;
|
|
81
95
|
this.credentials = credentials;
|
|
82
96
|
this.profile = profile;
|
|
83
|
-
this.browser = options.browser ?? openSystemBrowser;
|
|
84
|
-
this.onBrowserFailure = options.onBrowserFailure;
|
|
85
|
-
this.wait = options.sleep ?? sleep;
|
|
86
97
|
this.now = options.now ?? Date.now;
|
|
87
|
-
this.
|
|
88
|
-
this.
|
|
89
|
-
this.tokenManager = new TokenManager(client, credentials, profile);
|
|
98
|
+
this.environment = options.environment;
|
|
99
|
+
this.tokenManager = new TokenManager(client, credentials, profile, { environment: this.environment });
|
|
90
100
|
}
|
|
91
|
-
async login() {
|
|
101
|
+
async login(credentials, options = {}) {
|
|
102
|
+
const signal = options.signal;
|
|
92
103
|
try {
|
|
104
|
+
throwIfAborted(signal);
|
|
93
105
|
return await withProfileLock(this.profile, async () => {
|
|
106
|
+
throwIfAborted(signal);
|
|
94
107
|
let existing;
|
|
95
108
|
try {
|
|
96
109
|
existing = await this.credentials.get();
|
|
@@ -99,79 +112,54 @@ export class AuthService {
|
|
|
99
112
|
throw mapFailure(error);
|
|
100
113
|
}
|
|
101
114
|
if (existing) {
|
|
102
|
-
throw new CliAuthError("AUTH_ALREADY_LOGGED_IN",
|
|
115
|
+
throw new CliAuthError("AUTH_ALREADY_LOGGED_IN", `This profile is already logged in; run ${cliCommand("auth", "logout")} first.`, { exitCode: 3 });
|
|
103
116
|
}
|
|
104
|
-
|
|
105
|
-
let started;
|
|
117
|
+
let outcome;
|
|
106
118
|
try {
|
|
107
|
-
|
|
119
|
+
outcome = await this.client.terminalLogin(credentials.username, credentials.password, credentials.tenant_id, credentials.captcha_verification, { signal });
|
|
108
120
|
}
|
|
109
121
|
catch (error) {
|
|
110
|
-
|
|
122
|
+
if (signal?.aborted || (error instanceof HttpError && error.code === "USER_CANCELLED")) {
|
|
123
|
+
throw cancellationError();
|
|
124
|
+
}
|
|
125
|
+
throw mapTerminalFailure(error);
|
|
111
126
|
}
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
const accessToken = outcome.access_token;
|
|
128
|
+
const refreshCredential = outcome.refresh_credential;
|
|
129
|
+
if (typeof accessToken !== "string" || accessToken.length === 0
|
|
130
|
+
|| typeof refreshCredential !== "string" || refreshCredential.length === 0) {
|
|
131
|
+
await this.compensateCompletedLogin(refreshCredential);
|
|
132
|
+
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login response", { exitCode: 8 });
|
|
114
133
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
catch (error) {
|
|
126
|
-
if (error instanceof HttpError && error.retryable && this.now() < deadline) {
|
|
127
|
-
await this.wait(Math.min(delay, Math.max(1, deadline - this.now())));
|
|
128
|
-
delay = Math.min(this.maxDelay, Math.ceil(delay * 1.7));
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
throw mapFailure(error);
|
|
132
|
-
}
|
|
133
|
-
if (outcome.status === "pending" || outcome.status === "callback_processing") {
|
|
134
|
-
await this.wait(Math.min(delay, Math.max(1, deadline - this.now())));
|
|
135
|
-
delay = Math.min(this.maxDelay, Math.ceil(delay * 1.7));
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (outcome.status === "failed") {
|
|
139
|
-
throw new CliAuthError(outcome.error_code || "AUTH_RELOGIN_REQUIRED", "Browser authorization was not completed; run zhihu auth login again.", { exitCode: 3 });
|
|
140
|
-
}
|
|
141
|
-
if (outcome.status !== "completed") {
|
|
142
|
-
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login response", { exitCode: 8 });
|
|
143
|
-
}
|
|
144
|
-
const accessToken = outcome.access_token;
|
|
145
|
-
const refreshCredential = outcome.refresh_credential;
|
|
146
|
-
if (typeof accessToken !== "string" || accessToken.length === 0
|
|
147
|
-
|| typeof refreshCredential !== "string" || refreshCredential.length === 0) {
|
|
148
|
-
await this.compensateCompletedLogin(refreshCredential);
|
|
149
|
-
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login response", { exitCode: 8 });
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
await this.credentials.set(refreshCredential);
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
await this.compensateCompletedLogin(refreshCredential);
|
|
156
|
-
throw new CliAuthError("AUTH_RELOGIN_REQUIRED", "Credential storage failed; run zhihu auth login again.", { exitCode: 3 });
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
return displayFromToken(this.profile, accessToken, outcome.expires_in ?? DEFAULT_EXPIRES_IN_SECONDS, this.now(), browserOpened);
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
await this.compensateCompletedLogin(refreshCredential);
|
|
163
|
-
if (error instanceof CliAuthError)
|
|
164
|
-
throw error;
|
|
165
|
-
// Presentation errors are a server/protocol problem, never a
|
|
166
|
-
// transport failure. Do not expose arbitrary error text because it
|
|
167
|
-
// could contain a token supplied by an embedding caller.
|
|
168
|
-
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login token", { exitCode: 8 });
|
|
169
|
-
}
|
|
134
|
+
try {
|
|
135
|
+
await this.credentials.set(refreshCredential);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
await this.compensateCompletedLogin(refreshCredential);
|
|
139
|
+
throw new CliAuthError("AUTH_RELOGIN_REQUIRED", `Credential storage failed; run ${cliCommand("auth", "login")} again.`, { exitCode: 3 });
|
|
140
|
+
}
|
|
141
|
+
if (signal?.aborted) {
|
|
142
|
+
await this.compensateCompletedLogin(refreshCredential);
|
|
143
|
+
throw cancellationError();
|
|
170
144
|
}
|
|
171
|
-
|
|
172
|
-
|
|
145
|
+
try {
|
|
146
|
+
return displayFromToken(this.profile, accessToken, outcome.expires_in ?? DEFAULT_EXPIRES_IN_SECONDS, this.now());
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
await this.compensateCompletedLogin(refreshCredential);
|
|
150
|
+
if (error instanceof CliAuthError)
|
|
151
|
+
throw error;
|
|
152
|
+
// Presentation errors are a server/protocol problem, never a
|
|
153
|
+
// transport failure. Do not expose arbitrary error text because it
|
|
154
|
+
// could contain a token supplied by an embedding caller.
|
|
155
|
+
throw new CliAuthError("PROTOCOL_ERROR", "The server returned an invalid login token", { exitCode: 8 });
|
|
156
|
+
}
|
|
157
|
+
}, { signal, environment: this.environment });
|
|
173
158
|
}
|
|
174
159
|
catch (error) {
|
|
160
|
+
if (error instanceof ProfileLockCancelledError || signal?.aborted) {
|
|
161
|
+
throw cancellationError();
|
|
162
|
+
}
|
|
175
163
|
throw mapFailure(error);
|
|
176
164
|
}
|
|
177
165
|
}
|