psyclaw 0.24.0

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 (270) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/apps/panel/index.html +3416 -0
  4. package/dist/src/adapters/pi/extension.d.ts +19 -0
  5. package/dist/src/adapters/pi/extension.js +735 -0
  6. package/dist/src/adapters/pi/extension.js.map +1 -0
  7. package/dist/src/adapters/pi/model.d.ts +72 -0
  8. package/dist/src/adapters/pi/model.js +152 -0
  9. package/dist/src/adapters/pi/model.js.map +1 -0
  10. package/dist/src/adapters/pi/resources.d.ts +23 -0
  11. package/dist/src/adapters/pi/resources.js +54 -0
  12. package/dist/src/adapters/pi/resources.js.map +1 -0
  13. package/dist/src/adapters/pi/rpc.d.ts +56 -0
  14. package/dist/src/adapters/pi/rpc.js +248 -0
  15. package/dist/src/adapters/pi/rpc.js.map +1 -0
  16. package/dist/src/adapters/pi/session.d.ts +30 -0
  17. package/dist/src/adapters/pi/session.js +64 -0
  18. package/dist/src/adapters/pi/session.js.map +1 -0
  19. package/dist/src/agents/catalog.d.ts +30 -0
  20. package/dist/src/agents/catalog.js +118 -0
  21. package/dist/src/agents/catalog.js.map +1 -0
  22. package/dist/src/agents/discover.d.ts +28 -0
  23. package/dist/src/agents/discover.js +127 -0
  24. package/dist/src/agents/discover.js.map +1 -0
  25. package/dist/src/agents/import.d.ts +67 -0
  26. package/dist/src/agents/import.js +801 -0
  27. package/dist/src/agents/import.js.map +1 -0
  28. package/dist/src/analysis/hooks.d.ts +81 -0
  29. package/dist/src/analysis/hooks.js +139 -0
  30. package/dist/src/analysis/hooks.js.map +1 -0
  31. package/dist/src/analysis/pre-registration.d.ts +18 -0
  32. package/dist/src/analysis/pre-registration.js +86 -0
  33. package/dist/src/analysis/pre-registration.js.map +1 -0
  34. package/dist/src/branding.d.ts +43 -0
  35. package/dist/src/branding.js +127 -0
  36. package/dist/src/branding.js.map +1 -0
  37. package/dist/src/chat.d.ts +16 -0
  38. package/dist/src/chat.js +67 -0
  39. package/dist/src/chat.js.map +1 -0
  40. package/dist/src/cli.d.ts +2 -0
  41. package/dist/src/cli.js +316 -0
  42. package/dist/src/cli.js.map +1 -0
  43. package/dist/src/core/citations.d.ts +44 -0
  44. package/dist/src/core/citations.js +48 -0
  45. package/dist/src/core/citations.js.map +1 -0
  46. package/dist/src/core/contracts.d.ts +119 -0
  47. package/dist/src/core/contracts.js +2 -0
  48. package/dist/src/core/contracts.js.map +1 -0
  49. package/dist/src/core/docx.d.ts +11 -0
  50. package/dist/src/core/docx.js +46 -0
  51. package/dist/src/core/docx.js.map +1 -0
  52. package/dist/src/core/doi.d.ts +41 -0
  53. package/dist/src/core/doi.js +82 -0
  54. package/dist/src/core/doi.js.map +1 -0
  55. package/dist/src/core/evidence-policy.d.ts +24 -0
  56. package/dist/src/core/evidence-policy.js +308 -0
  57. package/dist/src/core/evidence-policy.js.map +1 -0
  58. package/dist/src/core/filekind.d.ts +15 -0
  59. package/dist/src/core/filekind.js +82 -0
  60. package/dist/src/core/filekind.js.map +1 -0
  61. package/dist/src/core/hash.d.ts +2 -0
  62. package/dist/src/core/hash.js +17 -0
  63. package/dist/src/core/hash.js.map +1 -0
  64. package/dist/src/core/pricing.d.ts +38 -0
  65. package/dist/src/core/pricing.js +110 -0
  66. package/dist/src/core/pricing.js.map +1 -0
  67. package/dist/src/core/redact.d.ts +12 -0
  68. package/dist/src/core/redact.js +48 -0
  69. package/dist/src/core/redact.js.map +1 -0
  70. package/dist/src/core/references.d.ts +55 -0
  71. package/dist/src/core/references.js +102 -0
  72. package/dist/src/core/references.js.map +1 -0
  73. package/dist/src/core/schemas.d.ts +162 -0
  74. package/dist/src/core/schemas.js +160 -0
  75. package/dist/src/core/schemas.js.map +1 -0
  76. package/dist/src/extension.d.ts +1 -0
  77. package/dist/src/extension.js +2 -0
  78. package/dist/src/extension.js.map +1 -0
  79. package/dist/src/index.d.ts +72 -0
  80. package/dist/src/index.js +73 -0
  81. package/dist/src/index.js.map +1 -0
  82. package/dist/src/install/installer.d.ts +147 -0
  83. package/dist/src/install/installer.js +743 -0
  84. package/dist/src/install/installer.js.map +1 -0
  85. package/dist/src/integrations/contracts.d.ts +35 -0
  86. package/dist/src/integrations/contracts.js +27 -0
  87. package/dist/src/integrations/contracts.js.map +1 -0
  88. package/dist/src/integrations/mcp.d.ts +155 -0
  89. package/dist/src/integrations/mcp.js +826 -0
  90. package/dist/src/integrations/mcp.js.map +1 -0
  91. package/dist/src/knowledge-map/contracts.d.ts +20 -0
  92. package/dist/src/knowledge-map/contracts.js +2 -0
  93. package/dist/src/knowledge-map/contracts.js.map +1 -0
  94. package/dist/src/knowledge-map/index.d.ts +4 -0
  95. package/dist/src/knowledge-map/index.js +39 -0
  96. package/dist/src/knowledge-map/index.js.map +1 -0
  97. package/dist/src/literature/contracts.d.ts +106 -0
  98. package/dist/src/literature/contracts.js +2 -0
  99. package/dist/src/literature/contracts.js.map +1 -0
  100. package/dist/src/literature/fulltext.d.ts +7 -0
  101. package/dist/src/literature/fulltext.js +24 -0
  102. package/dist/src/literature/fulltext.js.map +1 -0
  103. package/dist/src/literature/knowledge-map.d.ts +2 -0
  104. package/dist/src/literature/knowledge-map.js +20 -0
  105. package/dist/src/literature/knowledge-map.js.map +1 -0
  106. package/dist/src/literature/ledger.d.ts +3 -0
  107. package/dist/src/literature/ledger.js +17 -0
  108. package/dist/src/literature/ledger.js.map +1 -0
  109. package/dist/src/literature/metadata.d.ts +6 -0
  110. package/dist/src/literature/metadata.js +32 -0
  111. package/dist/src/literature/metadata.js.map +1 -0
  112. package/dist/src/memory/store.d.ts +22 -0
  113. package/dist/src/memory/store.js +73 -0
  114. package/dist/src/memory/store.js.map +1 -0
  115. package/dist/src/orchestration/contracts.d.ts +61 -0
  116. package/dist/src/orchestration/contracts.js +2 -0
  117. package/dist/src/orchestration/contracts.js.map +1 -0
  118. package/dist/src/orchestration/pi-executor.d.ts +28 -0
  119. package/dist/src/orchestration/pi-executor.js +169 -0
  120. package/dist/src/orchestration/pi-executor.js.map +1 -0
  121. package/dist/src/orchestration/runner.d.ts +196 -0
  122. package/dist/src/orchestration/runner.js +991 -0
  123. package/dist/src/orchestration/runner.js.map +1 -0
  124. package/dist/src/orchestration/scheduler.d.ts +8 -0
  125. package/dist/src/orchestration/scheduler.js +335 -0
  126. package/dist/src/orchestration/scheduler.js.map +1 -0
  127. package/dist/src/panel/events.d.ts +20 -0
  128. package/dist/src/panel/events.js +93 -0
  129. package/dist/src/panel/events.js.map +1 -0
  130. package/dist/src/panel/extension.d.ts +8 -0
  131. package/dist/src/panel/extension.js +114 -0
  132. package/dist/src/panel/extension.js.map +1 -0
  133. package/dist/src/panel/literature-map.d.ts +26 -0
  134. package/dist/src/panel/literature-map.js +34 -0
  135. package/dist/src/panel/literature-map.js.map +1 -0
  136. package/dist/src/panel/projection.d.ts +51 -0
  137. package/dist/src/panel/projection.js +288 -0
  138. package/dist/src/panel/projection.js.map +1 -0
  139. package/dist/src/panel/server.d.ts +46 -0
  140. package/dist/src/panel/server.js +1610 -0
  141. package/dist/src/panel/server.js.map +1 -0
  142. package/dist/src/panel/usage.d.ts +53 -0
  143. package/dist/src/panel/usage.js +150 -0
  144. package/dist/src/panel/usage.js.map +1 -0
  145. package/dist/src/project/bootstrap.d.ts +10 -0
  146. package/dist/src/project/bootstrap.js +83 -0
  147. package/dist/src/project/bootstrap.js.map +1 -0
  148. package/dist/src/project/hitl.d.ts +12 -0
  149. package/dist/src/project/hitl.js +43 -0
  150. package/dist/src/project/hitl.js.map +1 -0
  151. package/dist/src/project/jsonl.d.ts +16 -0
  152. package/dist/src/project/jsonl.js +93 -0
  153. package/dist/src/project/jsonl.js.map +1 -0
  154. package/dist/src/project/manuscript.d.ts +21 -0
  155. package/dist/src/project/manuscript.js +74 -0
  156. package/dist/src/project/manuscript.js.map +1 -0
  157. package/dist/src/project/paths.d.ts +38 -0
  158. package/dist/src/project/paths.js +166 -0
  159. package/dist/src/project/paths.js.map +1 -0
  160. package/dist/src/project/versions.d.ts +10 -0
  161. package/dist/src/project/versions.js +14 -0
  162. package/dist/src/project/versions.js.map +1 -0
  163. package/dist/src/psyclaw-theme.d.ts +88 -0
  164. package/dist/src/psyclaw-theme.js +89 -0
  165. package/dist/src/psyclaw-theme.js.map +1 -0
  166. package/dist/src/research/brief.d.ts +11 -0
  167. package/dist/src/research/brief.js +81 -0
  168. package/dist/src/research/brief.js.map +1 -0
  169. package/dist/src/research/ledger.d.ts +12 -0
  170. package/dist/src/research/ledger.js +43 -0
  171. package/dist/src/research/ledger.js.map +1 -0
  172. package/dist/src/run.d.ts +20 -0
  173. package/dist/src/run.js +34 -0
  174. package/dist/src/run.js.map +1 -0
  175. package/dist/src/setup.d.ts +54 -0
  176. package/dist/src/setup.js +221 -0
  177. package/dist/src/setup.js.map +1 -0
  178. package/dist/src/skills/contracts.d.ts +105 -0
  179. package/dist/src/skills/contracts.js +3 -0
  180. package/dist/src/skills/contracts.js.map +1 -0
  181. package/dist/src/skills/preflight.d.ts +10 -0
  182. package/dist/src/skills/preflight.js +39 -0
  183. package/dist/src/skills/preflight.js.map +1 -0
  184. package/dist/src/skills/registry.d.ts +28 -0
  185. package/dist/src/skills/registry.js +556 -0
  186. package/dist/src/skills/registry.js.map +1 -0
  187. package/dist/src/style/artifact.d.ts +6 -0
  188. package/dist/src/style/artifact.js +61 -0
  189. package/dist/src/style/artifact.js.map +1 -0
  190. package/dist/src/style/cli-ui.d.ts +41 -0
  191. package/dist/src/style/cli-ui.js +119 -0
  192. package/dist/src/style/cli-ui.js.map +1 -0
  193. package/dist/src/style/contracts.d.ts +34 -0
  194. package/dist/src/style/contracts.js +2 -0
  195. package/dist/src/style/contracts.js.map +1 -0
  196. package/dist/src/style/registry.d.ts +16 -0
  197. package/dist/src/style/registry.js +50 -0
  198. package/dist/src/style/registry.js.map +1 -0
  199. package/dist/src/trust/manifest.d.ts +42 -0
  200. package/dist/src/trust/manifest.js +53 -0
  201. package/dist/src/trust/manifest.js.map +1 -0
  202. package/dist/src/trust/sbom.d.ts +54 -0
  203. package/dist/src/trust/sbom.js +77 -0
  204. package/dist/src/trust/sbom.js.map +1 -0
  205. package/dist/src/tui/app.d.ts +3 -0
  206. package/dist/src/tui/app.js +103 -0
  207. package/dist/src/tui/app.js.map +1 -0
  208. package/dist/src/tui/model.d.ts +13 -0
  209. package/dist/src/tui/model.js +25 -0
  210. package/dist/src/tui/model.js.map +1 -0
  211. package/dist/src/updates/check.d.ts +43 -0
  212. package/dist/src/updates/check.js +68 -0
  213. package/dist/src/updates/check.js.map +1 -0
  214. package/dist/src/updates/manifest.d.ts +19 -0
  215. package/dist/src/updates/manifest.js +58 -0
  216. package/dist/src/updates/manifest.js.map +1 -0
  217. package/dist/src/updates/registry.d.ts +21 -0
  218. package/dist/src/updates/registry.js +82 -0
  219. package/dist/src/updates/registry.js.map +1 -0
  220. package/dist/src/updates/skills.d.ts +15 -0
  221. package/dist/src/updates/skills.js +39 -0
  222. package/dist/src/updates/skills.js.map +1 -0
  223. package/dist/src/updates/status.d.ts +7 -0
  224. package/dist/src/updates/status.js +37 -0
  225. package/dist/src/updates/status.js.map +1 -0
  226. package/dist/src/updates/update.d.ts +43 -0
  227. package/dist/src/updates/update.js +126 -0
  228. package/dist/src/updates/update.js.map +1 -0
  229. package/dist/src/wizard.d.ts +7 -0
  230. package/dist/src/wizard.js +90 -0
  231. package/dist/src/wizard.js.map +1 -0
  232. package/dist/src/workflows/analysis-delegation.d.ts +3 -0
  233. package/dist/src/workflows/analysis-delegation.js +96 -0
  234. package/dist/src/workflows/analysis-delegation.js.map +1 -0
  235. package/dist/src/workflows/expert-review-runner.d.ts +29 -0
  236. package/dist/src/workflows/expert-review-runner.js +35 -0
  237. package/dist/src/workflows/expert-review-runner.js.map +1 -0
  238. package/dist/src/workflows/expert-review.d.ts +140 -0
  239. package/dist/src/workflows/expert-review.js +111 -0
  240. package/dist/src/workflows/expert-review.js.map +1 -0
  241. package/dist/src/workflows/institutional-fulltext.d.ts +16 -0
  242. package/dist/src/workflows/institutional-fulltext.js +110 -0
  243. package/dist/src/workflows/institutional-fulltext.js.map +1 -0
  244. package/dist/src/workflows/literature-review.d.ts +3 -0
  245. package/dist/src/workflows/literature-review.js +76 -0
  246. package/dist/src/workflows/literature-review.js.map +1 -0
  247. package/dist/src/workflows/meta-analysis.d.ts +38 -0
  248. package/dist/src/workflows/meta-analysis.js +185 -0
  249. package/dist/src/workflows/meta-analysis.js.map +1 -0
  250. package/dist/src/workflows/publish.d.ts +51 -0
  251. package/dist/src/workflows/publish.js +153 -0
  252. package/dist/src/workflows/publish.js.map +1 -0
  253. package/dist/src/workflows/spec.d.ts +51 -0
  254. package/dist/src/workflows/spec.js +157 -0
  255. package/dist/src/workflows/spec.js.map +1 -0
  256. package/dist/src/workflows/style-contract.d.ts +24 -0
  257. package/dist/src/workflows/style-contract.js +23 -0
  258. package/dist/src/workflows/style-contract.js.map +1 -0
  259. package/dist/src/workflows/writing-review.d.ts +15 -0
  260. package/dist/src/workflows/writing-review.js +82 -0
  261. package/dist/src/workflows/writing-review.js.map +1 -0
  262. package/package.json +73 -0
  263. package/package.json.psyclaw +21 -0
  264. package/skills/core/citation-audit/SKILL.md +9 -0
  265. package/skills/core/evidence-capture/SKILL.md +9 -0
  266. package/skills/core/manifest.json +15 -0
  267. package/skills/core/research-brief/SKILL.md +11 -0
  268. package/skills/core/research-intake/SKILL.md +9 -0
  269. package/skills/recommended/catalog.json +52 -0
  270. package/skills/recommended/mcp-catalog.json +118 -0
@@ -0,0 +1,308 @@
1
+ const LEVEL_RANK = {
2
+ metadata: 0,
3
+ abstract: 1,
4
+ snippet: 2,
5
+ fulltext: 3,
6
+ // User-provided material is an input to review, not independently
7
+ // verified support. Keep it below every policy threshold by default.
8
+ user: -1,
9
+ };
10
+ const DEFAULT_MINIMUM = {
11
+ existence: "metadata",
12
+ definition: "abstract",
13
+ method: "snippet",
14
+ result: "fulltext",
15
+ interpretation: "snippet",
16
+ };
17
+ export function defaultEvidencePolicy(paradigm, claimKind) {
18
+ return {
19
+ paradigm,
20
+ claimKind,
21
+ minimumLevel: DEFAULT_MINIMUM[claimKind],
22
+ locatorRequired: claimKind !== "existence",
23
+ requiresIndependentSource: claimKind === "interpretation" || claimKind === "result",
24
+ requiresArtifactRun: claimKind === "result",
25
+ };
26
+ }
27
+ /**
28
+ * The paradigm profile changes only the evidence thresholds and required
29
+ * reporting, never the honesty/locator/source baseline. Qualitative and
30
+ * ethnographic material is coded primary data: a theme does not need a second
31
+ * independent source or a numeric artifact run, but it still needs a located,
32
+ * non-user source. Absence of an effect size must not make a qualitative
33
+ * finding invalid.
34
+ */
35
+ export function policiesForParadigm(paradigm) {
36
+ const kinds = ["existence", "definition", "method", "result", "interpretation"];
37
+ const policies = kinds.map((kind) => defaultEvidencePolicy(paradigm, kind));
38
+ const policyFor = (kind) => policies.find((item) => item.claimKind === kind);
39
+ switch (paradigm) {
40
+ case "qualitative-thematic":
41
+ case "ethnographic":
42
+ // Themes are coded primary data: a single located source suffices and no
43
+ // numeric artifact run exists.
44
+ policyFor("definition").requiresIndependentSource = false;
45
+ policyFor("interpretation").requiresIndependentSource = false;
46
+ policyFor("result").requiresIndependentSource = false;
47
+ policyFor("result").requiresArtifactRun = false;
48
+ break;
49
+ case "historical-documentary":
50
+ case "policy-legal":
51
+ // Primary archives / statutes are themselves the source of truth.
52
+ policyFor("result").requiresIndependentSource = false;
53
+ policyFor("interpretation").requiresIndependentSource = false;
54
+ policyFor("result").requiresArtifactRun = false;
55
+ break;
56
+ case "survey-observational":
57
+ // Observational design keeps the interpretation independent-source gate
58
+ // (overclaiming risk); no relaxation, so the baseline is left untouched.
59
+ break;
60
+ case "meta-analysis":
61
+ // PRISMA-grade screening needs full text, not an abstract, for method
62
+ // and pooled result claims.
63
+ policyFor("method").minimumLevel = "fulltext";
64
+ policyFor("result").minimumLevel = "fulltext";
65
+ break;
66
+ case "experimental":
67
+ case "quasi-experimental":
68
+ case "longitudinal-panel":
69
+ // Confirmatory designs keep the strictest baseline: fulltext + two
70
+ // independent sources + artifact run for results.
71
+ break;
72
+ case "mixed-methods":
73
+ // Triangulation: interpretation already requires an independent source
74
+ // under the baseline, so nothing is relaxed here.
75
+ break;
76
+ }
77
+ return policies;
78
+ }
79
+ /** Required report sections per paradigm, beyond the universal honesty baseline. */
80
+ export const PARADIGM_REPORT_FIELDS = {
81
+ "survey-observational": ["效应量与置信区间", "抽样方式与样本量", "缺失值处理", "共同方法偏差说明"],
82
+ "qualitative-thematic": ["研究者立场与反身性", "编码轨迹与主题", "反例与负例", "主题饱和说明"],
83
+ experimental: ["随机化与盲法", "主要结局预注册", "效应量与置信区间", "退出与流失", "违反方案说明"],
84
+ "quasi-experimental": ["识别策略与混淆控制", "平行趋势或均衡性检验", "效应量与置信区间"],
85
+ "longitudinal-panel": ["随访率与流失", "时变混杂处理", "缺失模式", "效应量与置信区间"],
86
+ "meta-analysis": ["检索式与纳入排除标准", "PRISMA 流程", "异质性 I²/τ²", "发表偏倚", "效应量与置信区间"],
87
+ ethnographic: ["田野与研究者立场", "参与者与研究关系", "三角验证", "伦理与匿名化"],
88
+ "historical-documentary": ["史料来源与真伪", "年代与语境", "解读可复核"],
89
+ "policy-legal": ["法条或判例出处", "管辖与时效", "解释立场"],
90
+ "mixed-methods": ["定量与定性整合逻辑", "混合设计类型", "两部分各自的质量标准"],
91
+ };
92
+ function hasLocator(evidence, policy) {
93
+ if (evidence.level === "snippet") {
94
+ if (!evidence.quote?.trim())
95
+ return false;
96
+ if (!hasPreciseLocator(evidence, new Set(["page", "section", "offset"])))
97
+ return false;
98
+ return true;
99
+ }
100
+ if (evidence.level === "fulltext") {
101
+ if (!evidence.sha256 || !/^[a-f0-9]{64}$/i.test(evidence.sha256.trim()))
102
+ return false;
103
+ if (!hasPreciseLocator(evidence, new Set(["page", "section", "row"])))
104
+ return false;
105
+ return true;
106
+ }
107
+ if (!policy.locatorRequired)
108
+ return true;
109
+ if (evidence.locators.length === 0)
110
+ return false;
111
+ return true;
112
+ }
113
+ function meetsLevel(evidence, minimum) {
114
+ // A user-supplied record must not become verified support merely because a
115
+ // caller asks for a low minimum. A custom policy can still inspect it as an
116
+ // input and mark the claim uncertain outside this default gate.
117
+ if (evidence.level === "user" || evidence.source.kind === "user")
118
+ return false;
119
+ return evidence.accessStatus === "verified" && LEVEL_RANK[evidence.level] >= LEVEL_RANK[minimum];
120
+ }
121
+ function hasPreciseLocator(evidence, allowed) {
122
+ return evidence.locators.some((locator) => allowed.has(locator.kind) && locator.value.trim().length > 0);
123
+ }
124
+ function normalizeDoi(value) {
125
+ let normalized = value.trim().toLowerCase();
126
+ normalized = normalized.replace(/^(?:https?:\/\/)?(?:dx\.)?doi\.org\//, "");
127
+ normalized = normalized.replace(/^doi:\s*/, "");
128
+ normalized = normalized.replace(/[\s]+/g, "");
129
+ normalized = normalized.replace(/[.,;:)}\]>]+$/, "");
130
+ return normalized.startsWith("10.") && normalized.includes("/") ? normalized : undefined;
131
+ }
132
+ function sourceIdentityKeys(evidence) {
133
+ const keys = [];
134
+ const sha = evidence.sha256?.trim().toLowerCase();
135
+ if (sha)
136
+ keys.push(`sha256:${sha}`);
137
+ const doi = normalizeDoi(evidence.source.locator);
138
+ if (doi)
139
+ keys.push(`doi:${doi}`);
140
+ // A DOI can be embedded in a URL or a source label. This catches common
141
+ // Crossref/publisher forms without treating arbitrary URLs as DOIs.
142
+ if (!doi) {
143
+ const embedded = evidence.source.locator.match(/10\.\d{4,9}\/[^\s"<>]+/i)?.[0];
144
+ const embeddedDoi = embedded ? normalizeDoi(embedded) : undefined;
145
+ if (embeddedDoi)
146
+ keys.push(`doi:${embeddedDoi}`);
147
+ }
148
+ if (keys.length === 0) {
149
+ const locator = evidence.source.locator.trim().replaceAll("\\", "/").toLowerCase();
150
+ keys.push(`${evidence.source.kind}:${locator}`);
151
+ }
152
+ return keys;
153
+ }
154
+ function countIndependentSources(items) {
155
+ // Union evidence records when *any* stable identity agrees. This means two
156
+ // PDF paths with the same SHA and two DOI spellings remain one source, even
157
+ // if their other locators differ.
158
+ const parent = new Map();
159
+ const find = (item) => {
160
+ const current = parent.get(item);
161
+ if (!current) {
162
+ parent.set(item, item);
163
+ return item;
164
+ }
165
+ if (current === item)
166
+ return item;
167
+ const root = find(current);
168
+ parent.set(item, root);
169
+ return root;
170
+ };
171
+ const union = (left, right) => {
172
+ const leftRoot = find(left);
173
+ const rightRoot = find(right);
174
+ if (leftRoot !== rightRoot)
175
+ parent.set(leftRoot, rightRoot);
176
+ };
177
+ for (const evidence of items) {
178
+ const keys = sourceIdentityKeys(evidence);
179
+ const first = keys[0];
180
+ if (!first)
181
+ continue;
182
+ find(first);
183
+ for (const key of keys.slice(1))
184
+ union(first, key);
185
+ }
186
+ const roots = new Set();
187
+ for (const evidence of items) {
188
+ const first = sourceIdentityKeys(evidence)[0];
189
+ if (first)
190
+ roots.add(find(first));
191
+ }
192
+ return roots.size;
193
+ }
194
+ export function checkEvidenceSufficiency(ctx) {
195
+ const evidenceById = new Map(ctx.evidence.map((item) => [item.id, item]));
196
+ const linksByClaim = new Map();
197
+ for (const link of ctx.links) {
198
+ const bucket = linksByClaim.get(link.claimId) ?? [];
199
+ bucket.push(link);
200
+ linksByClaim.set(link.claimId, bucket);
201
+ }
202
+ const results = [];
203
+ const claimIds = new Set(ctx.claims.map((claim) => claim.id));
204
+ const duplicateClaimIds = ctx.claims
205
+ .map((claim) => claim.id)
206
+ .filter((id, index, all) => all.indexOf(id) !== index);
207
+ if (duplicateClaimIds.length > 0) {
208
+ results.push({
209
+ gateId: "ledger:duplicate-claim-ids",
210
+ ok: false,
211
+ severity: "block",
212
+ reason: `账本包含重复 Claim ID: ${[...new Set(duplicateClaimIds)].join(", ")}`,
213
+ claimIds: [...new Set(duplicateClaimIds)],
214
+ });
215
+ }
216
+ for (const claim of ctx.claims) {
217
+ const resolvedPolicies = ctx.policies ?? policiesForParadigm(ctx.paradigm ?? "survey-observational");
218
+ const policy = resolvedPolicies.find((candidate) => candidate.claimKind === claim.kind) ?? defaultEvidencePolicy("survey-observational", claim.kind);
219
+ const links = linksByClaim.get(claim.id) ?? [];
220
+ const supporting = links.filter((link) => link.relation === "supports");
221
+ const contradictory = links.filter((link) => link.relation === "contradicts");
222
+ const qualifying = supporting.filter((link) => {
223
+ const evidence = evidenceById.get(link.evidenceId);
224
+ return Boolean(evidence && meetsLevel(evidence, policy.minimumLevel) && hasLocator(evidence, policy));
225
+ });
226
+ const reasons = [];
227
+ const declaredIds = new Set(claim.evidenceIds);
228
+ const duplicateEvidenceIds = claim.evidenceIds.filter((id, index, all) => all.indexOf(id) !== index);
229
+ if (duplicateEvidenceIds.length > 0) {
230
+ reasons.push(`Claim.evidenceIds 包含重复 ID: ${[...new Set(duplicateEvidenceIds)].join(", ")}`);
231
+ }
232
+ const linkedIds = new Set(links.map((link) => link.evidenceId));
233
+ const unlinkedDeclared = claim.evidenceIds.filter((id) => !linkedIds.has(id));
234
+ if (unlinkedDeclared.length > 0) {
235
+ reasons.push(`Claim 声明了未建立关系的 Evidence: ${[...new Set(unlinkedDeclared)].join(", ")}`);
236
+ }
237
+ const undeclaredLinked = [...linkedIds].filter((id) => !declaredIds.has(id));
238
+ if (undeclaredLinked.length > 0) {
239
+ reasons.push(`关系引用的 Evidence 未在 Claim.evidenceIds 声明: ${undeclaredLinked.join(", ")}`);
240
+ }
241
+ const duplicateLinks = links.filter((link, index, all) => {
242
+ const key = `${link.evidenceId}\u0000${link.relation}`;
243
+ return all.findIndex((candidate) => `${candidate.evidenceId}\u0000${candidate.relation}` === key) !== index;
244
+ });
245
+ if (duplicateLinks.length > 0) {
246
+ reasons.push("同一 Claim 存在重复 Evidence 关系");
247
+ }
248
+ const missingEvidenceIds = [...new Set([
249
+ ...claim.evidenceIds.filter((id) => !evidenceById.has(id)),
250
+ ...links.map((link) => link.evidenceId).filter((id) => !evidenceById.has(id)),
251
+ ])];
252
+ if (missingEvidenceIds.length > 0) {
253
+ reasons.push(`关系引用了不存在的 Evidence: ${missingEvidenceIds.join(", ")}`);
254
+ }
255
+ if (supporting.some((link) => evidenceById.get(link.evidenceId)?.accessStatus === "unavailable")) {
256
+ reasons.push("支持关系引用了不可用来源");
257
+ }
258
+ if (supporting.some((link) => {
259
+ const item = evidenceById.get(link.evidenceId);
260
+ return item && item.accessStatus !== "verified";
261
+ })) {
262
+ reasons.push("支持关系引用了尚未核验的来源");
263
+ }
264
+ if (supporting.some((link) => {
265
+ const item = evidenceById.get(link.evidenceId);
266
+ return item?.level === "user" || item?.source.kind === "user";
267
+ })) {
268
+ reasons.push("用户提供的 Evidence 默认不能作为已验证支持");
269
+ }
270
+ if (qualifying.length === 0)
271
+ reasons.push("没有达到当前 Claim 类型所需等级且可定位的支持证据");
272
+ if (contradictory.length > 0)
273
+ reasons.push("存在尚未处理的矛盾证据");
274
+ const qualifyingEvidence = qualifying
275
+ .map((link) => evidenceById.get(link.evidenceId))
276
+ .filter((item) => item !== undefined);
277
+ if (policy.requiresIndependentSource && countIndependentSources(qualifyingEvidence) < 2) {
278
+ reasons.push("当前策略要求至少两个独立支持来源");
279
+ }
280
+ if (policy.requiresArtifactRun && !ctx.artifactRunClaimIds?.has(claim.id)) {
281
+ reasons.push("结果型 Claim 缺少真实运行产物或结果哈希");
282
+ }
283
+ if (claim.status !== "supported" && qualifying.length > 0 && contradictory.length === 0) {
284
+ reasons.push(`Claim 状态为 ${claim.status},但已有满足策略的支持证据`);
285
+ }
286
+ results.push({
287
+ gateId: `evidence:${claim.id}`,
288
+ ok: reasons.length === 0,
289
+ severity: reasons.length === 0 ? "warn" : "block",
290
+ reason: reasons.length === 0 ? "证据关系满足当前 profile" : reasons.join(";"),
291
+ claimIds: [claim.id],
292
+ evidenceIds: links.map((link) => link.evidenceId),
293
+ });
294
+ }
295
+ const orphanLinks = ctx.links.filter((link) => !claimIds.has(link.claimId));
296
+ if (orphanLinks.length > 0) {
297
+ results.push({
298
+ gateId: "ledger:orphan-links",
299
+ ok: false,
300
+ severity: "block",
301
+ reason: `Evidence 关系引用了不存在的 Claim: ${[...new Set(orphanLinks.map((link) => link.claimId))].join(", ")}`,
302
+ claimIds: [...new Set(orphanLinks.map((link) => link.claimId))],
303
+ evidenceIds: [...new Set(orphanLinks.map((link) => link.evidenceId))],
304
+ });
305
+ }
306
+ return results;
307
+ }
308
+ //# sourceMappingURL=evidence-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-policy.js","sourceRoot":"","sources":["../../../src/core/evidence-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type FileKind = "pdf" | "docx" | "html" | "json" | "text" | "binary" | "empty" | "unknown";
2
+ /**
3
+ * Classify content by its leading bytes, never by its filename extension.
4
+ * This is the deterministic basis for the `fake-pdf-html` hard fail: an HTML
5
+ * login or captcha page must not be accepted as trusted full-text just
6
+ * because its name ends in `.pdf`.
7
+ */
8
+ export declare function sniffKindFromBuffer(buffer: Uint8Array): FileKind;
9
+ export declare function sniffFileKind(path: string): Promise<FileKind>;
10
+ /**
11
+ * Gate a local evidence import. `fulltext` imports must be a recognizable
12
+ * document; an HTML page or an empty/binary blob is rejected rather than
13
+ * silently recorded as trusted full-text.
14
+ */
15
+ export declare function assertEvidenceImportable(path: string, level: string): Promise<void>;
@@ -0,0 +1,82 @@
1
+ import { open } from "node:fs/promises";
2
+ const SAMPLE_BYTES = 16_384;
3
+ function asciiPrefix(buffer, prefix) {
4
+ for (let index = 0; index < prefix.length; index += 1) {
5
+ if (buffer[index] !== prefix.charCodeAt(index))
6
+ return false;
7
+ }
8
+ return true;
9
+ }
10
+ function isZip(buffer) {
11
+ // PK\x03\x04 local file header
12
+ return buffer.length >= 4 && buffer[0] === 0x50 && buffer[1] === 0x4b && buffer[2] === 0x03 && buffer[3] === 0x04;
13
+ }
14
+ function latin1(buffer) {
15
+ let output = "";
16
+ for (const byte of buffer)
17
+ output += String.fromCharCode(byte);
18
+ return output;
19
+ }
20
+ /**
21
+ * Classify content by its leading bytes, never by its filename extension.
22
+ * This is the deterministic basis for the `fake-pdf-html` hard fail: an HTML
23
+ * login or captcha page must not be accepted as trusted full-text just
24
+ * because its name ends in `.pdf`.
25
+ */
26
+ export function sniffKindFromBuffer(buffer) {
27
+ if (buffer.length === 0)
28
+ return "empty";
29
+ if (buffer.length >= 5 && asciiPrefix(buffer, "%PDF-"))
30
+ return "pdf";
31
+ if (isZip(buffer)) {
32
+ // A Word .docx is a ZIP whose entries live under word/ (word/document.xml).
33
+ // Other ZIPs (xlsx/pptx/plain archives) are not treated as Word evidence.
34
+ return latin1(buffer).toLowerCase().includes("word/") ? "docx" : "binary";
35
+ }
36
+ const sample = latin1(buffer.subarray(0, Math.min(buffer.length, SAMPLE_BYTES)))
37
+ .trimStart()
38
+ .toLowerCase();
39
+ if (sample.startsWith("<") || sample.startsWith("<!doctype") || sample.includes("<html")) {
40
+ return "html";
41
+ }
42
+ if (sample.startsWith("{") || sample.startsWith("["))
43
+ return "json";
44
+ for (const byte of buffer.subarray(0, Math.min(buffer.length, SAMPLE_BYTES))) {
45
+ if (byte === 0)
46
+ return "binary";
47
+ }
48
+ return "text";
49
+ }
50
+ export async function sniffFileKind(path) {
51
+ const handle = await open(path, "r");
52
+ try {
53
+ const buffer = new Uint8Array(SAMPLE_BYTES);
54
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
55
+ return sniffKindFromBuffer(buffer.subarray(0, bytesRead));
56
+ }
57
+ finally {
58
+ await handle.close();
59
+ }
60
+ }
61
+ /**
62
+ * Gate a local evidence import. `fulltext` imports must be a recognizable
63
+ * document; an HTML page or an empty/binary blob is rejected rather than
64
+ * silently recorded as trusted full-text.
65
+ */
66
+ export async function assertEvidenceImportable(path, level) {
67
+ if (level !== "fulltext")
68
+ return;
69
+ const kind = await sniffFileKind(path);
70
+ if (kind === "html") {
71
+ throw new Error("Refusing to import HTML as full-text evidence (possible login/captcha page)");
72
+ }
73
+ if (kind === "binary" || kind === "unknown") {
74
+ throw new Error("Refusing to import unrecognized binary content as full-text evidence");
75
+ }
76
+ if (kind === "empty") {
77
+ throw new Error("Refusing to import an empty file as full-text evidence");
78
+ }
79
+ // `docx` is accepted: it is a real document, converted to text/Markdown via
80
+ // `docxToText` / `docxToMarkdown` before any claim-evidence reading.
81
+ }
82
+ //# sourceMappingURL=filekind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filekind.js","sourceRoot":"","sources":["../../../src/core/filekind.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function sha256Text(value: string): string;
2
+ export declare function sha256File(path: string): Promise<string>;
@@ -0,0 +1,17 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ export function sha256Text(value) {
4
+ return createHash("sha256").update(value, "utf8").digest("hex");
5
+ }
6
+ export async function sha256File(path) {
7
+ return new Promise((resolve, reject) => {
8
+ const hash = createHash("sha256");
9
+ const stream = createReadStream(path);
10
+ stream.on("data", (chunk) => {
11
+ hash.update(chunk);
12
+ });
13
+ stream.on("error", reject);
14
+ stream.on("end", () => resolve(hash.digest("hex")));
15
+ });
16
+ }
17
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/core/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;YAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Per-1M-token pricing used to (a) estimate cost from token usage and (b)
3
+ * give Pi a real `cost` field so it records actual usage cost.
4
+ *
5
+ * USD values are approximate list prices for common providers; local
6
+ * providers (ollama) cost 0. For display, Chinese providers also carry
7
+ * official RMB (元) list prices; non-listed providers fall back to a fixed
8
+ * USD→CNY rate so the panel can always show 人民币.
9
+ */
10
+ export interface UsdPricing {
11
+ input: number;
12
+ output: number;
13
+ cacheRead: number;
14
+ cacheWrite: number;
15
+ }
16
+ export declare const DEFAULT_PRICING: UsdPricing;
17
+ /** Exact match by provider id (lowercased). */
18
+ export declare const PROVIDER_PRICING: Record<string, UsdPricing>;
19
+ /** Resolve pricing for a provider id (exact) or a provider/model string (family match). */
20
+ export declare function pricingFor(provider: string, model: string): UsdPricing;
21
+ /** Fixed USD→CNY fallback for providers without official RMB list prices. */
22
+ export declare const USD_CNY_RATE = 7.2;
23
+ /** CNY pricing for a provider, or null when the provider has no official RMB price. */
24
+ export declare function pricingCnyFor(provider: string, _model: string): UsdPricing | null;
25
+ /** Estimated cost in USD for one usage record. */
26
+ export declare function estimateUsageCost(usage: {
27
+ input?: unknown;
28
+ output?: unknown;
29
+ cacheRead?: unknown;
30
+ cacheWrite?: unknown;
31
+ }, provider: string, model: string): number;
32
+ /** Estimated cost in 人民币 (CNY) for one usage record: official RMB list price where available, else USD×rate. */
33
+ export declare function estimateUsageCostCny(usage: {
34
+ input?: unknown;
35
+ output?: unknown;
36
+ cacheRead?: unknown;
37
+ cacheWrite?: unknown;
38
+ }, provider: string, model: string): number;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Per-1M-token pricing used to (a) estimate cost from token usage and (b)
3
+ * give Pi a real `cost` field so it records actual usage cost.
4
+ *
5
+ * USD values are approximate list prices for common providers; local
6
+ * providers (ollama) cost 0. For display, Chinese providers also carry
7
+ * official RMB (元) list prices; non-listed providers fall back to a fixed
8
+ * USD→CNY rate so the panel can always show 人民币.
9
+ */
10
+ export const DEFAULT_PRICING = { input: 1, output: 3, cacheRead: 0.1, cacheWrite: 1 };
11
+ const DEEPSEEK = { input: 0.27, output: 1.1, cacheRead: 0.07, cacheWrite: 0.27 };
12
+ const OPENAI = { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 };
13
+ const ANTHROPIC = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 };
14
+ const QWEN = { input: 0.5, output: 2, cacheRead: 0.05, cacheWrite: 0.5 };
15
+ const GLM = { input: 0.5, output: 2, cacheRead: 0.05, cacheWrite: 0.5 };
16
+ const MOONSHOT = { input: 0.3, output: 0.6, cacheRead: 0.03, cacheWrite: 0.3 };
17
+ const GOOGLE = { input: 1.25, output: 5, cacheRead: 0.125, cacheWrite: 1.25 };
18
+ const LOCAL = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
19
+ /** Exact match by provider id (lowercased). */
20
+ export const PROVIDER_PRICING = {
21
+ deepseek: DEEPSEEK,
22
+ openai: OPENAI,
23
+ anthropic: ANTHROPIC,
24
+ qwen: QWEN,
25
+ dashscope: QWEN,
26
+ zhipu: GLM,
27
+ glm: GLM,
28
+ moonshot: MOONSHOT,
29
+ kimi: MOONSHOT,
30
+ google: GOOGLE,
31
+ gemini: GOOGLE,
32
+ ollama: LOCAL,
33
+ local: LOCAL,
34
+ };
35
+ /** Family keys that match by substring (for model ids like "gpt-5.5"). */
36
+ const FAMILY_KEYS = [
37
+ [["deepseek"], DEEPSEEK],
38
+ [["gpt", "openai"], OPENAI],
39
+ [["claude", "anthropic"], ANTHROPIC],
40
+ [["qwen", "dashscope"], QWEN],
41
+ [["glm", "zhipu"], GLM],
42
+ [["moonshot", "kimi"], MOONSHOT],
43
+ [["gemini", "google"], GOOGLE],
44
+ [["ollama", "local"], LOCAL],
45
+ ];
46
+ /** Resolve pricing for a provider id (exact) or a provider/model string (family match). */
47
+ export function pricingFor(provider, model) {
48
+ const normalized = provider.trim().toLowerCase();
49
+ const exact = PROVIDER_PRICING[normalized];
50
+ if (exact !== undefined)
51
+ return exact;
52
+ const haystack = `${normalized} ${model.toLowerCase()}`;
53
+ for (const [keys, pricing] of FAMILY_KEYS) {
54
+ if (keys.some((key) => haystack.includes(key)))
55
+ return pricing;
56
+ }
57
+ return DEFAULT_PRICING;
58
+ }
59
+ /** Fixed USD→CNY fallback for providers without official RMB list prices. */
60
+ export const USD_CNY_RATE = 7.2;
61
+ /** Official RMB (元) list prices per 1M tokens for Chinese providers. */
62
+ const CNY_PRICING = {
63
+ deepseek: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 2 },
64
+ qwen: { input: 1.6, output: 6.4, cacheRead: 0.16, cacheWrite: 1.6 },
65
+ dashscope: { input: 1.6, output: 6.4, cacheRead: 0.16, cacheWrite: 1.6 },
66
+ zhipu: { input: 5, output: 5, cacheRead: 0.5, cacheWrite: 5 },
67
+ glm: { input: 5, output: 5, cacheRead: 0.5, cacheWrite: 5 },
68
+ moonshot: { input: 12, output: 12, cacheRead: 1.2, cacheWrite: 12 },
69
+ kimi: { input: 12, output: 12, cacheRead: 1.2, cacheWrite: 12 },
70
+ ollama: LOCAL,
71
+ local: LOCAL,
72
+ };
73
+ /** CNY pricing for a provider, or null when the provider has no official RMB price. */
74
+ export function pricingCnyFor(provider, _model) {
75
+ const normalized = provider.trim().toLowerCase();
76
+ const exact = CNY_PRICING[normalized];
77
+ if (exact !== undefined)
78
+ return exact;
79
+ // Family fallback for Chinese providers matched by model string.
80
+ const haystack = `${normalized} ${_model.toLowerCase()}`;
81
+ const families = [
82
+ [["deepseek"], CNY_PRICING.deepseek],
83
+ [["qwen", "dashscope"], CNY_PRICING.qwen],
84
+ [["glm", "zhipu"], CNY_PRICING.zhipu],
85
+ [["moonshot", "kimi"], CNY_PRICING.moonshot],
86
+ [["ollama", "local"], LOCAL],
87
+ ];
88
+ for (const [keys, pricing] of families) {
89
+ if (keys.some((key) => haystack.includes(key)))
90
+ return pricing;
91
+ }
92
+ return null;
93
+ }
94
+ function estimateWith(usage, pricing) {
95
+ const num = (value) => (typeof value === "number" && Number.isFinite(value) ? value : 0);
96
+ return (num(usage.input) * pricing.input +
97
+ num(usage.output) * pricing.output +
98
+ num(usage.cacheRead) * pricing.cacheRead +
99
+ num(usage.cacheWrite) * pricing.cacheWrite) / 1e6;
100
+ }
101
+ /** Estimated cost in USD for one usage record. */
102
+ export function estimateUsageCost(usage, provider, model) {
103
+ return estimateWith(usage, pricingFor(provider, model));
104
+ }
105
+ /** Estimated cost in 人民币 (CNY) for one usage record: official RMB list price where available, else USD×rate. */
106
+ export function estimateUsageCostCny(usage, provider, model) {
107
+ const cny = pricingCnyFor(provider, model);
108
+ return cny !== null ? estimateWith(usage, cny) : estimateUsageCost(usage, provider, model) * USD_CNY_RATE;
109
+ }
110
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../../src/core/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,CAAC,MAAM,eAAe,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;AAElG,MAAM,QAAQ,GAAe,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC7F,MAAM,MAAM,GAAe,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC3F,MAAM,SAAS,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACzF,MAAM,IAAI,GAAe,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AACrF,MAAM,GAAG,GAAe,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AACpF,MAAM,QAAQ,GAAe,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AAC3F,MAAM,MAAM,GAAe,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC1F,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;AAE/E,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAA+B;IAC1D,QAAQ,EAAE,QAAQ;IAClB,MAAM,EAAE,MAAM;IACd,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,IAAI;IACV,SAAS,EAAE,IAAI;IACf,KAAK,EAAE,GAAG;IACV,GAAG,EAAE,GAAG;IACR,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,GAAkC;IACjD,CAAC,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;IACxB,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC;IACpC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC;IAC7B,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC;IACvB,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAChC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC9B,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC;CAC7B,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,WAAW,EAAE,CAAC;QAC1C,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;IACjE,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEhC,wEAAwE;AACxE,MAAM,WAAW,GAA+B;IAC9C,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE;IAChE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;IACnE,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;IACxE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE;IAC7D,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE;IAC3D,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE;IACnE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE;IAC/D,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,uFAAuF;AACvF,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,MAAc;IAC5D,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,iEAAiE;IACjE,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAkC;QAC9C,CAAC,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,QAAS,CAAC;QACrC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,IAAK,CAAC;QAC1C,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,KAAM,CAAC;QACtC,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,QAAS,CAAC;QAC7C,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC;KAC7B,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAuF,EAAE,OAAmB;IAChI,MAAM,GAAG,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1G,OAAO,CACL,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK;QAChC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM;QAClC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS;QACxC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAC3C,GAAG,GAAG,CAAC;AACV,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,iBAAiB,CAC/B,KAAuF,EACvF,QAAgB,EAChB,KAAa;IAEb,OAAO,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,oBAAoB,CAClC,KAAuF,EACvF,QAAgB,EAChB,KAAa;IAEb,MAAM,GAAG,GAAG,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,YAAY,CAAC;AAC5G,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Deterministic secret redaction for log and projection surfaces.
3
+ *
4
+ * psyclaw never treats raw material or credentials as content to log. As
5
+ * defense-in-depth, any free-form text that reaches an event log is scrubbed
6
+ * of high-signal credential shapes before it is persisted. This is a
7
+ * heuristic, not an OS boundary: callers must still avoid putting secrets in
8
+ * log payloads in the first place.
9
+ */
10
+ export declare function redactSecrets(input: string): string;
11
+ /** Return the distinct secret kinds detected in a string. */
12
+ export declare function findSecrets(input: string): string[];