protara 0.0.0-stage → 0.3.6

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 CHANGED
@@ -1,3 +1,103 @@
1
- # Temporary Holding Version
1
+ # protara
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Protara 的**终端客户端**:在终端里与 Agent 对话、跑本机工具、按需审批。无 GUI、可管道、退出码规范。
4
+
5
+ 与桌面端共用同一份内核(同一套会话 / 权限判定 / 工具执行),区别只在呈现层。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm i -g protara
11
+ protara --version
12
+ ```
13
+
14
+ 要求 **Node.js ≥ 22.6**。
15
+
16
+ > 如果你之前在本仓里 `npm link` 过,先 `npm unlink -g protara`,否则跑的还是仓库那份。
17
+
18
+ ## 第一次用:先登录
19
+
20
+ CLI 用**独立的**登录态(`credentials.cli.json`),不与桌面端共享 —— 服务端的刷新令牌一次一换,共用一份会互相踢下线。
21
+
22
+ ```bash
23
+ protara --login # 走设备码:浏览器里确认一下就完成
24
+ protara status # 查登录态 / 凭据路径 / 终端指纹(排障入口)
25
+ ```
26
+
27
+ ## 用法
28
+
29
+ ```bash
30
+ protara # 交互界面(需要真 TTY)
31
+ protara -p "帮我看下这个仓库" # 一次性提问;stdout 只有答案正文
32
+ cat log.txt | protara -p - # 从管道读正文
33
+ protara --json -p "…" # NDJSON 事件流(给脚本)
34
+ protara --resume-last -p "继续" # 续最近一条会话
35
+ protara -C ~/proj --permission standard -p "跑一下测试"
36
+ protara --help # 全部参数 + 退出码表
37
+ ```
38
+
39
+ ### 三种输出形态
40
+
41
+ | 形态 | 用途 | stdout 内容 |
42
+ |---|---|---|
43
+ | 默认(TTY) | 人读 | 交互界面 |
44
+ | `-p "…"` | 脚本 / 管道 | **只有答案正文**(逐字节) |
45
+ | `--json` | 机器解析 | NDJSON 事件流,每行一个 JSON |
46
+
47
+ `-p` 模式下 **stdout 保证纯净**:所有诊断走 stderr 且带 `protara:` 前缀,或写进日志文件。
48
+
49
+ ### 退出码
50
+
51
+ | 码 | 含义 |
52
+ |---|---|
53
+ | 0 | 回合正常收尾 |
54
+ | 1 | 回合失败或被停止 |
55
+ | 2 | 用法错误 |
56
+ | 3 | 未登录 / 凭据失效 |
57
+ | 4 | 配额用尽 |
58
+ | 5 | 审批未通过 |
59
+ | 6 | 连接中断且无法附着 |
60
+ | 7 | 会话 / Agent / 模型不存在 |
61
+ | 130 | 收到 Ctrl-C(会先收掉本机后台进程) |
62
+
63
+ ### 审批
64
+
65
+ 管道和 CI 里没人能点确认框 ⇒ 默认立即按「未通过」结算(退出码 5)。要用更宽的权限,用
66
+ `--permission <档位>` 在**建会话时**声明,或用 `--approval=remote` 在浏览器里点。
67
+
68
+ ⛔ 没有 `--yolo`:这个客户端不提供跳过审批的开关。
69
+
70
+ ## 日志
71
+
72
+ 诊断**默认写文件,不打到终端**(否则会把对话流冲散):
73
+
74
+ ```
75
+ $DESKTOP_HOME/logs/cli.log # 默认 ~/.desktop-agents/logs/cli.log
76
+ ```
77
+
78
+ - 按大小轮转(5 MB × 3 份)
79
+ - `error` 级别带调用栈,`info` / `warn` 不带
80
+ - 想当场看到诊断:`protara -v …`(`--verbose`)
81
+
82
+ ## 三条需要预先知道的代价
83
+
84
+ 1. **要单独登录一次**:CLI 与桌面端各用一份凭据(刷新令牌一次一换,共用会互相踢下线)。
85
+ 2. **连接器(MCP)的授权不跨客户端共享**:配置共享,但令牌不共享 ⇒ CLI 里每个 HTTP
86
+ 连接器要重新「去认证」一次。
87
+ 3. **凭据目前是明文 `0600` 文件**(refresh 令牌寿命 30 天)。在共享机器上慎用 `--login`。
88
+
89
+ ## 当前未支持
90
+
91
+ 连接器「去认证」交互面板、计划条、作业角标面板、diff 分页、图片拖入、多行编辑框
92
+ (TUI 逐行提交)、Windows 上的沙箱助手。
93
+
94
+ ## 环境变量
95
+
96
+ | 变量 | 作用 |
97
+ |---|---|
98
+ | `DESKTOP_HOME` | 机器级根目录(默认 `~/.desktop-agents`):账号、技能、日志都在这里 |
99
+ | `PROTARA_ORIGIN` | 平台地址(等价于 `--origin`) |
100
+
101
+ ## 许可
102
+
103
+ `UNLICENSED` —— 内部工具,不授权外部分发。
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `protara` 的可执行入口(`bin/protara`)。
4
+ *
5
+ * ⚠️ 这是一个**极薄的垫片**,只有三件事:找到产物、调它、把退出码带出去。
6
+ * 所有逻辑都在 `dist/cli/index.cjs`(由 `scripts/build-main.mjs` 产出)。
7
+ *
8
+ * ## 为什么需要这一层(而不是直接 `main: dist/cli/index.cjs`)
9
+ *
10
+ * 1. `dist/cli/index.cjs` 是 **CJS**(包是 `type: module`,所以扩展名必须是 `.cjs`),
11
+ * 而 `bin` 的 shebang 指向 `node` —— 中间必须有一个能 `require` 的入口;
12
+ * 2. **产物不存在时要给人话**(「请先 npm run build」),而不是
13
+ * `Cannot find module '…/dist/cli/index.cjs'` 这种把用户劝退的栈;
14
+ * 3. 退出码必须**显式**传出去(`process.exitCode = …`),否则一律是 0 —— 那会让
15
+ * 所有 CI 判据变成假绿。
16
+ */
17
+ import { existsSync } from 'node:fs'
18
+ import { dirname, join } from 'node:path'
19
+ import { fileURLToPath } from 'node:url'
20
+
21
+ const here = dirname(fileURLToPath(import.meta.url))
22
+ const bundle = join(here, '..', 'dist', 'cli', 'index.cjs')
23
+
24
+ if (!existsSync(bundle)) {
25
+ process.stderr.write(
26
+ 'protara: 还没有构建产物(dist/cli/index.cjs)。\n' +
27
+ 'protara: 在仓库里跑一次 `npm run build:main` 即可。\n',
28
+ )
29
+ process.exitCode = 2 // 用法 / 环境错误,⛔ 不是「回合失败」
30
+ } else {
31
+ const mod = await import(bundle)
32
+ const code = await mod.guardedMain(process.argv.slice(2))
33
+ process.exitCode = code
34
+ }