@hflin/cclin 0.1.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 (200) hide show
  1. package/README.md +124 -0
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +165 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/client.d.ts +32 -0
  7. package/dist/llm/client.d.ts.map +1 -0
  8. package/dist/llm/client.js +280 -0
  9. package/dist/llm/client.js.map +1 -0
  10. package/dist/runtime/compaction.d.ts +49 -0
  11. package/dist/runtime/compaction.d.ts.map +1 -0
  12. package/dist/runtime/compaction.js +118 -0
  13. package/dist/runtime/compaction.js.map +1 -0
  14. package/dist/runtime/compaction.test.d.ts +7 -0
  15. package/dist/runtime/compaction.test.d.ts.map +1 -0
  16. package/dist/runtime/compaction.test.js +70 -0
  17. package/dist/runtime/compaction.test.js.map +1 -0
  18. package/dist/runtime/history.d.ts +34 -0
  19. package/dist/runtime/history.d.ts.map +1 -0
  20. package/dist/runtime/history.js +63 -0
  21. package/dist/runtime/history.js.map +1 -0
  22. package/dist/runtime/hooks.d.ts +54 -0
  23. package/dist/runtime/hooks.d.ts.map +1 -0
  24. package/dist/runtime/hooks.js +113 -0
  25. package/dist/runtime/hooks.js.map +1 -0
  26. package/dist/runtime/hooks.test.d.ts +7 -0
  27. package/dist/runtime/hooks.test.d.ts.map +1 -0
  28. package/dist/runtime/hooks.test.js +73 -0
  29. package/dist/runtime/hooks.test.js.map +1 -0
  30. package/dist/runtime/model-profile.d.ts +42 -0
  31. package/dist/runtime/model-profile.d.ts.map +1 -0
  32. package/dist/runtime/model-profile.js +84 -0
  33. package/dist/runtime/model-profile.js.map +1 -0
  34. package/dist/runtime/prompt.d.ts +38 -0
  35. package/dist/runtime/prompt.d.ts.map +1 -0
  36. package/dist/runtime/prompt.js +152 -0
  37. package/dist/runtime/prompt.js.map +1 -0
  38. package/dist/runtime/prompt.md +64 -0
  39. package/dist/runtime/prompt.test.d.ts +7 -0
  40. package/dist/runtime/prompt.test.d.ts.map +1 -0
  41. package/dist/runtime/prompt.test.js +38 -0
  42. package/dist/runtime/prompt.test.js.map +1 -0
  43. package/dist/runtime/react-loop.d.ts +82 -0
  44. package/dist/runtime/react-loop.d.ts.map +1 -0
  45. package/dist/runtime/react-loop.js +311 -0
  46. package/dist/runtime/react-loop.js.map +1 -0
  47. package/dist/runtime/react-loop.test.d.ts +7 -0
  48. package/dist/runtime/react-loop.test.d.ts.map +1 -0
  49. package/dist/runtime/react-loop.test.js +78 -0
  50. package/dist/runtime/react-loop.test.js.map +1 -0
  51. package/dist/runtime/session.d.ts +109 -0
  52. package/dist/runtime/session.d.ts.map +1 -0
  53. package/dist/runtime/session.js +252 -0
  54. package/dist/runtime/session.js.map +1 -0
  55. package/dist/runtime/skills.d.ts +36 -0
  56. package/dist/runtime/skills.d.ts.map +1 -0
  57. package/dist/runtime/skills.js +187 -0
  58. package/dist/runtime/skills.js.map +1 -0
  59. package/dist/runtime/skills.test.d.ts +7 -0
  60. package/dist/runtime/skills.test.d.ts.map +1 -0
  61. package/dist/runtime/skills.test.js +92 -0
  62. package/dist/runtime/skills.test.js.map +1 -0
  63. package/dist/tools/approval.d.ts +61 -0
  64. package/dist/tools/approval.d.ts.map +1 -0
  65. package/dist/tools/approval.js +119 -0
  66. package/dist/tools/approval.js.map +1 -0
  67. package/dist/tools/approval.test.d.ts +9 -0
  68. package/dist/tools/approval.test.d.ts.map +1 -0
  69. package/dist/tools/approval.test.js +112 -0
  70. package/dist/tools/approval.test.js.map +1 -0
  71. package/dist/tools/bash.d.ts +6 -0
  72. package/dist/tools/bash.d.ts.map +1 -0
  73. package/dist/tools/bash.js +58 -0
  74. package/dist/tools/bash.js.map +1 -0
  75. package/dist/tools/edit-file.d.ts +6 -0
  76. package/dist/tools/edit-file.d.ts.map +1 -0
  77. package/dist/tools/edit-file.js +58 -0
  78. package/dist/tools/edit-file.js.map +1 -0
  79. package/dist/tools/get-memory.d.ts +9 -0
  80. package/dist/tools/get-memory.d.ts.map +1 -0
  81. package/dist/tools/get-memory.js +56 -0
  82. package/dist/tools/get-memory.js.map +1 -0
  83. package/dist/tools/list-directory.d.ts +6 -0
  84. package/dist/tools/list-directory.d.ts.map +1 -0
  85. package/dist/tools/list-directory.js +68 -0
  86. package/dist/tools/list-directory.js.map +1 -0
  87. package/dist/tools/mcp-client.d.ts +74 -0
  88. package/dist/tools/mcp-client.d.ts.map +1 -0
  89. package/dist/tools/mcp-client.js +129 -0
  90. package/dist/tools/mcp-client.js.map +1 -0
  91. package/dist/tools/mcp-config.d.ts +31 -0
  92. package/dist/tools/mcp-config.d.ts.map +1 -0
  93. package/dist/tools/mcp-config.js +55 -0
  94. package/dist/tools/mcp-config.js.map +1 -0
  95. package/dist/tools/mcp-registry.d.ts +39 -0
  96. package/dist/tools/mcp-registry.d.ts.map +1 -0
  97. package/dist/tools/mcp-registry.js +88 -0
  98. package/dist/tools/mcp-registry.js.map +1 -0
  99. package/dist/tools/orchestrator.d.ts +52 -0
  100. package/dist/tools/orchestrator.d.ts.map +1 -0
  101. package/dist/tools/orchestrator.js +190 -0
  102. package/dist/tools/orchestrator.js.map +1 -0
  103. package/dist/tools/orchestrator.test.d.ts +8 -0
  104. package/dist/tools/orchestrator.test.d.ts.map +1 -0
  105. package/dist/tools/orchestrator.test.js +122 -0
  106. package/dist/tools/orchestrator.test.js.map +1 -0
  107. package/dist/tools/read-file.d.ts +6 -0
  108. package/dist/tools/read-file.d.ts.map +1 -0
  109. package/dist/tools/read-file.js +50 -0
  110. package/dist/tools/read-file.js.map +1 -0
  111. package/dist/tools/registry.d.ts +55 -0
  112. package/dist/tools/registry.d.ts.map +1 -0
  113. package/dist/tools/registry.js +75 -0
  114. package/dist/tools/registry.js.map +1 -0
  115. package/dist/tools/registry.test.d.ts +8 -0
  116. package/dist/tools/registry.test.d.ts.map +1 -0
  117. package/dist/tools/registry.test.js +100 -0
  118. package/dist/tools/registry.test.js.map +1 -0
  119. package/dist/tools/router.d.ts +62 -0
  120. package/dist/tools/router.d.ts.map +1 -0
  121. package/dist/tools/router.js +119 -0
  122. package/dist/tools/router.js.map +1 -0
  123. package/dist/tools/router.test.d.ts +7 -0
  124. package/dist/tools/router.test.d.ts.map +1 -0
  125. package/dist/tools/router.test.js +102 -0
  126. package/dist/tools/router.test.js.map +1 -0
  127. package/dist/tools/safety.d.ts +16 -0
  128. package/dist/tools/safety.d.ts.map +1 -0
  129. package/dist/tools/safety.js +81 -0
  130. package/dist/tools/safety.js.map +1 -0
  131. package/dist/tools/safety.test.d.ts +7 -0
  132. package/dist/tools/safety.test.d.ts.map +1 -0
  133. package/dist/tools/safety.test.js +104 -0
  134. package/dist/tools/safety.test.js.map +1 -0
  135. package/dist/tools/search-files.d.ts +9 -0
  136. package/dist/tools/search-files.d.ts.map +1 -0
  137. package/dist/tools/search-files.js +114 -0
  138. package/dist/tools/search-files.js.map +1 -0
  139. package/dist/tools/update-plan.d.ts +9 -0
  140. package/dist/tools/update-plan.d.ts.map +1 -0
  141. package/dist/tools/update-plan.js +99 -0
  142. package/dist/tools/update-plan.js.map +1 -0
  143. package/dist/tools/write-file.d.ts +6 -0
  144. package/dist/tools/write-file.d.ts.map +1 -0
  145. package/dist/tools/write-file.js +41 -0
  146. package/dist/tools/write-file.js.map +1 -0
  147. package/dist/tui/app.d.ts +31 -0
  148. package/dist/tui/app.d.ts.map +1 -0
  149. package/dist/tui/app.js +121 -0
  150. package/dist/tui/app.js.map +1 -0
  151. package/dist/tui/chatwidget/markdown_renderer.d.ts +20 -0
  152. package/dist/tui/chatwidget/markdown_renderer.d.ts.map +1 -0
  153. package/dist/tui/chatwidget/markdown_renderer.js +188 -0
  154. package/dist/tui/chatwidget/markdown_renderer.js.map +1 -0
  155. package/dist/tui/cjk_text.d.ts +25 -0
  156. package/dist/tui/cjk_text.d.ts.map +1 -0
  157. package/dist/tui/cjk_text.js +84 -0
  158. package/dist/tui/cjk_text.js.map +1 -0
  159. package/dist/tui/cjk_text.test.d.ts +2 -0
  160. package/dist/tui/cjk_text.test.d.ts.map +1 -0
  161. package/dist/tui/cjk_text.test.js +62 -0
  162. package/dist/tui/cjk_text.test.js.map +1 -0
  163. package/dist/tui/composer_input.d.ts +31 -0
  164. package/dist/tui/composer_input.d.ts.map +1 -0
  165. package/dist/tui/composer_input.js +184 -0
  166. package/dist/tui/composer_input.js.map +1 -0
  167. package/dist/tui/composer_input.test.d.ts +2 -0
  168. package/dist/tui/composer_input.test.d.ts.map +1 -0
  169. package/dist/tui/composer_input.test.js +87 -0
  170. package/dist/tui/composer_input.test.js.map +1 -0
  171. package/dist/tui/input.d.ts +21 -0
  172. package/dist/tui/input.d.ts.map +1 -0
  173. package/dist/tui/input.js +166 -0
  174. package/dist/tui/input.js.map +1 -0
  175. package/dist/tui/output.d.ts +17 -0
  176. package/dist/tui/output.d.ts.map +1 -0
  177. package/dist/tui/output.js +104 -0
  178. package/dist/tui/output.js.map +1 -0
  179. package/dist/tui/state/chat_timeline.d.ts +50 -0
  180. package/dist/tui/state/chat_timeline.d.ts.map +1 -0
  181. package/dist/tui/state/chat_timeline.js +129 -0
  182. package/dist/tui/state/chat_timeline.js.map +1 -0
  183. package/dist/tui/types.d.ts +45 -0
  184. package/dist/tui/types.d.ts.map +1 -0
  185. package/dist/tui/types.js +14 -0
  186. package/dist/tui/types.js.map +1 -0
  187. package/dist/types.d.ts +435 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/types.js +8 -0
  190. package/dist/types.js.map +1 -0
  191. package/dist/utils/tokenizer.d.ts +21 -0
  192. package/dist/utils/tokenizer.d.ts.map +1 -0
  193. package/dist/utils/tokenizer.js +71 -0
  194. package/dist/utils/tokenizer.js.map +1 -0
  195. package/dist/utils/tokenizer.test.d.ts +7 -0
  196. package/dist/utils/tokenizer.test.d.ts.map +1 -0
  197. package/dist/utils/tokenizer.test.js +51 -0
  198. package/dist/utils/tokenizer.test.js.map +1 -0
  199. package/package.json +41 -0
  200. package/src/runtime/prompt.md +64 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file 模型能力配置 — 根据模型名推断其支持的特性。
3
+ *
4
+ * 参考 memo-code 的 model_profile.ts,
5
+ * 不同模型支持不同能力(并行工具调用、思考链等)。
6
+ */
7
+ import type OpenAI from 'openai';
8
+ /** 模型能力画像。 */
9
+ export type ModelProfile = {
10
+ /** 是否支持并行工具调用。 */
11
+ supportsParallelToolCalls: boolean;
12
+ /** 是否支持 reasoning_content 字段。 */
13
+ supportsReasoningContent: boolean;
14
+ /** 上下文窗口大小(token)。 */
15
+ contextWindow: number;
16
+ /** 是否是回退配置(无精确匹配)。 */
17
+ isFallback: boolean;
18
+ };
19
+ /**
20
+ * 根据模型名解析能力配置。
21
+ * 使用最长前缀匹配策略。
22
+ */
23
+ export declare function resolveModelProfile(model: string): ModelProfile;
24
+ type ToolSpec = {
25
+ type: 'function';
26
+ function: {
27
+ name: string;
28
+ description: string;
29
+ parameters: Record<string, unknown>;
30
+ };
31
+ };
32
+ /**
33
+ * 根据模型 profile 构建 chat completion 请求参数。
34
+ */
35
+ export declare function buildChatCompletionRequest(params: {
36
+ model: string;
37
+ messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[];
38
+ tools?: ToolSpec[];
39
+ profile: ModelProfile;
40
+ }): OpenAI.Chat.Completions.ChatCompletionCreateParams;
41
+ export {};
42
+ //# sourceMappingURL=model-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-profile.d.ts","sourceRoot":"","sources":["../../src/runtime/model-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAIhC,cAAc;AACd,MAAM,MAAM,YAAY,GAAG;IACvB,kBAAkB;IAClB,yBAAyB,EAAE,OAAO,CAAA;IAClC,iCAAiC;IACjC,wBAAwB,EAAE,OAAO,CAAA;IACjC,sBAAsB;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB;IACtB,UAAU,EAAE,OAAO,CAAA;CACtB,CAAA;AA+CD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAqB/D;AAID,KAAK,QAAQ,GAAG;IACZ,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACtC,CAAA;CACJ,CAAA;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAA;IAC9D,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;IAClB,OAAO,EAAE,YAAY,CAAA;CACxB,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,CAgBrD"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @file 模型能力配置 — 根据模型名推断其支持的特性。
3
+ *
4
+ * 参考 memo-code 的 model_profile.ts,
5
+ * 不同模型支持不同能力(并行工具调用、思考链等)。
6
+ */
7
+ /** 保守的回退配置。 */
8
+ const FALLBACK = {
9
+ supportsParallelToolCalls: false,
10
+ supportsReasoningContent: false,
11
+ contextWindow: 128_000,
12
+ };
13
+ /**
14
+ * 已知模型的能力映射。
15
+ * key 为模型名前缀(小写),匹配时取最长前缀。
16
+ */
17
+ const KNOWN_PROFILES = {
18
+ 'gpt-4o': {
19
+ supportsParallelToolCalls: true,
20
+ supportsReasoningContent: false,
21
+ contextWindow: 128_000,
22
+ },
23
+ 'gpt-4o-mini': {
24
+ supportsParallelToolCalls: true,
25
+ supportsReasoningContent: false,
26
+ contextWindow: 128_000,
27
+ },
28
+ 'deepseek-chat': {
29
+ supportsParallelToolCalls: false,
30
+ supportsReasoningContent: false,
31
+ contextWindow: 64_000,
32
+ },
33
+ 'deepseek-reasoner': {
34
+ supportsParallelToolCalls: false,
35
+ supportsReasoningContent: true,
36
+ contextWindow: 64_000,
37
+ },
38
+ 'claude': {
39
+ supportsParallelToolCalls: true,
40
+ supportsReasoningContent: false,
41
+ contextWindow: 200_000,
42
+ },
43
+ };
44
+ // ─── 解析函数 ─────────────────────────────────────────────────────────────────
45
+ /**
46
+ * 根据模型名解析能力配置。
47
+ * 使用最长前缀匹配策略。
48
+ */
49
+ export function resolveModelProfile(model) {
50
+ const slug = model.trim().toLowerCase();
51
+ // 精确匹配
52
+ if (KNOWN_PROFILES[slug]) {
53
+ return { ...KNOWN_PROFILES[slug], isFallback: false };
54
+ }
55
+ // 前缀匹配(取最长匹配)
56
+ let bestKey = '';
57
+ for (const key of Object.keys(KNOWN_PROFILES)) {
58
+ if (slug.startsWith(key) && key.length > bestKey.length) {
59
+ bestKey = key;
60
+ }
61
+ }
62
+ if (bestKey) {
63
+ return { ...KNOWN_PROFILES[bestKey], isFallback: false };
64
+ }
65
+ return { ...FALLBACK, isFallback: true };
66
+ }
67
+ /**
68
+ * 根据模型 profile 构建 chat completion 请求参数。
69
+ */
70
+ export function buildChatCompletionRequest(params) {
71
+ const request = {
72
+ model: params.model,
73
+ messages: params.messages,
74
+ };
75
+ if (params.tools && params.tools.length > 0) {
76
+ request.tools = params.tools;
77
+ request.tool_choice = 'auto';
78
+ if (params.profile.supportsParallelToolCalls) {
79
+ request.parallel_tool_calls = true;
80
+ }
81
+ }
82
+ return request;
83
+ }
84
+ //# sourceMappingURL=model-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-profile.js","sourceRoot":"","sources":["../../src/runtime/model-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH,eAAe;AACf,MAAM,QAAQ,GAAiB;IAC3B,yBAAyB,EAAE,KAAK;IAChC,wBAAwB,EAAE,KAAK;IAC/B,aAAa,EAAE,OAAO;CACzB,CAAA;AAED;;;GAGG;AACH,MAAM,cAAc,GAAiC;IACjD,QAAQ,EAAE;QACN,yBAAyB,EAAE,IAAI;QAC/B,wBAAwB,EAAE,KAAK;QAC/B,aAAa,EAAE,OAAO;KACzB;IACD,aAAa,EAAE;QACX,yBAAyB,EAAE,IAAI;QAC/B,wBAAwB,EAAE,KAAK;QAC/B,aAAa,EAAE,OAAO;KACzB;IACD,eAAe,EAAE;QACb,yBAAyB,EAAE,KAAK;QAChC,wBAAwB,EAAE,KAAK;QAC/B,aAAa,EAAE,MAAM;KACxB;IACD,mBAAmB,EAAE;QACjB,yBAAyB,EAAE,KAAK;QAChC,wBAAwB,EAAE,IAAI;QAC9B,aAAa,EAAE,MAAM;KACxB;IACD,QAAQ,EAAE;QACN,yBAAyB,EAAE,IAAI;QAC/B,wBAAwB,EAAE,KAAK;QAC/B,aAAa,EAAE,OAAO;KACzB;CACJ,CAAA;AAED,6EAA6E;AAE7E;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAEvC,OAAO;IACP,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;IACzD,CAAC;IAED,cAAc;IACd,IAAI,OAAO,GAAG,EAAE,CAAA;IAChB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACtD,OAAO,GAAG,GAAG,CAAA;QACjB,CAAC;IACL,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,GAAG,cAAc,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;IAC5D,CAAC;IAED,OAAO,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAC5C,CAAC;AAaD;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAK1C;IACG,MAAM,OAAO,GAAuD;QAChE,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC5B,CAAA;IAED,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;QAC5B,OAAO,CAAC,WAAW,GAAG,MAAM,CAAA;QAE5B,IAAI,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC;YAC3C,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAA;QACtC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAA;AAClB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file Prompt 管理模块 — 模板引擎 + 系统提示词动态组装。
3
+ *
4
+ * Phase 5:实现灵活的系统提示词加载:
5
+ * 1. 读取 prompt.md 模板
6
+ * 2. 渲染变量替换({{date}}, {{user}}, {{pwd}})
7
+ * 3. 加载 AGENTS.md(项目级指令)
8
+ * 4. 加载 SOUL.md(用户人格偏好)
9
+ * 5. 组装完整 system prompt
10
+ */
11
+ /**
12
+ * 渲染模板字符串,将 {{key}} 替换为 vars 中的值。
13
+ *
14
+ * 设计决策:使用简单的正则替换而非完整模板引擎,
15
+ * 因为我们只需要少量变量替换,不需要条件/循环等高级特性。
16
+ */
17
+ export declare function renderTemplate(template: string, vars: Record<string, string>): string;
18
+ export type LoadSystemPromptOptions = {
19
+ /** 项目根目录,默认 process.cwd()。 */
20
+ cwd?: string;
21
+ /** 工具的 Markdown 描述文本(对应 {{tools}} 占位符)。 */
22
+ toolsText?: string;
23
+ /** Skills section 文本(由 renderSkillsSection 生成)。 */
24
+ skillsText?: string;
25
+ };
26
+ /**
27
+ * 加载并组装完整的系统提示词。
28
+ *
29
+ * 组装流程:
30
+ * 1. 读取 prompt.md 模板文件
31
+ * 2. 读取 SOUL.md(可选)
32
+ * 3. 渲染模板变量(date, user, pwd, soul_section)
33
+ * 4. 若模板中无 soul 占位符但有 SOUL.md → 追加到末尾
34
+ * 5. 读取 AGENTS.md(可选)→ 追加到末尾
35
+ * 6. 返回组装后的完整 system prompt
36
+ */
37
+ export declare function loadSystemPrompt(options?: LoadSystemPromptOptions): Promise<string>;
38
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/runtime/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAKR;AA4FD,MAAM,MAAM,uBAAuB,GAAG;IAClC,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAClC,OAAO,GAAE,uBAA4B,GACtC,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @file Prompt 管理模块 — 模板引擎 + 系统提示词动态组装。
3
+ *
4
+ * Phase 5:实现灵活的系统提示词加载:
5
+ * 1. 读取 prompt.md 模板
6
+ * 2. 渲染变量替换({{date}}, {{user}}, {{pwd}})
7
+ * 3. 加载 AGENTS.md(项目级指令)
8
+ * 4. 加载 SOUL.md(用户人格偏好)
9
+ * 5. 组装完整 system prompt
10
+ */
11
+ import os from 'node:os';
12
+ import { readFile } from 'node:fs/promises';
13
+ import { join, dirname, resolve } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ // ─── 模板引擎 ────────────────────────────────────────────────────────────────
16
+ /** 模板变量匹配正则:{{varName}} */
17
+ const TEMPLATE_PATTERN = /\{\{\s*([\w.-]+)\s*\}\}/g;
18
+ /**
19
+ * 渲染模板字符串,将 {{key}} 替换为 vars 中的值。
20
+ *
21
+ * 设计决策:使用简单的正则替换而非完整模板引擎,
22
+ * 因为我们只需要少量变量替换,不需要条件/循环等高级特性。
23
+ */
24
+ export function renderTemplate(template, vars) {
25
+ return template.replace(TEMPLATE_PATTERN, (_match, key) => vars[key] ?? '');
26
+ }
27
+ // ─── 环境信息 ────────────────────────────────────────────────────────────────
28
+ /** 获取当前操作系统用户名。 */
29
+ function resolveUsername() {
30
+ try {
31
+ return os.userInfo().username;
32
+ }
33
+ catch {
34
+ return process.env.USER ?? process.env.USERNAME ?? 'unknown';
35
+ }
36
+ }
37
+ /**
38
+ * 解析 cclin 主目录(存放 SOUL.md 等用户配置)。
39
+ *
40
+ * 优先级:环境变量 CCLIN_HOME > ~/.cclin
41
+ */
42
+ function resolveCclinHome() {
43
+ const homeDir = os.homedir();
44
+ const configured = process.env.CCLIN_HOME?.trim();
45
+ if (configured) {
46
+ if (configured.startsWith('~/')) {
47
+ return resolve(join(homeDir, configured.slice(2)));
48
+ }
49
+ return resolve(configured);
50
+ }
51
+ return join(homeDir, '.cclin');
52
+ }
53
+ /**
54
+ * 读取项目根目录的 AGENTS.md。
55
+ *
56
+ * AGENTS.md 包含项目级的开发规范和指令,
57
+ * 加载后会追加到系统提示词末尾。
58
+ */
59
+ async function readProjectAgentsMd(projectRoot) {
60
+ const agentsPath = join(projectRoot, 'AGENTS.md');
61
+ try {
62
+ const content = await readFile(agentsPath, 'utf-8');
63
+ if (!content.trim())
64
+ return null;
65
+ return { path: agentsPath, content };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * 读取用户人格偏好文件 SOUL.md。
73
+ *
74
+ * SOUL.md 存放在 ~/.cclin/SOUL.md,包含用户的
75
+ * 语言、风格等个性化偏好,属于"软偏好层"。
76
+ */
77
+ async function readSoulMd() {
78
+ const soulPath = join(resolveCclinHome(), 'SOUL.md');
79
+ try {
80
+ const content = await readFile(soulPath, 'utf-8');
81
+ if (!content.trim())
82
+ return null;
83
+ return { path: soulPath, content };
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ // ─── Prompt 组装 ─────────────────────────────────────────────────────────────
90
+ /** SOUL.md 占位符正则。 */
91
+ const SOUL_PLACEHOLDER = /\{\{\s*soul_section\s*\}\}/;
92
+ /**
93
+ * 将 SOUL.md 内容渲染为带说明的 section。
94
+ *
95
+ * 包含优先级说明:SOUL.md 是"软偏好层",
96
+ * 不应覆盖安全规则或 AGENTS.md 指令。
97
+ */
98
+ function renderSoulSection(soul) {
99
+ return `## User Personality (SOUL.md)
100
+ Loaded from: ${soul.path}
101
+
102
+ - Treat as soft preference for tone, style, and behavior.
103
+ - Do NOT override safety rules, AGENTS.md, or explicit user instructions.
104
+
105
+ ${soul.content}`;
106
+ }
107
+ /**
108
+ * 加载并组装完整的系统提示词。
109
+ *
110
+ * 组装流程:
111
+ * 1. 读取 prompt.md 模板文件
112
+ * 2. 读取 SOUL.md(可选)
113
+ * 3. 渲染模板变量(date, user, pwd, soul_section)
114
+ * 4. 若模板中无 soul 占位符但有 SOUL.md → 追加到末尾
115
+ * 5. 读取 AGENTS.md(可选)→ 追加到末尾
116
+ * 6. 返回组装后的完整 system prompt
117
+ */
118
+ export async function loadSystemPrompt(options = {}) {
119
+ const cwd = options.cwd ?? process.cwd();
120
+ // 1. 定位并读取 prompt.md 模板
121
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
122
+ const promptPath = join(moduleDir, 'prompt.md');
123
+ const template = await readFile(promptPath, 'utf-8');
124
+ // 2. 读取 SOUL.md
125
+ const soul = await readSoulMd();
126
+ const soulSection = soul ? renderSoulSection(soul) : '';
127
+ const hasSoulPlaceholder = SOUL_PLACEHOLDER.test(template);
128
+ // 3. 渲染模板变量
129
+ const vars = {
130
+ date: new Date().toISOString(),
131
+ user: resolveUsername(),
132
+ pwd: cwd,
133
+ soul_section: soulSection,
134
+ tools: options.toolsText ?? 'No tools available.',
135
+ };
136
+ let prompt = renderTemplate(template, vars);
137
+ // 4. 若模板中没有 soul 占位符,但有 SOUL.md → 追加
138
+ if (!hasSoulPlaceholder && soulSection) {
139
+ prompt = `${prompt}\n\n${soulSection}`;
140
+ }
141
+ // 5. 追加 Skills section(放在 AGENTS.md 之前)
142
+ if (options.skillsText) {
143
+ prompt = `${prompt}\n\n${options.skillsText}`;
144
+ }
145
+ // 6. 追加 AGENTS.md(放在越后面,优先级越高)
146
+ const agents = await readProjectAgentsMd(cwd);
147
+ if (agents) {
148
+ prompt = `${prompt}\n\n## Project AGENTS.md\nLoaded from: ${agents.path}\n\n${agents.content}`;
149
+ }
150
+ return prompt;
151
+ }
152
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/runtime/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ You are **cclin**, an interactive CLI coding assistant. Use the tools available to you to help the user with software engineering tasks.
2
+
3
+ **IMPORTANT**: Refuse to write or explain code that may be used maliciously.
4
+
5
+ ---
6
+
7
+ # Core Identity
8
+
9
+ - **Local First**: You operate directly on the user's machine. File operations and commands happen in the real environment.
10
+ - **Project Aware**: Read and follow `AGENTS.md` files containing project structure, conventions, and preferences.
11
+ - **Tool Rich**: Use your comprehensive toolkit to gather information and complete tasks.
12
+ - **Safety Conscious**: The environment is NOT sandboxed. Your actions have immediate effects.
13
+
14
+ {{soul_section}}
15
+
16
+ # Session Context
17
+
18
+ - Date: {{date}}
19
+ - User: {{user}}
20
+ - PWD: {{pwd}}
21
+
22
+ ---
23
+
24
+ # Tone and Style
25
+
26
+ - Answer directly without preamble or postamble
27
+ - Keep responses concise unless the user asks for detail
28
+ - One word answers are best when appropriate
29
+
30
+ ---
31
+
32
+ # Tool Usage Policy
33
+
34
+ - Prefer specialized tools over generic shell calls
35
+ - Use tools extensively to read and understand before modifying
36
+ - Follow existing code conventions and patterns
37
+
38
+ ## Available Tools
39
+
40
+ {{tools}}
41
+
42
+ ---
43
+
44
+ # Working Environment
45
+
46
+ ⚠️ **WARNING**: Environment is NOT SANDBOXED. Actions immediately affect the user's system.
47
+
48
+ - Never access files outside working directory unless instructed
49
+ - Note: On Windows, paths are case-insensitive (e.g., 'd:\' and 'D:\' are the same). Do not falsely reject valid paths due to case differences.
50
+ - Be careful with destructive operations
51
+ - Validate inputs before shell commands
52
+
53
+ ## Project Context (AGENTS.md)
54
+
55
+ Files named `AGENTS.md` may exist with project-specific guidance. Follow their instructions.
56
+
57
+ ---
58
+
59
+ # Ultimate Reminders
60
+
61
+ - **Concise**: Keep text short
62
+ - **Quality-focused**: Run lint/typecheck after changes
63
+ - **Safety conscious**: Actions have real consequences
64
+ - **Focused**: Only make necessary changes
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @file Unit tests for Prompt management (Phase 5).
3
+ *
4
+ * Tests: renderTemplate
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=prompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.test.d.ts","sourceRoot":"","sources":["../../src/runtime/prompt.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file Unit tests for Prompt management (Phase 5).
3
+ *
4
+ * Tests: renderTemplate
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import { renderTemplate } from './prompt.js';
8
+ describe('renderTemplate', () => {
9
+ it('should replace variables with values', () => {
10
+ const template = 'Hello, {{NAME}}! Welcome to {{PLACE}}.';
11
+ const vars = { NAME: 'Alice', PLACE: 'Wonderland' };
12
+ const result = renderTemplate(template, vars);
13
+ expect(result).toBe('Hello, Alice! Welcome to Wonderland.');
14
+ });
15
+ it('should handle whitespace in template tags', () => {
16
+ const template = 'Value: {{ KEY }}';
17
+ const vars = { KEY: '123' };
18
+ const result = renderTemplate(template, vars);
19
+ expect(result).toBe('Value: 123');
20
+ });
21
+ it('should replace undefined variables with empty string', () => {
22
+ const template = 'Hello, {{NAME}}!';
23
+ const vars = {}; // NAME is missing
24
+ const result = renderTemplate(template, vars);
25
+ expect(result).toBe('Hello, !');
26
+ });
27
+ it('should leave text unchanged if no tags', () => {
28
+ const template = 'Just normal text without tags.';
29
+ const result = renderTemplate(template, { KEY: 'val' });
30
+ expect(result).toBe('Just normal text without tags.');
31
+ });
32
+ it('should replace multiple occurrences of the same variable', () => {
33
+ const template = '{{A}} plus {{A}} is 2{{A}}';
34
+ const result = renderTemplate(template, { A: '1' });
35
+ expect(result).toBe('1 plus 1 is 21');
36
+ });
37
+ });
38
+ //# sourceMappingURL=prompt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.test.js","sourceRoot":"","sources":["../../src/runtime/prompt.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC5C,MAAM,QAAQ,GAAG,wCAAwC,CAAA;QACzD,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;QACnD,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACjD,MAAM,QAAQ,GAAG,oBAAoB,CAAA;QACrC,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;QAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC5D,MAAM,QAAQ,GAAG,kBAAkB,CAAA;QACnC,MAAM,IAAI,GAAG,EAAE,CAAA,CAAC,kBAAkB;QAClC,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAC9C,MAAM,QAAQ,GAAG,gCAAgC,CAAA;QACjD,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;QACvD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,4BAA4B,CAAA;QAC7C,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAA;QACnD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @file ReAct 循环核心引擎。
3
+ *
4
+ * Phase 2:实现 Think → Act → Observe 循环骨架。
5
+ * 工具执行通过 `executeTool` 注入,Phase 2 使用 mock 实现。
6
+ *
7
+ * 设计:纯函数 `runTurn()`,不持有状态,所有状态通过参数传入。
8
+ * 这样 Session 类只做状态管理,循环逻辑可独立测试。
9
+ */
10
+ import type { CallLLM, ChatMessage, LLMResponse, ParsedAssistant, TurnResult, ExecuteTool, TokenUsage, TokenCounter, CompactResult } from '../types.js';
11
+ import type { HookRunnerMap } from './hooks.js';
12
+ /**
13
+ * 从 LLM 响应中提取文本内容和工具调用块。
14
+ *
15
+ * 将 ContentBlock[] 分拆为两个维度:
16
+ * - textContent:所有 TextBlock 拼接的纯文本
17
+ * - toolUseBlocks:所有 ToolUseBlock 的结构化数据
18
+ */
19
+ export declare function normalizeLLMResponse(response: LLMResponse): {
20
+ textContent: string;
21
+ toolUseBlocks: Array<{
22
+ id: string;
23
+ name: string;
24
+ input: unknown;
25
+ }>;
26
+ stopReason: string;
27
+ usage: Partial<TokenUsage> | undefined;
28
+ reasoningContent: string | undefined;
29
+ };
30
+ /**
31
+ * 将 normalized 响应转为 ParsedAssistant 结构。
32
+ *
33
+ * 判定逻辑:
34
+ * 1. 有工具调用 → action(取第一个工具),文本部分作为 thinking
35
+ * 2. 无工具调用但有文本 → final
36
+ * 3. 两者皆无 → 空对象
37
+ */
38
+ export declare function parseLLMResponse(textContent: string, toolUseBlocks: Array<{
39
+ id: string;
40
+ name: string;
41
+ input: unknown;
42
+ }>): ParsedAssistant;
43
+ /** runTurn 的依赖注入参数。 */
44
+ export type RunTurnDeps = {
45
+ /** 对话历史(会被就地修改)。 */
46
+ history: ChatMessage[];
47
+ /** LLM 调用函数。 */
48
+ callLLM: CallLLM;
49
+ /** 工具执行函数(Phase 2 默认 mock)。 */
50
+ executeTool?: ExecuteTool;
51
+ /** Token 计数器(Phase 6,启用压缩必需)。 */
52
+ tokenCounter?: TokenCounter;
53
+ /** 上下文窗口大小(token 数)。 */
54
+ contextWindow?: number;
55
+ /** 自动压缩阈值百分比。 */
56
+ compactThreshold?: number;
57
+ /** 自动压缩回调(由 Session 注入)。 */
58
+ compactFn?: () => Promise<CompactResult>;
59
+ /** Hook 注册表(Phase 7)。 */
60
+ hookRunners?: HookRunnerMap;
61
+ /** Session ID(供 Hook payload 使用)。 */
62
+ sessionId?: string;
63
+ /** 当前轮次编号(供 Hook payload 使用)。 */
64
+ turnIndex?: number;
65
+ /** 清理本轮一次性授权(Turn 结束时调用)。 */
66
+ clearApprovalsFn?: () => void;
67
+ /** 流式文本 chunk 回调(TUI 实时显示)。 */
68
+ onAssistantChunk?: (step: number, chunk: string) => void;
69
+ };
70
+ /**
71
+ * 执行一次 Turn 的 ReAct 循环。
72
+ *
73
+ * 流程:
74
+ * 1. 将用户输入追加到 history
75
+ * 2. 循环调用 LLM → 解析响应 → 处理工具/最终回答
76
+ * 3. 返回 TurnResult
77
+ *
78
+ * @param input - 用户输入文本
79
+ * @param deps - 依赖注入(history, callLLM, executeTool)
80
+ */
81
+ export declare function runTurn(input: string, deps: RunTurnDeps): Promise<TurnResult>;
82
+ //# sourceMappingURL=react-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-loop.d.ts","sourceRoot":"","sources":["../../src/runtime/react-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACR,OAAO,EACP,WAAW,EACX,WAAW,EAEX,eAAe,EAEf,UAAU,EAEV,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EAChB,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO/C;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,WAAW,GAAG;IACzD,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;IACtC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;CACvC,CAwBA;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC5B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,GACnE,eAAe,CAqBjB;AAuBD,uBAAuB;AACvB,MAAM,MAAM,WAAW,GAAG;IACtB,oBAAoB;IACpB,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,gBAAgB;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,+BAA+B;IAC/B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,iCAAiC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACxC,yBAAyB;IACzB,WAAW,CAAC,EAAE,aAAa,CAAA;IAC3B,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3D,CAAA;AAUD;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CACzB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,GAClB,OAAO,CAAC,UAAU,CAAC,CA8OrB"}