@tachu/extensions 1.0.0-beta.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 (152) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +201 -0
  3. package/README.md +825 -0
  4. package/README_ZH.md +815 -0
  5. package/dist/backends/file.d.ts +18 -0
  6. package/dist/backends/file.d.ts.map +1 -0
  7. package/dist/backends/file.js +69 -0
  8. package/dist/backends/file.js.map +1 -0
  9. package/dist/backends/index.d.ts +4 -0
  10. package/dist/backends/index.d.ts.map +1 -0
  11. package/dist/backends/index.js +4 -0
  12. package/dist/backends/index.js.map +1 -0
  13. package/dist/backends/terminal.d.ts +18 -0
  14. package/dist/backends/terminal.d.ts.map +1 -0
  15. package/dist/backends/terminal.js +57 -0
  16. package/dist/backends/terminal.js.map +1 -0
  17. package/dist/backends/web.d.ts +18 -0
  18. package/dist/backends/web.d.ts.map +1 -0
  19. package/dist/backends/web.js +53 -0
  20. package/dist/backends/web.js.map +1 -0
  21. package/dist/common/net.d.ts +31 -0
  22. package/dist/common/net.d.ts.map +1 -0
  23. package/dist/common/net.js +162 -0
  24. package/dist/common/net.js.map +1 -0
  25. package/dist/common/path.d.ts +18 -0
  26. package/dist/common/path.d.ts.map +1 -0
  27. package/dist/common/path.js +34 -0
  28. package/dist/common/path.js.map +1 -0
  29. package/dist/common/process.d.ts +19 -0
  30. package/dist/common/process.d.ts.map +1 -0
  31. package/dist/common/process.js +67 -0
  32. package/dist/common/process.js.map +1 -0
  33. package/dist/index.d.ts +9 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +9 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +3 -0
  38. package/dist/mcp/index.d.ts.map +1 -0
  39. package/dist/mcp/index.js +3 -0
  40. package/dist/mcp/index.js.map +1 -0
  41. package/dist/mcp/sse-adapter.d.ts +70 -0
  42. package/dist/mcp/sse-adapter.d.ts.map +1 -0
  43. package/dist/mcp/sse-adapter.js +176 -0
  44. package/dist/mcp/sse-adapter.js.map +1 -0
  45. package/dist/mcp/stdio-adapter.d.ts +73 -0
  46. package/dist/mcp/stdio-adapter.d.ts.map +1 -0
  47. package/dist/mcp/stdio-adapter.js +178 -0
  48. package/dist/mcp/stdio-adapter.js.map +1 -0
  49. package/dist/observability/index.d.ts +3 -0
  50. package/dist/observability/index.d.ts.map +1 -0
  51. package/dist/observability/index.js +3 -0
  52. package/dist/observability/index.js.map +1 -0
  53. package/dist/observability/jsonl-emitter.d.ts +58 -0
  54. package/dist/observability/jsonl-emitter.d.ts.map +1 -0
  55. package/dist/observability/jsonl-emitter.js +96 -0
  56. package/dist/observability/jsonl-emitter.js.map +1 -0
  57. package/dist/observability/otel-emitter.d.ts +52 -0
  58. package/dist/observability/otel-emitter.d.ts.map +1 -0
  59. package/dist/observability/otel-emitter.js +143 -0
  60. package/dist/observability/otel-emitter.js.map +1 -0
  61. package/dist/providers/anthropic.d.ts +54 -0
  62. package/dist/providers/anthropic.d.ts.map +1 -0
  63. package/dist/providers/anthropic.js +298 -0
  64. package/dist/providers/anthropic.js.map +1 -0
  65. package/dist/providers/index.d.ts +4 -0
  66. package/dist/providers/index.d.ts.map +1 -0
  67. package/dist/providers/index.js +4 -0
  68. package/dist/providers/index.js.map +1 -0
  69. package/dist/providers/mock.d.ts +38 -0
  70. package/dist/providers/mock.d.ts.map +1 -0
  71. package/dist/providers/mock.js +79 -0
  72. package/dist/providers/mock.js.map +1 -0
  73. package/dist/providers/openai.d.ts +61 -0
  74. package/dist/providers/openai.d.ts.map +1 -0
  75. package/dist/providers/openai.js +299 -0
  76. package/dist/providers/openai.js.map +1 -0
  77. package/dist/rules/index.d.ts +9 -0
  78. package/dist/rules/index.d.ts.map +1 -0
  79. package/dist/rules/index.js +15 -0
  80. package/dist/rules/index.js.map +1 -0
  81. package/dist/rules/no-hallucination.md +11 -0
  82. package/dist/rules/no-sensitive-output.md +11 -0
  83. package/dist/rules/prefer-concise-response.md +11 -0
  84. package/dist/rules/require-tool-verification.md +11 -0
  85. package/dist/tools/apply-patch/descriptor.md +27 -0
  86. package/dist/tools/apply-patch/executor.d.ts +19 -0
  87. package/dist/tools/apply-patch/executor.d.ts.map +1 -0
  88. package/dist/tools/apply-patch/executor.js +190 -0
  89. package/dist/tools/apply-patch/executor.js.map +1 -0
  90. package/dist/tools/fetch-url/descriptor.md +38 -0
  91. package/dist/tools/fetch-url/executor.d.ts +20 -0
  92. package/dist/tools/fetch-url/executor.d.ts.map +1 -0
  93. package/dist/tools/fetch-url/executor.js +34 -0
  94. package/dist/tools/fetch-url/executor.js.map +1 -0
  95. package/dist/tools/index.d.ts +12 -0
  96. package/dist/tools/index.d.ts.map +1 -0
  97. package/dist/tools/index.js +191 -0
  98. package/dist/tools/index.js.map +1 -0
  99. package/dist/tools/list-dir/descriptor.md +29 -0
  100. package/dist/tools/list-dir/executor.d.ts +22 -0
  101. package/dist/tools/list-dir/executor.d.ts.map +1 -0
  102. package/dist/tools/list-dir/executor.js +46 -0
  103. package/dist/tools/list-dir/executor.js.map +1 -0
  104. package/dist/tools/read-file/descriptor.md +28 -0
  105. package/dist/tools/read-file/executor.d.ts +15 -0
  106. package/dist/tools/read-file/executor.d.ts.map +1 -0
  107. package/dist/tools/read-file/executor.js +22 -0
  108. package/dist/tools/read-file/executor.js.map +1 -0
  109. package/dist/tools/run-shell/descriptor.md +39 -0
  110. package/dist/tools/run-shell/executor.d.ts +20 -0
  111. package/dist/tools/run-shell/executor.d.ts.map +1 -0
  112. package/dist/tools/run-shell/executor.js +76 -0
  113. package/dist/tools/run-shell/executor.js.map +1 -0
  114. package/dist/tools/search-code/descriptor.md +31 -0
  115. package/dist/tools/search-code/executor.d.ts +23 -0
  116. package/dist/tools/search-code/executor.d.ts.map +1 -0
  117. package/dist/tools/search-code/executor.js +113 -0
  118. package/dist/tools/search-code/executor.js.map +1 -0
  119. package/dist/tools/shared.d.ts +21 -0
  120. package/dist/tools/shared.d.ts.map +1 -0
  121. package/dist/tools/shared.js +12 -0
  122. package/dist/tools/shared.js.map +1 -0
  123. package/dist/tools/write-file/descriptor.md +30 -0
  124. package/dist/tools/write-file/executor.d.ts +16 -0
  125. package/dist/tools/write-file/executor.d.ts.map +1 -0
  126. package/dist/tools/write-file/executor.js +18 -0
  127. package/dist/tools/write-file/executor.js.map +1 -0
  128. package/dist/transformers/document-to-text.d.ts +23 -0
  129. package/dist/transformers/document-to-text.d.ts.map +1 -0
  130. package/dist/transformers/document-to-text.js +69 -0
  131. package/dist/transformers/document-to-text.js.map +1 -0
  132. package/dist/transformers/image-to-text.d.ts +38 -0
  133. package/dist/transformers/image-to-text.d.ts.map +1 -0
  134. package/dist/transformers/image-to-text.js +81 -0
  135. package/dist/transformers/image-to-text.js.map +1 -0
  136. package/dist/transformers/index.d.ts +3 -0
  137. package/dist/transformers/index.d.ts.map +1 -0
  138. package/dist/transformers/index.js +3 -0
  139. package/dist/transformers/index.js.map +1 -0
  140. package/dist/vector/index.d.ts +3 -0
  141. package/dist/vector/index.d.ts.map +1 -0
  142. package/dist/vector/index.js +3 -0
  143. package/dist/vector/index.js.map +1 -0
  144. package/dist/vector/local-fs.d.ts +76 -0
  145. package/dist/vector/local-fs.d.ts.map +1 -0
  146. package/dist/vector/local-fs.js +153 -0
  147. package/dist/vector/local-fs.js.map +1 -0
  148. package/dist/vector/qdrant.d.ts +65 -0
  149. package/dist/vector/qdrant.d.ts.map +1 -0
  150. package/dist/vector/qdrant.js +176 -0
  151. package/dist/vector/qdrant.js.map +1 -0
  152. package/package.json +74 -0
@@ -0,0 +1,28 @@
1
+ ---
2
+ kind: tool
3
+ name: read-file
4
+ description: 读取工作区内的文件内容
5
+ sideEffect: readonly
6
+ idempotent: true
7
+ requiresApproval: false
8
+ timeout: 5000
9
+ inputSchema:
10
+ type: object
11
+ properties:
12
+ path:
13
+ type: string
14
+ encoding:
15
+ type: string
16
+ enum: [utf-8, base64]
17
+ required: [path]
18
+ outputSchema:
19
+ type: object
20
+ properties:
21
+ content:
22
+ type: string
23
+ bytes:
24
+ type: number
25
+ execute: read-file
26
+ ---
27
+
28
+ 读取工作区内文件内容。默认返回 UTF-8 文本,可选返回 base64。
@@ -0,0 +1,15 @@
1
+ import type { ToolExecutor } from "../shared";
2
+ interface ReadFileInput {
3
+ path: string;
4
+ encoding?: "utf-8" | "base64";
5
+ }
6
+ interface ReadFileOutput {
7
+ content: string;
8
+ bytes: number;
9
+ }
10
+ /**
11
+ * 读取文件 Tool 执行器。
12
+ */
13
+ export declare const readFileExecutor: ToolExecutor<ReadFileInput, ReadFileOutput>;
14
+ export {};
15
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/read-file/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAK9C,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,aAAa,EAAE,cAAc,CAoBxE,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { stat, readFile } from "node:fs/promises";
2
+ import { ValidationError } from "@tachu/core";
3
+ import { resolveWorkspacePath } from "../../common/path";
4
+ import { assertNotAborted } from "../shared";
5
+ const MAX_FILE_BYTES = 10 * 1024 * 1024;
6
+ /**
7
+ * 读取文件 Tool 执行器。
8
+ */
9
+ export const readFileExecutor = async (input, context) => {
10
+ assertNotAborted(context.abortSignal);
11
+ const target = resolveWorkspacePath(context.workspaceRoot, input.path);
12
+ const fileStat = await stat(target);
13
+ if (fileStat.size > MAX_FILE_BYTES) {
14
+ throw new ValidationError("VALIDATION_FILE_TOO_LARGE", `文件超过限制: ${fileStat.size} bytes > ${MAX_FILE_BYTES} bytes`, { context: { path: input.path, size: fileStat.size, max: MAX_FILE_BYTES } });
15
+ }
16
+ const bytes = await readFile(target);
17
+ return {
18
+ content: input.encoding === "base64" ? Buffer.from(bytes).toString("base64") : bytes.toString(),
19
+ bytes: bytes.byteLength,
20
+ };
21
+ };
22
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/read-file/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAYxC;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAgD,KAAK,EAChF,KAAK,EACL,OAAO,EACP,EAAE;IACF,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,QAAQ,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,eAAe,CACvB,2BAA2B,EAC3B,WAAW,QAAQ,CAAC,IAAI,YAAY,cAAc,QAAQ,EAC1D,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;QAC/F,KAAK,EAAE,KAAK,CAAC,UAAU;KACxB,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ ---
2
+ kind: tool
3
+ name: run-shell
4
+ description: 在受控环境中执行 shell 命令
5
+ sideEffect: irreversible
6
+ idempotent: false
7
+ requiresApproval: true
8
+ timeout: 30000
9
+ inputSchema:
10
+ type: object
11
+ properties:
12
+ command:
13
+ type: string
14
+ args:
15
+ type: array
16
+ items:
17
+ type: string
18
+ cwd:
19
+ type: string
20
+ env:
21
+ type: object
22
+ timeoutMs:
23
+ type: number
24
+ required: [command]
25
+ outputSchema:
26
+ type: object
27
+ properties:
28
+ stdout:
29
+ type: string
30
+ stderr:
31
+ type: string
32
+ exitCode:
33
+ type: number
34
+ durationMs:
35
+ type: number
36
+ execute: run-shell
37
+ ---
38
+
39
+ 执行 shell 命令并返回 stdout/stderr,默认只继承 PATH/HOME/LANG 环境变量。
@@ -0,0 +1,20 @@
1
+ import type { ToolExecutor } from "../shared";
2
+ interface RunShellInput {
3
+ command: string;
4
+ args?: string[];
5
+ cwd?: string;
6
+ env?: Record<string, string>;
7
+ timeoutMs?: number;
8
+ }
9
+ interface RunShellOutput {
10
+ stdout: string;
11
+ stderr: string;
12
+ exitCode: number;
13
+ durationMs: number;
14
+ }
15
+ /**
16
+ * 执行 shell Tool 执行器。
17
+ */
18
+ export declare const runShellExecutor: ToolExecutor<RunShellInput, RunShellOutput>;
19
+ export {};
20
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/run-shell/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,aAAa,EAAE,cAAc,CA0DxE,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { ValidationError } from "@tachu/core";
2
+ import { resolveWorkspacePath } from "../../common/path";
3
+ import { readStreamWithLimit, terminateProcess } from "../../common/process";
4
+ import { assertNotAborted } from "../shared";
5
+ const DEFAULT_TIMEOUT_MS = 30_000;
6
+ const STREAM_LIMIT_BYTES = 1024 * 1024;
7
+ const DEFAULT_ENV_ALLOWLIST = ["PATH", "HOME", "LANG"];
8
+ const buildSandboxedEnv = (extra) => {
9
+ const env = {};
10
+ for (const key of DEFAULT_ENV_ALLOWLIST) {
11
+ const value = process.env[key];
12
+ if (typeof value === "string") {
13
+ env[key] = value;
14
+ }
15
+ }
16
+ for (const [key, value] of Object.entries(extra ?? {})) {
17
+ env[key] = value;
18
+ }
19
+ return env;
20
+ };
21
+ /**
22
+ * 执行 shell Tool 执行器。
23
+ */
24
+ export const runShellExecutor = async (input, context) => {
25
+ assertNotAborted(context.abortSignal);
26
+ if (!input.command || input.command.trim().length === 0) {
27
+ throw new ValidationError("VALIDATION_EMPTY_COMMAND", "command 不能为空");
28
+ }
29
+ const cwd = input.cwd
30
+ ? resolveWorkspacePath(context.workspaceRoot, input.cwd)
31
+ : context.workspaceRoot;
32
+ const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;
33
+ const startedAt = Date.now();
34
+ const processRef = Bun.spawn({
35
+ cmd: [input.command, ...(input.args ?? [])],
36
+ cwd,
37
+ env: buildSandboxedEnv(input.env),
38
+ stdout: "pipe",
39
+ stderr: "pipe",
40
+ });
41
+ const onAbort = () => {
42
+ if (processRef.pid) {
43
+ void terminateProcess(processRef.pid);
44
+ }
45
+ };
46
+ context.abortSignal.addEventListener("abort", onAbort, { once: true });
47
+ const timeout = setTimeout(() => {
48
+ if (processRef.pid) {
49
+ void terminateProcess(processRef.pid);
50
+ }
51
+ }, timeoutMs);
52
+ try {
53
+ const [stdoutResult, stderrResult, exitCode] = await Promise.all([
54
+ readStreamWithLimit(processRef.stdout, STREAM_LIMIT_BYTES),
55
+ readStreamWithLimit(processRef.stderr, STREAM_LIMIT_BYTES),
56
+ processRef.exited,
57
+ ]);
58
+ const stdout = stdoutResult.truncated
59
+ ? `${stdoutResult.text}\n[truncated:${STREAM_LIMIT_BYTES}]`
60
+ : stdoutResult.text;
61
+ const stderr = stderrResult.truncated
62
+ ? `${stderrResult.text}\n[truncated:${STREAM_LIMIT_BYTES}]`
63
+ : stderrResult.text;
64
+ return {
65
+ stdout,
66
+ stderr,
67
+ exitCode,
68
+ durationMs: Date.now() - startedAt,
69
+ };
70
+ }
71
+ finally {
72
+ clearTimeout(timeout);
73
+ context.abortSignal.removeEventListener("abort", onAbort);
74
+ }
75
+ };
76
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/run-shell/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAiB7C,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAC;AACvC,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAEhE,MAAM,iBAAiB,GAAG,CAAC,KAA8B,EAA0B,EAAE;IACnF,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnB,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAgD,KAAK,EAChF,KAAK,EACL,OAAO,EACP,EAAE;IACF,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,eAAe,CAAC,0BAA0B,EAAE,cAAc,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG;QACnB,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC;QACxD,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC;QAC3B,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC3C,GAAG;QACH,GAAG,EAAE,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC;QACjC,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACnB,KAAK,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACnB,KAAK,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,EAAE,SAAS,CAAC,CAAC;IAEd,IAAI,CAAC;QACH,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC/D,mBAAmB,CAAC,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC;YAC1D,mBAAmB,CAAC,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC;YAC1D,UAAU,CAAC,MAAM;SAClB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS;YACnC,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,gBAAgB,kBAAkB,GAAG;YAC3D,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;QACtB,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS;YACnC,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,gBAAgB,kBAAkB,GAAG;YAC3D,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;QACtB,OAAO;YACL,MAAM;YACN,MAAM;YACN,QAAQ;YACR,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;SACnC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ ---
2
+ kind: tool
3
+ name: search-code
4
+ description: 在工作区内按模式搜索代码
5
+ sideEffect: readonly
6
+ idempotent: true
7
+ requiresApproval: false
8
+ timeout: 10000
9
+ inputSchema:
10
+ type: object
11
+ properties:
12
+ pattern:
13
+ type: string
14
+ path:
15
+ type: string
16
+ fileGlob:
17
+ type: string
18
+ maxResults:
19
+ type: number
20
+ caseSensitive:
21
+ type: boolean
22
+ required: [pattern]
23
+ outputSchema:
24
+ type: object
25
+ properties:
26
+ matches:
27
+ type: array
28
+ execute: search-code
29
+ ---
30
+
31
+ 优先使用 ripgrep 搜索;若系统不存在 rg,则回退到 JS 递归搜索。
@@ -0,0 +1,23 @@
1
+ import type { ToolExecutor } from "../shared";
2
+ interface SearchCodeInput {
3
+ pattern: string;
4
+ path?: string;
5
+ fileGlob?: string;
6
+ maxResults?: number;
7
+ caseSensitive?: boolean;
8
+ }
9
+ interface SearchCodeMatch {
10
+ file: string;
11
+ line: number;
12
+ text: string;
13
+ }
14
+ interface SearchCodeOutput {
15
+ matches: SearchCodeMatch[];
16
+ truncated: boolean;
17
+ }
18
+ /**
19
+ * 搜索代码 Tool 执行器。
20
+ */
21
+ export declare const searchCodeExecutor: ToolExecutor<SearchCodeInput, SearchCodeOutput>;
22
+ export {};
23
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/search-code/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAI9C,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;CACpB;AA0BD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,YAAY,CAAC,eAAe,EAAE,gBAAgB,CAyF9E,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { assertNotAborted } from "../shared";
4
+ import { resolveWorkspacePath, toWorkspaceRelativePath } from "../../common/path";
5
+ const parseRgOutput = (output, maxResults) => {
6
+ const matches = [];
7
+ const lines = output.split("\n").filter((line) => line.length > 0);
8
+ for (const line of lines) {
9
+ const first = line.indexOf(":");
10
+ const second = first >= 0 ? line.indexOf(":", first + 1) : -1;
11
+ if (first <= 0 || second <= first + 1) {
12
+ continue;
13
+ }
14
+ matches.push({
15
+ file: line.slice(0, first),
16
+ line: Number(line.slice(first + 1, second)),
17
+ text: line.slice(second + 1),
18
+ });
19
+ if (matches.length >= maxResults) {
20
+ return { matches, truncated: true };
21
+ }
22
+ }
23
+ return { matches, truncated: false };
24
+ };
25
+ /**
26
+ * 搜索代码 Tool 执行器。
27
+ */
28
+ export const searchCodeExecutor = async (input, context) => {
29
+ assertNotAborted(context.abortSignal);
30
+ const root = resolveWorkspacePath(context.workspaceRoot, input.path ?? ".");
31
+ const maxResults = input.maxResults ?? 100;
32
+ try {
33
+ const args = [
34
+ "--line-number",
35
+ "--no-heading",
36
+ "--color",
37
+ "never",
38
+ input.caseSensitive ? "--case-sensitive" : "--ignore-case",
39
+ "--max-count",
40
+ String(maxResults),
41
+ ];
42
+ if (input.fileGlob) {
43
+ args.push("--glob", input.fileGlob);
44
+ }
45
+ args.push(input.pattern, root);
46
+ const process = Bun.spawn({
47
+ cmd: ["rg", ...args],
48
+ stdout: "pipe",
49
+ stderr: "pipe",
50
+ cwd: root,
51
+ });
52
+ const [stdout, stderr] = await Promise.all([
53
+ new Response(process.stdout).text(),
54
+ new Response(process.stderr).text(),
55
+ ]);
56
+ const code = await process.exited;
57
+ if (code !== 0 && code !== 1) {
58
+ throw new Error(stderr || `rg exited with code ${code}`);
59
+ }
60
+ const parsed = parseRgOutput(stdout, maxResults);
61
+ return {
62
+ matches: parsed.matches.map((item) => ({
63
+ ...item,
64
+ file: toWorkspaceRelativePath(context.workspaceRoot, join(root, item.file)),
65
+ })),
66
+ truncated: parsed.truncated,
67
+ };
68
+ }
69
+ catch {
70
+ const matcher = new RegExp(input.pattern, input.caseSensitive ? "g" : "gi");
71
+ const matches = [];
72
+ let truncated = false;
73
+ const walk = async (dir) => {
74
+ const children = await readdir(dir, { withFileTypes: true });
75
+ for (const child of children) {
76
+ if (matches.length >= maxResults) {
77
+ truncated = true;
78
+ return;
79
+ }
80
+ const target = join(dir, child.name);
81
+ if (child.isDirectory()) {
82
+ await walk(target);
83
+ continue;
84
+ }
85
+ if (!child.isFile()) {
86
+ continue;
87
+ }
88
+ if (input.fileGlob && !target.endsWith(input.fileGlob.replace("*", ""))) {
89
+ continue;
90
+ }
91
+ const content = await readFile(target, "utf8").catch(() => "");
92
+ const lines = content.split("\n");
93
+ lines.forEach((line, index) => {
94
+ if (matches.length >= maxResults) {
95
+ truncated = true;
96
+ return;
97
+ }
98
+ if (matcher.test(line)) {
99
+ matches.push({
100
+ file: toWorkspaceRelativePath(context.workspaceRoot, target),
101
+ line: index + 1,
102
+ text: line,
103
+ });
104
+ }
105
+ matcher.lastIndex = 0;
106
+ });
107
+ }
108
+ };
109
+ await walk(root);
110
+ return { matches, truncated };
111
+ }
112
+ };
113
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/search-code/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Session } from "@tachu/core";
2
+ /**
3
+ * Tool 执行时上下文。
4
+ */
5
+ export interface ToolExecutionContext {
6
+ abortSignal: AbortSignal;
7
+ workspaceRoot: string;
8
+ session: Session;
9
+ }
10
+ /**
11
+ * Tool 执行器签名。
12
+ */
13
+ export type ToolExecutor<TInput = unknown, TOutput = unknown> = (input: TInput, context: ToolExecutionContext) => Promise<TOutput>;
14
+ /**
15
+ * 检查中断状态。
16
+ *
17
+ * @param signal 取消信号
18
+ * @throws Error 当已中断
19
+ */
20
+ export declare const assertNotAborted: (signal: AbortSignal) => void;
21
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CAC9D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,WAAW,KAAG,IAItD,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 检查中断状态。
3
+ *
4
+ * @param signal 取消信号
5
+ * @throws Error 当已中断
6
+ */
7
+ export const assertNotAborted = (signal) => {
8
+ if (signal.aborted) {
9
+ throw signal.reason ?? new Error("aborted");
10
+ }
11
+ };
12
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAmBA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAmB,EAAQ,EAAE;IAC5D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,30 @@
1
+ ---
2
+ kind: tool
3
+ name: write-file
4
+ description: 写入工作区内文件内容
5
+ sideEffect: write
6
+ idempotent: false
7
+ requiresApproval: true
8
+ timeout: 5000
9
+ inputSchema:
10
+ type: object
11
+ properties:
12
+ path:
13
+ type: string
14
+ content:
15
+ type: string
16
+ encoding:
17
+ type: string
18
+ enum: [utf-8, base64]
19
+ createDirs:
20
+ type: boolean
21
+ required: [path, content]
22
+ outputSchema:
23
+ type: object
24
+ properties:
25
+ bytesWritten:
26
+ type: number
27
+ execute: write-file
28
+ ---
29
+
30
+ 向工作区写入文件,支持 UTF-8 与 base64 输入。
@@ -0,0 +1,16 @@
1
+ import type { ToolExecutor } from "../shared";
2
+ interface WriteFileInput {
3
+ path: string;
4
+ content: string;
5
+ encoding?: "utf-8" | "base64";
6
+ createDirs?: boolean;
7
+ }
8
+ interface WriteFileOutput {
9
+ bytesWritten: number;
10
+ }
11
+ /**
12
+ * 写入文件 Tool 执行器。
13
+ */
14
+ export declare const writeFileExecutor: ToolExecutor<WriteFileInput, WriteFileOutput>;
15
+ export {};
16
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/write-file/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,eAAe;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAAC,cAAc,EAAE,eAAe,CAa3E,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { resolveWorkspacePath } from "../../common/path";
4
+ import { assertNotAborted } from "../shared";
5
+ /**
6
+ * 写入文件 Tool 执行器。
7
+ */
8
+ export const writeFileExecutor = async (input, context) => {
9
+ assertNotAborted(context.abortSignal);
10
+ const target = resolveWorkspacePath(context.workspaceRoot, input.path);
11
+ if (input.createDirs) {
12
+ await mkdir(dirname(target), { recursive: true });
13
+ }
14
+ const payload = input.encoding === "base64" ? Buffer.from(input.content, "base64") : Buffer.from(input.content);
15
+ await writeFile(target, payload);
16
+ return { bytesWritten: payload.byteLength };
17
+ };
18
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/write-file/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAa7C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAkD,KAAK,EACnF,KAAK,EACL,OAAO,EACP,EAAE;IACF,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,OAAO,GACX,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClG,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;AAC9C,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { InputEnvelope, InputMetadata, InputTransformer, ModelCapabilities } from "@tachu/core";
2
+ /**
3
+ * 文档转文本转换器(PDF / DOCX)。
4
+ */
5
+ export declare class DocumentToTextTransformer implements InputTransformer {
6
+ readonly modality = "document";
7
+ /**
8
+ * 判断是否需要文档降级。
9
+ *
10
+ * @param metadata 输入元信息
11
+ * @param modelCapabilities 模型能力
12
+ * @returns true 表示需要转换
13
+ */
14
+ canHandle(metadata: InputMetadata, modelCapabilities: ModelCapabilities): boolean;
15
+ /**
16
+ * 将文档转换为文本信封。
17
+ *
18
+ * @param envelope 输入信封
19
+ * @returns 文本信封
20
+ */
21
+ transform(envelope: InputEnvelope): Promise<InputEnvelope>;
22
+ }
23
+ //# sourceMappingURL=document-to-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-to-text.d.ts","sourceRoot":"","sources":["../../src/transformers/document-to-text.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAkBrG;;GAEG;AACH,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,QAAQ,CAAC,QAAQ,cAAc;IAE/B;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO;IAMjF;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAkCjE"}
@@ -0,0 +1,69 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { PDFParse } from "pdf-parse";
3
+ import mammoth from "mammoth";
4
+ import { ValidationError } from "@tachu/core";
5
+ const MAX_TEXT_CHARS = 500_000;
6
+ const truncateIfNeeded = (text) => {
7
+ if (text.length <= MAX_TEXT_CHARS) {
8
+ return text;
9
+ }
10
+ const trimmed = text.slice(0, MAX_TEXT_CHARS);
11
+ return `${trimmed}\n\n[TRUNCATED:${text.length - MAX_TEXT_CHARS}]`;
12
+ };
13
+ /**
14
+ * 文档转文本转换器(PDF / DOCX)。
15
+ */
16
+ export class DocumentToTextTransformer {
17
+ modality = "document";
18
+ /**
19
+ * 判断是否需要文档降级。
20
+ *
21
+ * @param metadata 输入元信息
22
+ * @param modelCapabilities 模型能力
23
+ * @returns true 表示需要转换
24
+ */
25
+ canHandle(metadata, modelCapabilities) {
26
+ const modality = metadata.modality ?? "";
27
+ const isDocument = modality === "document" || modality === "file";
28
+ return isDocument && !modelCapabilities.supportedModalities.includes("file");
29
+ }
30
+ /**
31
+ * 将文档转换为文本信封。
32
+ *
33
+ * @param envelope 输入信封
34
+ * @returns 文本信封
35
+ */
36
+ async transform(envelope) {
37
+ const content = envelope.content;
38
+ if (!content.path) {
39
+ throw new ValidationError("VALIDATION_DOCUMENT_PATH", "文档输入缺少 path");
40
+ }
41
+ const mimeType = content.mimeType ?? envelope.metadata.mimeType ?? "";
42
+ let text = "";
43
+ if (mimeType.includes("pdf") || content.path.toLowerCase().endsWith(".pdf")) {
44
+ const buffer = await readFile(content.path);
45
+ const parser = new PDFParse({ data: buffer });
46
+ const parsed = await parser.getText();
47
+ text = parsed.text;
48
+ await parser.destroy();
49
+ }
50
+ else if (mimeType.includes("word") ||
51
+ mimeType.includes("officedocument") ||
52
+ content.path.toLowerCase().endsWith(".docx")) {
53
+ const result = await mammoth.extractRawText({ path: content.path });
54
+ text = result.value;
55
+ }
56
+ else {
57
+ text = await readFile(content.path, "utf8");
58
+ }
59
+ return {
60
+ content: truncateIfNeeded(text),
61
+ metadata: {
62
+ ...envelope.metadata,
63
+ modality: "text",
64
+ mimeType: "text/plain",
65
+ },
66
+ };
67
+ }
68
+ }
69
+ //# sourceMappingURL=document-to-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-to-text.js","sourceRoot":"","sources":["../../src/transformers/document-to-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE;IAChD,IAAI,IAAI,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IAC9C,OAAO,GAAG,OAAO,kBAAkB,IAAI,CAAC,MAAM,GAAG,cAAc,GAAG,CAAC;AACrE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,yBAAyB;IAC3B,QAAQ,GAAG,UAAU,CAAC;IAE/B;;;;;;OAMG;IACH,SAAS,CAAC,QAAuB,EAAE,iBAAoC;QACrE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,MAAM,CAAC;QAClE,OAAO,UAAU,IAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,QAAuB;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAA0B,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,eAAe,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QAEtE,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5E,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACnB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;aAAM,IACL,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YACzB,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC5C,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACpE,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QAED,OAAO;YACL,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC;YAC/B,QAAQ,EAAE;gBACR,GAAG,QAAQ,CAAC,QAAQ;gBACpB,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,YAAY;aACvB;SACF,CAAC;IACJ,CAAC;CACF"}