@openturtle/cli 0.3.5 → 0.3.7

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
@@ -56,7 +56,7 @@ ot knowledge search "部署"
56
56
  ot knowledge local search "部署"
57
57
  ot meetings list --project <project-id>
58
58
  ot work summary --project <project-id>
59
- ot worklogs record --summary "完成联调" --type progress
59
+ ot worklogs record --summary "完成联调" --type progress --todo <todo-id>
60
60
  ot report draft --today
61
61
  ```
62
62
 
@@ -79,7 +79,7 @@ ot todos progress <todo-id> --message "完成接口联调,等待验收"
79
79
  ### 记录一条工作日志
80
80
 
81
81
  ```bash
82
- ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress
82
+ ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress --todo <todo-id>
83
83
  ```
84
84
 
85
85
  ### 聚合搜索知识
@@ -446,7 +446,7 @@ ot meetings updates ignore <meeting-id> <update-id> --dry-run
446
446
 
447
447
  ```bash
448
448
  ot worklogs list --today
449
- ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress
449
+ ot worklogs record --summary "完成 Qoder CLI 接入验证" --type progress --todo <todo-id>
450
450
  ot worklogs record --summary "Codex CLI 登录需要用户确认" --type blocker
451
451
  ot worklogs create --body-file worklog.json --dry-run
452
452
  ```
@@ -487,7 +487,7 @@ ot projects resolve "项目名"
487
487
  ot context get --project <project-id>
488
488
  ot meetings list --project <project-id>
489
489
  ot todos progress <todo-id> --message "..."
490
- ot worklogs record --summary "..." --type progress
490
+ ot worklogs record --summary "..." --type progress --todo <todo-id>
491
491
  ot report draft --today
492
492
  ```
493
493
 
@@ -21,7 +21,7 @@ export function createResourceCommands(client = new ApiClient()) {
21
21
  return client.patch(`/api/todos/${encodeURIComponent(todoId)}/status`, { status });
22
22
  },
23
23
  async updateTodoProgress(todoId, message) {
24
- return client.patch(`/api/todos/${encodeURIComponent(todoId)}/progress-description`, {
24
+ return client.put(`/api/todos/${encodeURIComponent(todoId)}/progress-description`, {
25
25
  progress_description: message,
26
26
  });
27
27
  },
@@ -31,6 +31,16 @@ export function createResourceCommands(client = new ApiClient()) {
31
31
  async showKnowledge(knowledgeId) {
32
32
  return client.get(`/api/memory/objects/${encodeURIComponent(knowledgeId)}`);
33
33
  },
34
+ async rememberKnowledge(options) {
35
+ return client.post('/api/memory/remember', {
36
+ what: options.what,
37
+ why: options.why ?? '',
38
+ how_to_apply: options.howToApply ?? '',
39
+ kind: options.kind ?? 'note',
40
+ scope: options.scope ?? 'org',
41
+ project_id: options.project,
42
+ });
43
+ },
34
44
  async searchKnowledge(keyword, options = {}) {
35
45
  return client.get('/api/memory/search', listQuery({
36
46
  q: keyword,
@@ -49,14 +59,33 @@ export function createResourceCommands(client = new ApiClient()) {
49
59
  async listWorklogs(options) {
50
60
  return client.get('/api/work-logs', listQuery(options));
51
61
  },
52
- async recordWorklog(summary, type = 'note') {
62
+ async recordWorklog(summary, type = 'note', references = {}) {
53
63
  return client.post('/api/work-logs', {
64
+ ...(references.project ? { project_id: references.project } : {}),
65
+ ...(references.goal ? { goal_id: references.goal } : {}),
66
+ ...(references.todo ? { todo_id: references.todo } : {}),
54
67
  summary,
55
68
  event_type: type,
56
69
  source: 'manual',
57
70
  metadata: { source_client: 'ot-cli' },
58
71
  });
59
72
  },
73
+ async listEvolutionReports(options) {
74
+ return client.get('/api/memory/evolution/reports', listQuery(options));
75
+ },
76
+ async triggerEvolution() {
77
+ // 找到「组织记忆自进化」内置 job 并手动触发一次(异步执行,立即返回)。
78
+ const res = await client.get('/api/system-config/scheduled-jobs', {
79
+ page: 1,
80
+ page_size: 100,
81
+ });
82
+ const jobs = res?.items ?? res ?? [];
83
+ const job = jobs.find((j) => j.handler === 'memory_org_evolution');
84
+ if (!job)
85
+ throw new Error('未找到「组织记忆自进化」定时任务(handler=memory_org_evolution)');
86
+ await client.post(`/api/system-config/scheduled-jobs/${job.id}/trigger`, {});
87
+ return { triggered: true, job: { id: job.id, name: job.name, cron: job.cron } };
88
+ },
60
89
  };
61
90
  }
62
91
  function knowledgeQuery(options) {
@@ -42,6 +42,9 @@ export class ApiClient {
42
42
  patch(path, body) {
43
43
  return this.request('PATCH', path, body);
44
44
  }
45
+ put(path, body) {
46
+ return this.request('PUT', path, body);
47
+ }
45
48
  delete(path, body) {
46
49
  return this.request('DELETE', path, body);
47
50
  }
package/dist/index.js CHANGED
@@ -250,6 +250,24 @@ knowledge
250
250
  .option('--json')
251
251
  .action(action(async (filePath, options) => print(await resources.readKnowledgeSource(filePath), options.json)));
252
252
  registerLocalKnowledgeCommands(knowledge, { print, fatal });
253
+ program
254
+ .command('remember')
255
+ .description('随手记一条团队记忆(坑/决策/真相),进草稿待 AI 审核')
256
+ .requiredOption('--what <fact>', '一句话原子事实,如「溯源接口在测试环境会 404」')
257
+ .option('--why <reason>', '为什么值得记(根因/决策理由)')
258
+ .option('--how-to-apply <action>', '下次怎么用(避坑动作/决策依据)')
259
+ .option('--kind <kind>', 'note|decision|fact', 'note')
260
+ .option('--scope <scope>', 'org|project', 'org')
261
+ .option('--project <id>', '可选项目归属')
262
+ .option('--json')
263
+ .action(action(async (options) => print(await resources.rememberKnowledge({
264
+ what: options.what,
265
+ why: options.why,
266
+ howToApply: options.howToApply,
267
+ kind: options.kind,
268
+ scope: options.scope,
269
+ project: options.project,
270
+ }), options.json)));
253
271
  const worklogs = program.command('worklogs');
254
272
  worklogs
255
273
  .command('list')
@@ -261,6 +279,9 @@ worklogs
261
279
  .command('record')
262
280
  .option('--summary <text>')
263
281
  .option('--type <type>', 'progress|blocker|decision|commit|note|meeting', 'note')
282
+ .option('--project <id>', 'optional project reference')
283
+ .option('--goal <id>', 'optional goal reference')
284
+ .option('--todo <id>', 'optional Todo reference')
264
285
  .option('--dry-run')
265
286
  .action(action(async (options) => {
266
287
  requireOption(options.summary, '--summary');
@@ -271,6 +292,9 @@ worklogs
271
292
  method: 'POST',
272
293
  path: '/api/work-logs',
273
294
  body: {
295
+ ...(options.project ? { project_id: options.project } : {}),
296
+ ...(options.goal ? { goal_id: options.goal } : {}),
297
+ ...(options.todo ? { todo_id: options.todo } : {}),
274
298
  summary: options.summary,
275
299
  event_type: options.type,
276
300
  source: 'manual',
@@ -280,9 +304,26 @@ worklogs
280
304
  });
281
305
  return;
282
306
  }
283
- print(await resources.recordWorklog(options.summary, options.type));
307
+ print(await resources.recordWorklog(options.summary, options.type, {
308
+ project: options.project,
309
+ goal: options.goal,
310
+ todo: options.todo,
311
+ }));
284
312
  }));
285
313
  registerCollaborationCommands(program, { goals, todos, knowledge, worklogs }, { print, fatal });
314
+ const evolution = program.command('evolution').description('组织记忆自进化(演化报告与手动触发)');
315
+ evolution
316
+ .command('reports')
317
+ .description('列出组织记忆自进化报告(按运行时间倒序)')
318
+ .option('--page <number>', 'page number', Number)
319
+ .option('--page-size <number>', 'items per page', Number)
320
+ .option('--json')
321
+ .action(action(async (options) => print(await resources.listEvolutionReports(options), options.json)));
322
+ evolution
323
+ .command('run')
324
+ .description('手动触发一次组织记忆自进化(异步执行)')
325
+ .option('--json')
326
+ .action(action(async (options) => print(await resources.triggerEvolution(), options.json)));
286
327
  program
287
328
  .command('report [subcommand]')
288
329
  .description('daily report commands')
@@ -113,7 +113,13 @@ async function indexAsset(asset, existing, statements) {
113
113
  return;
114
114
  }
115
115
  const content = bytes.toString('utf8');
116
- const chunks = textChunks(asset.entry ? `${asset.entry.title}\n\n${content}` : content);
116
+ const chunks = [];
117
+ // 表单标题作为元数据行(line 0)单独索引,不拼进正文——这样标题可搜,且正文 chunk
118
+ // 保持源文件行号(1-based),citation 能指回原文真实行。
119
+ const title = asset.entry?.title?.trim();
120
+ if (title)
121
+ chunks.push({ content: title, lineStart: 0, lineEnd: 0 });
122
+ chunks.push(...textChunks(content));
117
123
  chunks.forEach((chunk, index) => statements.insertChunk.run(asset.id, index, chunk.lineStart, chunk.lineEnd, chunk.content));
118
124
  setIndexStatus(statements, asset, 'indexed');
119
125
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openturtle/cli",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "OpenTurtle collaboration, knowledge, meeting, and agent CLI",
5
5
  "keywords": [
6
6
  "openturtle",
@@ -26,7 +26,8 @@ ot --json doctor
26
26
  2. 用 `ot roster list --project <id>` 解析成员;先匹配 canonical `display_name`,再参考 aliases 和项目角色,重名或无法唯一匹配时询问用户。
27
27
  3. 用 `ot context get --project <id> --query <term>` 获取项目上下文;复杂问题拆成少量明确查询词。
28
28
  4. 按对象读取:`ot work summary`、`ot goals list/show`、`ot todos list/show`、`ot knowledge list/show/search`、`ot knowledge local list/search/read`、`ot meetings list/show/transcript/minutes/participants`、`ot worklogs list`。
29
- 5. 高层命令缺失时才使用只读逃生口 `ot request get /api/...`。
29
+ 5. 记录 Todo 执行进展时优先使用 `ot worklogs record --summary "..." --type progress --todo <todo-id>`,可同时传 `--project` / `--goal`,不要只把关联 ID 塞进 metadata。
30
+ 6. 高层命令缺失时才使用只读逃生口 `ot request get /api/...`。
30
31
 
31
32
  ## 写入规则
32
33