@dsh-edge/dsh-edge-agent 0.0.0-stage → 0.1.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 (238) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/LICENSE +21 -0
  3. package/README.md +372 -2
  4. package/config/edge.example.json +179 -0
  5. package/config/privacy-policy.json +202 -0
  6. package/cordis.desktop-safe.patch.yml +129 -0
  7. package/cordis.patch.yml +382 -0
  8. package/cordis.yml +374 -0
  9. package/lib/attestation.d.ts +2 -0
  10. package/lib/attestation.d.ts.map +1 -0
  11. package/lib/attestation.js +2 -0
  12. package/lib/audit-log.d.ts +2 -0
  13. package/lib/audit-log.d.ts.map +1 -0
  14. package/lib/audit-log.js +2 -0
  15. package/lib/client.js +87 -0
  16. package/lib/cloud-llm-adapter.d.ts +2 -0
  17. package/lib/cloud-llm-adapter.d.ts.map +1 -0
  18. package/lib/cloud-llm-adapter.js +2 -0
  19. package/lib/dsh-adapter/attestation.d.ts +42 -0
  20. package/lib/dsh-adapter/attestation.d.ts.map +1 -0
  21. package/lib/dsh-adapter/attestation.js +40 -0
  22. package/lib/dsh-adapter/audit-log.d.ts +139 -0
  23. package/lib/dsh-adapter/audit-log.d.ts.map +1 -0
  24. package/lib/dsh-adapter/audit-log.js +376 -0
  25. package/lib/dsh-adapter/cloud-egress.d.ts +181 -0
  26. package/lib/dsh-adapter/cloud-egress.d.ts.map +1 -0
  27. package/lib/dsh-adapter/cloud-egress.js +257 -0
  28. package/lib/dsh-adapter/cloud-llm-adapter.d.ts +416 -0
  29. package/lib/dsh-adapter/cloud-llm-adapter.d.ts.map +1 -0
  30. package/lib/dsh-adapter/cloud-llm-adapter.js +1472 -0
  31. package/lib/dsh-adapter/contract.d.ts +80 -0
  32. package/lib/dsh-adapter/contract.d.ts.map +1 -0
  33. package/lib/dsh-adapter/contract.js +194 -0
  34. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts +214 -0
  35. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts.map +1 -0
  36. package/lib/dsh-adapter/desktop-cookie-janitor.js +409 -0
  37. package/lib/dsh-adapter/dsh-edge-agent.d.ts +48 -0
  38. package/lib/dsh-adapter/dsh-edge-agent.d.ts.map +1 -0
  39. package/lib/dsh-adapter/dsh-edge-agent.js +64 -0
  40. package/lib/dsh-adapter/edge-config.d.ts +484 -0
  41. package/lib/dsh-adapter/edge-config.d.ts.map +1 -0
  42. package/lib/dsh-adapter/edge-config.js +898 -0
  43. package/lib/dsh-adapter/edge-context-view.d.ts +184 -0
  44. package/lib/dsh-adapter/edge-context-view.d.ts.map +1 -0
  45. package/lib/dsh-adapter/edge-context-view.js +483 -0
  46. package/lib/dsh-adapter/effective-model.d.ts +85 -0
  47. package/lib/dsh-adapter/effective-model.d.ts.map +1 -0
  48. package/lib/dsh-adapter/effective-model.js +171 -0
  49. package/lib/dsh-adapter/etscli-shell-guard.d.ts +244 -0
  50. package/lib/dsh-adapter/etscli-shell-guard.d.ts.map +1 -0
  51. package/lib/dsh-adapter/etscli-shell-guard.js +420 -0
  52. package/lib/dsh-adapter/etscli-tools.d.ts +112 -0
  53. package/lib/dsh-adapter/etscli-tools.d.ts.map +1 -0
  54. package/lib/dsh-adapter/etscli-tools.js +393 -0
  55. package/lib/dsh-adapter/file-logger.d.ts +294 -0
  56. package/lib/dsh-adapter/file-logger.d.ts.map +1 -0
  57. package/lib/dsh-adapter/file-logger.js +564 -0
  58. package/lib/dsh-adapter/function-call-external.d.ts +357 -0
  59. package/lib/dsh-adapter/function-call-external.d.ts.map +1 -0
  60. package/lib/dsh-adapter/function-call-external.js +1005 -0
  61. package/lib/dsh-adapter/host-egress-guard.d.ts +161 -0
  62. package/lib/dsh-adapter/host-egress-guard.d.ts.map +1 -0
  63. package/lib/dsh-adapter/host-egress-guard.js +213 -0
  64. package/lib/dsh-adapter/host-llm-trace.d.ts +198 -0
  65. package/lib/dsh-adapter/host-llm-trace.d.ts.map +1 -0
  66. package/lib/dsh-adapter/host-llm-trace.js +344 -0
  67. package/lib/dsh-adapter/http-api-routes.d.ts +61 -0
  68. package/lib/dsh-adapter/http-api-routes.d.ts.map +1 -0
  69. package/lib/dsh-adapter/http-api-routes.js +79 -0
  70. package/lib/dsh-adapter/http-api-sessions.d.ts +105 -0
  71. package/lib/dsh-adapter/http-api-sessions.d.ts.map +1 -0
  72. package/lib/dsh-adapter/http-api-sessions.js +173 -0
  73. package/lib/dsh-adapter/http-api.d.ts +221 -0
  74. package/lib/dsh-adapter/http-api.d.ts.map +1 -0
  75. package/lib/dsh-adapter/http-api.js +1811 -0
  76. package/lib/dsh-adapter/index.d.ts +62 -0
  77. package/lib/dsh-adapter/index.d.ts.map +1 -0
  78. package/lib/dsh-adapter/index.js +97 -0
  79. package/lib/dsh-adapter/input-guard-messages.d.ts +56 -0
  80. package/lib/dsh-adapter/input-guard-messages.d.ts.map +1 -0
  81. package/lib/dsh-adapter/input-guard-messages.js +136 -0
  82. package/lib/dsh-adapter/input-guard.d.ts +508 -0
  83. package/lib/dsh-adapter/input-guard.d.ts.map +1 -0
  84. package/lib/dsh-adapter/input-guard.js +2174 -0
  85. package/lib/dsh-adapter/intent-prompts.d.ts +77 -0
  86. package/lib/dsh-adapter/intent-prompts.d.ts.map +1 -0
  87. package/lib/dsh-adapter/intent-prompts.js +97 -0
  88. package/lib/dsh-adapter/intent-router.d.ts +710 -0
  89. package/lib/dsh-adapter/intent-router.d.ts.map +1 -0
  90. package/lib/dsh-adapter/intent-router.js +2802 -0
  91. package/lib/dsh-adapter/intent-signals.d.ts +208 -0
  92. package/lib/dsh-adapter/intent-signals.d.ts.map +1 -0
  93. package/lib/dsh-adapter/intent-signals.js +391 -0
  94. package/lib/dsh-adapter/invariant-install.d.ts +16 -0
  95. package/lib/dsh-adapter/invariant-install.d.ts.map +1 -0
  96. package/lib/dsh-adapter/invariant-install.js +15 -0
  97. package/lib/dsh-adapter/invariant.d.ts +16 -0
  98. package/lib/dsh-adapter/invariant.d.ts.map +1 -0
  99. package/lib/dsh-adapter/invariant.js +22 -0
  100. package/lib/dsh-adapter/llm-adapters.d.ts +19 -0
  101. package/lib/dsh-adapter/llm-adapters.d.ts.map +1 -0
  102. package/lib/dsh-adapter/llm-adapters.js +16 -0
  103. package/lib/dsh-adapter/llm-internal-caller.d.ts +92 -0
  104. package/lib/dsh-adapter/llm-internal-caller.d.ts.map +1 -0
  105. package/lib/dsh-adapter/llm-internal-caller.js +100 -0
  106. package/lib/dsh-adapter/llm-max-turns.d.ts +55 -0
  107. package/lib/dsh-adapter/llm-max-turns.d.ts.map +1 -0
  108. package/lib/dsh-adapter/llm-max-turns.js +127 -0
  109. package/lib/dsh-adapter/llm-trace-store.d.ts +131 -0
  110. package/lib/dsh-adapter/llm-trace-store.d.ts.map +1 -0
  111. package/lib/dsh-adapter/llm-trace-store.js +205 -0
  112. package/lib/dsh-adapter/llm-trace.d.ts +450 -0
  113. package/lib/dsh-adapter/llm-trace.d.ts.map +1 -0
  114. package/lib/dsh-adapter/llm-trace.js +463 -0
  115. package/lib/dsh-adapter/local-llm-adapter.d.ts +141 -0
  116. package/lib/dsh-adapter/local-llm-adapter.d.ts.map +1 -0
  117. package/lib/dsh-adapter/local-llm-adapter.js +787 -0
  118. package/lib/dsh-adapter/local-storage.d.ts +96 -0
  119. package/lib/dsh-adapter/local-storage.d.ts.map +1 -0
  120. package/lib/dsh-adapter/local-storage.js +198 -0
  121. package/lib/dsh-adapter/model-router.d.ts +79 -0
  122. package/lib/dsh-adapter/model-router.d.ts.map +1 -0
  123. package/lib/dsh-adapter/model-router.js +107 -0
  124. package/lib/dsh-adapter/ohttp-gateway.d.ts +49 -0
  125. package/lib/dsh-adapter/ohttp-gateway.d.ts.map +1 -0
  126. package/lib/dsh-adapter/ohttp-gateway.js +32 -0
  127. package/lib/dsh-adapter/openai-sse.d.ts +85 -0
  128. package/lib/dsh-adapter/openai-sse.d.ts.map +1 -0
  129. package/lib/dsh-adapter/openai-sse.js +462 -0
  130. package/lib/dsh-adapter/pii-utils.d.ts +96 -0
  131. package/lib/dsh-adapter/pii-utils.d.ts.map +1 -0
  132. package/lib/dsh-adapter/pii-utils.js +324 -0
  133. package/lib/dsh-adapter/plugin-host.d.ts +38 -0
  134. package/lib/dsh-adapter/plugin-host.d.ts.map +1 -0
  135. package/lib/dsh-adapter/plugin-host.js +38 -0
  136. package/lib/dsh-adapter/plugin.d.ts +46 -0
  137. package/lib/dsh-adapter/plugin.d.ts.map +1 -0
  138. package/lib/dsh-adapter/plugin.js +100 -0
  139. package/lib/dsh-adapter/privacy-policy.d.ts +237 -0
  140. package/lib/dsh-adapter/privacy-policy.d.ts.map +1 -0
  141. package/lib/dsh-adapter/privacy-policy.js +391 -0
  142. package/lib/dsh-adapter/prompt-guard.d.ts +152 -0
  143. package/lib/dsh-adapter/prompt-guard.d.ts.map +1 -0
  144. package/lib/dsh-adapter/prompt-guard.js +872 -0
  145. package/lib/dsh-adapter/realm-skill-bridge.d.ts +365 -0
  146. package/lib/dsh-adapter/realm-skill-bridge.d.ts.map +1 -0
  147. package/lib/dsh-adapter/realm-skill-bridge.js +1180 -0
  148. package/lib/dsh-adapter/sanitizer-pipeline.d.ts +140 -0
  149. package/lib/dsh-adapter/sanitizer-pipeline.d.ts.map +1 -0
  150. package/lib/dsh-adapter/sanitizer-pipeline.js +431 -0
  151. package/lib/dsh-adapter/secure-bridge.d.ts +47 -0
  152. package/lib/dsh-adapter/secure-bridge.d.ts.map +1 -0
  153. package/lib/dsh-adapter/secure-bridge.js +35 -0
  154. package/lib/dsh-adapter/session-attribution.d.ts +70 -0
  155. package/lib/dsh-adapter/session-attribution.d.ts.map +1 -0
  156. package/lib/dsh-adapter/session-attribution.js +76 -0
  157. package/lib/dsh-adapter/sessions.d.ts +86 -0
  158. package/lib/dsh-adapter/sessions.d.ts.map +1 -0
  159. package/lib/dsh-adapter/sessions.js +179 -0
  160. package/lib/dsh-adapter/tcm.d.ts +55 -0
  161. package/lib/dsh-adapter/tcm.d.ts.map +1 -0
  162. package/lib/dsh-adapter/tcm.js +94 -0
  163. package/lib/dsh-adapter/td-bus.d.ts +87 -0
  164. package/lib/dsh-adapter/td-bus.d.ts.map +1 -0
  165. package/lib/dsh-adapter/td-bus.js +196 -0
  166. package/lib/dsh-adapter/tool-runner.d.ts +185 -0
  167. package/lib/dsh-adapter/tool-runner.d.ts.map +1 -0
  168. package/lib/dsh-adapter/tool-runner.js +271 -0
  169. package/lib/dsh-adapter/tools.d.ts +118 -0
  170. package/lib/dsh-adapter/tools.d.ts.map +1 -0
  171. package/lib/dsh-adapter/tools.js +292 -0
  172. package/lib/dsh-adapter/types.d.ts +23 -0
  173. package/lib/dsh-adapter/types.d.ts.map +1 -0
  174. package/lib/dsh-adapter/types.js +16 -0
  175. package/lib/dsh-adapter/voice-input.d.ts +30 -0
  176. package/lib/dsh-adapter/voice-input.d.ts.map +1 -0
  177. package/lib/dsh-adapter/voice-input.js +34 -0
  178. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts +152 -0
  179. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts.map +1 -0
  180. package/lib/dsh-adapter/web-search-tavily-bocha.js +289 -0
  181. package/lib/http-api.d.ts +2 -0
  182. package/lib/http-api.d.ts.map +1 -0
  183. package/lib/http-api.js +2 -0
  184. package/lib/index.d.ts +48 -0
  185. package/lib/index.d.ts.map +1 -0
  186. package/lib/index.js +49 -0
  187. package/lib/intent-router.d.ts +2 -0
  188. package/lib/intent-router.d.ts.map +1 -0
  189. package/lib/intent-router.js +2 -0
  190. package/lib/llm-adapters.d.ts +2 -0
  191. package/lib/llm-adapters.d.ts.map +1 -0
  192. package/lib/llm-adapters.js +2 -0
  193. package/lib/local-llm-adapter.d.ts +2 -0
  194. package/lib/local-llm-adapter.d.ts.map +1 -0
  195. package/lib/local-llm-adapter.js +2 -0
  196. package/lib/local-storage.d.ts +2 -0
  197. package/lib/local-storage.d.ts.map +1 -0
  198. package/lib/local-storage.js +2 -0
  199. package/lib/model-router.d.ts +2 -0
  200. package/lib/model-router.d.ts.map +1 -0
  201. package/lib/model-router.js +2 -0
  202. package/lib/ohttp-gateway.d.ts +2 -0
  203. package/lib/ohttp-gateway.d.ts.map +1 -0
  204. package/lib/ohttp-gateway.js +2 -0
  205. package/lib/plugin-host.d.ts +2 -0
  206. package/lib/plugin-host.d.ts.map +1 -0
  207. package/lib/plugin-host.js +2 -0
  208. package/lib/privacy-policy.d.ts +2 -0
  209. package/lib/privacy-policy.d.ts.map +1 -0
  210. package/lib/privacy-policy.js +2 -0
  211. package/lib/prompt-guard.d.ts +2 -0
  212. package/lib/prompt-guard.d.ts.map +1 -0
  213. package/lib/prompt-guard.js +2 -0
  214. package/lib/sanitizer-pipeline.d.ts +2 -0
  215. package/lib/sanitizer-pipeline.d.ts.map +1 -0
  216. package/lib/sanitizer-pipeline.js +2 -0
  217. package/lib/secure-bridge.d.ts +2 -0
  218. package/lib/secure-bridge.d.ts.map +1 -0
  219. package/lib/secure-bridge.js +2 -0
  220. package/lib/sessions.d.ts +2 -0
  221. package/lib/sessions.d.ts.map +1 -0
  222. package/lib/sessions.js +2 -0
  223. package/lib/tcm.d.ts +2 -0
  224. package/lib/tcm.d.ts.map +1 -0
  225. package/lib/tcm.js +2 -0
  226. package/lib/td-bus.d.ts +2 -0
  227. package/lib/td-bus.d.ts.map +1 -0
  228. package/lib/td-bus.js +2 -0
  229. package/lib/tools.d.ts +2 -0
  230. package/lib/tools.d.ts.map +1 -0
  231. package/lib/tools.js +2 -0
  232. package/lib/voice-input.d.ts +2 -0
  233. package/lib/voice-input.d.ts.map +1 -0
  234. package/lib/voice-input.js +2 -0
  235. package/package.json +341 -3
  236. package/presets/agent-preset-edge.json +50 -0
  237. package/presets/edge.desktop-safe.patch.yml +503 -0
  238. package/presets/edge.patch.yml +557 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * file-logger — M6 durable file exporter for Cordis `ctx.logger`.
3
+ *
4
+ * DSH host does not ship a service logger (`dsh --help` has no `--log-file`),
5
+ * and Cordis's LoggerService only installs an in-memory ring buffer (1000
6
+ * entries). Without an external exporter every `ctx.logger.info(...)` call
7
+ * lands in that buffer and is lost on exit. We register a file exporter so
8
+ * every dsh-edge-agent plugin's log output is durably persisted to disk,
9
+ * rotated on size, and tail-able for offline troubleshooting.
10
+ *
11
+ * Cordis `export()` contract is **strictly synchronous** (see
12
+ * `@deepseek-ai/cordis@4.0.1/src/logger.ts:46`; the loop at `:154-159`
13
+ * does not await) — the only safe pattern is to synchronously push the
14
+ * formatted line into an in-memory queue, then let a background
15
+ * `setInterval().unref()` flush the queue to disk. The audit-log plugin
16
+ * uses the same pattern (`audit-log.ts:147-152`).
17
+ *
18
+ * Loop avoidance: `export()` must NEVER call `ctx.logger.error(...)` —
19
+ * audit-log's own diagnostics already do (`audit-log.ts:266/309`), and a
20
+ * failure here would re-enter our own `export()` and spin. Failures are
21
+ * swallowed silently and counted; a stderr notice is emitted on the first
22
+ * drop and every 1000th drop after that.
23
+ *
24
+ * Append-mode (`fs.open(path, 'a')`) means each process boot appends to
25
+ * the existing file instead of truncating it, so install.sh's truncate-on-
26
+ * restart semantics are no longer in play — dsh-edge-agent's own writer
27
+ * owns the file lifecycle.
28
+ *
29
+ * ═══════════════════════════════════════════════════════════════════════
30
+ * OPERATIONS / AUDIT CHANNEL DISCIPLINE (2026-09-01)
31
+ * ═══════════════════════════════════════════════════════════════════════
32
+ * Two log channels. They serve different consumers. Do not blur them.
33
+ *
34
+ * ┌─ OPERATIONS LOG ──────────────────────────────────────────────────┐
35
+ * │ Path: ~/.dsh-edge-agent/log/dsh-edge-agent.log (this file) │
36
+ * │ Source: every `ctx.logger.{info,warn,error,debug}` call │
37
+ * │ Rule: **info / warn / error entries MUST NOT contain request │
38
+ * │ bodies, response bodies, tool arguments, prompt text, │
39
+ * │ or any user PII.** Only metadata (provider, model, │
40
+ * │ reqId, durationMs, counts) and error diagnostics. │
41
+ * │ │
42
+ * │ **debug entries MAY carry LLM call bodies** (request │
43
+ * │ messages + response text) for offline triage — opt-in │
44
+ * │ via `DSH_EDGE_LOG_LEVEL=debug`. 2026-09-11 default │
45
+ * │ flipped from `debug` to `info` (users said log was too │
46
+ * │ noisy — every LLM call landed 4 body lines). Re-enable │
47
+ * │ with `DSH_EDGE_LOG_LEVEL=debug`. CLOUD prompts are │
48
+ * │ pre-sanitized by input-guard before egress, so the │
49
+ * │ captured prompt is already placeholder-text for │
50
+ * │ sensitive spans. CLOUD response text is NOT redacted. │
51
+ * │ Call sites: cloud-llm-adapter.ts, local-llm-adapter.ts. │
52
+ * │ Used by operators to triage service flow, failures, and │
53
+ * │ LLM call replay. │
54
+ * └───────────────────────────────────────────────────────────────────┘
55
+ *
56
+ * ┌─ AUDIT LOG ───────────────────────────────────────────────────────┐
57
+ * │ Path: ~/.dsh-edge-agent/audit/audit.plain.jsonl │
58
+ * │ Source: every `auditLog.log({...})` call — explicit, opt-in │
59
+ * │ Rule: **Records the actual call content** (provider, model, │
60
+ * │ promptLen, messageCount, toolName, redacted args, │
61
+ * │ durationMs). Fields are PII-redacted via │
62
+ * │ `pii-utils.redactObject()` before write. Used by │
63
+ * │ compliance / legal / security review. │
64
+ * └───────────────────────────────────────────────────────────────────┘
65
+ *
66
+ * Concretely: every existing `ctx.logger.info(...)` call in dsh-edge-agent
67
+ * carries only metadata. **Before adding a new ctx.logger call**, confirm
68
+ * it does not embed any of: `messages`, `args` (tool args), `promptText`,
69
+ * response bodies, session content, or user-supplied strings. If you need
70
+ * to log that data, route it through `auditLog.log(...)` so it lands in
71
+ * the audit JSONL with field-level redaction, NOT here.
72
+ *
73
+ * Wiring (2026-09-01): file-logger is registered as a standalone Cordis
74
+ * plugin id (`profiles/dsh-edge-agent/cordis.patch.yml`) so its apply()
75
+ * runs at boot — before audit-log / http-api / etc. The disabled
76
+ * aggregator `dsh-edge-agent` (see cordis.patch.yml:26-29) means the
77
+ * internal `src/dsh-adapter/index.ts:apply()` is never invoked, so we
78
+ * can't rely on it to install the exporter. Each plugin id in the patch
79
+ * is loaded independently via its `name:` field.
80
+ *
81
+ * @module dsh-edge-agent/file-logger
82
+ */
83
+ import type { Context, Message } from '@deepseek-ai/cordis';
84
+ import { Service } from '@deepseek-ai/cordis';
85
+ import Schema from '@deepseek-ai/schemastery';
86
+ export declare const name = "file-logger";
87
+ /**
88
+ * 无硬依赖(§7.169,2026-10-31)。
89
+ *
90
+ * 原来是 `inject = ['web']`,只为了一句 boot 诊断(web-diag)能读
91
+ * `ctx.web.searchProviders.size`。代价是**整个 ops log 通道被一个无关服务
92
+ * 卡住**:cordis 要等 `web` 服务就绪才让本插件 apply,而**注册文件导出器的
93
+ * 正是本插件** ⇒ 凡是比 file-logger 更早 apply 的插件,它的启动日志(乃至
94
+ * 拒绝行)会**静默丢失**。
95
+ *
96
+ * 实测(§7.169,headless `dsh-edge-agent` profile,探针实测):
97
+ * - 守卫 apply 那一刻 `ctx.logger` 还没有落盘导出器;
98
+ * - 同一 ctx 上 `ctx.logger.info(...)` 在 t0 **丢失**,t300 / t1500 / t4000
99
+ * 才落盘 —— 即「闸门上膛」启动行与拒绝行都可能无处可落。
100
+ *
101
+ * 改法:`web` 从硬依赖降为**延迟注入**(`ctx.inject(['web'], cb)`,与
102
+ * edge-context-view / input-guard 同款纪律),本插件零静态依赖 ⇒ 导出器注册
103
+ * 不再被无关服务拖后。**注意**:实测同层插件的 apply 先后由模块解析速度
104
+ * 决定、不靠配置树顺序(§7.169),所以「通道就位」不能靠"谁先 apply"保证 ——
105
+ * 消费方要用 `ctx.inject(['fileLogger'], …)` 延迟注入,回调触发时导出器必已
106
+ * 注册(cordis `_updateState` 只在 providing fiber 变 ACTIVE 后 notify)。
107
+ *
108
+ * 注意:桌面版 ops log 的文件名(`dsh-edge-agent-desktop.log`)来自**行**
109
+ * 的 config,本插件行必须比裸包名聚合行先装载 —— 零依赖后这个顺序只会更稳。
110
+ */
111
+ export declare const inject: readonly [];
112
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
113
+ export interface Config {
114
+ /** Directory holding the log file. Created if missing. */
115
+ root: string;
116
+ /** Filename inside `root` for the persistent log. */
117
+ filename: string;
118
+ /** Background flush cadence in ms. */
119
+ flushIntervalMs: number;
120
+ /** In-memory queue cap; oldest entry is dropped on overflow. */
121
+ queueCapacity: number;
122
+ /** Rotate log when file exceeds this size (bytes). 0 = disabled. */
123
+ maxFileSizeBytes: number;
124
+ /**
125
+ * Calendar-day rotation: rotate when the file's last-write day is at
126
+ * least this many local calendar days before today. `1` = daily
127
+ * rotation (first flush after midnight moves the old file to `.1`).
128
+ * `0` = disabled.
129
+ *
130
+ * §7.56 (2026-09-15): previously this compared elapsed `now - mtime`,
131
+ * which NEVER fires for an active append-mode log — continuous writes
132
+ * keep mtime at "moments ago", so `ageDays ≈ 0` forever (the shipped
133
+ * `maxFileAgeDays: 0` masked the dead branch). Calendar-day diff works
134
+ * for continuously-written files: at the first flush of a new day the
135
+ * mtime's date is yesterday, so dayDiff ≥ 1 triggers the rotation.
136
+ */
137
+ maxFileAgeDays: number;
138
+ /** Maximum number of rotated files to keep. */
139
+ maxRotatedFiles: number;
140
+ /**
141
+ * Minimum logger level emitted to disk. 2026-09-11: default flipped
142
+ * from `debug` back to `info` (per user feedback "log 太冗余") so the
143
+ * LLM body debug calls in `cloud-llm-adapter.ts` /
144
+ * `local-llm-adapter.ts` (LLM_REQUEST / LLM_MESSAGES / LLM_RESPONSE
145
+ * / LLM_RESPONSE_TEXT) are filtered by Cordis and don't reach the
146
+ * ops log. Set `DSH_EDGE_LOG_LEVEL=debug` to re-enable body capture
147
+ * for offline triage. Previously flipped 2026-09-02 info→debug; see
148
+ * PROGRESS §7.23 for the original flip.
149
+ */
150
+ level: LogLevel;
151
+ }
152
+ export declare const Config: Schema<Config>;
153
+ declare module '@deepseek-ai/cordis' {
154
+ interface Context {
155
+ fileLogger: FileLoggerServiceImpl;
156
+ }
157
+ }
158
+ /**
159
+ * Singleton service exposed on `ctx.fileLogger`. Owns the in-memory queue
160
+ * and the background flush loop. The Cordis exporter callback installed
161
+ * by `installFileLogger` simply forwards to `export()` on this service.
162
+ */
163
+ export declare class FileLoggerServiceImpl extends Service {
164
+ private readonly filePath;
165
+ private readonly flushIntervalMs;
166
+ private readonly queueCapacity;
167
+ private readonly maxFileSizeBytes;
168
+ private readonly maxFileAgeDays;
169
+ private readonly maxRotatedFiles;
170
+ /** Formatted lines waiting to be flushed to disk. */
171
+ private queue;
172
+ /** Number of entries dropped because `queue` was full. */
173
+ private droppedCount;
174
+ /** Monotonically increasing serial so we can debug dropped-entry runs. */
175
+ private flushSerial;
176
+ private flushTimer;
177
+ private flushPromise;
178
+ constructor(ctx: Context, config: Config);
179
+ /** Test helper returning the resolved log file path. */
180
+ filePathForTests(): string;
181
+ /** Test helper: how many entries have been dropped because the queue was full. */
182
+ droppedCountForTests(): number;
183
+ /** Start the periodic flush; idempotent. Call once from `installFileLogger`. */
184
+ start(): void;
185
+ /** Stop the periodic flush; for tests and the dispose hook. */
186
+ stop(): void;
187
+ /**
188
+ * Cordis exporter callback. **Synchronous, no await**. Push the
189
+ * formatted line onto the queue; the background timer drains it.
190
+ *
191
+ * NEVER call `this.ctx.logger.*` from here — audit-log does that on
192
+ * its own errors (`audit-log.ts:266/309`), which would re-enter this
193
+ * method and spin the loop. We swallow everything silently and count
194
+ * drops; a one-shot stderr notice flags the first drop and every
195
+ * 1000th drop after.
196
+ */
197
+ export(message: Message): void;
198
+ /**
199
+ * Drain the queue to disk. Serialised through `flushPromise` so
200
+ * overlapping calls (timer + dispose) don't interleave writes.
201
+ *
202
+ * Uses `fs.open(path, 'a')` rather than audit-log's read-merge-write
203
+ * pattern — there is no upstream reader modifying the file, so
204
+ * append-at-the-tail is sufficient.
205
+ */
206
+ flush(): Promise<void>;
207
+ /**
208
+ * Size + age based rotation. Copied from audit-log's
209
+ * `checkAndRotate` (`audit-log.ts:278-311`) — the algorithm is the same
210
+ * but this exporter has no read-merge-write coupling, so we only rotate
211
+ * here (audit-log couples rotation with its write path).
212
+ */
213
+ private checkAndRotate;
214
+ }
215
+ /** Resolved config used by `installFileLogger`. Pure data, easy to mock. */
216
+ export interface ResolvedLoggerConfig {
217
+ root: string;
218
+ filename: string;
219
+ flushIntervalMs: number;
220
+ queueCapacity: number;
221
+ maxFileSizeBytes: number;
222
+ maxFileAgeDays: number;
223
+ maxRotatedFiles: number;
224
+ level: LogLevel;
225
+ }
226
+ /**
227
+ * Resolve the file-logger config from env vars with sensible defaults.
228
+ * Centralised here so tests can call it directly and `installFileLogger`
229
+ * stays a one-liner.
230
+ *
231
+ * Path resolution: `DSH_EDGE_LOG_ROOT` wins, then `USERPROFILE` (Windows),
232
+ * then `HOME` (POSIX). File name is fixed (`dsh-edge-agent.log`) so
233
+ * operators always know what file to tail.
234
+ *
235
+ * Level resolution: `DSH_EDGE_LOG_LEVEL` wins, otherwise `info`. The
236
+ * `info` default (2026-09-11, flipped from `debug` per user feedback
237
+ * "log 太冗余") suppresses LLM body debug calls in
238
+ * `cloud-llm-adapter.ts` / `local-llm-adapter.ts` — set
239
+ * `DSH_EDGE_LOG_LEVEL=debug` to re-enable.
240
+ */
241
+ export declare function resolveLoggerConfig(env?: NodeJS.ProcessEnv): ResolvedLoggerConfig;
242
+ /**
243
+ * Install the file exporter on a fresh Cordis context. Called once at
244
+ * the very top of `apply()` (`src/dsh-adapter/index.ts`) before any
245
+ * other plugin can call `ctx.logger.*`.
246
+ *
247
+ * Gating:
248
+ * - `DSH_EDGE_LOG_FILE=false` disables (tests opt out).
249
+ * - `DSH_EDGE_LOG_FILE=force` 仍被接受(历史兼容),但已是默认行为。
250
+ *
251
+ * §7.118 (2026-10-26) — 守卫语义修正:
252
+ *
253
+ * 旧守卫是 `ctx.logger.exporters.size > 1 → return undefined`,理由是
254
+ * "宿主若已注册 file exporter,我们再写一份就是双写"。但这个 size 启发式
255
+ * **分不出控制台 exporter 和文件 exporter**:
256
+ *
257
+ * - 桌面 App 的 dsh-desktop-host 注册的是**控制台** exporter(输出走
258
+ * Electron 的 stdout,不落盘 —— `~/Library/Logs/DeepSeek Harness/`
259
+ * 实测是空目录)。size 变成 2 → 我们跳过 → **桌面 ops log 整份消失**,
260
+ * 最后一次写入停在 2026-10-25 19:47。
261
+ * - CLI profile 同理(这正是 `DSH_EDGE_LOG_FILE=force` 逃逸口存在的原因,
262
+ * 见本文件下方的历史注释)。
263
+ *
264
+ * 也就是说,这个守卫防的是一个**不会发生**的碰撞(两个 exporter 写同一个
265
+ * 文件),代价却是让 ops log 在两种真实宿主里都从不落盘。而"会不会写坏
266
+ * 文件"根本不成立:我们的输出路径是 **edge 独占**的
267
+ * `~/.dsh-edge-agent/log/`,宿主没有任何理由往那儿写。
268
+ *
269
+ * 真正需要防的"我们自己被装载两次"由下面的重复 `provide` try/catch 负责,
270
+ * 不该由 size 启发式兜。
271
+ *
272
+ * 现在:除非显式 `false`,一律注册。
273
+ */
274
+ export declare function installFileLogger(ctx: Context, resolved?: ResolvedLoggerConfig): FileLoggerServiceImpl | undefined;
275
+ /**
276
+ * Stop the flush timer and drain the queue. Wired into the apply()
277
+ * dispose hook in `index.ts` so a clean shutdown loses at most one
278
+ * interval's worth of logs.
279
+ */
280
+ export declare function shutdownFileLogger(service: FileLoggerServiceImpl | undefined): Promise<void>;
281
+ /**
282
+ * Standard Cordis plugin apply — installs the file exporter on first
283
+ * load and returns a disposer that drains the queue on shutdown.
284
+ *
285
+ * Wired into repo-root `cordis.patch.yml` (per §7.25 + §7.31 — bundle is
286
+ * self-contained) as a standalone plugin id `file-logger` so this runs
287
+ * at boot, before any other dsh-edge-agent plugin (audit-log / http-api /
288
+ * etc.) emits log lines.
289
+ *
290
+ * Idempotency: `installFileLogger` already has a first-wins guard via
291
+ * `ctx.logger.exporters.size > 1`. Calling it twice is a no-op.
292
+ */
293
+ export declare function apply(ctx: Context, config: Config): Promise<() => Promise<void>>;
294
+ //# sourceMappingURL=file-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-logger.d.ts","sourceRoot":"","sources":["../../src/dsh-adapter/file-logger.ts"],"names":[],"mappings":"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"}