@whispering233/ai-editor-tools 0.0.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.
Files changed (109) hide show
  1. package/dist/analysis/conflict.d.ts +20 -0
  2. package/dist/analysis/conflict.d.ts.map +1 -0
  3. package/dist/analysis/conflict.js +116 -0
  4. package/dist/analysis/conflict.js.map +1 -0
  5. package/dist/analysis/consistency.d.ts +28 -0
  6. package/dist/analysis/consistency.d.ts.map +1 -0
  7. package/dist/analysis/consistency.js +108 -0
  8. package/dist/analysis/consistency.js.map +1 -0
  9. package/dist/analysis/hook.d.ts +157 -0
  10. package/dist/analysis/hook.d.ts.map +1 -0
  11. package/dist/analysis/hook.js +381 -0
  12. package/dist/analysis/hook.js.map +1 -0
  13. package/dist/analysis/orphan.d.ts +60 -0
  14. package/dist/analysis/orphan.d.ts.map +1 -0
  15. package/dist/analysis/orphan.js +153 -0
  16. package/dist/analysis/orphan.js.map +1 -0
  17. package/dist/analysis/path.d.ts +23 -0
  18. package/dist/analysis/path.d.ts.map +1 -0
  19. package/dist/analysis/path.js +114 -0
  20. package/dist/analysis/path.js.map +1 -0
  21. package/dist/analysis/suggest.d.ts +19 -0
  22. package/dist/analysis/suggest.d.ts.map +1 -0
  23. package/dist/analysis/suggest.js +92 -0
  24. package/dist/analysis/suggest.js.map +1 -0
  25. package/dist/analysis/utils.d.ts +54 -0
  26. package/dist/analysis/utils.d.ts.map +1 -0
  27. package/dist/analysis/utils.js +123 -0
  28. package/dist/analysis/utils.js.map +1 -0
  29. package/dist/context.d.ts +10 -0
  30. package/dist/context.d.ts.map +1 -0
  31. package/dist/context.js +11 -0
  32. package/dist/context.js.map +1 -0
  33. package/dist/executor/delta.d.ts +4 -0
  34. package/dist/executor/delta.d.ts.map +1 -0
  35. package/dist/executor/delta.js +22 -0
  36. package/dist/executor/delta.js.map +1 -0
  37. package/dist/executor/entity.d.ts +8 -0
  38. package/dist/executor/entity.d.ts.map +1 -0
  39. package/dist/executor/entity.js +47 -0
  40. package/dist/executor/entity.js.map +1 -0
  41. package/dist/executor/hook.d.ts +8 -0
  42. package/dist/executor/hook.d.ts.map +1 -0
  43. package/dist/executor/hook.js +183 -0
  44. package/dist/executor/hook.js.map +1 -0
  45. package/dist/executor/index.d.ts +22 -0
  46. package/dist/executor/index.d.ts.map +1 -0
  47. package/dist/executor/index.js +89 -0
  48. package/dist/executor/index.js.map +1 -0
  49. package/dist/executor/outline.d.ts +8 -0
  50. package/dist/executor/outline.d.ts.map +1 -0
  51. package/dist/executor/outline.js +39 -0
  52. package/dist/executor/outline.js.map +1 -0
  53. package/dist/executor/relation.d.ts +6 -0
  54. package/dist/executor/relation.d.ts.map +1 -0
  55. package/dist/executor/relation.js +33 -0
  56. package/dist/executor/relation.js.map +1 -0
  57. package/dist/executor/types.d.ts +25 -0
  58. package/dist/executor/types.d.ts.map +1 -0
  59. package/dist/executor/types.js +54 -0
  60. package/dist/executor/types.js.map +1 -0
  61. package/dist/index.d.ts +23 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +359 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/proposal/delta.d.ts +8 -0
  66. package/dist/proposal/delta.d.ts.map +1 -0
  67. package/dist/proposal/delta.js +29 -0
  68. package/dist/proposal/delta.js.map +1 -0
  69. package/dist/proposal/entity.d.ts +16 -0
  70. package/dist/proposal/entity.d.ts.map +1 -0
  71. package/dist/proposal/entity.js +54 -0
  72. package/dist/proposal/entity.js.map +1 -0
  73. package/dist/proposal/hook.d.ts +24 -0
  74. package/dist/proposal/hook.d.ts.map +1 -0
  75. package/dist/proposal/hook.js +81 -0
  76. package/dist/proposal/hook.js.map +1 -0
  77. package/dist/proposal/outline.d.ts +24 -0
  78. package/dist/proposal/outline.d.ts.map +1 -0
  79. package/dist/proposal/outline.js +78 -0
  80. package/dist/proposal/outline.js.map +1 -0
  81. package/dist/proposal/relation.d.ts +12 -0
  82. package/dist/proposal/relation.d.ts.map +1 -0
  83. package/dist/proposal/relation.js +50 -0
  84. package/dist/proposal/relation.js.map +1 -0
  85. package/dist/proposal/types.d.ts +72 -0
  86. package/dist/proposal/types.d.ts.map +1 -0
  87. package/dist/proposal/types.js +105 -0
  88. package/dist/proposal/types.js.map +1 -0
  89. package/dist/query/delta.d.ts +20 -0
  90. package/dist/query/delta.d.ts.map +1 -0
  91. package/dist/query/delta.js +41 -0
  92. package/dist/query/delta.js.map +1 -0
  93. package/dist/query/entity.d.ts +29 -0
  94. package/dist/query/entity.d.ts.map +1 -0
  95. package/dist/query/entity.js +53 -0
  96. package/dist/query/entity.js.map +1 -0
  97. package/dist/query/outline.d.ts +20 -0
  98. package/dist/query/outline.d.ts.map +1 -0
  99. package/dist/query/outline.js +68 -0
  100. package/dist/query/outline.js.map +1 -0
  101. package/dist/query/relation.d.ts +12 -0
  102. package/dist/query/relation.d.ts.map +1 -0
  103. package/dist/query/relation.js +30 -0
  104. package/dist/query/relation.js.map +1 -0
  105. package/dist/registry.d.ts +41 -0
  106. package/dist/registry.d.ts.map +1 -0
  107. package/dist/registry.js +46 -0
  108. package/dist/registry.js.map +1 -0
  109. package/package.json +35 -0
@@ -0,0 +1,20 @@
1
+ import type { ToolContext } from "../context.js";
2
+ import type { DetectConflictsArgs } from "@whispering233/ai-editor-shared";
3
+ /** 单条跨实体矛盾(tools.md detect_conflicts 返回项;entity_a/entity_b 为实体 id) */
4
+ export interface ConflictIssue {
5
+ entity_a: string;
6
+ entity_b: string;
7
+ field: string;
8
+ description: string;
9
+ }
10
+ /**
11
+ * 关系矛盾检测(tools.md detect_conflicts)。
12
+ * types 限定参与检测的实体类型(缺省全部);relation_filter 限定参与检测的关系类型
13
+ * (缺省全部——规则按交集生效:R1 只查集合内的对称类型、R2 只查互斥对均在集合内、R3 只查集合含 kills)。
14
+ * 软删对象不可见(listEntities/listRelations 默认过滤,决策 12)。
15
+ * 返回按 (entity_a, entity_b) 稳定排序。
16
+ */
17
+ export declare function runDetectConflicts(ctx: ToolContext, args: DetectConflictsArgs, signal?: AbortSignal): {
18
+ conflicts: ConflictIssue[];
19
+ };
20
+ //# sourceMappingURL=conflict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict.d.ts","sourceRoot":"","sources":["../../src/analysis/conflict.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAwBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG;IAAE,SAAS,EAAE,aAAa,EAAE,CAAA;CAAE,CA0FpI"}
@@ -0,0 +1,116 @@
1
+ // 分析类工具:detect_conflicts(跨实体设定矛盾检测,S6.4)
2
+ // 契约来源:doc/api/tools.md「一致性分析」→ { conflicts: [{ entity_a, entity_b, field, description }] }
3
+ // 语义:从关系图自动发现设定矛盾(「A↔B 关系缺失导致的不一致」):
4
+ // - R1 对称缺失(error):ally/family 为对称关系,单向存在即矛盾(A ally B 但 B 未 ally A)
5
+ // - R2 互斥并存(warning):同一对实体同时互为盟友与对手(ally + rival 并存)
6
+ // - R3 互杀(error):A kills B 且 B kills A(双方互相击杀)
7
+ // 数据访问:db 查询层(listEntities 全量非软删实体 + listRelations 全量可见关系)+ 纯函数图分析,无原生 SQL。
8
+ // signal:全量关系遍历为长任务候选,循环中检查(决策 16 ③)。
9
+ import { listEntities, listRelations } from "@whispering233/ai-editor-db";
10
+ import { isEntityType, throwIfAborted } from "./utils.js";
11
+ /** 对称关系类型(R1:单向存在即矛盾) */
12
+ const SYMMETRIC_RELATION_TYPES = ["ally", "family"];
13
+ /** 互斥关系对(R2:同一对实体并存即矛盾) */
14
+ const MUTUALLY_EXCLUSIVE_PAIRS = [["ally", "rival"]];
15
+ /** 互杀关系类型(R3:双向同时存在即矛盾) */
16
+ const KILLS_RELATION_TYPE = "kills";
17
+ /** 实体 id → 名字(矛盾描述可读化) */
18
+ function nameOf(entities, id) {
19
+ return entities.find((e) => e.id === id)?.name ?? id;
20
+ }
21
+ /**
22
+ * 关系矛盾检测(tools.md detect_conflicts)。
23
+ * types 限定参与检测的实体类型(缺省全部);relation_filter 限定参与检测的关系类型
24
+ * (缺省全部——规则按交集生效:R1 只查集合内的对称类型、R2 只查互斥对均在集合内、R3 只查集合含 kills)。
25
+ * 软删对象不可见(listEntities/listRelations 默认过滤,决策 12)。
26
+ * 返回按 (entity_a, entity_b) 稳定排序。
27
+ */
28
+ export function runDetectConflicts(ctx, args, signal) {
29
+ const types = args.types;
30
+ const relFilter = args.relation_filter !== undefined ? new Set(args.relation_filter) : null;
31
+ // 1. 全量非软删实体 + 全量可见关系(一次查询层调用各一)
32
+ const entities = listEntities(ctx.db, { limit: 200 }).items;
33
+ const relations = listRelations(ctx.db, {}, 1, ctx.outlineDir).relations;
34
+ throwIfAborted(signal);
35
+ // 2. 过滤:两端均为实体、类型在 types 内、关系类型在 relFilter 内(或缺省全量)
36
+ const typeFilter = types !== undefined ? new Set(types) : null;
37
+ const relevant = relations.filter((r) => isEntityType(r.sourceType) &&
38
+ isEntityType(r.targetType) &&
39
+ (typeFilter === null || typeFilter.has(r.sourceType)) &&
40
+ (typeFilter === null || typeFilter.has(r.targetType)) &&
41
+ (relFilter === null || relFilter.has(r.relationType)));
42
+ throwIfAborted(signal);
43
+ // 3. 有向对聚合(无向 pairKey 归一,方向集合分别记录)
44
+ const pairs = new Map();
45
+ for (const r of relevant) {
46
+ const [a, b] = r.sourceId < r.targetId ? [r.sourceId, r.targetId] : [r.targetId, r.sourceId];
47
+ let pair = pairs.get(`${a}|${b}`);
48
+ if (pair === undefined) {
49
+ pair = { a, b, ab: new Set(), ba: new Set() };
50
+ pairs.set(`${a}|${b}`, pair);
51
+ }
52
+ if (r.sourceId === pair.a)
53
+ pair.ab.add(r.relationType);
54
+ else
55
+ pair.ba.add(r.relationType);
56
+ }
57
+ // 4. 规则判定(R1/R2/R3,逐对)
58
+ const conflicts = [];
59
+ for (const pair of pairs.values()) {
60
+ throwIfAborted(signal);
61
+ const nameA = nameOf(entities, pair.a);
62
+ const nameB = nameOf(entities, pair.b);
63
+ // R1:对称关系单向缺失
64
+ for (const sym of SYMMETRIC_RELATION_TYPES) {
65
+ if (relFilter !== null && !relFilter.has(sym))
66
+ continue;
67
+ const hasAb = pair.ab.has(sym);
68
+ const hasBa = pair.ba.has(sym);
69
+ if (hasAb && !hasBa) {
70
+ conflicts.push({
71
+ entity_a: pair.a,
72
+ entity_b: pair.b,
73
+ field: "relations",
74
+ description: `「${nameA}」对「${nameB}」存在单向 ${sym} 关系,反向缺失(对称关系应双向建立)`,
75
+ });
76
+ }
77
+ else if (hasBa && !hasAb) {
78
+ conflicts.push({
79
+ entity_a: pair.b,
80
+ entity_b: pair.a,
81
+ field: "relations",
82
+ description: `「${nameB}」对「${nameA}」存在单向 ${sym} 关系,反向缺失(对称关系应双向建立)`,
83
+ });
84
+ }
85
+ }
86
+ // R2:互斥关系并存(无向)
87
+ for (const [x, y] of MUTUALLY_EXCLUSIVE_PAIRS) {
88
+ if (relFilter !== null && (!relFilter.has(x) || !relFilter.has(y)))
89
+ continue;
90
+ const both = (pair.ab.has(x) && (pair.ab.has(y) || pair.ba.has(y))) || (pair.ba.has(x) && (pair.ab.has(y) || pair.ba.has(y)));
91
+ if (both) {
92
+ conflicts.push({
93
+ entity_a: pair.a,
94
+ entity_b: pair.b,
95
+ field: "relations",
96
+ description: `「${nameA}」与「${nameB}」同时存在 ${x} 与 ${y} 关系(互斥关系并存,设定矛盾)`,
97
+ });
98
+ }
99
+ }
100
+ // R3:互杀(双向 kills)
101
+ if (relFilter === null || relFilter.has(KILLS_RELATION_TYPE)) {
102
+ if (pair.ab.has(KILLS_RELATION_TYPE) && pair.ba.has(KILLS_RELATION_TYPE)) {
103
+ conflicts.push({
104
+ entity_a: pair.a,
105
+ entity_b: pair.b,
106
+ field: "relations",
107
+ description: `「${nameA}」与「${nameB}」互相击杀(双向 ${KILLS_RELATION_TYPE}),死亡设定矛盾`,
108
+ });
109
+ }
110
+ }
111
+ }
112
+ // 5. 稳定排序(entity_a 升序,再 entity_b 升序)——可预测输出
113
+ conflicts.sort((x, y) => (x.entity_a === y.entity_a ? x.entity_b.localeCompare(y.entity_b) : x.entity_a.localeCompare(y.entity_a)));
114
+ return { conflicts };
115
+ }
116
+ //# sourceMappingURL=conflict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict.js","sourceRoot":"","sources":["../../src/analysis/conflict.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { EntityRow } from "@whispering233/ai-editor-shared";
2
+ import type { Db } from "@whispering233/ai-editor-db";
3
+ import type { OutlineFileTree } from "@whispering233/ai-editor-shared";
4
+ import type { ToolContext } from "../context.js";
5
+ import type { AnalyzeConsistencyArgs } from "@whispering233/ai-editor-shared";
6
+ /** 一致性问题的严重级别(error = 确定矛盾;warning = 可疑/待确认) */
7
+ export type IssueSeverity = "error" | "warning";
8
+ /** 单条一致性问题(tools.md analyze_consistency 返回项) */
9
+ export interface ConsistencyIssue {
10
+ severity: IssueSeverity;
11
+ /** 矛盾的 data 字段名(如 "personality" / "expected_resolve_node_id") */
12
+ field: string;
13
+ description: string;
14
+ }
15
+ /**
16
+ * 实体档案一致性检查(tools.md analyze_consistency(entity_id))。
17
+ * 规则表(按类型分发,均纯函数判定):
18
+ * - character:R1 负年龄(error)、R2 性格反义词对(warning)
19
+ * - hook:R3 已兑现未标注节点(warning)、R4 兑现节点悬空引用(error)
20
+ * - setting/location:R5 parent_id 悬空引用(warning)
21
+ * 实体不存在/已软删 → null(查询无结果,LLM 自纠)。
22
+ */
23
+ export declare function analyzeEntityConsistency(row: EntityRow, tree: OutlineFileTree, db: Db): ConsistencyIssue[];
24
+ /** 工具执行入口(注册表 run 形态:signal 供长任务取消;中止优先于参数校验) */
25
+ export declare function runAnalyzeConsistency(ctx: ToolContext, args: AnalyzeConsistencyArgs, signal?: AbortSignal): {
26
+ issues: ConsistencyIssue[];
27
+ } | null;
28
+ //# sourceMappingURL=consistency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consistency.d.ts","sourceRoot":"","sources":["../../src/analysis/consistency.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,CAAC;IACxB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AA6ED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,EAAE,GAAG,gBAAgB,EAAE,CAW1G;AAED,iDAAiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,WAAW,GACnB;IAAE,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAAG,IAAI,CAMvC"}
@@ -0,0 +1,108 @@
1
+ // 分析类工具:analyze_consistency(实体档案一致性检查,S6.4)
2
+ // 契约来源:doc/api/tools.md「一致性分析」→ { issues: [{ severity, field, description }] }
3
+ // 语义:检查单个实体 data 档案内部的矛盾(「性格坚韧但曾因小事放弃」类)。
4
+ // 规则表驱动(单一职责、可扩展):每条规则纯函数判定,按实体类型分发。
5
+ // 数据访问:db 查询层(getEntity 过滤软删)+ outline.json 读取(引用字段校验),无原生 SQL。
6
+ import { getEntity, findOutlineNode, readOutlineFile } from "@whispering233/ai-editor-db";
7
+ import { throwIfAborted } from "./utils.js";
8
+ /** 内置性格反义词对(R2 矛盾检测词表;「勇敢」与「怯懦」并存 = 档案内部矛盾) */
9
+ const PERSONALITY_ANTONYMS = [
10
+ ["勇敢", "怯懦"],
11
+ ["善良", "残忍"],
12
+ ["慷慨", "吝啬"],
13
+ ["诚实", "狡诈"],
14
+ ["冷静", "冲动"],
15
+ ];
16
+ // ============ 规则集(按实体类型分发) ============
17
+ /** R1:character.data.age 为负数 → 数值矛盾(error) */
18
+ function checkNegativeAge(data) {
19
+ const age = data.age;
20
+ if (typeof age === "number" && age < 0) {
21
+ return [{ severity: "error", field: "age", description: `年龄为负数(${age}),与常理矛盾` }];
22
+ }
23
+ return [];
24
+ }
25
+ /** R2:character.data.personality 同时含反义词对 → 性格矛盾(warning,逐对检出) */
26
+ function checkPersonalityAntonyms(data) {
27
+ const personality = data.personality;
28
+ if (!Array.isArray(personality))
29
+ return [];
30
+ const issues = [];
31
+ for (const [a, b] of PERSONALITY_ANTONYMS) {
32
+ if (personality.includes(a) && personality.includes(b)) {
33
+ issues.push({
34
+ severity: "warning",
35
+ field: "personality",
36
+ description: `性格同时标注「${a}」与「${b}」(互为反义),档案内部矛盾`,
37
+ });
38
+ }
39
+ }
40
+ return issues;
41
+ }
42
+ /** R3:hook.data.status=resolved 但未标注兑现节点 → 终态缺引用(warning) */
43
+ function checkResolvedWithoutNode(data) {
44
+ if (data.status === "resolved" && data.expected_resolve_node_id === undefined) {
45
+ return [
46
+ {
47
+ severity: "warning",
48
+ field: "expected_resolve_node_id",
49
+ description: "伏笔状态为 resolved(已兑现)但未标注 expected_resolve_node_id(兑现节点),无法回溯兑现位置",
50
+ },
51
+ ];
52
+ }
53
+ return [];
54
+ }
55
+ /** R4:hook.data.expected_resolve_node_id 指向不存在/已软删的节点 → 悬空引用(error) */
56
+ function checkResolveNodeReference(data, tree) {
57
+ const nodeId = data.expected_resolve_node_id;
58
+ if (typeof nodeId !== "string" || nodeId === "")
59
+ return [];
60
+ const node = findOutlineNode(tree, nodeId);
61
+ if (node === undefined) {
62
+ return [{ severity: "error", field: "expected_resolve_node_id", description: `兑现节点 ${nodeId} 不存在(已物理删除或 id 拼写错误)` }];
63
+ }
64
+ if (node.deleted === true) {
65
+ return [{ severity: "error", field: "expected_resolve_node_id", description: `兑现节点「${node.title}」已被软删,引用悬空` }];
66
+ }
67
+ return [];
68
+ }
69
+ /** R5:setting/location.data.parent_id 指向不存在/已软删的实体 → 悬空引用(warning) */
70
+ function checkParentReference(data, db) {
71
+ const parentId = data.parent_id;
72
+ if (typeof parentId !== "string" || parentId === "")
73
+ return [];
74
+ if (getEntity(db, parentId) === null) {
75
+ return [{ severity: "warning", field: "parent_id", description: `parent_id 指向的实体 ${parentId} 不存在或已软删,层级引用悬空` }];
76
+ }
77
+ return [];
78
+ }
79
+ /**
80
+ * 实体档案一致性检查(tools.md analyze_consistency(entity_id))。
81
+ * 规则表(按类型分发,均纯函数判定):
82
+ * - character:R1 负年龄(error)、R2 性格反义词对(warning)
83
+ * - hook:R3 已兑现未标注节点(warning)、R4 兑现节点悬空引用(error)
84
+ * - setting/location:R5 parent_id 悬空引用(warning)
85
+ * 实体不存在/已软删 → null(查询无结果,LLM 自纠)。
86
+ */
87
+ export function analyzeEntityConsistency(row, tree, db) {
88
+ const data = row.data;
89
+ switch (row.type) {
90
+ case "character":
91
+ return [...checkNegativeAge(data), ...checkPersonalityAntonyms(data)];
92
+ case "hook":
93
+ return [...checkResolvedWithoutNode(data), ...checkResolveNodeReference(data, tree)];
94
+ case "setting":
95
+ case "location":
96
+ return checkParentReference(data, db);
97
+ }
98
+ }
99
+ /** 工具执行入口(注册表 run 形态:signal 供长任务取消;中止优先于参数校验) */
100
+ export function runAnalyzeConsistency(ctx, args, signal) {
101
+ throwIfAborted(signal);
102
+ const row = getEntity(ctx.db, args.entity_id);
103
+ if (row === null)
104
+ return null;
105
+ const tree = readOutlineFile(ctx.outlineDir);
106
+ return { issues: analyzeEntityConsistency(row, tree, ctx.db) };
107
+ }
108
+ //# sourceMappingURL=consistency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consistency.js","sourceRoot":"","sources":["../../src/analysis/consistency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import type { EntityRow, RelationRecord } from "@whispering233/ai-editor-shared";
2
+ import type { ToolContext } from "../context.js";
3
+ import { type ChapterIndex } from "./utils.js";
4
+ import type { AnalyzeHookHealthArgs, DetectHookConflictsArgs, FindHookOpportunitiesArgs, SuggestHookPayoffArgs, TraceHookLifecycleArgs } from "@whispering233/ai-editor-shared";
5
+ /** 单个伏笔的完整上下文(实体 + 生命周期关系分组,源数据均来自 db 查询层) */
6
+ export interface HookRecord {
7
+ entity: EntityRow;
8
+ /** 埋设节点关系(outline_node → hook,plants) */
9
+ plants: RelationRecord[];
10
+ /** 推进节点关系(advances) */
11
+ advances: RelationRecord[];
12
+ /** 回收节点关系(resolves) */
13
+ resolves: RelationRecord[];
14
+ /** 本 hook 依赖的其他 hook(source=本 hook,depends_on) */
15
+ dependsOn: RelationRecord[];
16
+ /** 依赖本 hook 的其他 hook(target=本 hook,depends_on——循环依赖检测用) */
17
+ dependedOnBy: RelationRecord[];
18
+ }
19
+ /** 单 hook 健康指标(决策 21;指标名与 hooks.md 逐字对齐) */
20
+ export interface HookHealth {
21
+ /** 当前章节 - 埋设章节(无 plants 或当前章节未定 → null) */
22
+ age: number | null;
23
+ /** 当前章节 - 最后活跃章节(advances 最新;无 advances → 埋设章;无埋设 → null) */
24
+ dormancy: number | null;
25
+ /** dormancy > half_life(缺数据 → null) */
26
+ stale: boolean | null;
27
+ /** age > half_life * 2(缺数据 → null) */
28
+ overdue: boolean | null;
29
+ /** expected_resolve_node_id 已设置:current >= 该节点章节序;未设置/节点无章号 → null(不猜测) */
30
+ ready_to_resolve: boolean | null;
31
+ /** 存在依赖(depends_on)尚未 resolved */
32
+ blocked: boolean;
33
+ /** 阻塞本 hook 的依赖 hook id 列表 */
34
+ blocked_by: string[];
35
+ /** 半衰期(显式 half_life 优先;缺省按 payoff_timing 映射,决策 21) */
36
+ half_life: number;
37
+ }
38
+ /**
39
+ * half_life 缺省映射(决策 21):显式 half_life(正数)优先;
40
+ * 未设置按 payoff_timing 取 DEFAULT_HALF_LIFE;payoff_timing 缺失/非法 → slow_burn
41
+ * (长线保守默认——避免过早判定 stale 误报)。
42
+ * 防御:trunc 后再次检查 > 0——0 < half_life < 1(如 0.5)截断为 0 会让 stale/overdue 恒真,
43
+ * 此时退化走 payoff_timing 映射(oracle 修复轮)。
44
+ */
45
+ export declare function resolveHalfLife(data: Record<string, unknown>): number;
46
+ /**
47
+ * 健康指标计算(决策 21;**纯函数,不修改任何输入**——绝不写回 data):
48
+ * - age:current - 最早埋设章(plants 章节序 min)
49
+ * - dormancy:current - 最后活跃章(advances 章节序 max;无 advances → 埋设章——埋下后从未推进)
50
+ * - stale/overdue/ready_to_resolve/blocked 见 HookHealth 注释
51
+ */
52
+ export declare function computeHookHealth(chapterIndex: ChapterIndex, rec: HookRecord, hookStatuses: ReadonlyMap<string, string>): HookHealth;
53
+ /** 伏笔健康总览结果(hooks.md analyze_hook_health 返回结构,字段名逐字对齐 snake_case) */
54
+ export interface HookHealthOverview {
55
+ /** 当前章节(current_position 口径,决策 21;未设置时退化树末章) */
56
+ current_chapter: number | null;
57
+ /** 活跃伏笔数(status ∈ planted/progressing) */
58
+ active_count: number;
59
+ /** 休眠超过半衰期的活跃伏笔 id */
60
+ stale: string[];
61
+ /** 埋设超过两倍半衰期的活跃伏笔 id */
62
+ overdue: string[];
63
+ /** 被依赖阻塞的伏笔(blocked)及其阻塞源 */
64
+ blocked_chains: {
65
+ hookId: string;
66
+ blockedBy: string[];
67
+ }[];
68
+ /** 人类可读警告(stale/overdue/blocked 各一条) */
69
+ warnings: string[];
70
+ }
71
+ /**
72
+ * 伏笔健康总览(hooks.md analyze_hook_health(),无参全项目扫描)。
73
+ * 仅统计活跃伏笔(planted/progressing);_health 为运行时计算,不写回 data。
74
+ * 输出按 hook id 升序(稳定排序);signal:循环中检查(决策 16 ③)。
75
+ */
76
+ export declare function runAnalyzeHookHealth(ctx: ToolContext, _args: AnalyzeHookHealthArgs, signal?: AbortSignal): HookHealthOverview;
77
+ /** 生命周期节点事件(hooks.md trace_hook_lifecycle) */
78
+ export interface HookNodeEvent {
79
+ nodeId: string;
80
+ nodeName: string;
81
+ /** 所属章序号(节点无章号 → null) */
82
+ chapter: number | null;
83
+ }
84
+ /** 生命周期追踪结果(hooks.md trace_hook_lifecycle(hook_id) 返回结构,字段名逐字对齐 snake_case) */
85
+ export interface HookLifecycle {
86
+ hook: EntityRow;
87
+ plant: HookNodeEvent | null;
88
+ /** 推进节点(按章节序升序) */
89
+ advances: HookNodeEvent[];
90
+ resolve: HookNodeEvent | null;
91
+ /** 当前休眠章数(current - 最后活跃章;缺数据 → null) */
92
+ dormancy: number | null;
93
+ /** 时间线图(plant → advances → resolve 按章节序合并) */
94
+ timeline_graph: {
95
+ events: (HookNodeEvent & {
96
+ kind: "plant" | "advance" | "resolve";
97
+ })[];
98
+ };
99
+ }
100
+ /**
101
+ * 生命周期追踪(hooks.md trace_hook_lifecycle(hook_id))。
102
+ * hook 不存在/已软删 → null(查询无结果);plant 取最早埋设节点、resolve 取最新回收节点;
103
+ * dormancy 口径与 _health 一致(advances 最新,无 advances → 埋设章)。
104
+ */
105
+ export declare function runTraceHookLifecycle(ctx: ToolContext, args: TraceHookLifecycleArgs, signal?: AbortSignal): HookLifecycle | null;
106
+ /** 回收建议结果(hooks.md suggest_hook_payoff(hook_id) 返回结构) */
107
+ export interface HookPayoffSuggestion {
108
+ at_node: string;
109
+ reason: string;
110
+ }
111
+ /**
112
+ * 回收建议(hooks.md suggest_hook_payoff(hook_id)):
113
+ * 候选 = 大纲中**当前章节之后**(含当前章)的场景节点(非软删),排除已回收节点;
114
+ * 理想回收点 = 埋设章 + 半衰期(节奏匹配);按与理想点距离升序取 top 3。
115
+ * hook 不存在/已软删 → null;无埋设记录或大纲无候选场景 → 空建议。
116
+ */
117
+ export declare function runSuggestHookPayoff(ctx: ToolContext, args: SuggestHookPayoffArgs, signal?: AbortSignal): {
118
+ suggestions: HookPayoffSuggestion[];
119
+ } | null;
120
+ /** 埋设机会结果(hooks.md find_hook_opportunities(outline_node_id) 返回结构) */
121
+ export interface HookOpportunity {
122
+ category: string;
123
+ reason: string;
124
+ }
125
+ /**
126
+ * 埋设机会发现(hooks.md find_hook_opportunities(outline_node_id)):
127
+ * 基于节点叙事特征建议适合的伏笔类别(每类别至多一条,规则表驱动):
128
+ * - R1 无伏笔埋设(无 plants 关系)→ mystery(悬念/谜团)
129
+ * - R2 角色在场 ≥ 2(appears_in 目标)→ relationship(人物关系)
130
+ * - R3 scene 冲突含外部层面(extra_personal)→ world_building(世界观)
131
+ * - R4 scene 价值转向(value_from ≠ value_to 且均非空)→ character_growth(角色成长)
132
+ * 节点不存在/已软删 → null。
133
+ */
134
+ export declare function runFindHookOpportunities(ctx: ToolContext, args: FindHookOpportunitiesArgs, signal?: AbortSignal): {
135
+ opportunities: HookOpportunity[];
136
+ } | null;
137
+ /** 伏笔矛盾结果(hooks.md detect_hook_conflicts() 返回结构) */
138
+ export interface HookConflict {
139
+ hook_a: string;
140
+ hook_b: string;
141
+ field: string;
142
+ description: string;
143
+ }
144
+ /**
145
+ * 伏笔矛盾检测(hooks.md detect_hook_conflicts(),无参全项目扫描):
146
+ * - R1 循环依赖(error):A depends_on B 且 B depends_on A——永远无法同时回收
147
+ * **限制(MVP)**:仅检测二元互依赖(A↔B);三节点及以上长环零检出——依赖图按
148
+ * depends_on 稀疏构建,长环罕见,需 DFS 找环(后续切片评估),此处明示不静默承诺
149
+ * - R2 依赖已废弃(error):A depends_on B 且 B abandoned——依赖永远无法满足
150
+ * - R3 回收早于埋设(error):resolves 节点章节 < plants 节点章节——时间悖论
151
+ * - R4 推进早于埋设(error):advances 节点章节 < plants 节点章节——时间悖论
152
+ * 输出按 (hook_a, hook_b) 稳定排序;signal:循环中检查(决策 16 ③)。
153
+ */
154
+ export declare function runDetectHookConflicts(ctx: ToolContext, _args: DetectHookConflictsArgs, signal?: AbortSignal): {
155
+ conflicts: HookConflict[];
156
+ };
157
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/analysis/hook.ts"],"names":[],"mappings":"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"}