@fanchao8609/agent_brain_sync 1.14.0 → 1.14.1

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/hooks/abs.pi.ts CHANGED
@@ -116,6 +116,10 @@ let autoTaskSeen = false
116
116
  * 只存文件名,不存内容 —— 断点是"记到哪",不是快照。 */
117
117
  let lastTouchedFile = ''
118
118
 
119
+ /** 最近一轮的用户指令原文。只用于「第一次真改文件时」抽任务关键词 ——
120
+ * 登记时机已从 before_agent_start 挪到 tool_call(用户实报:一按回车就登记太早)。 */
121
+ let pendingPrompt = ''
122
+
119
123
  /** 最近一次渲染拿到的 tui 引用。hidePanel 用它请求重绘 —— 面板消失时动画
120
124
  * 定时器已停,没有别的重绘通道(见 hidePanel 的坑注解)。 */
121
125
  let lastTui: any = null
@@ -623,6 +627,7 @@ export default function absPiHook(pi: ExtensionAPI): void {
623
627
  // 新会话 = 重新登记:不重置则同进程的第二个会话永远不再落断点
624
628
  autoTaskSeen = false
625
629
  lastTouchedFile = ''
630
+ pendingPrompt = ''
626
631
  resetThrottle()
627
632
  // 本会话的随机昵称 —— 在这里抽一次(不是每帧抽,否则面板会疯狂闪)。
628
633
  // 每次 session_start(startup/reload/new/resume/fork)重抽 → “每次打开 pi 都是随机的”。
@@ -667,7 +672,13 @@ export default function absPiHook(pi: ExtensionAPI): void {
667
672
  const bp = file ? `改了 ${file.slice(0, 120)}` : '开始改文件'
668
673
  if (file) lastTouchedFile = file.slice(0, 120)
669
674
  const sid = sessionIdFor(ctx)
670
- if (sid) spawnAutoTask(cwd, ['--session', sid, '--note', bp])
675
+ // 首次真改文件 = "真开工了" → 此刻才登记(带用户指令抽关键词)+ 落断点。
676
+ // 这是唯一登记入口:光说/说问/讨论都不登记(2026-10-05 用户实报时机太早)。
677
+ if (sid) {
678
+ const args = ['--session', sid, '--note', bp]
679
+ if (pendingPrompt) args.push('--prompt', pendingPrompt)
680
+ spawnAutoTask(cwd, args)
681
+ }
671
682
  logHook(`tool_call auto_task name=${name} sid=${sid || '-'}`).catch(() => {})
672
683
  }
673
684
  })
@@ -700,14 +711,10 @@ export default function absPiHook(pi: ExtensionAPI): void {
700
711
  const ok = injectTodoGuidelines(event?.systemPromptOptions)
701
712
  logHook(`before_agent_start todo_guide=${ok ? 'on' : 'off'} cwd=${cwd}`).catch(() => {})
702
713
 
703
- // 自动登记(2026-10-05):有图谱 + 指令有实质内容 → 先把任务落到看板上。
704
- // 抽不出关键词("在吗"/"继续")时 abs 侧会静默跳过 —— 宁可不登记也不脏看板。
705
- // 一会话一条:同会话后续的 before_agent_start 会命中已有条目,只更新断点。
706
- // ★ 位置必须在 no_brain 分支【之后】—— 放到里面等于"只有没图谱时才登记",逻辑全反。
707
- const sid = sessionIdFor(ctx)
708
- if (sid && event?.prompt) {
709
- spawnAutoTask(cwd, ['--session', sid, '--prompt', String(event.prompt).slice(0, 200)])
710
- }
714
+ // 只【记住】本轮用户指令,不在这里登记(2026-10-05 用户实报时机太早)。
715
+ // 旧行为: 一按回车就登记 → 用户还在说/聊、需求没成型,看板上就已经开出了任务。
716
+ // 现在: 留到第一次真改文件时(tool_call)才登记,那时才算"真开工了"。
717
+ if (event?.prompt) pendingPrompt = String(event.prompt).slice(0, 200)
711
718
  } catch (e: any) {
712
719
  logHook(`before_agent_start error=${e?.message || 'unknown'}`).catch(() => {})
713
720
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanchao8609/agent_brain_sync",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "agent-brain-sync: 跨会话 AI 编码记忆 — hook 纯触发 + CLI/MCP 读写 .brain markdown 图谱, 防并发写保护。",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/store.js CHANGED
@@ -1198,6 +1198,23 @@ export function autoTaskId(text) {
1198
1198
  return slug.length >= 2 ? slug : null;
1199
1199
  }
1200
1200
 
1201
+ /** 从断点文本提一个像样的 slug。
1202
+ *
1203
+ * 断点形如 `改了 src/store.js` / `本轮到 hooks/abs.pi.ts`;直接当 slug 会得到
1204
+ * `改了`(首词)这种废名。这里取【文件名】当 slug —— 「改了哪个文件」比「改了」有意义。
1205
+ */
1206
+ export function autoTaskSlugFromNote(note) {
1207
+ const s = String(note || '').replace(/[\u200b\u200c\u200d\ufeff]/g, '');
1208
+ // 文件路径优先(含 / 或 . 扩展名)
1209
+ const m = s.match(/[\w./-]*[\w-]+\.[A-Za-z0-9]{1,8}/);
1210
+ if (m) {
1211
+ const base = m[0].split('/').pop().replace(/\.[A-Za-z0-9]{1,8}$/, '');
1212
+ if (base && base.length >= 2) return `改 ${base}`;
1213
+ }
1214
+ // 退而求其次:抽到的关键词(可能为空)
1215
+ return autoTaskId(s);
1216
+ }
1217
+
1201
1218
  /** hook 自动登记: 一会话一条 + 断点更新。
1202
1219
  *
1203
1220
  * @param {object} o
@@ -1235,8 +1252,14 @@ export async function cmdAutoTask({ dir, session, prompt, note }) {
1235
1252
  return r?.changed ? `↳ ${existingId} 断点更新` : null;
1236
1253
  }
1237
1254
 
1238
- // 首次: 抽不出关键词就不登记
1239
- const slug = autoTaskId(prompt);
1255
+ // 首次登记: 关键词优先从用户指令抽;抽不出(寒暄/提问/无指令)时用断点兜底。
1256
+ //
1257
+ // 为何 note 也能兜底(2026-10-05 时机改动后新增):登记时机已挪到"第一次真改文件",
1258
+ // 那一刻【已经动过文件】就是最可靠的"这是件事"的证据 —— 此时因抽不出关键词而放弃,
1259
+ // 等于用户寒暄两句后开始干活却什么都没记。用文件名当兜底 slug 比不登记有用。
1260
+ // 兜底仅在【有断点】时启用 —— 断点的存在本身就意味着"刚动过文件"。
1261
+ // 只有 prompt 而抽不出关键词(纯寒暄/提问、且没动文件)→ 依然不登记(用户实报的那个坑)。
1262
+ const slug = autoTaskId(prompt) || (note ? autoTaskSlugFromNote(note) : null);
1240
1263
  if (!slug) return null;
1241
1264
  // id = 关键词(可读);同 slug 已存在则加序号,避免两条不同活撞同一个 id。
1242
1265
  let id = `${AUTO_TASK_PREFIX}${slug}`;