@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,61 @@
1
+ /**
2
+ * @file 审批管理器 — 管理工具执行的审批策略和授权缓存。
3
+ *
4
+ * Phase 4:基于工具的 isMutating 属性决定是否需要审批。
5
+ *
6
+ * 设计思路:
7
+ * 1. 非 mutating 工具(read_file / list_directory)→ 自动放行
8
+ * 2. mutating 工具(write_file / bash / edit_file)→ 需要审批
9
+ * 3. 用"指纹"去重,避免重复询问相同操作
10
+ *
11
+ * 三种策略:
12
+ * - always:每次都询问(最严格)
13
+ * - once:同指纹本轮只问一次
14
+ * - session:同指纹整个会话有效
15
+ */
16
+ import type { ApprovalPolicy, ApprovalDecision, ApprovalCheckResult } from '../types.js';
17
+ export declare function generateFingerprint(toolName: string, input: unknown): string;
18
+ /** ApprovalManager 构造参数。 */
19
+ export type ApprovalManagerOptions = {
20
+ /** 审批策略,默认 'once'。 */
21
+ policy?: ApprovalPolicy;
22
+ };
23
+ /**
24
+ * 审批管理器。
25
+ *
26
+ * 管理工具执行权限:
27
+ * - 检查工具是否需要审批
28
+ * - 缓存已授权的操作指纹
29
+ * - 支持按轮次或会话级别的授权生命周期
30
+ */
31
+ export declare class ApprovalManager {
32
+ private _policy;
33
+ /** once 级别授权缓存(Turn 结束时清除)。 */
34
+ private onceGrants;
35
+ /** session 级别授权缓存(Session 结束时清除)。 */
36
+ private sessionGrants;
37
+ constructor(options?: ApprovalManagerOptions);
38
+ /** 获取当前策略。 */
39
+ get policy(): ApprovalPolicy;
40
+ /**
41
+ * 动态切换审批策略。
42
+ * 切换策略时会自动清空旧的授权缓存,防止状态混乱。
43
+ */
44
+ set policy(newPolicy: ApprovalPolicy);
45
+ /**
46
+ * 检查工具调用是否需要审批。
47
+ *
48
+ * 非 mutating 工具自动放行;
49
+ * mutating 工具根据策略和缓存决定。
50
+ */
51
+ check(toolName: string, input: unknown, isMutating: boolean): ApprovalCheckResult;
52
+ /** 记录用户决定。 */
53
+ recordDecision(fingerprint: string, decision: ApprovalDecision): void;
54
+ /** 检查指纹是否已授权。 */
55
+ isGranted(fingerprint: string): boolean;
56
+ /** 清除 once 级别授权(Turn 结束时调用)。 */
57
+ clearOnceApprovals(): void;
58
+ /** 清除所有授权(Session 结束时调用)。 */
59
+ dispose(): void;
60
+ }
61
+ //# sourceMappingURL=approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../src/tools/approval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACR,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACtB,MAAM,aAAa,CAAA;AAyBpB,wBAAgB,mBAAmB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,GACf,MAAM,CAER;AAID,4BAA4B;AAC5B,MAAM,MAAM,sBAAsB,GAAG;IACjC,sBAAsB;IACtB,MAAM,CAAC,EAAE,cAAc,CAAA;CAC1B,CAAA;AAED;;;;;;;GAOG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,OAAO,CAAgB;IAE/B,+BAA+B;IAC/B,OAAO,CAAC,UAAU,CAAyB;IAE3C,qCAAqC;IACrC,OAAO,CAAC,aAAa,CAAyB;gBAElC,OAAO,GAAE,sBAA2B;IAIhD,cAAc;IACd,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED;;;OAGG;IACH,IAAI,MAAM,CAAC,SAAS,EAAE,cAAc,EAGnC;IAED;;;;;OAKG;IACH,KAAK,CACD,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,OAAO,GACpB,mBAAmB;IAsBtB,cAAc;IACd,cAAc,CACV,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,gBAAgB,GAC3B,IAAI;IAWP,iBAAiB;IACjB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOvC,gCAAgC;IAChC,kBAAkB,IAAI,IAAI;IAI1B,6BAA6B;IAC7B,OAAO,IAAI,IAAI;CAIlB"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @file 审批管理器 — 管理工具执行的审批策略和授权缓存。
3
+ *
4
+ * Phase 4:基于工具的 isMutating 属性决定是否需要审批。
5
+ *
6
+ * 设计思路:
7
+ * 1. 非 mutating 工具(read_file / list_directory)→ 自动放行
8
+ * 2. mutating 工具(write_file / bash / edit_file)→ 需要审批
9
+ * 3. 用"指纹"去重,避免重复询问相同操作
10
+ *
11
+ * 三种策略:
12
+ * - always:每次都询问(最严格)
13
+ * - once:同指纹本轮只问一次
14
+ * - session:同指纹整个会话有效
15
+ */
16
+ // ─── 指纹生成 ─────────────────────────────────────────────────────────────────
17
+ /**
18
+ * 生成工具调用指纹。
19
+ *
20
+ * 将工具名和输入参数序列化为稳定字符串,用于去重。
21
+ * 使用排序后的 JSON 保证相同参数产生相同指纹。
22
+ */
23
+ function stableStringify(value) {
24
+ if (value === null || value === undefined)
25
+ return '';
26
+ if (typeof value !== 'object')
27
+ return String(value);
28
+ const sorted = Object.keys(value)
29
+ .sort()
30
+ .reduce((acc, key) => {
31
+ acc[key] = value[key];
32
+ return acc;
33
+ }, {});
34
+ return JSON.stringify(sorted);
35
+ }
36
+ export function generateFingerprint(toolName, input) {
37
+ return `${toolName}::${stableStringify(input)}`;
38
+ }
39
+ /**
40
+ * 审批管理器。
41
+ *
42
+ * 管理工具执行权限:
43
+ * - 检查工具是否需要审批
44
+ * - 缓存已授权的操作指纹
45
+ * - 支持按轮次或会话级别的授权生命周期
46
+ */
47
+ export class ApprovalManager {
48
+ _policy;
49
+ /** once 级别授权缓存(Turn 结束时清除)。 */
50
+ onceGrants = new Set();
51
+ /** session 级别授权缓存(Session 结束时清除)。 */
52
+ sessionGrants = new Set();
53
+ constructor(options = {}) {
54
+ this._policy = options.policy ?? 'once';
55
+ }
56
+ /** 获取当前策略。 */
57
+ get policy() {
58
+ return this._policy;
59
+ }
60
+ /**
61
+ * 动态切换审批策略。
62
+ * 切换策略时会自动清空旧的授权缓存,防止状态混乱。
63
+ */
64
+ set policy(newPolicy) {
65
+ this._policy = newPolicy;
66
+ this.dispose(); // 清空原有的授权
67
+ }
68
+ /**
69
+ * 检查工具调用是否需要审批。
70
+ *
71
+ * 非 mutating 工具自动放行;
72
+ * mutating 工具根据策略和缓存决定。
73
+ */
74
+ check(toolName, input, isMutating) {
75
+ // 非 mutating 工具直接放行
76
+ if (!isMutating) {
77
+ return { needsApproval: false };
78
+ }
79
+ const fingerprint = generateFingerprint(toolName, input);
80
+ // 检查缓存
81
+ if (this.isGranted(fingerprint)) {
82
+ return { needsApproval: false };
83
+ }
84
+ return {
85
+ needsApproval: true,
86
+ fingerprint,
87
+ reason: `工具 "${toolName}" 会修改外部状态,需要你的确认。`,
88
+ toolName,
89
+ input,
90
+ };
91
+ }
92
+ /** 记录用户决定。 */
93
+ recordDecision(fingerprint, decision) {
94
+ if (decision !== 'approve')
95
+ return;
96
+ if (this._policy === 'once') {
97
+ this.onceGrants.add(fingerprint);
98
+ }
99
+ else if (this._policy === 'session') {
100
+ this.sessionGrants.add(fingerprint);
101
+ }
102
+ // always 策略不缓存
103
+ }
104
+ /** 检查指纹是否已授权。 */
105
+ isGranted(fingerprint) {
106
+ return (this.onceGrants.has(fingerprint) ||
107
+ this.sessionGrants.has(fingerprint));
108
+ }
109
+ /** 清除 once 级别授权(Turn 结束时调用)。 */
110
+ clearOnceApprovals() {
111
+ this.onceGrants.clear();
112
+ }
113
+ /** 清除所有授权(Session 结束时调用)。 */
114
+ dispose() {
115
+ this.onceGrants.clear();
116
+ this.sessionGrants.clear();
117
+ }
118
+ }
119
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/tools/approval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @file Unit tests for ApprovalManager (Phase 4).
3
+ *
4
+ * Tests: check (non-mutating auto-pass, mutating requires approval),
5
+ * recordDecision, policies (always/once/session),
6
+ * clearOnceApprovals, dispose, generateFingerprint
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=approval.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.test.d.ts","sourceRoot":"","sources":["../../src/tools/approval.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @file Unit tests for ApprovalManager (Phase 4).
3
+ *
4
+ * Tests: check (non-mutating auto-pass, mutating requires approval),
5
+ * recordDecision, policies (always/once/session),
6
+ * clearOnceApprovals, dispose, generateFingerprint
7
+ */
8
+ import { describe, it, expect, beforeEach } from 'vitest';
9
+ import { ApprovalManager, generateFingerprint } from './approval.js';
10
+ // ─── generateFingerprint ──────────────────────────────────────────────────────
11
+ describe('generateFingerprint', () => {
12
+ it('should produce stable fingerprint for same input', () => {
13
+ const fp1 = generateFingerprint('bash', { command: 'ls' });
14
+ const fp2 = generateFingerprint('bash', { command: 'ls' });
15
+ expect(fp1).toBe(fp2);
16
+ });
17
+ it('should be order-independent for object keys', () => {
18
+ const fp1 = generateFingerprint('tool', { a: 1, b: 2 });
19
+ const fp2 = generateFingerprint('tool', { b: 2, a: 1 });
20
+ expect(fp1).toBe(fp2);
21
+ });
22
+ it('should differ for different tool names', () => {
23
+ const fp1 = generateFingerprint('bash', { command: 'ls' });
24
+ const fp2 = generateFingerprint('write_file', { command: 'ls' });
25
+ expect(fp1).not.toBe(fp2);
26
+ });
27
+ it('should handle null/undefined input', () => {
28
+ const fp1 = generateFingerprint('tool', null);
29
+ const fp2 = generateFingerprint('tool', undefined);
30
+ expect(fp1).toBe(fp2);
31
+ });
32
+ });
33
+ // ─── ApprovalManager ──────────────────────────────────────────────────────────
34
+ describe('ApprovalManager', () => {
35
+ let manager;
36
+ beforeEach(() => {
37
+ manager = new ApprovalManager();
38
+ });
39
+ // ── Non-mutating auto-pass ──
40
+ it('should auto-pass non-mutating tools', () => {
41
+ const result = manager.check('read_file', { path: 'x' }, false);
42
+ expect(result.needsApproval).toBe(false);
43
+ });
44
+ it('should default to once policy', () => {
45
+ expect(manager.policy).toBe('once');
46
+ });
47
+ it('should require approval for mutating tools', () => {
48
+ const result = manager.check('write_file', { path: 'x' }, true);
49
+ expect(result.needsApproval).toBe(true);
50
+ if (result.needsApproval) {
51
+ expect(result.toolName).toBe('write_file');
52
+ expect(result.fingerprint).toBeTruthy();
53
+ }
54
+ });
55
+ it('should cache approval under once policy', () => {
56
+ const r1 = manager.check('bash', { command: 'ls' }, true);
57
+ if (r1.needsApproval)
58
+ manager.recordDecision(r1.fingerprint, 'approve');
59
+ const r2 = manager.check('bash', { command: 'ls' }, true);
60
+ expect(r2.needsApproval).toBe(false);
61
+ });
62
+ it('should clear once approvals on clearOnceApprovals', () => {
63
+ const r1 = manager.check('bash', { command: 'ls' }, true);
64
+ if (r1.needsApproval)
65
+ manager.recordDecision(r1.fingerprint, 'approve');
66
+ manager.clearOnceApprovals();
67
+ const r2 = manager.check('bash', { command: 'ls' }, true);
68
+ expect(r2.needsApproval).toBe(true);
69
+ });
70
+ it('should always require approval under always policy', () => {
71
+ manager = new ApprovalManager({ policy: 'always' });
72
+ const r1 = manager.check('bash', { command: 'ls' }, true);
73
+ if (r1.needsApproval)
74
+ manager.recordDecision(r1.fingerprint, 'approve');
75
+ const r2 = manager.check('bash', { command: 'ls' }, true);
76
+ expect(r2.needsApproval).toBe(true);
77
+ });
78
+ it('should persist approval across turns under session policy', () => {
79
+ manager = new ApprovalManager({ policy: 'session' });
80
+ const r1 = manager.check('bash', { cmd: 'ls' }, true);
81
+ if (r1.needsApproval)
82
+ manager.recordDecision(r1.fingerprint, 'approve');
83
+ manager.clearOnceApprovals(); // simulate turn end
84
+ const r2 = manager.check('bash', { cmd: 'ls' }, true);
85
+ expect(r2.needsApproval).toBe(false);
86
+ });
87
+ it('should not cache denied decisions', () => {
88
+ const r1 = manager.check('bash', { command: 'ls' }, true);
89
+ if (r1.needsApproval)
90
+ manager.recordDecision(r1.fingerprint, 'deny');
91
+ const r2 = manager.check('bash', { command: 'ls' }, true);
92
+ expect(r2.needsApproval).toBe(true);
93
+ });
94
+ it('should clear all caches on dispose', () => {
95
+ manager = new ApprovalManager({ policy: 'session' });
96
+ const r1 = manager.check('bash', { cmd: 'ls' }, true);
97
+ if (r1.needsApproval)
98
+ manager.recordDecision(r1.fingerprint, 'approve');
99
+ manager.dispose();
100
+ const r2 = manager.check('bash', { cmd: 'ls' }, true);
101
+ expect(r2.needsApproval).toBe(true);
102
+ });
103
+ it('should clear cache when switching policy', () => {
104
+ const r1 = manager.check('bash', { cmd: 'ls' }, true);
105
+ if (r1.needsApproval)
106
+ manager.recordDecision(r1.fingerprint, 'approve');
107
+ manager.policy = 'always';
108
+ const r2 = manager.check('bash', { cmd: 'ls' }, true);
109
+ expect(r2.needsApproval).toBe(true);
110
+ });
111
+ });
112
+ //# sourceMappingURL=approval.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.test.js","sourceRoot":"","sources":["../../src/tools/approval.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAEpE,iFAAiF;AAEjF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QACxD,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1D,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1D,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACnD,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QACvD,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QACvD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAC9C,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1D,MAAM,GAAG,GAAG,mBAAmB,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAChE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC1C,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC7C,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAClD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA;AAEF,iFAAiF;AAEjF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,IAAI,OAAwB,CAAA;IAE5B,UAAU,CAAC,GAAG,EAAE;QACZ,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,+BAA+B;IAE/B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;QAC/D,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;QAC/D,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YAC1C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,UAAU,EAAE,CAAA;QAC3C,CAAC;IACL,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QAC/C,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QACzD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,OAAO,CAAC,kBAAkB,EAAE,CAAA;QAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC1D,OAAO,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACnD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACjE,OAAO,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;QACpD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,OAAO,CAAC,kBAAkB,EAAE,CAAA,CAAC,oBAAoB;QACjD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QACpE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACzD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC1C,OAAO,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;QACpD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,OAAO,CAAC,OAAO,EAAE,CAAA;QACjB,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAChD,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,IAAI,EAAE,CAAC,aAAa;YAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACvE,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAA;QACzB,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QACrD,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file bash 工具 — 执行 Shell 命令。
3
+ */
4
+ import type { ToolDefinition } from '../types.js';
5
+ export declare const bashTool: ToolDefinition;
6
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKjD,eAAO,MAAM,QAAQ,EAAE,cA2DtB,CAAA"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @file bash 工具 — 执行 Shell 命令。
3
+ */
4
+ import { execSync } from 'node:child_process';
5
+ import { classifyCommand } from './safety.js';
6
+ const DEFAULT_TIMEOUT_MS = 30_000;
7
+ export const bashTool = {
8
+ name: 'bash',
9
+ description: 'Execute a shell command and return its output. ' +
10
+ 'Use this for running scripts, installing packages, ' +
11
+ 'checking system state, etc. ' +
12
+ 'Dangerous commands will be blocked.',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ command: { type: 'string', description: 'The shell command to execute.' },
17
+ timeout_ms: { type: 'number', description: 'Timeout in ms. Defaults to 30000.' },
18
+ },
19
+ required: ['command'],
20
+ },
21
+ isMutating: true,
22
+ async execute(input) {
23
+ const command = String(input.command ?? '');
24
+ if (!command)
25
+ return { output: 'Error: command is required.', isError: true };
26
+ const safety = classifyCommand(command);
27
+ if (safety === 'block') {
28
+ return { output: `Blocked: "${command}" is a dangerous command.`, isError: true };
29
+ }
30
+ if (safety === 'confirm') {
31
+ console.log(` ⚠️ [bash] confirm-level command: ${command}`);
32
+ }
33
+ const timeout = Number(input.timeout_ms) || DEFAULT_TIMEOUT_MS;
34
+ try {
35
+ const result = execSync(command, {
36
+ encoding: 'utf-8',
37
+ timeout,
38
+ maxBuffer: 1024 * 1024,
39
+ stdio: ['pipe', 'pipe', 'pipe'],
40
+ });
41
+ return { output: result || '(no output)' };
42
+ }
43
+ catch (err) {
44
+ const execErr = err;
45
+ const parts = [];
46
+ if (execErr.stdout)
47
+ parts.push(execErr.stdout);
48
+ if (execErr.stderr)
49
+ parts.push(execErr.stderr);
50
+ if (parts.length > 0) {
51
+ const prefix = `Exit code: ${execErr.status ?? 'unknown'}\n`;
52
+ return { output: prefix + parts.join('\n') };
53
+ }
54
+ return { output: `bash failed: ${execErr.message}`, isError: true };
55
+ }
56
+ },
57
+ };
58
+ //# sourceMappingURL=bash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAEjC,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACpC,IAAI,EAAE,MAAM;IACZ,WAAW,EACP,iDAAiD;QACjD,qDAAqD;QACrD,8BAA8B;QAC9B,qCAAqC;IACzC,WAAW,EAAE;QACT,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACR,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE;YACzE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;SACnF;QACD,QAAQ,EAAE,CAAC,SAAS,CAAC;KACxB;IACD,UAAU,EAAE,IAAI;IAEhB,KAAK,CAAC,OAAO,CAAC,KAAK;QACf,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;QAC3C,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,MAAM,EAAE,6BAA6B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAE7E,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,aAAa,OAAO,2BAA2B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACrF,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAA;QAChE,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,kBAAkB,CAAA;QAE9D,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;gBAC7B,QAAQ,EAAE,OAAO;gBACjB,OAAO;gBACP,SAAS,EAAE,IAAI,GAAG,IAAI;gBACtB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAA;YACF,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,aAAa,EAAE,CAAA;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,GAKf,CAAA;YAED,MAAM,KAAK,GAAa,EAAE,CAAA;YAC1B,IAAI,OAAO,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAC9C,IAAI,OAAO,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAE9C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnB,MAAM,MAAM,GAAG,cAAc,OAAO,CAAC,MAAM,IAAI,SAAS,IAAI,CAAA;gBAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;YAChD,CAAC;YAED,OAAO,EAAE,MAAM,EAAE,gBAAgB,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACvE,CAAC;IACL,CAAC;CACJ,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file edit_file 工具 — 文件内容替换。
3
+ */
4
+ import type { ToolDefinition } from '../types.js';
5
+ export declare const editFileTool: ToolDefinition;
6
+ //# sourceMappingURL=edit-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../src/tools/edit-file.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGjD,eAAO,MAAM,YAAY,EAAE,cAqD1B,CAAA"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @file edit_file 工具 — 文件内容替换。
3
+ */
4
+ import * as fs from 'node:fs/promises';
5
+ import * as path from 'node:path';
6
+ import { validatePath } from './safety.js';
7
+ export const editFileTool = {
8
+ name: 'edit_file',
9
+ description: 'Edit a file by replacing old_text with new_text. ' +
10
+ 'The old_text must match exactly (including whitespace).',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ path: { type: 'string', description: 'File path to edit.' },
15
+ old_text: { type: 'string', description: 'Exact text to find and replace.' },
16
+ new_text: { type: 'string', description: 'Replacement text.' },
17
+ },
18
+ required: ['path', 'old_text', 'new_text'],
19
+ },
20
+ isMutating: true,
21
+ async execute(input) {
22
+ const filePath = String(input.path ?? '');
23
+ const oldText = String(input.old_text ?? '');
24
+ const newText = String(input.new_text ?? '');
25
+ if (!filePath)
26
+ return { output: 'Error: path is required.', isError: true };
27
+ if (!oldText)
28
+ return { output: 'Error: old_text is required.', isError: true };
29
+ const validation = validatePath(filePath);
30
+ if (!validation.ok)
31
+ return { output: validation.error, isError: true };
32
+ const resolved = path.resolve(filePath);
33
+ try {
34
+ const original = await fs.readFile(resolved, 'utf-8');
35
+ const idx = original.indexOf(oldText);
36
+ if (idx === -1) {
37
+ return { output: 'Error: old_text not found in file.', isError: true };
38
+ }
39
+ const secondIdx = original.indexOf(oldText, idx + 1);
40
+ if (secondIdx !== -1) {
41
+ return { output: 'Error: old_text matches multiple locations. Please provide more specific text.', isError: true };
42
+ }
43
+ const updated = original.replace(oldText, newText);
44
+ await fs.writeFile(resolved, updated, 'utf-8');
45
+ const oldLines = oldText.split('\n').length;
46
+ const newLines = newText.split('\n').length;
47
+ return { output: `File edited: ${resolved} (replaced ${oldLines} lines with ${newLines} lines)` };
48
+ }
49
+ catch (err) {
50
+ const code = err.code;
51
+ const msg = code === 'ENOENT'
52
+ ? `File not found: ${resolved}`
53
+ : `edit_file failed: ${err.message}`;
54
+ return { output: msg, isError: true };
55
+ }
56
+ },
57
+ };
58
+ //# sourceMappingURL=edit-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file.js","sourceRoot":"","sources":["../../src/tools/edit-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @file get_memory 工具 — 读取项目级记忆(AGENTS.md)。
3
+ *
4
+ * 参考 memo-code 的 get_memory.ts,
5
+ * 让 Agent 能在需要时检索项目的关键指令和上下文。
6
+ */
7
+ import type { ToolDefinition } from '../types.js';
8
+ export declare const getMemoryTool: ToolDefinition;
9
+ //# sourceMappingURL=get-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-memory.d.ts","sourceRoot":"","sources":["../../src/tools/get-memory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAOjD,eAAO,MAAM,aAAa,EAAE,cAmD3B,CAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @file get_memory 工具 — 读取项目级记忆(AGENTS.md)。
3
+ *
4
+ * 参考 memo-code 的 get_memory.ts,
5
+ * 让 Agent 能在需要时检索项目的关键指令和上下文。
6
+ */
7
+ import * as fs from 'node:fs/promises';
8
+ import * as path from 'node:path';
9
+ /** 支持的 memory_id → 文件路径映射。 */
10
+ const MEMORY_FILES = {
11
+ project: 'AGENTS.md',
12
+ };
13
+ export const getMemoryTool = {
14
+ name: 'get_memory',
15
+ description: 'Load stored memory for a given memory_id. ' +
16
+ 'Use memory_id "project" to read the project-level AGENTS.md.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ memory_id: {
21
+ type: 'string',
22
+ description: 'Memory identifier. Currently supports: "project".',
23
+ },
24
+ },
25
+ required: ['memory_id'],
26
+ },
27
+ isMutating: false,
28
+ async execute(input) {
29
+ const memoryId = String(input.memory_id ?? '').trim();
30
+ if (!memoryId) {
31
+ return { output: 'Error: memory_id is required.', isError: true };
32
+ }
33
+ const filename = MEMORY_FILES[memoryId];
34
+ if (!filename) {
35
+ const supported = Object.keys(MEMORY_FILES).join(', ');
36
+ return {
37
+ output: `Error: unknown memory_id "${memoryId}". Supported: ${supported}`,
38
+ isError: true,
39
+ };
40
+ }
41
+ const resolved = path.resolve(filename);
42
+ try {
43
+ const content = await fs.readFile(resolved, 'utf-8');
44
+ return {
45
+ output: JSON.stringify({ memory_id: memoryId, memory_summary: content }, null, 2),
46
+ };
47
+ }
48
+ catch {
49
+ return {
50
+ output: `memory not found for memory_id=${memoryId}`,
51
+ isError: true,
52
+ };
53
+ }
54
+ },
55
+ };
56
+ //# sourceMappingURL=get-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-memory.js","sourceRoot":"","sources":["../../src/tools/get-memory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAGjC,8BAA8B;AAC9B,MAAM,YAAY,GAA2B;IACzC,OAAO,EAAE,WAAW;CACvB,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAmB;IACzC,IAAI,EAAE,YAAY;IAClB,WAAW,EACP,4CAA4C;QAC5C,8DAA8D;IAClE,WAAW,EAAE;QACT,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACR,SAAS,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EACP,mDAAmD;aAC1D;SACJ;QACD,QAAQ,EAAE,CAAC,WAAW,CAAC;KAC1B;IACD,UAAU,EAAE,KAAK;IAEjB,KAAK,CAAC,OAAO,CAAC,KAAK;QACf,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,EAAE,MAAM,EAAE,+BAA+B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACrE,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;QACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtD,OAAO;gBACH,MAAM,EAAE,6BAA6B,QAAQ,iBAAiB,SAAS,EAAE;gBACzE,OAAO,EAAE,IAAI;aAChB,CAAA;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAEvC,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YACpD,OAAO;gBACH,MAAM,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,EAChD,IAAI,EACJ,CAAC,CACJ;aACJ,CAAA;QACL,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,MAAM,EAAE,kCAAkC,QAAQ,EAAE;gBACpD,OAAO,EAAE,IAAI;aAChB,CAAA;QACL,CAAC;IACL,CAAC;CACJ,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file list_directory 工具 — 列出目录内容。
3
+ */
4
+ import type { ToolDefinition } from '../types.js';
5
+ export declare const listDirectoryTool: ToolDefinition;
6
+ //# sourceMappingURL=list-directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-directory.d.ts","sourceRoot":"","sources":["../../src/tools/list-directory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGjD,eAAO,MAAM,iBAAiB,EAAE,cAuD/B,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @file list_directory 工具 — 列出目录内容。
3
+ */
4
+ import * as fs from 'node:fs/promises';
5
+ import * as path from 'node:path';
6
+ import { validatePath } from './safety.js';
7
+ export const listDirectoryTool = {
8
+ name: 'list_directory',
9
+ description: 'List the contents of a directory. ' +
10
+ 'Returns file names, types (file/dir), and sizes.',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ path: { type: 'string', description: 'Directory path to list.' },
15
+ },
16
+ required: ['path'],
17
+ },
18
+ isMutating: false,
19
+ async execute(input) {
20
+ const dirPath = String(input.path ?? '');
21
+ if (!dirPath)
22
+ return { output: 'Error: path is required.', isError: true };
23
+ const validation = validatePath(dirPath);
24
+ if (!validation.ok)
25
+ return { output: validation.error, isError: true };
26
+ const resolved = path.resolve(dirPath);
27
+ try {
28
+ const entries = await fs.readdir(resolved, { withFileTypes: true });
29
+ if (entries.length === 0) {
30
+ return { output: `${resolved}/ (empty directory)` };
31
+ }
32
+ const lines = [];
33
+ for (const entry of entries) {
34
+ const fullPath = path.join(resolved, entry.name);
35
+ if (entry.isDirectory()) {
36
+ lines.push(` [DIR] ${entry.name}/`);
37
+ }
38
+ else {
39
+ try {
40
+ const stat = await fs.stat(fullPath);
41
+ lines.push(` [FILE] ${entry.name} (${formatSize(stat.size)})`);
42
+ }
43
+ catch {
44
+ lines.push(` [FILE] ${entry.name}`);
45
+ }
46
+ }
47
+ }
48
+ return { output: `${resolved}/ (${entries.length} entries)\n${lines.join('\n')}` };
49
+ }
50
+ catch (err) {
51
+ const code = err.code;
52
+ const msg = code === 'ENOENT'
53
+ ? `Directory not found: ${resolved}`
54
+ : code === 'ENOTDIR'
55
+ ? `Not a directory: ${resolved}`
56
+ : `list_directory failed: ${err.message}`;
57
+ return { output: msg, isError: true };
58
+ }
59
+ },
60
+ };
61
+ function formatSize(bytes) {
62
+ if (bytes < 1024)
63
+ return `${bytes} B`;
64
+ if (bytes < 1024 * 1024)
65
+ return `${(bytes / 1024).toFixed(1)} KB`;
66
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
67
+ }
68
+ //# sourceMappingURL=list-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-directory.js","sourceRoot":"","sources":["../../src/tools/list-directory.ts"],"names":[],"mappings":"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"}