@fanchao8609/agent_brain_sync 1.13.0 → 1.13.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/bin/abs.js +1 -1
- package/package.json +1 -1
- package/src/lint.js +38 -4
- package/src/store.js +1 -1
- package/src/todo.js +10 -3
package/bin/abs.js
CHANGED
|
@@ -521,7 +521,7 @@ async function main() {
|
|
|
521
521
|
}
|
|
522
522
|
case 'lint': {
|
|
523
523
|
rejectExtra(opts._, 'abs lint');
|
|
524
|
-
console.log(await cmdLint({ dir: opts.dir }));
|
|
524
|
+
console.log(await cmdLint({ dir: opts.dir, all: opts.all }));
|
|
525
525
|
break;
|
|
526
526
|
}
|
|
527
527
|
// 内部命令(hook 专用,不出现在 help):Stop 时机械快照未完成任务
|
package/package.json
CHANGED
package/src/lint.js
CHANGED
|
@@ -145,7 +145,7 @@ async function checkRootFiles(vault) {
|
|
|
145
145
|
`TODO-BREAKPOINT-BLOAT: ${BRAIN_DIR}/${file}:${i + 1} (断点 ${bp.length} 字 > ${LINT_BREAKPOINT_MAX};` +
|
|
146
146
|
`断点只写「改到哪个文件哪一步」,报告迁 sessions/ 或 sources/)`,
|
|
147
147
|
);
|
|
148
|
-
} else if (bp.split(/[
|
|
148
|
+
} else if (bp.split(/[。!?!?]+|\s*[\u2460-\u2473]\s*/).map((x) => x.trim()).filter(Boolean).length > 2) {
|
|
149
149
|
issues.push(
|
|
150
150
|
`TODO-BREAKPOINT-PROSE: ${BRAIN_DIR}/${file}:${i + 1} (断点写了多句 = 报告体;` +
|
|
151
151
|
`todo 只放待办,长文迁 sessions/ 或 sources/)`,
|
|
@@ -345,7 +345,7 @@ async function readFileOrNull(p) {
|
|
|
345
345
|
|
|
346
346
|
// ---------- 入口 ----------
|
|
347
347
|
|
|
348
|
-
export async function cmdLint({ dir }) {
|
|
348
|
+
export async function cmdLint({ dir, all = false }) {
|
|
349
349
|
let root;
|
|
350
350
|
try {
|
|
351
351
|
root = await requireBrain(dir || process.cwd());
|
|
@@ -374,10 +374,44 @@ export async function cmdLint({ dir }) {
|
|
|
374
374
|
issues.push(...await checkRootFiles(vault));
|
|
375
375
|
|
|
376
376
|
const n = issues.length;
|
|
377
|
+
// ★ 同类折叠(2026-10-05):体检输出必须按问题**类型**折叠计数。
|
|
378
|
+
// 为什么:给根文件加形状校验后,abs 自带的 log.md 有 102 条历史行缺 `[[作者]]`,
|
|
379
|
+
// 102 条 LOG-ENTRY 淹没了其它 12 条真问题(DRAFT-STALE/DEAD-LINK/NO-INBOUND)——
|
|
380
|
+
// lint 的价值是「让人看见该修的」,被噪声淹没就退化成不可读。
|
|
381
|
+
// 同族约束:既有 Rule `读取侧输出不得随规模增长`、Done 区已按日期折叠计数。
|
|
382
|
+
// 形态:同类 > THRESHOLD 时只报「N 条同类 + 前 SAMPLE 条样例」。
|
|
383
|
+
// 注:全量明细仍可用 `abs lint --all` 拿到(不静默丢信息)。
|
|
384
|
+
const folded = all ? issues : foldSameKind(issues);
|
|
385
|
+
const n2 = folded.length;
|
|
377
386
|
return [
|
|
378
|
-
...
|
|
387
|
+
...folded,
|
|
379
388
|
'',
|
|
380
|
-
`lint: ${
|
|
389
|
+
`lint: ${n2} problem(s).${n2 !== n ? ` (共 ${n} 条,同类已折叠;全量: abs lint --all)` : ''}`,
|
|
381
390
|
n === 0 ? '✓ 图谱健康' : '',
|
|
382
391
|
].filter(Boolean).join('\n');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** 同类问题折叠:按错误码分组,超过阈值只报计数 + 前几条样例。
|
|
395
|
+
* 错误码 = 首行的 `CODE:` 前缀(checkPage/checkGraph/checkRootFiles 都是这个形态)。
|
|
396
|
+
* 保序:按「首次出现顺序」输出,不因折叠打乱阅读节奏。 */
|
|
397
|
+
const FOLD_THRESHOLD = 10;
|
|
398
|
+
const FOLD_SAMPLE = 3;
|
|
399
|
+
export function foldSameKind(issues) {
|
|
400
|
+
const groups = new Map(); // code -> { items, order }
|
|
401
|
+
for (const it of issues) {
|
|
402
|
+
const m = String(it).match(/^([A-Z][A-Z0-9-]+):/);
|
|
403
|
+
const code = m ? m[1] : '(其它)';
|
|
404
|
+
if (!groups.has(code)) groups.set(code, { items: [] });
|
|
405
|
+
groups.get(code).items.push(it);
|
|
406
|
+
}
|
|
407
|
+
const out = [];
|
|
408
|
+
for (const [code, g] of groups) {
|
|
409
|
+
if (g.items.length <= FOLD_THRESHOLD) {
|
|
410
|
+
out.push(...g.items);
|
|
411
|
+
} else {
|
|
412
|
+
out.push(...g.items.slice(0, FOLD_SAMPLE));
|
|
413
|
+
out.push(` … 还有 ${g.items.length - FOLD_SAMPLE} 条同类的 ${code}(共 ${g.items.length} 条)`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return out;
|
|
383
417
|
}
|
package/src/store.js
CHANGED
|
@@ -11,7 +11,7 @@ import { keywords, pickRelevant, renderRelevant, recentFiles, rankPage, topicStr
|
|
|
11
11
|
import { impactOf } from './codegraph.js';
|
|
12
12
|
|
|
13
13
|
// Re-export lint.js symbols so external importers (e.g. bin/mcp.js, bin/abs.js) still work.
|
|
14
|
-
export { cmdLint, listPages, hasTail, PAGE_DIRS } from './lint.js';
|
|
14
|
+
export { cmdLint, listPages, hasTail, PAGE_DIRS, foldSameKind } from './lint.js';
|
|
15
15
|
import { SOURCES_MAX, PAGE_DIRS, listPages } from './lint.js';
|
|
16
16
|
|
|
17
17
|
// ---------- init: 建 .brain/ 骨架 ----------
|
package/src/todo.js
CHANGED
|
@@ -206,7 +206,11 @@ export const ENTRY_SHAPES = {
|
|
|
206
206
|
test: (l) => {
|
|
207
207
|
if (/^#{1,3}\s/.test(l)) return null; // 标题行(## Done / ### 日期)不是条目
|
|
208
208
|
if (!/^-\s/.test(l)) return null; // 非条目行(如缩进的 ↳ 断点)由下面单独判
|
|
209
|
-
// Done
|
|
209
|
+
// Done 区的归档行:`- [[log-日期]] 完成任务 N 条`。
|
|
210
|
+
// ★ 历史命名不统一:还有 `[[2026-09-12-todo归档]]` 这种旧写法(实测),
|
|
211
|
+
// 只认 `log-` 前缀会把它误报为「缺状态标记」。状归档行与任务行的
|
|
212
|
+
// 区别不是命名而是**形态**:没有 `[ ]`/`[x]` 复选框的 [[链接]] 行。
|
|
213
|
+
if (/^-\s*\[\[[^\]]+\]\]\s+完成任务/.test(l)) return null;
|
|
210
214
|
if (/^-\s*\[\[log-\d{4}-\d{2}-\d{2}\]\]/.test(l)) return null;
|
|
211
215
|
const m = l.match(/^-\s*\[([ x])\]\s*(.*)$/);
|
|
212
216
|
if (!m) return '应以 `- [ ] ` 或 `- [x] ` 开头';
|
|
@@ -504,12 +508,15 @@ const REPORT_MARKERS = [
|
|
|
504
508
|
];
|
|
505
509
|
|
|
506
510
|
/** 数一个断点里有几个「句子」—— 断点是一件事,多句 = 在塞报告。
|
|
507
|
-
*
|
|
511
|
+
* 分隔符只用**句末标点**(。!?!?)与带圈编号 ①②③。
|
|
512
|
+
* ★ 分号(;/;)**不算**分隔符:中文技术写作里它常用来连接同一个意思的两部分
|
|
513
|
+
* (「改到哪个文件;同类约束见 xx」),算成两句会误伤正常断点(实测:
|
|
514
|
+
* 一条正常的「改到哪 + 同类约束 + 待确认」被判 3 句而拒绝写入)。
|
|
508
515
|
* 为什么不用关键词表:关键词命中不稳(「功能/方案」正常描述也会出现),
|
|
509
516
|
* 而「一句还是一段」是结构判据 —— 结构判据才可靠。 */
|
|
510
517
|
function sentenceCount(s) {
|
|
511
518
|
return String(s)
|
|
512
|
-
.split(/[
|
|
519
|
+
.split(/[。!?!?]+|\s*[\u2460-\u2473]\s*/)
|
|
513
520
|
.map((x) => x.trim())
|
|
514
521
|
.filter(Boolean).length;
|
|
515
522
|
}
|