@openturtle/cli 0.3.2 → 0.3.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 CHANGED
@@ -12,7 +12,7 @@ OpenTurtle CLI 是一个本地命令行工具。它让你不安装 Desktop,也
12
12
  npm install --global @openturtle/cli
13
13
  ```
14
14
 
15
- CLI 启动时会在后台检查 npm 新版本,最多每 24 小时检查一次。检查不会阻塞当前命令;发现新版本后会通过 npm 自动完成全局升级。
15
+ CLI 启动时会在后台检查 npm 新版本,最多每 24 小时检查一次。检查不会阻塞当前命令;发现新版本后会通过 npm 自动完成全局升级,并刷新此前通过 `ot install` 安装的 Skill、Rule 和 Steering。
16
16
 
17
17
  也可以手动检查或立即升级:
18
18
 
@@ -27,7 +27,7 @@ ot update
27
27
  export OPENTURTLE_DISABLE_AUTO_UPDATE=1
28
28
  ```
29
29
 
30
- 源码运行、`pnpm link` 等开发安装不会被自动覆盖。自动更新状态记录在 `~/.openturtle/cli/update.json`。
30
+ 源码运行、`pnpm link` 等开发安装不会被自动覆盖。自动更新状态记录在 `~/.openturtle/cli/update.json`,Agent 安装记录保存在 `~/.openturtle/cli/installations.json`。
31
31
 
32
32
  临时使用、不全局安装时:
33
33
 
@@ -53,18 +53,14 @@ ot projects list
53
53
  ot roster list
54
54
  ot context get --project <project-id>
55
55
  ot knowledge search "部署"
56
+ ot knowledge local search "部署"
56
57
  ot meetings list --project <project-id>
58
+ ot work summary --project <project-id>
57
59
  ot worklogs record --summary "完成联调" --type progress
58
60
  ot report draft --today
59
61
  ```
60
62
 
61
- 如果你希望 AI 工具自动帮你记录开发过程,再执行:
62
-
63
- ```bash
64
- ot install --target all --with-agent-hooks
65
- ```
66
-
67
- hooks 只负责记录,不会阻止提交代码,也不会改变 AI 工具原本的行为。
63
+ `ot install` 只安装 CLI 使用指引。Agent 直接执行 `ot ... --json`,不需要 MCP 或 Hook。
68
64
 
69
65
  ## 常用场景
70
66
 
@@ -83,15 +79,22 @@ ot todos progress <todo-id> --message "完成接口联调,等待验收"
83
79
  ### 记录一条工作日志
84
80
 
85
81
  ```bash
86
- ot worklogs record --summary "完成 Qoder hook 接入验证" --type progress
82
+ ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress
87
83
  ```
88
84
 
89
- ### 搜索知识
85
+ ### 聚合搜索知识
90
86
 
91
87
  ```bash
92
88
  ot knowledge search "日报"
93
89
  ```
94
90
 
91
+ 默认同时搜索云端知识和本地全文索引。只搜索本地:
92
+
93
+ ```bash
94
+ ot knowledge search "日报" --local-only
95
+ ot knowledge local search "日报"
96
+ ```
97
+
95
98
  ### 上传录音并处理会议
96
99
 
97
100
  ```bash
@@ -182,7 +185,6 @@ ot auth logout
182
185
  | ----------------- | -------------------- |
183
186
  | CLI command | `ot` |
184
187
  | Package | `@openturtle/cli` |
185
- | MCP server name | `ot-cli` |
186
188
  | Project state dir | `.openturtle-cli/` |
187
189
  | Global state dir | `~/.openturtle/cli/` |
188
190
 
@@ -191,7 +193,6 @@ ot auth logout
191
193
  - CLI 项目状态只写 `.openturtle-cli/`
192
194
  - CLI 全局状态只写 `~/.openturtle/cli/`
193
195
  - 不要创建或写入项目 `.openturtle/`
194
- - 不要覆盖 Desktop 的 `openturtle-knowledge`
195
196
  - 不要覆盖 Desktop 的 `openturtle-automations`
196
197
  - 不要覆盖旧的 `openturtle-todo`
197
198
 
@@ -239,7 +240,6 @@ ot init --update-gitignore
239
240
  .openturtle-cli/
240
241
  ├── config.json
241
242
  ├── state.db
242
- ├── hooks/
243
243
  ├── drafts/
244
244
  └── cache/
245
245
  ```
@@ -289,22 +289,15 @@ ot auth status
289
289
 
290
290
  ### 5. 安装 Agent 接入
291
291
 
292
- 默认安装 MCP、rules/skills Git hook,不安装 Agent hooks
292
+ 安装 Agent CLI Skill、Rule Steering
293
293
 
294
294
  ```bash
295
295
  ot install --target all
296
296
  ```
297
297
 
298
- 安装 Agent hooks:
299
-
300
- ```bash
301
- ot install --target all --with-agent-hooks
302
- ```
303
-
304
298
  只安装某个目标:
305
299
 
306
300
  ```bash
307
- ot install --target git
308
301
  ot install --target claude
309
302
  ot install --target codex
310
303
  ot install --target cursor
@@ -336,92 +329,25 @@ ot uninstall --target kiro
336
329
  ot uninstall --target all
337
330
  ```
338
331
 
339
- 卸载只会删除 `ot-cli` MCP server、`OPENTURTLE-CLI` 托管 hook、CLI 写入的 rule/skill/steering/agent 文件,以及 `.openturtle-cli/` 本地状态目录。它会保留非 OpenTurtle 配置、用户自己的 hook、Desktop/旧版 MCP server,例如 `openturtle-knowledge`、`openturtle-automations`、`openturtle-todo`。
332
+ 卸载只会删除 CLI 写入的 rule/skill/steering/managed note,以及 `.openturtle-cli/` 本地状态目录。它会保留用户自己的 Agent 配置。
340
333
 
341
- 如果 Git 原来已有 `post-commit` hook,卸载会恢复原 hook,然后删除 OpenTurtle CLI 的备份文件。
334
+ 安装时会迁移旧版本:删除旧 `ot-cli` MCP `OPENTURTLE-CLI` 托管 Hook 条目,同时保留用户自己的 MCP server 和 Hook。`ot uninstall --target git` 仅作为旧版 Git Hook 的清理入口保留,已经不能再安装 Git Hook。
342
335
 
343
336
  ### 6. Target 安装矩阵
344
337
 
345
- | Target | 默认安装 | `--with-agent-hooks` |
346
- | ------ | --------------------------------------------- | ----------------------------------------------------------------------------- |
347
- | Git | `.git/hooks/post-commit` | 同默认 |
348
- | Claude | `ot-cli` MCP、Skill | `UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop` |
349
- | Codex | `ot-cli` MCP、Skill、`AGENTS.md` managed note | `PreToolUse`、`PostToolUse`、`Stop` |
350
- | Cursor | project `.mcp.json`、Cursor Rule | `preToolUse`、`postToolUse` |
351
- | Qoder | MCP、Skill | `UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`Stop` |
352
- | Kiro | MCP、Steering | `agentSpawn`、`userPromptSubmit`、`preToolUse`、`postToolUse`、`stop` |
353
-
354
- Qoder 和 Kiro 支持 native hook。CLI 仍保留 `import-history` 和 `watch`,用于补齐旧会话或未启用 hook 的环境。
355
-
356
- ### 7. Hooks 的作用
357
-
358
- hooks 是本地记录入口。它们把开发过程写入 `.openturtle-cli/state.db`,用于工作日志、待办进展证据和日报草稿。
338
+ | Target | 安装内容 |
339
+ | ------ | ------------------------------- |
340
+ | Claude | Skill |
341
+ | Codex | Skill、`AGENTS.md` managed note |
342
+ | Cursor | Cursor Rule |
343
+ | Qoder | Skill |
344
+ | Kiro | Steering |
359
345
 
360
- 会记录:
346
+ ### 7. CLI 接入模型
361
347
 
362
- - Git commit
363
- - 用户提交给 Agent 的 prompt
364
- - Agent tool call 前后
365
- - Agent tool call 失败
366
- - Agent session stop
367
- - history import 记录
348
+ 所有 Agent 都直接执行 `ot ... --json`。读取命令直接运行;写命令先加 `--dry-run` 检查请求,再执行正式写入。CLI 本身负责认证、后端访问、稳定 JSON、自动更新,以及升级后刷新已安装的 Agent 指引。
368
349
 
369
- 不会做:
370
-
371
- - 不阻止 Git commit
372
- - 不阻止 Agent tool call
373
- - 不替用户批准危险操作
374
- - 不上传私有文件内容
375
- - 不修改 Desktop MCP server
376
-
377
- Git hook 会保留已有 hook。原 hook 的退出码会保留,OpenTurtle 采集失败不会改变 commit 结果。
378
-
379
- ### 8. MCP server
380
-
381
- MCP server 名固定为:
382
-
383
- ```text
384
- ot-cli
385
- ```
386
-
387
- 启动:
388
-
389
- ```bash
390
- ot mcp serve
391
- ```
392
-
393
- tools:
394
-
395
- ```text
396
- list_my_todos
397
- list_goals
398
- list_workspace_knowledge
399
- search_workspace_knowledge
400
- list_knowledge_source_files
401
- read_knowledge_source_file
402
- record_worklog
403
- list_worklogs
404
- draft_daily_report
405
- update_todo_progress
406
- update_todo_status
407
- ```
408
-
409
- `list_workspace_knowledge` / `search_workspace_knowledge` 查询可复用知识对象。`list_knowledge_source_files` / `read_knowledge_source_file` 只查看知识背后的来源文件或原文文件,不把来源文件当成第二套知识库。
410
-
411
- MCP tools 优先访问 OpenTurtle API。云端不可用时,尽量返回本地缓存或本地草稿信息,并标记 `source: "local_cache"`。
412
-
413
- MCP smoke test:
414
-
415
- ```bash
416
- printf '%s\n' \
417
- '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
418
- '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
419
- | ot mcp serve
420
- ```
421
-
422
- 期望 `serverInfo.name` 是 `ot-cli`。
423
-
424
- ### 9. 资源命令
350
+ ### 8. 资源命令
425
351
 
426
352
  项目、团队成员和项目上下文:
427
353
 
@@ -430,6 +356,9 @@ ot projects list --keyword "OpenTurtle"
430
356
  ot projects resolve "OpenTurtle"
431
357
  ot projects show <project-id> --members
432
358
  ot roster list
359
+ ot roster list --project <project-id>
360
+ ot work summary --project <project-id>
361
+ ot digest get --project <project-id> --window this_week
433
362
  ot context get --project <project-id> --query "本周风险" --section risk
434
363
  ot context item meeting <meeting-id> --project <project-id>
435
364
  ```
@@ -463,6 +392,8 @@ ot todos review <todo-id> --body-file review-decision.json --dry-run
463
392
  ```bash
464
393
  ot knowledge list
465
394
  ot knowledge search "日报"
395
+ ot knowledge search "日报" --cloud-only
396
+ ot knowledge search "日报" --local-only
466
397
  ot knowledge show <knowledge-id>
467
398
  ot knowledge relations <knowledge-id>
468
399
  ot knowledge save --body-file knowledge.json --dry-run
@@ -479,9 +410,16 @@ ot knowledge attachment-download <knowledge-id> <attachment-id> --output ./desig
479
410
  ot knowledge sources --path docs
480
411
  ot knowledge sources --q "WPS"
481
412
  ot knowledge source docs/guide.md
413
+ ot knowledge local list
414
+ ot knowledge local search "部署规范"
415
+ ot knowledge local read <asset-id>
416
+ ot knowledge local import ./docs --dry-run
417
+ ot knowledge local create --body-file local-note.json --dry-run
418
+ ot knowledge local update <asset-id> --body-file local-note.json --dry-run
419
+ ot knowledge local remove <asset-id> --dry-run
482
420
  ```
483
421
 
484
- 知识对象是可复用的结论、规范、经验、决策沉淀和操作手册。来源文件是知识背后的原文、附件或仓库文档。
422
+ `ot knowledge search` 返回 `{ query, cloud, local }` 聚合结果;`--cloud-only` 和 `--local-only` 可限定范围。知识对象是可复用的结论、规范、经验、决策沉淀和操作手册。来源文件是知识背后的原文、附件或仓库文档,本地知识索引可脱离 Desktop 使用。
485
423
 
486
424
  会议:
487
425
 
@@ -508,8 +446,8 @@ ot meetings updates ignore <meeting-id> <update-id> --dry-run
508
446
 
509
447
  ```bash
510
448
  ot worklogs list --today
511
- ot worklogs record --summary "完成 Qoder hook 接入验证" --type progress
512
- ot worklogs record --summary "Codex hook trust 需要用户确认" --type blocker
449
+ ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress
450
+ ot worklogs record --summary "Codex CLI 登录需要用户确认" --type blocker
513
451
  ot worklogs create --body-file worklog.json --dry-run
514
452
  ```
515
453
 
@@ -529,26 +467,7 @@ ot report draft --today
529
467
  ot report draft --today --output .openturtle-cli/drafts/today.md
530
468
  ```
531
469
 
532
- ### 10. 历史导入与监听
533
-
534
- 一次性导入:
535
-
536
- ```bash
537
- ot import-history --target qoder
538
- ot import-history --target kiro
539
- ot import-history --target all
540
- ```
541
-
542
- 查看 watcher 路径:
543
-
544
- ```bash
545
- ot watch --target qoder
546
- ot watch --target kiro
547
- ```
548
-
549
- v1 优先使用 native hook。`import-history` 和 `watch` 是兜底能力。
550
-
551
- ### 11. AI Agent 推荐流程
470
+ ### 9. AI Agent 推荐流程
552
471
 
553
472
  当你需要在一个新工作区启用 CLI:
554
473
 
@@ -560,12 +479,6 @@ ot install --target all
560
479
  ot --json doctor
561
480
  ```
562
481
 
563
- 只有用户明确要求自动记录 Agent 行为时,才执行:
564
-
565
- ```bash
566
- ot install --target all --with-agent-hooks
567
- ```
568
-
569
482
  然后优先使用高层命令:
570
483
 
571
484
  ```bash
@@ -580,21 +493,19 @@ ot report draft --today
580
493
 
581
494
  不要直接改 `.openturtle-cli/state.db`,除非用户明确要求底层排查。
582
495
 
583
- ### 12. AI Agent 禁止事项
496
+ ### 10. AI Agent 禁止事项
584
497
 
585
498
  - 不要写项目 `.openturtle/`
586
- - 不要覆盖 `openturtle-knowledge`
587
499
  - 不要覆盖 `openturtle-automations`
588
500
  - 不要覆盖旧 `openturtle-todo`
589
501
  - 不要删除用户已有 Agent 配置
590
502
  - 不要把 token 写入代码、README、commit 或日志
591
- - 不要让 hook 阻塞 Git commit 或 Agent tool call
592
- - 不要伪造 Codex hook trust state
503
+ - 不要安装或调用旧版 OpenTurtle MCP/Hook
593
504
  - 不要在会议 Knowledge 尚未发布时确认项目更新
594
505
  - 不要跳过 `meetings updates list` 直接批量确认会议草稿
595
506
  - 不要修改 Qoder/Kiro 私有未知格式文件;只写本文列出的配置面
596
507
 
597
- ### 13. JSON 输出约定
508
+ ### 11. JSON 输出约定
598
509
 
599
510
  CLI 默认输出 JSON,便于 AI Agent 读取。
600
511
 
@@ -624,7 +535,7 @@ CLI 默认输出 JSON,便于 AI Agent 读取。
624
535
 
625
536
  token 不应该被完整打印,`auth status` 只显示脱敏 token。
626
537
 
627
- ### 14. 开发验证
538
+ ### 12. 开发验证
628
539
 
629
540
  在 `frontend` 目录执行:
630
541
 
@@ -642,7 +553,9 @@ npm pack --dry-run
642
553
 
643
554
  期望包内只包含 `dist/`、`README.md` 和 `package.json` 等运行所需文件,不包含 `src/` 或 `test/`。
644
555
 
645
- ### 15. npm 自动发布
556
+ ### 13. npm 自动发布
557
+
558
+ 完整的校验、Trusted Publisher、人工兜底、npm 二次认证、远端 `master` 对齐和 Skill 刷新检查见 [RELEASE_RUNBOOK.md](./RELEASE_RUNBOOK.md)。
646
559
 
647
560
  `.github/workflows/cli-npm-release.yml` 会在 `master` 的 CLI 文件发生变化时运行测试和构建,
648
561
  然后以仓库版本为最低版本、基于 npm 已发布版本自动递增 patch,发布公开包 `@openturtle/cli`。
@@ -659,28 +572,15 @@ npm pack --dry-run
659
572
  创建包并配置 Trusted Publisher 后,后续 `master` 发布只使用短期 OIDC 凭证。发布固定使用
660
573
  `https://registry.npmjs.org/`,不受开发机 `npmmirror` 配置影响。
661
574
 
662
- 构建后 MCP smoke test:
663
-
664
- ```bash
665
- printf '%s\n' \
666
- '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
667
- '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
668
- | node apps/cli/dist/index.js mcp serve
669
- ```
670
-
671
575
  ## 常见问题
672
576
 
673
577
  ### 我没有安装 Desktop,可以用吗?
674
578
 
675
579
  可以。CLI 的目标就是让没有 Desktop 的用户也能使用 OpenTurtle。
676
580
 
677
- ### 安装 hook 会不会影响我提交代码?
678
-
679
- 不会。它只记录信息,记录失败也不会改变提交结果。
680
-
681
- ### Qoder 和 Kiro 支持 hook 吗?
581
+ ### 为什么升级 CLI 后 Skill 也会更新?
682
582
 
683
- 支持。Qoder 使用 settings hook;Kiro 使用 hooks/agent 配置。
583
+ `ot install` 会记录安装过的 target、scope 和工作区。手动执行 `ot update` 或启动时自动更新 npm 包后,新版 CLI 会重新写入这些 Skill、Rule 和 Steering,并清理旧的 OpenTurtle MCP/Hook 配置。
684
584
 
685
585
  ### 为什么不用 `.openturtle/`?
686
586
 
@@ -0,0 +1,193 @@
1
+ # OpenTurtle CLI Release Runbook
2
+
3
+ This runbook publishes `@openturtle/cli` to the public npm registry and verifies that the installed `ot` command and companion Agent guidance are usable outside the source repository.
4
+
5
+ ## Release Boundaries
6
+
7
+ - Package: `@openturtle/cli`
8
+ - Binary: `ot`
9
+ - Registry: `https://registry.npmjs.org/`
10
+ - Source: `packages/frontend/apps/cli`
11
+ - Release branch: `master`
12
+ - Workflow: `.github/workflows/cli-npm-release.yml`
13
+ - Authentication: npm Trusted Publisher in CI; npm browser authentication for manual fallback
14
+
15
+ The package is CLI + Skill/Rule/Steering only. It must not ship the removed OpenTurtle MCP server, Hook commands, Git Hook installer, or history watcher.
16
+
17
+ ## Prerequisites
18
+
19
+ Run from the repository root unless a command says otherwise.
20
+
21
+ ```bash
22
+ node --version
23
+ pnpm --version
24
+ npm --version
25
+ git status --short
26
+ npm view @openturtle/cli version --registry=https://registry.npmjs.org
27
+ ```
28
+
29
+ Requirements:
30
+
31
+ - Node.js satisfies `packages/frontend/apps/cli/package.json#engines`.
32
+ - Dependencies are installed from the repository lockfile.
33
+ - CLI changes are isolated from unrelated worktree changes.
34
+ - The intended release commit is present on both GitLab and GitHub `master` before declaring source delivery complete.
35
+ - npm Trusted Publisher points to `aka-danielZhang/openturtle-os` and `cli-npm-release.yml`.
36
+
37
+ Never stage unrelated Desktop, backend, mobile, generated local state, or `.openturtle-cli/` files with a CLI release.
38
+
39
+ ## Required Validation
40
+
41
+ ```bash
42
+ cd packages/frontend
43
+ pnpm install --frozen-lockfile
44
+ pnpm --filter @openturtle/cli test
45
+ pnpm --filter @openturtle/cli build
46
+
47
+ cd apps/cli
48
+ npm pack --dry-run --json --registry=https://registry.npmjs.org
49
+ ```
50
+
51
+ The tarball must contain `dist/index.js`, runtime modules, `README.md`, and `package.json`. It must not contain any of these removed runtime files:
52
+
53
+ ```text
54
+ dist/mcp/server.js
55
+ dist/commands/hook.js
56
+ dist/installers/git.js
57
+ dist/watchers/importers.js
58
+ ```
59
+
60
+ The build script deletes `dist` before TypeScript compilation so removed source files cannot survive as stale package artifacts.
61
+
62
+ ## Normal Release: GitHub Actions
63
+
64
+ The normal path is a push to GitHub `master` that changes the CLI package or root lockfile.
65
+
66
+ 1. Merge the validated CLI commit into `master` without including unrelated files.
67
+ 2. Push `master` to GitLab and GitHub.
68
+ 3. Confirm `.github/workflows/cli-npm-release.yml` starts on GitHub.
69
+ 4. Wait for test, build, version resolution, package inspection, and publish steps to complete.
70
+ 5. Verify the published package from npm, not only the workflow status.
71
+
72
+ The workflow treats the repository package version as a floor. If npm already has that version or a newer one, `nextReleaseVersion()` increments the published patch version. The workflow does not require `NPM_TOKEN` or `NODE_AUTH_TOKEN`.
73
+
74
+ Verification:
75
+
76
+ ```bash
77
+ npm view @openturtle/cli version dist.tarball dist.shasum --json \
78
+ --registry=https://registry.npmjs.org
79
+ ```
80
+
81
+ Do not declare completion while the workflow is queued, running, or blocked by GitHub billing. Use the manual fallback when CI cannot start and the release is required immediately.
82
+
83
+ ## Manual Fallback
84
+
85
+ Use this only when Trusted Publisher CI is unavailable or when an explicitly requested release must happen before the `master` merge.
86
+
87
+ 1. Confirm npm login and the currently published version:
88
+
89
+ ```bash
90
+ npm whoami --registry=https://registry.npmjs.org
91
+ npm view @openturtle/cli version --registry=https://registry.npmjs.org
92
+ ```
93
+
94
+ 2. Set `packages/frontend/apps/cli/package.json` to an unused stable version.
95
+ 3. Run the required validation above.
96
+ 4. Publish from the package directory:
97
+
98
+ ```bash
99
+ cd packages/frontend/apps/cli
100
+ npm publish --access public --registry=https://registry.npmjs.org
101
+ ```
102
+
103
+ 5. Complete npm's browser authentication when prompted. A successful terminal result contains:
104
+
105
+ ```text
106
+ + @openturtle/cli@<version>
107
+ ```
108
+
109
+ 6. Verify the exact published version and tarball metadata:
110
+
111
+ ```bash
112
+ npm view @openturtle/cli@<version> version dist.tarball dist.shasum --json \
113
+ --registry=https://registry.npmjs.org
114
+ ```
115
+
116
+ After a manual publish, still merge and push the exact source to both `master` branches. A later CI run may publish the next patch because the workflow always chooses an unused version.
117
+
118
+ ## Installed Package Smoke Test
119
+
120
+ Test the public package from a temporary directory, not only from the repository:
121
+
122
+ ```bash
123
+ release_tmp="$(mktemp -d)"
124
+ cd "$release_tmp"
125
+ pnpm dlx @openturtle/cli@<version> --help
126
+ pnpm dlx @openturtle/cli@<version> --json doctor
127
+ ```
128
+
129
+ For a global-install smoke test:
130
+
131
+ ```bash
132
+ npm install --global @openturtle/cli@<version> \
133
+ --registry=https://registry.npmjs.org
134
+ command -v ot
135
+ ot --version
136
+ ot --json doctor
137
+ ```
138
+
139
+ `doctor` may report missing authentication, but it must return stable JSON rather than crash.
140
+
141
+ ## Skill Refresh Verification
142
+
143
+ `ot install` records Agent installations in `~/.openturtle/cli/installations.json`. Both `ot update` and the startup auto-update worker reinstall the recorded Skill, Rule, or Steering after npm updates.
144
+
145
+ Verify at least one installed target:
146
+
147
+ ```bash
148
+ ot install --target codex --scope user
149
+ ot update --check
150
+ ```
151
+
152
+ After an actual version update, confirm the installed Skill contains the new direct CLI guidance:
153
+
154
+ ```bash
155
+ rg -n "ot --json doctor|ot \.\.\. --json" ~/.codex/skills/openturtle-cli/SKILL.md
156
+ ```
157
+
158
+ Installation and refresh must also remove only the legacy OpenTurtle-managed `ot-cli` MCP and `OPENTURTLE-CLI` Hook entries. User-owned MCP servers, Hooks, rules, and settings must remain intact.
159
+
160
+ ## Source Delivery Verification
161
+
162
+ Before closing the release, compare the intended commit with both remotes:
163
+
164
+ ```bash
165
+ git ls-remote --heads gitlab master
166
+ git ls-remote --heads origin master
167
+ git log -1 --oneline master
168
+ ```
169
+
170
+ If the remotes differ, inspect ancestry and merge rather than force-pushing:
171
+
172
+ ```bash
173
+ git merge-base --is-ancestor <gitlab-master> <release-commit>
174
+ git merge-base --is-ancestor <github-master> <release-commit>
175
+ ```
176
+
177
+ Report all of the following:
178
+
179
+ - Published npm version and tarball shasum
180
+ - Test/build/package inspection result
181
+ - GitLab `master` commit
182
+ - GitHub `master` commit
183
+ - Workflow result or the reason manual fallback was used
184
+ - Installed `ot --version` and Skill refresh result
185
+
186
+ ## Failure Recovery
187
+
188
+ - `npm publish` reports an existing version: choose a new stable version; never reuse or overwrite an npm version.
189
+ - Browser authentication expires: rerun `npm publish` and complete the newly generated npm authentication URL.
190
+ - CI cannot start because of billing: use the manual fallback, then still merge the source to `master`.
191
+ - Package contains removed files: ensure the build cleans `dist`, rebuild, and repeat `npm pack --dry-run --json`.
192
+ - Skill is stale after update: inspect `~/.openturtle/cli/installations.json`, rerun `ot install --target <agent> --scope <scope>`, then verify the installed Skill/Rule/Steering.
193
+ - One remote `master` is ahead: fetch both remotes, inspect commits, merge in a clean worktree, and push without force.
@@ -29,17 +29,73 @@ export function createCollaborationCommands(client = new ApiClient()) {
29
29
  candidates: exact ? [] : items,
30
30
  };
31
31
  },
32
- async listRoster(teamId) {
32
+ async listRoster(teamId, projectId) {
33
33
  const team = teamId ? { id: teamId } : await client.get('/api/teams/me');
34
34
  const resolvedTeamId = String(team.id || teamId || '');
35
35
  if (!resolvedTeamId)
36
36
  throw new Error('Current team response did not include an id');
37
- const [members, profile, rosterProfile] = await Promise.all([
37
+ const [members, profile, rosterProfile, projectMembers] = await Promise.all([
38
38
  client.get(`/api/teams/${encodeURIComponent(resolvedTeamId)}/members`, { page_size: 100 }),
39
39
  client.get('/api/me/profile').catch(() => null),
40
40
  client.get('/api/me/roster-profile').catch(() => null),
41
+ projectId
42
+ ? client.get(`/api/projects/${encodeURIComponent(projectId)}/members`).catch(() => null)
43
+ : Promise.resolve(null),
41
44
  ]);
42
- return { team, profile, roster_profile: rosterProfile, members };
45
+ return { team, profile, roster_profile: rosterProfile, project_id: projectId || null, members, project_members: projectMembers };
46
+ },
47
+ async getWorkSummary(options) {
48
+ const limit = Number(options.limit) || 20;
49
+ const goalId = String(options.goal || '');
50
+ const projectId = String(options.project || '');
51
+ const todos = goalId
52
+ ? client.get(`/api/goals/${encodeURIComponent(goalId)}/todos`, {
53
+ status: options.status,
54
+ page: 1,
55
+ page_size: limit,
56
+ })
57
+ : client.get('/api/todos', {
58
+ scope: 'assigned',
59
+ project_id: projectId || undefined,
60
+ status: options.status,
61
+ page: 1,
62
+ page_size: limit,
63
+ });
64
+ const [digest, todoPage, notifications] = await Promise.all([
65
+ client.get('/api/goals/daily-digest/me'),
66
+ todos,
67
+ options.notifications === false
68
+ ? Promise.resolve(null)
69
+ : client.get('/api/notifications', { is_read: false, page: 1, page_size: limit }),
70
+ ]);
71
+ return {
72
+ project_id: projectId || null,
73
+ goal_id: goalId || null,
74
+ digest,
75
+ todos: todoPage,
76
+ notifications,
77
+ };
78
+ },
79
+ getProjectDigest: (projectId, window) => client.get('/api/digest', { project_id: projectId, window }),
80
+ async runOrgSyncSynthesis(options, dryRun = false) {
81
+ const scope = String(options.scope || 'active-project');
82
+ const projectId = String(options.project || '');
83
+ if (scope !== 'all' && !projectId)
84
+ throw new Error('--project is required unless --scope all is used');
85
+ const body = listQuery({
86
+ project_id: scope === 'all' ? undefined : projectId,
87
+ limit: options.limit,
88
+ updated_after: options.updatedAfter,
89
+ });
90
+ if (dryRun)
91
+ return dryRunRequest('POST', '/api/orgsync-synthesis/run', body);
92
+ const result = await client.post('/api/orgsync-synthesis/run', body);
93
+ return {
94
+ scope: scope === 'all' ? 'all' : 'active_project',
95
+ project_id: scope === 'all' ? null : projectId,
96
+ updated_after: options.updatedAfter || null,
97
+ result,
98
+ };
43
99
  },
44
100
  resolveContext: (body) => client.post('/api/project-context/resolve', body),
45
101
  getContextItem: (sourceType, sourceId, options) => client.get(`/api/project-context/items/${encodeURIComponent(sourceType)}/${encodeURIComponent(sourceId)}`, listQuery(options)),
@@ -127,7 +183,35 @@ export function registerCollaborationCommands(program, groups, callbacks) {
127
183
  .description('Current team roster')
128
184
  .command('list')
129
185
  .option('--team <id>')
130
- .action(action(async (options) => print(await commands.listRoster(options.team))));
186
+ .option('--project <id>', 'include project roles and membership')
187
+ .action(action(async (options) => print(await commands.listRoster(options.team, options.project))));
188
+ program
189
+ .command('work')
190
+ .description('Current user action summary')
191
+ .command('summary')
192
+ .option('--project <id>')
193
+ .option('--goal <id>')
194
+ .option('--status <status>')
195
+ .option('--limit <number>', 'maximum todos and notifications', Number)
196
+ .option('--no-notifications')
197
+ .action(action(async (options) => print(await commands.getWorkSummary(options))));
198
+ program
199
+ .command('digest')
200
+ .description('Project execution digest')
201
+ .command('get')
202
+ .option('--project <id>')
203
+ .option('--window <window>', 'today|yesterday|this_week|last_week|this_month', 'today')
204
+ .action(action(async (options) => print(await commands.getProjectDigest(options.project, options.window))));
205
+ program
206
+ .command('orgsync')
207
+ .description('Generate reviewable organization knowledge candidates')
208
+ .command('synthesize')
209
+ .option('--scope <scope>', 'active-project|all', 'active-project')
210
+ .option('--project <id>')
211
+ .option('--limit <number>', 'maximum recent sessions', Number, 20)
212
+ .option('--updated-after <iso-time>')
213
+ .option('--dry-run')
214
+ .action(action(async (options) => print(await commands.runOrgSyncSynthesis(options, Boolean(options.dryRun)))));
131
215
  const context = program.command('context').description('Viewer-scoped project context');
132
216
  context
133
217
  .command('get')