iosm-cli 0.2.7 → 0.2.9

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 (149) hide show
  1. package/CHANGELOG.md +61 -1
  2. package/README.md +4 -4
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +12 -4
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-profiles.d.ts.map +1 -1
  7. package/dist/core/agent-profiles.js +15 -2
  8. package/dist/core/agent-profiles.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +3 -0
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +214 -2
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/sdk.d.ts +2 -2
  14. package/dist/core/sdk.d.ts.map +1 -1
  15. package/dist/core/sdk.js +7 -4
  16. package/dist/core/sdk.js.map +1 -1
  17. package/dist/core/settings-manager.d.ts +57 -0
  18. package/dist/core/settings-manager.d.ts.map +1 -1
  19. package/dist/core/settings-manager.js +197 -0
  20. package/dist/core/settings-manager.js.map +1 -1
  21. package/dist/core/shadow-guard.d.ts.map +1 -1
  22. package/dist/core/shadow-guard.js +12 -1
  23. package/dist/core/shadow-guard.js.map +1 -1
  24. package/dist/core/system-prompt.d.ts.map +1 -1
  25. package/dist/core/system-prompt.js +109 -4
  26. package/dist/core/system-prompt.js.map +1 -1
  27. package/dist/core/tools/db-run.d.ts +84 -0
  28. package/dist/core/tools/db-run.d.ts.map +1 -0
  29. package/dist/core/tools/db-run.js +690 -0
  30. package/dist/core/tools/db-run.js.map +1 -0
  31. package/dist/core/tools/git-common.d.ts +45 -0
  32. package/dist/core/tools/git-common.d.ts.map +1 -0
  33. package/dist/core/tools/git-common.js +185 -0
  34. package/dist/core/tools/git-common.js.map +1 -0
  35. package/dist/core/tools/git-read.d.ts +15 -13
  36. package/dist/core/tools/git-read.d.ts.map +1 -1
  37. package/dist/core/tools/git-read.js +101 -153
  38. package/dist/core/tools/git-read.js.map +1 -1
  39. package/dist/core/tools/git-write.d.ts +75 -0
  40. package/dist/core/tools/git-write.d.ts.map +1 -0
  41. package/dist/core/tools/git-write.js +298 -0
  42. package/dist/core/tools/git-write.js.map +1 -0
  43. package/dist/core/tools/index.d.ts +91 -1
  44. package/dist/core/tools/index.d.ts.map +1 -1
  45. package/dist/core/tools/index.js +26 -0
  46. package/dist/core/tools/index.js.map +1 -1
  47. package/dist/core/tools/lint-run.d.ts +42 -0
  48. package/dist/core/tools/lint-run.d.ts.map +1 -0
  49. package/dist/core/tools/lint-run.js +276 -0
  50. package/dist/core/tools/lint-run.js.map +1 -0
  51. package/dist/core/tools/task.js +1 -1
  52. package/dist/core/tools/task.js.map +1 -1
  53. package/dist/core/tools/test-run.d.ts +36 -0
  54. package/dist/core/tools/test-run.d.ts.map +1 -0
  55. package/dist/core/tools/test-run.js +255 -0
  56. package/dist/core/tools/test-run.js.map +1 -0
  57. package/dist/core/tools/typecheck-run.d.ts +44 -0
  58. package/dist/core/tools/typecheck-run.d.ts.map +1 -0
  59. package/dist/core/tools/typecheck-run.js +343 -0
  60. package/dist/core/tools/typecheck-run.js.map +1 -0
  61. package/dist/core/tools/verification-runner.d.ts +53 -0
  62. package/dist/core/tools/verification-runner.d.ts.map +1 -0
  63. package/dist/core/tools/verification-runner.js +235 -0
  64. package/dist/core/tools/verification-runner.js.map +1 -0
  65. package/dist/core/tools/web-search.d.ts +72 -0
  66. package/dist/core/tools/web-search.d.ts.map +1 -0
  67. package/dist/core/tools/web-search.js +702 -0
  68. package/dist/core/tools/web-search.js.map +1 -0
  69. package/dist/index.d.ts +2 -2
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +1 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  74. package/dist/modes/interactive/components/branch-summary-message.js +2 -1
  75. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  76. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  77. package/dist/modes/interactive/components/compaction-summary-message.js +2 -1
  78. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  79. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  80. package/dist/modes/interactive/components/config-selector.js +7 -2
  81. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  82. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  83. package/dist/modes/interactive/components/custom-message.js +2 -1
  84. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  85. package/dist/modes/interactive/components/mcp-selector.d.ts.map +1 -1
  86. package/dist/modes/interactive/components/mcp-selector.js +3 -1
  87. package/dist/modes/interactive/components/mcp-selector.js.map +1 -1
  88. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  89. package/dist/modes/interactive/components/model-selector.js +12 -2
  90. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  91. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  92. package/dist/modes/interactive/components/oauth-selector.js +11 -0
  93. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  94. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  95. package/dist/modes/interactive/components/scoped-models-selector.js +16 -5
  96. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  97. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  98. package/dist/modes/interactive/components/session-selector.js +4 -2
  99. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  100. package/dist/modes/interactive/components/settings-selector.d.ts +25 -0
  101. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  102. package/dist/modes/interactive/components/settings-selector.js +182 -2
  103. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  104. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  105. package/dist/modes/interactive/components/show-images-selector.js +7 -2
  106. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  107. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  108. package/dist/modes/interactive/components/skill-invocation-message.js +4 -2
  109. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  110. package/dist/modes/interactive/components/subagent-message.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/subagent-message.js +3 -1
  112. package/dist/modes/interactive/components/subagent-message.js.map +1 -1
  113. package/dist/modes/interactive/components/task-plan-message.d.ts.map +1 -1
  114. package/dist/modes/interactive/components/task-plan-message.js +2 -1
  115. package/dist/modes/interactive/components/task-plan-message.js.map +1 -1
  116. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  117. package/dist/modes/interactive/components/theme-selector.js +7 -2
  118. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  119. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  120. package/dist/modes/interactive/components/thinking-selector.js +7 -2
  121. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  122. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  123. package/dist/modes/interactive/components/tool-execution.js +25 -7
  124. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  125. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/tree-selector.js +18 -3
  127. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  128. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/user-message-selector.js +8 -0
  130. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  131. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  132. package/dist/modes/interactive/components/user-message.js +2 -1
  133. package/dist/modes/interactive/components/user-message.js.map +1 -1
  134. package/dist/modes/interactive/interactive-mode.d.ts +8 -0
  135. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  136. package/dist/modes/interactive/interactive-mode.js +622 -11
  137. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  138. package/dist/modes/interactive/theme/dark.json +39 -38
  139. package/dist/modes/interactive/theme/light.json +29 -29
  140. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  141. package/dist/modes/interactive/theme/theme.js +16 -25
  142. package/dist/modes/interactive/theme/theme.js.map +1 -1
  143. package/dist/modes/interactive/theme/universal.json +85 -0
  144. package/docs/cli-reference.md +32 -2
  145. package/docs/configuration.md +86 -2
  146. package/docs/development-and-testing.md +1 -1
  147. package/docs/interactive-mode.md +8 -3
  148. package/docs/rpc-json-sdk.md +1 -1
  149. package/package.json +1 -1
@@ -0,0 +1,36 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import { type Static } from "@sinclair/typebox";
3
+ import type { TruncationResult } from "./truncate.js";
4
+ declare const testRunSchema: import("@sinclair/typebox").TObject<{
5
+ runner: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"npm">, import("@sinclair/typebox").TLiteral<"pnpm">, import("@sinclair/typebox").TLiteral<"yarn">, import("@sinclair/typebox").TLiteral<"bun">, import("@sinclair/typebox").TLiteral<"vitest">, import("@sinclair/typebox").TLiteral<"jest">, import("@sinclair/typebox").TLiteral<"pytest">]>>;
6
+ script: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
8
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
10
+ }>;
11
+ export type TestRunToolInput = Static<typeof testRunSchema>;
12
+ export type TestRunRunner = "auto" | "npm" | "pnpm" | "yarn" | "bun" | "vitest" | "jest" | "pytest";
13
+ export type TestRunStatus = "passed" | "failed" | "no_tests" | "error";
14
+ type ResolvedTestRunner = Exclude<TestRunRunner, "auto">;
15
+ export interface TestRunToolDetails {
16
+ resolvedRunner: ResolvedTestRunner;
17
+ resolvedCommand: string;
18
+ resolvedArgs: string[];
19
+ cwd: string;
20
+ exitCode: number;
21
+ status: TestRunStatus;
22
+ durationMs: number;
23
+ captureTruncated?: boolean;
24
+ truncation?: TruncationResult;
25
+ }
26
+ export declare const DEFAULT_TEST_RUN_TIMEOUT_SECONDS = 900;
27
+ export declare function createTestRunTool(cwd: string): AgentTool<typeof testRunSchema>;
28
+ export declare const testRunTool: AgentTool<import("@sinclair/typebox").TObject<{
29
+ runner: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"npm">, import("@sinclair/typebox").TLiteral<"pnpm">, import("@sinclair/typebox").TLiteral<"yarn">, import("@sinclair/typebox").TLiteral<"bun">, import("@sinclair/typebox").TLiteral<"vitest">, import("@sinclair/typebox").TLiteral<"jest">, import("@sinclair/typebox").TLiteral<"pytest">]>>;
30
+ script: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
31
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
32
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
33
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
34
+ }>, any>;
35
+ export {};
36
+ //# sourceMappingURL=test-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../../src/core/tools/test-run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAatD,QAAA,MAAM,aAAa;;;;;;EA8BjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAC5D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AACpG,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAEvE,KAAK,kBAAkB,GAAG,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AAQzD,MAAM,WAAW,kBAAkB;IAClC,cAAc,EAAE,kBAAkB,CAAC;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAiMpD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CA6E9E;AAED,eAAO,MAAM,WAAW;;;;;;QAAmC,CAAC"}
@@ -0,0 +1,255 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Type } from "@sinclair/typebox";
4
+ import { resolveToCwd } from "./path-utils.js";
5
+ import { commandExists, detectPackageManager, ensureCommandOrThrow, formatVerificationOutput, readPackageJson, resolvePackageManagerExecInvocation, resolvePackageManagerRunInvocation, runVerificationCommand, } from "./verification-runner.js";
6
+ const testRunSchema = Type.Object({
7
+ runner: Type.Optional(Type.Union([
8
+ Type.Literal("auto"),
9
+ Type.Literal("npm"),
10
+ Type.Literal("pnpm"),
11
+ Type.Literal("yarn"),
12
+ Type.Literal("bun"),
13
+ Type.Literal("vitest"),
14
+ Type.Literal("jest"),
15
+ Type.Literal("pytest"),
16
+ ], {
17
+ description: "Test runner: auto | npm | pnpm | yarn | bun | vitest | jest | pytest",
18
+ })),
19
+ script: Type.Optional(Type.String({
20
+ description: "Package script for npm/pnpm/yarn/bun runners (default: test).",
21
+ })),
22
+ args: Type.Optional(Type.Array(Type.String(), {
23
+ description: "Additional arguments forwarded to the selected runner.",
24
+ })),
25
+ path: Type.Optional(Type.String({ description: "Working directory for running tests (default: current directory)." })),
26
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 900)." })),
27
+ });
28
+ export const DEFAULT_TEST_RUN_TIMEOUT_SECONDS = 900;
29
+ function normalizeTimeoutSeconds(raw) {
30
+ if (raw === undefined)
31
+ return DEFAULT_TEST_RUN_TIMEOUT_SECONDS;
32
+ const value = Math.floor(raw);
33
+ if (!Number.isFinite(value) || value <= 0) {
34
+ throw new Error("timeout must be a positive number.");
35
+ }
36
+ return value;
37
+ }
38
+ function normalizeStringArray(raw) {
39
+ return (raw ?? []).map((item) => String(item));
40
+ }
41
+ function normalizeScriptName(raw, fallback) {
42
+ const script = (raw ?? fallback).trim();
43
+ if (script.length === 0) {
44
+ throw new Error("script must not be empty.");
45
+ }
46
+ return script;
47
+ }
48
+ function hasAnyFile(cwd, fileNames) {
49
+ return fileNames.some((name) => existsSync(join(cwd, name)));
50
+ }
51
+ function hasVitestConfig(cwd) {
52
+ return hasAnyFile(cwd, [
53
+ "vitest.config.ts",
54
+ "vitest.config.js",
55
+ "vitest.config.mjs",
56
+ "vitest.config.cjs",
57
+ "vitest.config.mts",
58
+ "vitest.config.cts",
59
+ ]);
60
+ }
61
+ function hasJestConfig(cwd, packageJsonJest) {
62
+ if (packageJsonJest && typeof packageJsonJest === "object") {
63
+ return true;
64
+ }
65
+ return hasAnyFile(cwd, [
66
+ "jest.config.ts",
67
+ "jest.config.js",
68
+ "jest.config.mjs",
69
+ "jest.config.cjs",
70
+ "jest.config.json",
71
+ "jest.config.mts",
72
+ "jest.config.cts",
73
+ ]);
74
+ }
75
+ function hasPythonMarkers(cwd) {
76
+ return hasAnyFile(cwd, [
77
+ "pyproject.toml",
78
+ "pytest.ini",
79
+ "tox.ini",
80
+ "setup.cfg",
81
+ "requirements.txt",
82
+ "requirements-dev.txt",
83
+ ]);
84
+ }
85
+ function assertPackageManagerAvailable(packageManager) {
86
+ if (packageManager === "bun") {
87
+ ensureCommandOrThrow("bun", 'Command "bun" is required for bun-based test execution.');
88
+ return;
89
+ }
90
+ ensureCommandOrThrow(packageManager, `Command "${packageManager}" is required for test execution.`);
91
+ }
92
+ function resolveScriptBasedCommand(packageManager, script, args) {
93
+ assertPackageManagerAvailable(packageManager);
94
+ const invocation = resolvePackageManagerRunInvocation(packageManager, script, args);
95
+ return {
96
+ resolvedRunner: packageManager,
97
+ command: invocation.command,
98
+ args: invocation.args,
99
+ };
100
+ }
101
+ function resolveFrameworkCommand(packageManager, runner, args) {
102
+ assertPackageManagerAvailable(packageManager);
103
+ const invocation = resolvePackageManagerExecInvocation(packageManager, runner, args);
104
+ ensureCommandOrThrow(invocation.command, `Command "${invocation.command}" is required to run ${runner}. Install ${packageManager} tooling first.`);
105
+ return {
106
+ resolvedRunner: runner,
107
+ command: invocation.command,
108
+ args: invocation.args,
109
+ };
110
+ }
111
+ function resolvePytestCommand(args) {
112
+ if (commandExists("python3")) {
113
+ return {
114
+ resolvedRunner: "pytest",
115
+ command: "python3",
116
+ args: ["-m", "pytest", ...args],
117
+ };
118
+ }
119
+ if (commandExists("pytest")) {
120
+ return {
121
+ resolvedRunner: "pytest",
122
+ command: "pytest",
123
+ args,
124
+ };
125
+ }
126
+ throw new Error('No pytest runtime found. Install python3 + pytest or expose "pytest" in PATH.');
127
+ }
128
+ function resolveAutoRunner(cwd, script) {
129
+ const packageJson = readPackageJson(cwd);
130
+ if (packageJson?.scripts[script]) {
131
+ return detectPackageManager(cwd);
132
+ }
133
+ if (hasVitestConfig(cwd))
134
+ return "vitest";
135
+ if (hasJestConfig(cwd, packageJson?.raw?.jest))
136
+ return "jest";
137
+ if (hasPythonMarkers(cwd))
138
+ return "pytest";
139
+ throw new Error('Unable to auto-detect test runner. Expected package.json script, vitest/jest config, or python pytest markers.');
140
+ }
141
+ function resolveTestCommand(input) {
142
+ const packageJson = readPackageJson(input.cwd);
143
+ const detectedPackageManager = detectPackageManager(input.cwd);
144
+ let resolvedRunner;
145
+ if (input.runner === "auto") {
146
+ resolvedRunner = resolveAutoRunner(input.cwd, input.script);
147
+ }
148
+ else {
149
+ resolvedRunner = input.runner;
150
+ }
151
+ if (resolvedRunner === "npm" || resolvedRunner === "pnpm" || resolvedRunner === "yarn" || resolvedRunner === "bun") {
152
+ if (!packageJson) {
153
+ throw new Error(`package.json is required to run ${resolvedRunner} scripts.`);
154
+ }
155
+ if (!packageJson.scripts[input.script]) {
156
+ throw new Error(`Script "${input.script}" is not defined in package.json.`);
157
+ }
158
+ return resolveScriptBasedCommand(resolvedRunner, input.script, input.args);
159
+ }
160
+ if (resolvedRunner === "vitest" || resolvedRunner === "jest") {
161
+ return resolveFrameworkCommand(detectedPackageManager, resolvedRunner, input.args);
162
+ }
163
+ return resolvePytestCommand(input.args);
164
+ }
165
+ function mapTestStatus(resolvedRunner, exitCode) {
166
+ if (exitCode === 0)
167
+ return "passed";
168
+ if (resolvedRunner === "pytest" && exitCode === 5)
169
+ return "no_tests";
170
+ if (exitCode === 1)
171
+ return "failed";
172
+ return "error";
173
+ }
174
+ function indicatesPytestModuleMissing(output) {
175
+ return /No module named pytest|ModuleNotFoundError:\s*No module named ['"]pytest['"]/i.test(output);
176
+ }
177
+ function renderSummary(details, output) {
178
+ const argsText = details.resolvedArgs.length > 0 ? ` ${details.resolvedArgs.join(" ")}` : "";
179
+ return [
180
+ `test_run status: ${details.status}`,
181
+ `runner: ${details.resolvedRunner}`,
182
+ `command: ${details.resolvedCommand}${argsText}`,
183
+ `cwd: ${details.cwd}`,
184
+ `exit_code: ${details.exitCode}`,
185
+ `duration_ms: ${details.durationMs}`,
186
+ "",
187
+ output,
188
+ ].join("\n");
189
+ }
190
+ export function createTestRunTool(cwd) {
191
+ return {
192
+ name: "test_run",
193
+ label: "test_run",
194
+ description: "Structured test runner with auto detection across npm/pnpm/yarn/bun, vitest, jest, and pytest. Returns normalized status without throwing on ordinary test failures.",
195
+ parameters: testRunSchema,
196
+ execute: async (_toolCallId, input, signal) => {
197
+ const executionCwd = resolveToCwd(input.path || ".", cwd);
198
+ const timeoutSeconds = normalizeTimeoutSeconds(input.timeout);
199
+ const normalizedArgs = normalizeStringArray(input.args);
200
+ const script = normalizeScriptName(input.script, "test");
201
+ const runner = input.runner ?? "auto";
202
+ let command = resolveTestCommand({
203
+ cwd: executionCwd,
204
+ runner,
205
+ script,
206
+ args: normalizedArgs,
207
+ });
208
+ let result = await runVerificationCommand({
209
+ command: command.command,
210
+ args: command.args,
211
+ cwd: executionCwd,
212
+ timeoutMs: timeoutSeconds * 1000,
213
+ signal,
214
+ });
215
+ // python3 -m pytest fallback to bare pytest when pytest module is unavailable
216
+ if (command.resolvedRunner === "pytest" &&
217
+ command.command === "python3" &&
218
+ result.exitCode !== 0 &&
219
+ indicatesPytestModuleMissing(`${result.stdout}\n${result.stderr}`) &&
220
+ commandExists("pytest")) {
221
+ const fallback = await runVerificationCommand({
222
+ command: "pytest",
223
+ args: normalizedArgs,
224
+ cwd: executionCwd,
225
+ timeoutMs: timeoutSeconds * 1000,
226
+ signal,
227
+ });
228
+ command = { resolvedRunner: "pytest", command: "pytest", args: normalizedArgs };
229
+ result = {
230
+ ...fallback,
231
+ durationMs: result.durationMs + fallback.durationMs,
232
+ };
233
+ }
234
+ const status = mapTestStatus(command.resolvedRunner, result.exitCode);
235
+ const formatted = formatVerificationOutput(result.stdout, result.stderr, result.captureTruncated, "No test output");
236
+ const details = {
237
+ resolvedRunner: command.resolvedRunner,
238
+ resolvedCommand: command.command,
239
+ resolvedArgs: command.args,
240
+ cwd: executionCwd,
241
+ exitCode: result.exitCode,
242
+ status,
243
+ durationMs: result.durationMs,
244
+ captureTruncated: result.captureTruncated || undefined,
245
+ truncation: formatted.truncation,
246
+ };
247
+ return {
248
+ content: [{ type: "text", text: renderSummary(details, formatted.text) }],
249
+ details,
250
+ };
251
+ },
252
+ };
253
+ }
254
+ export const testRunTool = createTestRunTool(process.cwd());
255
+ //# sourceMappingURL=test-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run.js","sourceRoot":"","sources":["../../../src/core/tools/test-run.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport type { TruncationResult } from \"./truncate.js\";\nimport {\n\ttype PackageManager,\n\tcommandExists,\n\tdetectPackageManager,\n\tensureCommandOrThrow,\n\tformatVerificationOutput,\n\treadPackageJson,\n\tresolvePackageManagerExecInvocation,\n\tresolvePackageManagerRunInvocation,\n\trunVerificationCommand,\n} from \"./verification-runner.js\";\n\nconst testRunSchema = Type.Object({\n\trunner: Type.Optional(\n\t\tType.Union(\n\t\t\t[\n\t\t\t\tType.Literal(\"auto\"),\n\t\t\t\tType.Literal(\"npm\"),\n\t\t\t\tType.Literal(\"pnpm\"),\n\t\t\t\tType.Literal(\"yarn\"),\n\t\t\t\tType.Literal(\"bun\"),\n\t\t\t\tType.Literal(\"vitest\"),\n\t\t\t\tType.Literal(\"jest\"),\n\t\t\t\tType.Literal(\"pytest\"),\n\t\t\t],\n\t\t\t{\n\t\t\t\tdescription: \"Test runner: auto | npm | pnpm | yarn | bun | vitest | jest | pytest\",\n\t\t\t},\n\t\t),\n\t),\n\tscript: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Package script for npm/pnpm/yarn/bun runners (default: test).\",\n\t\t}),\n\t),\n\targs: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Additional arguments forwarded to the selected runner.\",\n\t\t}),\n\t),\n\tpath: Type.Optional(Type.String({ description: \"Working directory for running tests (default: current directory).\" })),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (default: 900).\" })),\n});\n\nexport type TestRunToolInput = Static<typeof testRunSchema>;\nexport type TestRunRunner = \"auto\" | \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"vitest\" | \"jest\" | \"pytest\";\nexport type TestRunStatus = \"passed\" | \"failed\" | \"no_tests\" | \"error\";\n\ntype ResolvedTestRunner = Exclude<TestRunRunner, \"auto\">;\n\ninterface ResolvedTestCommand {\n\tresolvedRunner: ResolvedTestRunner;\n\tcommand: string;\n\targs: string[];\n}\n\nexport interface TestRunToolDetails {\n\tresolvedRunner: ResolvedTestRunner;\n\tresolvedCommand: string;\n\tresolvedArgs: string[];\n\tcwd: string;\n\texitCode: number;\n\tstatus: TestRunStatus;\n\tdurationMs: number;\n\tcaptureTruncated?: boolean;\n\ttruncation?: TruncationResult;\n}\n\nexport const DEFAULT_TEST_RUN_TIMEOUT_SECONDS = 900;\n\nfunction normalizeTimeoutSeconds(raw: number | undefined): number {\n\tif (raw === undefined) return DEFAULT_TEST_RUN_TIMEOUT_SECONDS;\n\tconst value = Math.floor(raw);\n\tif (!Number.isFinite(value) || value <= 0) {\n\t\tthrow new Error(\"timeout must be a positive number.\");\n\t}\n\treturn value;\n}\n\nfunction normalizeStringArray(raw: string[] | undefined): string[] {\n\treturn (raw ?? []).map((item) => String(item));\n}\n\nfunction normalizeScriptName(raw: string | undefined, fallback: string): string {\n\tconst script = (raw ?? fallback).trim();\n\tif (script.length === 0) {\n\t\tthrow new Error(\"script must not be empty.\");\n\t}\n\treturn script;\n}\n\nfunction hasAnyFile(cwd: string, fileNames: string[]): boolean {\n\treturn fileNames.some((name) => existsSync(join(cwd, name)));\n}\n\nfunction hasVitestConfig(cwd: string): boolean {\n\treturn hasAnyFile(cwd, [\n\t\t\"vitest.config.ts\",\n\t\t\"vitest.config.js\",\n\t\t\"vitest.config.mjs\",\n\t\t\"vitest.config.cjs\",\n\t\t\"vitest.config.mts\",\n\t\t\"vitest.config.cts\",\n\t]);\n}\n\nfunction hasJestConfig(cwd: string, packageJsonJest: unknown): boolean {\n\tif (packageJsonJest && typeof packageJsonJest === \"object\") {\n\t\treturn true;\n\t}\n\treturn hasAnyFile(cwd, [\n\t\t\"jest.config.ts\",\n\t\t\"jest.config.js\",\n\t\t\"jest.config.mjs\",\n\t\t\"jest.config.cjs\",\n\t\t\"jest.config.json\",\n\t\t\"jest.config.mts\",\n\t\t\"jest.config.cts\",\n\t]);\n}\n\nfunction hasPythonMarkers(cwd: string): boolean {\n\treturn hasAnyFile(cwd, [\n\t\t\"pyproject.toml\",\n\t\t\"pytest.ini\",\n\t\t\"tox.ini\",\n\t\t\"setup.cfg\",\n\t\t\"requirements.txt\",\n\t\t\"requirements-dev.txt\",\n\t]);\n}\n\nfunction assertPackageManagerAvailable(packageManager: PackageManager): void {\n\tif (packageManager === \"bun\") {\n\t\tensureCommandOrThrow(\"bun\", 'Command \"bun\" is required for bun-based test execution.');\n\t\treturn;\n\t}\n\tensureCommandOrThrow(packageManager, `Command \"${packageManager}\" is required for test execution.`);\n}\n\nfunction resolveScriptBasedCommand(\n\tpackageManager: PackageManager,\n\tscript: string,\n\targs: string[],\n): ResolvedTestCommand {\n\tassertPackageManagerAvailable(packageManager);\n\tconst invocation = resolvePackageManagerRunInvocation(packageManager, script, args);\n\treturn {\n\t\tresolvedRunner: packageManager,\n\t\tcommand: invocation.command,\n\t\targs: invocation.args,\n\t};\n}\n\nfunction resolveFrameworkCommand(\n\tpackageManager: PackageManager,\n\trunner: \"vitest\" | \"jest\",\n\targs: string[],\n): ResolvedTestCommand {\n\tassertPackageManagerAvailable(packageManager);\n\tconst invocation = resolvePackageManagerExecInvocation(packageManager, runner, args);\n\tensureCommandOrThrow(\n\t\tinvocation.command,\n\t\t`Command \"${invocation.command}\" is required to run ${runner}. Install ${packageManager} tooling first.`,\n\t);\n\treturn {\n\t\tresolvedRunner: runner,\n\t\tcommand: invocation.command,\n\t\targs: invocation.args,\n\t};\n}\n\nfunction resolvePytestCommand(args: string[]): ResolvedTestCommand {\n\tif (commandExists(\"python3\")) {\n\t\treturn {\n\t\t\tresolvedRunner: \"pytest\",\n\t\t\tcommand: \"python3\",\n\t\t\targs: [\"-m\", \"pytest\", ...args],\n\t\t};\n\t}\n\tif (commandExists(\"pytest\")) {\n\t\treturn {\n\t\t\tresolvedRunner: \"pytest\",\n\t\t\tcommand: \"pytest\",\n\t\t\targs,\n\t\t};\n\t}\n\tthrow new Error('No pytest runtime found. Install python3 + pytest or expose \"pytest\" in PATH.');\n}\n\nfunction resolveAutoRunner(cwd: string, script: string): ResolvedTestRunner {\n\tconst packageJson = readPackageJson(cwd);\n\tif (packageJson?.scripts[script]) {\n\t\treturn detectPackageManager(cwd);\n\t}\n\tif (hasVitestConfig(cwd)) return \"vitest\";\n\tif (hasJestConfig(cwd, packageJson?.raw?.jest)) return \"jest\";\n\tif (hasPythonMarkers(cwd)) return \"pytest\";\n\tthrow new Error(\n\t\t'Unable to auto-detect test runner. Expected package.json script, vitest/jest config, or python pytest markers.',\n\t);\n}\n\nfunction resolveTestCommand(input: {\n\tcwd: string;\n\trunner: TestRunRunner;\n\tscript: string;\n\targs: string[];\n}): ResolvedTestCommand {\n\tconst packageJson = readPackageJson(input.cwd);\n\tconst detectedPackageManager = detectPackageManager(input.cwd);\n\tlet resolvedRunner: ResolvedTestRunner;\n\n\tif (input.runner === \"auto\") {\n\t\tresolvedRunner = resolveAutoRunner(input.cwd, input.script);\n\t} else {\n\t\tresolvedRunner = input.runner;\n\t}\n\n\tif (resolvedRunner === \"npm\" || resolvedRunner === \"pnpm\" || resolvedRunner === \"yarn\" || resolvedRunner === \"bun\") {\n\t\tif (!packageJson) {\n\t\t\tthrow new Error(`package.json is required to run ${resolvedRunner} scripts.`);\n\t\t}\n\t\tif (!packageJson.scripts[input.script]) {\n\t\t\tthrow new Error(`Script \"${input.script}\" is not defined in package.json.`);\n\t\t}\n\t\treturn resolveScriptBasedCommand(resolvedRunner, input.script, input.args);\n\t}\n\n\tif (resolvedRunner === \"vitest\" || resolvedRunner === \"jest\") {\n\t\treturn resolveFrameworkCommand(detectedPackageManager, resolvedRunner, input.args);\n\t}\n\n\treturn resolvePytestCommand(input.args);\n}\n\nfunction mapTestStatus(resolvedRunner: ResolvedTestRunner, exitCode: number): TestRunStatus {\n\tif (exitCode === 0) return \"passed\";\n\tif (resolvedRunner === \"pytest\" && exitCode === 5) return \"no_tests\";\n\tif (exitCode === 1) return \"failed\";\n\treturn \"error\";\n}\n\nfunction indicatesPytestModuleMissing(output: string): boolean {\n\treturn /No module named pytest|ModuleNotFoundError:\\s*No module named ['\"]pytest['\"]/i.test(output);\n}\n\nfunction renderSummary(details: TestRunToolDetails, output: string): string {\n\tconst argsText = details.resolvedArgs.length > 0 ? ` ${details.resolvedArgs.join(\" \")}` : \"\";\n\treturn [\n\t\t`test_run status: ${details.status}`,\n\t\t`runner: ${details.resolvedRunner}`,\n\t\t`command: ${details.resolvedCommand}${argsText}`,\n\t\t`cwd: ${details.cwd}`,\n\t\t`exit_code: ${details.exitCode}`,\n\t\t`duration_ms: ${details.durationMs}`,\n\t\t\"\",\n\t\toutput,\n\t].join(\"\\n\");\n}\n\nexport function createTestRunTool(cwd: string): AgentTool<typeof testRunSchema> {\n\treturn {\n\t\tname: \"test_run\",\n\t\tlabel: \"test_run\",\n\t\tdescription:\n\t\t\t\"Structured test runner with auto detection across npm/pnpm/yarn/bun, vitest, jest, and pytest. Returns normalized status without throwing on ordinary test failures.\",\n\t\tparameters: testRunSchema,\n\t\texecute: async (_toolCallId: string, input: TestRunToolInput, signal?: AbortSignal) => {\n\t\t\tconst executionCwd = resolveToCwd(input.path || \".\", cwd);\n\t\t\tconst timeoutSeconds = normalizeTimeoutSeconds(input.timeout);\n\t\t\tconst normalizedArgs = normalizeStringArray(input.args);\n\t\t\tconst script = normalizeScriptName(input.script, \"test\");\n\t\t\tconst runner = input.runner ?? \"auto\";\n\n\t\t\tlet command = resolveTestCommand({\n\t\t\t\tcwd: executionCwd,\n\t\t\t\trunner,\n\t\t\t\tscript,\n\t\t\t\targs: normalizedArgs,\n\t\t\t});\n\n\t\t\tlet result = await runVerificationCommand({\n\t\t\t\tcommand: command.command,\n\t\t\t\targs: command.args,\n\t\t\t\tcwd: executionCwd,\n\t\t\t\ttimeoutMs: timeoutSeconds * 1000,\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\t// python3 -m pytest fallback to bare pytest when pytest module is unavailable\n\t\t\tif (\n\t\t\t\tcommand.resolvedRunner === \"pytest\" &&\n\t\t\t\tcommand.command === \"python3\" &&\n\t\t\t\tresult.exitCode !== 0 &&\n\t\t\t\tindicatesPytestModuleMissing(`${result.stdout}\\n${result.stderr}`) &&\n\t\t\t\tcommandExists(\"pytest\")\n\t\t\t) {\n\t\t\t\tconst fallback = await runVerificationCommand({\n\t\t\t\t\tcommand: \"pytest\",\n\t\t\t\t\targs: normalizedArgs,\n\t\t\t\t\tcwd: executionCwd,\n\t\t\t\t\ttimeoutMs: timeoutSeconds * 1000,\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\tcommand = { resolvedRunner: \"pytest\", command: \"pytest\", args: normalizedArgs };\n\t\t\t\tresult = {\n\t\t\t\t\t...fallback,\n\t\t\t\t\tdurationMs: result.durationMs + fallback.durationMs,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst status = mapTestStatus(command.resolvedRunner, result.exitCode);\n\t\t\tconst formatted = formatVerificationOutput(\n\t\t\t\tresult.stdout,\n\t\t\t\tresult.stderr,\n\t\t\t\tresult.captureTruncated,\n\t\t\t\t\"No test output\",\n\t\t\t);\n\n\t\t\tconst details: TestRunToolDetails = {\n\t\t\t\tresolvedRunner: command.resolvedRunner,\n\t\t\t\tresolvedCommand: command.command,\n\t\t\t\tresolvedArgs: command.args,\n\t\t\t\tcwd: executionCwd,\n\t\t\t\texitCode: result.exitCode,\n\t\t\t\tstatus,\n\t\t\t\tdurationMs: result.durationMs,\n\t\t\t\tcaptureTruncated: result.captureTruncated || undefined,\n\t\t\t\ttruncation: formatted.truncation,\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: renderSummary(details, formatted.text) }],\n\t\t\t\tdetails,\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport const testRunTool = createTestRunTool(process.cwd());\n\n"]}
@@ -0,0 +1,44 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import { type Static } from "@sinclair/typebox";
3
+ import type { TruncationResult } from "./truncate.js";
4
+ declare const typecheckRunSchema: import("@sinclair/typebox").TObject<{
5
+ runner: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"npm">, import("@sinclair/typebox").TLiteral<"pnpm">, import("@sinclair/typebox").TLiteral<"yarn">, import("@sinclair/typebox").TLiteral<"bun">, import("@sinclair/typebox").TLiteral<"tsc">, import("@sinclair/typebox").TLiteral<"vue_tsc">, import("@sinclair/typebox").TLiteral<"pyright">, import("@sinclair/typebox").TLiteral<"mypy">]>>;
6
+ script: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ targets: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
8
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
9
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
11
+ }>;
12
+ export type TypecheckRunToolInput = Static<typeof typecheckRunSchema>;
13
+ export type TypecheckRunRunner = "auto" | "npm" | "pnpm" | "yarn" | "bun" | "tsc" | "vue_tsc" | "pyright" | "mypy";
14
+ export type TypecheckRunStatus = "passed" | "failed" | "no_files" | "error";
15
+ type ResolvedTypecheckRunner = Exclude<TypecheckRunRunner, "auto">;
16
+ export interface TypecheckRunItemDetails {
17
+ resolvedRunner: ResolvedTypecheckRunner;
18
+ resolvedCommand: string;
19
+ resolvedArgs: string[];
20
+ exitCode: number;
21
+ status: TypecheckRunStatus;
22
+ durationMs: number;
23
+ captureTruncated?: boolean;
24
+ truncation?: TruncationResult;
25
+ }
26
+ export interface TypecheckRunToolDetails {
27
+ status: TypecheckRunStatus;
28
+ cwd: string;
29
+ durationMs: number;
30
+ runs: TypecheckRunItemDetails[];
31
+ aggregateExitCode: number;
32
+ }
33
+ export declare const DEFAULT_TYPECHECK_RUN_TIMEOUT_SECONDS = 600;
34
+ export declare function createTypecheckRunTool(cwd: string): AgentTool<typeof typecheckRunSchema>;
35
+ export declare const typecheckRunTool: AgentTool<import("@sinclair/typebox").TObject<{
36
+ runner: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"npm">, import("@sinclair/typebox").TLiteral<"pnpm">, import("@sinclair/typebox").TLiteral<"yarn">, import("@sinclair/typebox").TLiteral<"bun">, import("@sinclair/typebox").TLiteral<"tsc">, import("@sinclair/typebox").TLiteral<"vue_tsc">, import("@sinclair/typebox").TLiteral<"pyright">, import("@sinclair/typebox").TLiteral<"mypy">]>>;
37
+ script: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
38
+ targets: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
39
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
40
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
41
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
42
+ }>, any>;
43
+ export {};
44
+ //# sourceMappingURL=typecheck-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typecheck-run.d.ts","sourceRoot":"","sources":["../../../src/core/tools/typecheck-run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAatD,QAAA,MAAM,kBAAkB;;;;;;;EAoCtB,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAC3B,MAAM,GACN,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,KAAK,GACL,SAAS,GACT,SAAS,GACT,MAAM,CAAC;AACV,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5E,KAAK,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAQnE,MAAM,WAAW,uBAAuB;IACvC,cAAc,EAAE,uBAAuB,CAAC;IACxC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,uBAAuB,EAAE,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,qCAAqC,MAAM,CAAC;AAgSzD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,kBAAkB,CAAC,CA2FxF;AAED,eAAO,MAAM,gBAAgB;;;;;;;QAAwC,CAAC"}