@a5c-ai/agent-mux-harness-mock 0.2.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.
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/dist/bin/mock-harness.d.ts +33 -0
- package/dist/bin/mock-harness.d.ts.map +1 -0
- package/dist/bin/mock-harness.js +165 -0
- package/dist/bin/mock-harness.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/mock-process.d.ts +47 -0
- package/dist/mock-process.d.ts.map +1 -0
- package/dist/mock-process.js +207 -0
- package/dist/mock-process.js.map +1 -0
- package/dist/probe.d.ts +60 -0
- package/dist/probe.d.ts.map +1 -0
- package/dist/probe.js +168 -0
- package/dist/probe.js.map +1 -0
- package/dist/scenarios/errors.d.ts +22 -0
- package/dist/scenarios/errors.d.ts.map +1 -0
- package/dist/scenarios/errors.js +73 -0
- package/dist/scenarios/errors.js.map +1 -0
- package/dist/scenarios/hooks.d.ts +13 -0
- package/dist/scenarios/hooks.d.ts.map +1 -0
- package/dist/scenarios/hooks.js +61 -0
- package/dist/scenarios/hooks.js.map +1 -0
- package/dist/scenarios/index.d.ts +23 -0
- package/dist/scenarios/index.d.ts.map +1 -0
- package/dist/scenarios/index.js +47 -0
- package/dist/scenarios/index.js.map +1 -0
- package/dist/scenarios/interactive.d.ts +18 -0
- package/dist/scenarios/interactive.d.ts.map +1 -0
- package/dist/scenarios/interactive.js +46 -0
- package/dist/scenarios/interactive.js.map +1 -0
- package/dist/scenarios/per-agent.d.ts +46 -0
- package/dist/scenarios/per-agent.d.ts.map +1 -0
- package/dist/scenarios/per-agent.js +150 -0
- package/dist/scenarios/per-agent.js.map +1 -0
- package/dist/scenarios/wire-format.d.ts +36 -0
- package/dist/scenarios/wire-format.d.ts.map +1 -0
- package/dist/scenarios/wire-format.js +96 -0
- package/dist/scenarios/wire-format.js.map +1 -0
- package/dist/scenarios.d.ts +30 -0
- package/dist/scenarios.d.ts.map +1 -0
- package/dist/scenarios.js +141 -0
- package/dist/scenarios.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/workspace.d.ts +53 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +157 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 a5c-ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @a5c-ai/agent-mux-harness-mock
|
|
2
|
+
|
|
3
|
+
Mock harness simulator for [agent-mux](https://github.com/a5c-ai/agent-mux) adapter testing. Replays recorded/synthesized `claude-code`, `codex`, and other harness output streams so you can develop and test adapters without hitting real APIs.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev @a5c-ai/agent-mux-harness-mock
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js >= 20.9.0.
|
|
12
|
+
|
|
13
|
+
## CLI
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mock-harness --list
|
|
17
|
+
mock-harness --scenario claude-code-simple
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Programmatic
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createMockProcess, scenarios } from '@a5c-ai/agent-mux-harness-mock';
|
|
24
|
+
|
|
25
|
+
const proc = createMockProcess(scenarios['claude-code-simple']);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
See the [repository README](https://github.com/a5c-ai/agent-mux#readme) for details.
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
MIT © a5c-ai
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* mock-harness — CLI binary that replays a mock scenario to stdout/stderr.
|
|
4
|
+
*
|
|
5
|
+
* Flags:
|
|
6
|
+
* --scenario <name> Scenario id (see `--list`).
|
|
7
|
+
* --agent <name> Restrict resolution to a specific agent prefix.
|
|
8
|
+
* --delay <ms> Per-chunk delay override.
|
|
9
|
+
* --stdin-echo Echo stdin back to stdout (for interaction tests).
|
|
10
|
+
* --exit-code <n> Force exit code after scenario finishes.
|
|
11
|
+
* --fail-after <n> Exit with code n after emitting n output chunks.
|
|
12
|
+
* --list Print scenario names and exit.
|
|
13
|
+
*/
|
|
14
|
+
import type { HarnessScenario } from '../types.js';
|
|
15
|
+
interface Args {
|
|
16
|
+
scenario?: string;
|
|
17
|
+
agent?: string;
|
|
18
|
+
delay?: number;
|
|
19
|
+
stdinEcho: boolean;
|
|
20
|
+
exitCode?: number;
|
|
21
|
+
failAfter?: number;
|
|
22
|
+
list: boolean;
|
|
23
|
+
help: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function parseArgs(argv: string[]): Args;
|
|
26
|
+
export declare function applyOverrides(scenario: HarnessScenario, args: Args): HarnessScenario;
|
|
27
|
+
export declare function runMockHarness(args: Args, streams?: {
|
|
28
|
+
stdout: NodeJS.WritableStream;
|
|
29
|
+
stderr: NodeJS.WritableStream;
|
|
30
|
+
stdin?: NodeJS.ReadableStream;
|
|
31
|
+
}): Promise<number>;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=mock-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-harness.d.ts","sourceRoot":"","sources":["../../src/bin/mock-harness.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,UAAU,IAAI;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAwB9C;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,IAAI,GAAG,eAAe,CAcrF;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IAAE,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAA;CAC5B,GACzE,OAAO,CAAC,MAAM,CAAC,CA+BjB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* mock-harness — CLI binary that replays a mock scenario to stdout/stderr.
|
|
4
|
+
*
|
|
5
|
+
* Flags:
|
|
6
|
+
* --scenario <name> Scenario id (see `--list`).
|
|
7
|
+
* --agent <name> Restrict resolution to a specific agent prefix.
|
|
8
|
+
* --delay <ms> Per-chunk delay override.
|
|
9
|
+
* --stdin-echo Echo stdin back to stdout (for interaction tests).
|
|
10
|
+
* --exit-code <n> Force exit code after scenario finishes.
|
|
11
|
+
* --fail-after <n> Exit with code n after emitting n output chunks.
|
|
12
|
+
* --list Print scenario names and exit.
|
|
13
|
+
*/
|
|
14
|
+
import { resolveScenario, listScenarioNames } from '../scenarios/index.js';
|
|
15
|
+
export function parseArgs(argv) {
|
|
16
|
+
const out = { stdinEcho: false, list: false, help: false };
|
|
17
|
+
for (let i = 0; i < argv.length; i++) {
|
|
18
|
+
const a = argv[i];
|
|
19
|
+
const next = () => {
|
|
20
|
+
const v = argv[++i];
|
|
21
|
+
if (v === undefined)
|
|
22
|
+
throw new Error(`Missing value for ${a}`);
|
|
23
|
+
return v;
|
|
24
|
+
};
|
|
25
|
+
switch (a) {
|
|
26
|
+
case '--scenario':
|
|
27
|
+
out.scenario = next();
|
|
28
|
+
break;
|
|
29
|
+
case '--agent':
|
|
30
|
+
out.agent = next();
|
|
31
|
+
break;
|
|
32
|
+
case '--delay':
|
|
33
|
+
out.delay = Number(next());
|
|
34
|
+
break;
|
|
35
|
+
case '--stdin-echo':
|
|
36
|
+
out.stdinEcho = true;
|
|
37
|
+
break;
|
|
38
|
+
case '--exit-code':
|
|
39
|
+
out.exitCode = Number(next());
|
|
40
|
+
break;
|
|
41
|
+
case '--fail-after':
|
|
42
|
+
out.failAfter = Number(next());
|
|
43
|
+
break;
|
|
44
|
+
case '--list':
|
|
45
|
+
out.list = true;
|
|
46
|
+
break;
|
|
47
|
+
case '-h':
|
|
48
|
+
case '--help':
|
|
49
|
+
out.help = true;
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
if (a && a.startsWith('--'))
|
|
53
|
+
throw new Error(`Unknown flag: ${a}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
export function applyOverrides(scenario, args) {
|
|
59
|
+
const out = {
|
|
60
|
+
...scenario,
|
|
61
|
+
output: scenario.output.map((c) => ({ ...c, delayMs: args.delay ?? c.delayMs })),
|
|
62
|
+
process: { ...scenario.process },
|
|
63
|
+
};
|
|
64
|
+
if (args.exitCode !== undefined && Number.isFinite(args.exitCode)) {
|
|
65
|
+
out.process = { ...out.process, exitCode: args.exitCode };
|
|
66
|
+
}
|
|
67
|
+
if (args.failAfter !== undefined && Number.isFinite(args.failAfter)) {
|
|
68
|
+
out.output = out.output.slice(0, args.failAfter);
|
|
69
|
+
out.process = { ...out.process, exitCode: out.process.exitCode || 1 };
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
export async function runMockHarness(args, streams = { stdout: process.stdout, stderr: process.stderr, stdin: process.stdin }) {
|
|
74
|
+
if (args.help) {
|
|
75
|
+
streams.stderr.write(helpText());
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
if (args.list) {
|
|
79
|
+
for (const n of listScenarioNames())
|
|
80
|
+
streams.stdout.write(n + '\n');
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
if (!args.scenario) {
|
|
84
|
+
streams.stderr.write('error: --scenario is required (use --list)\n');
|
|
85
|
+
return 2;
|
|
86
|
+
}
|
|
87
|
+
const resolved = resolveScenario(args.scenario);
|
|
88
|
+
if (!resolved) {
|
|
89
|
+
streams.stderr.write(`error: unknown scenario: ${args.scenario}\n`);
|
|
90
|
+
return 2;
|
|
91
|
+
}
|
|
92
|
+
const scenario = applyOverrides(resolved, args);
|
|
93
|
+
// Stdin echo: pipe stdin lines straight to stdout so interaction tests
|
|
94
|
+
// can verify which approval response arrived.
|
|
95
|
+
if (args.stdinEcho && streams.stdin) {
|
|
96
|
+
streams.stdin.on('data', (chunk) => {
|
|
97
|
+
const s = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
98
|
+
streams.stdout.write(`stdin:${s}`);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
await replayScenario(scenario, streams);
|
|
102
|
+
return scenario.process.exitCode;
|
|
103
|
+
}
|
|
104
|
+
async function replayScenario(scenario, streams) {
|
|
105
|
+
const startup = scenario.process.startupDelayMs ?? 0;
|
|
106
|
+
if (startup > 0)
|
|
107
|
+
await wait(startup);
|
|
108
|
+
for (const chunk of scenario.output) {
|
|
109
|
+
if (chunk.delayMs && chunk.delayMs > 0)
|
|
110
|
+
await wait(chunk.delayMs);
|
|
111
|
+
if (chunk.stream === 'stdout')
|
|
112
|
+
streams.stdout.write(chunk.data);
|
|
113
|
+
else
|
|
114
|
+
streams.stderr.write(chunk.data);
|
|
115
|
+
}
|
|
116
|
+
if (scenario.process.hang) {
|
|
117
|
+
await new Promise(() => { });
|
|
118
|
+
}
|
|
119
|
+
const shutdown = scenario.process.shutdownDelayMs ?? 0;
|
|
120
|
+
if (shutdown > 0)
|
|
121
|
+
await wait(shutdown);
|
|
122
|
+
}
|
|
123
|
+
function wait(ms) {
|
|
124
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
125
|
+
}
|
|
126
|
+
function helpText() {
|
|
127
|
+
return [
|
|
128
|
+
'mock-harness — replay a mock agent scenario.',
|
|
129
|
+
'',
|
|
130
|
+
'Usage: mock-harness --scenario <name> [flags]',
|
|
131
|
+
'',
|
|
132
|
+
'Flags:',
|
|
133
|
+
' --scenario <name> Scenario id (try --list)',
|
|
134
|
+
' --agent <name> Informational; restrict scope to an agent',
|
|
135
|
+
' --delay <ms> Override per-chunk delay',
|
|
136
|
+
' --stdin-echo Echo stdin back to stdout',
|
|
137
|
+
' --exit-code <n> Force process exit code',
|
|
138
|
+
' --fail-after <n> Truncate scenario to n chunks and fail',
|
|
139
|
+
' --list List scenario names',
|
|
140
|
+
' -h, --help Show this help',
|
|
141
|
+
'',
|
|
142
|
+
].join('\n');
|
|
143
|
+
}
|
|
144
|
+
// Entrypoint guard — invoked only when executed as a script.
|
|
145
|
+
const invokedAsScript = (() => {
|
|
146
|
+
try {
|
|
147
|
+
const argv1 = process.argv[1];
|
|
148
|
+
if (!argv1)
|
|
149
|
+
return false;
|
|
150
|
+
// Match on known filename fragment rather than import.meta.url, which
|
|
151
|
+
// requires ESM-only syntax that plays poorly with the tsconfig setup.
|
|
152
|
+
return /mock-harness(\.js|\.ts)?$/.test(argv1);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
})();
|
|
158
|
+
if (invokedAsScript) {
|
|
159
|
+
const args = parseArgs(process.argv.slice(2));
|
|
160
|
+
runMockHarness(args).then((code) => { process.exit(code); }, (err) => {
|
|
161
|
+
process.stderr.write(`mock-harness failed: ${err.message}\n`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=mock-harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-harness.js","sourceRoot":"","sources":["../../src/bin/mock-harness.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @a5c-ai/agent-mux-harness-mock
|
|
3
|
+
*
|
|
4
|
+
* Mock harness simulator for testing agent-mux adapters.
|
|
5
|
+
* Simulates claude-code, codex, and other CLI harnesses without
|
|
6
|
+
* requiring real installations or API keys.
|
|
7
|
+
*
|
|
8
|
+
* Main components:
|
|
9
|
+
* - MockProcess: simulates a harness subprocess
|
|
10
|
+
* - WorkspaceSandbox: isolated filesystem for file operation testing
|
|
11
|
+
* - Scenarios: pre-built behavior configurations for common test cases
|
|
12
|
+
* - Probe: tools for capturing real harness behavior profiles
|
|
13
|
+
*/
|
|
14
|
+
export type { HarnessType, FileOperation, ProcessBehavior, OutputChunk, StdinInteraction, MockEvent, HarnessScenario, MockHarnessHandle, HarnessBehaviorProfile, } from './types.js';
|
|
15
|
+
export { MockProcess } from './mock-process.js';
|
|
16
|
+
export { WorkspaceSandbox } from './workspace.js';
|
|
17
|
+
export type { WorkspaceOptions } from './workspace.js';
|
|
18
|
+
export { claudeCodeSuccess, claudeCodeToolApproval, claudeCodeTimeout, claudeCodeCrash, claudeCodeFileOps, codexSuccess, codexFileOps, codexFailure, emptySuccess, slowStartup, largeOutput, } from './scenarios.js';
|
|
19
|
+
export { resolveScenario, listScenarioNames, AGENT_SCENARIOS, ERROR_SCENARIOS, INTERACTION_SCENARIOS, claudeBasicText, claudeToolCall, claudeMultiTurn, codexBasicText, codexCodeGeneration, geminiBasicText, geminiStreaming, copilotScenarios, cursorScenarios, opencodeScenarios, piScenarios, ompScenarios, openclawScenarios, hermesScenarios, buildInteractiveScenario, claudeSystemInit, claudeAssistantText, claudeToolUse, claudeToolResult, claudeThinking, claudeResult, claudeError, codexMessage, codexFunctionCall, codexFunctionCallOutput, codexError, geminiText, geminiToolCall, geminiToolResult, geminiError, genericText, genericToolCall, genericError, stdoutChunk, stderrChunk, } from './scenarios/index.js';
|
|
20
|
+
export type { InteractionMode } from './scenarios/interactive.js';
|
|
21
|
+
export type { ErrorScenarioMeta } from './scenarios/errors.js';
|
|
22
|
+
export type { ToolCall } from './scenarios/wire-format.js';
|
|
23
|
+
export { probeHarness, probeAllHarnesses, compareProfiles, PROBE_CONFIGS, } from './probe.js';
|
|
24
|
+
export type { ProbeConfig, ProbeResult, ProfileDiff, } from './probe.js';
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,YAAY,EACV,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,qBAAqB,EAErB,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,eAAe,EAEf,wBAAwB,EAExB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @a5c-ai/agent-mux-harness-mock
|
|
3
|
+
*
|
|
4
|
+
* Mock harness simulator for testing agent-mux adapters.
|
|
5
|
+
* Simulates claude-code, codex, and other CLI harnesses without
|
|
6
|
+
* requiring real installations or API keys.
|
|
7
|
+
*
|
|
8
|
+
* Main components:
|
|
9
|
+
* - MockProcess: simulates a harness subprocess
|
|
10
|
+
* - WorkspaceSandbox: isolated filesystem for file operation testing
|
|
11
|
+
* - Scenarios: pre-built behavior configurations for common test cases
|
|
12
|
+
* - Probe: tools for capturing real harness behavior profiles
|
|
13
|
+
*/
|
|
14
|
+
// Mock process
|
|
15
|
+
export { MockProcess } from './mock-process.js';
|
|
16
|
+
// Workspace sandbox
|
|
17
|
+
export { WorkspaceSandbox } from './workspace.js';
|
|
18
|
+
// Pre-built scenarios
|
|
19
|
+
export { claudeCodeSuccess, claudeCodeToolApproval, claudeCodeTimeout, claudeCodeCrash, claudeCodeFileOps, codexSuccess, codexFileOps, codexFailure, emptySuccess, slowStartup, largeOutput, } from './scenarios.js';
|
|
20
|
+
// Scenario presets: per-agent, interactive, errors + wire-format helpers.
|
|
21
|
+
export {
|
|
22
|
+
// resolvers + registries
|
|
23
|
+
resolveScenario, listScenarioNames, AGENT_SCENARIOS, ERROR_SCENARIOS, INTERACTION_SCENARIOS,
|
|
24
|
+
// per-agent presets
|
|
25
|
+
claudeBasicText, claudeToolCall, claudeMultiTurn, codexBasicText, codexCodeGeneration, geminiBasicText, geminiStreaming, copilotScenarios, cursorScenarios, opencodeScenarios, piScenarios, ompScenarios, openclawScenarios, hermesScenarios,
|
|
26
|
+
// interactive
|
|
27
|
+
buildInteractiveScenario,
|
|
28
|
+
// wire-format
|
|
29
|
+
claudeSystemInit, claudeAssistantText, claudeToolUse, claudeToolResult, claudeThinking, claudeResult, claudeError, codexMessage, codexFunctionCall, codexFunctionCallOutput, codexError, geminiText, geminiToolCall, geminiToolResult, geminiError, genericText, genericToolCall, genericError, stdoutChunk, stderrChunk, } from './scenarios/index.js';
|
|
30
|
+
// Probe tools
|
|
31
|
+
export { probeHarness, probeAllHarnesses, compareProfiles, PROBE_CONFIGS, } from './probe.js';
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,oBAAoB;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,sBAAsB;AACtB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAExB,0EAA0E;AAC1E,OAAO;AACL,yBAAyB;AACzB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,qBAAqB;AACrB,oBAAoB;AACpB,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,eAAe;AACf,cAAc;AACd,wBAAwB;AACxB,cAAc;AACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAK9B,cAAc;AACd,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MockProcess — simulates a harness subprocess with configurable behavior.
|
|
3
|
+
*
|
|
4
|
+
* Emits output chunks on a schedule, handles stdin interactions,
|
|
5
|
+
* simulates file operations, and exits with the configured code/timing.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from 'node:events';
|
|
8
|
+
import type { HarnessScenario, MockHarnessHandle, FileOperation } from './types.js';
|
|
9
|
+
export declare class MockProcess extends EventEmitter implements MockHarnessHandle {
|
|
10
|
+
readonly scenario: HarnessScenario;
|
|
11
|
+
readonly pid: number;
|
|
12
|
+
private _exited;
|
|
13
|
+
private _exitCode;
|
|
14
|
+
private _stdout;
|
|
15
|
+
private _stderr;
|
|
16
|
+
private _fileChanges;
|
|
17
|
+
private _killed;
|
|
18
|
+
private _timers;
|
|
19
|
+
private _stdinBuffer;
|
|
20
|
+
constructor(scenario: HarnessScenario);
|
|
21
|
+
get exited(): boolean;
|
|
22
|
+
get exitCode(): number | undefined;
|
|
23
|
+
get stdout(): string;
|
|
24
|
+
get stderr(): string;
|
|
25
|
+
get fileChanges(): FileOperation[];
|
|
26
|
+
write(data: string): void;
|
|
27
|
+
kill(signal?: string): void;
|
|
28
|
+
waitForExit(): Promise<{
|
|
29
|
+
exitCode: number;
|
|
30
|
+
stdout: string;
|
|
31
|
+
stderr: string;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Start the mock process. Call this after setting up event listeners.
|
|
35
|
+
* Returns the handle for chaining.
|
|
36
|
+
*/
|
|
37
|
+
start(): MockHarnessHandle;
|
|
38
|
+
private _emitOutputChunks;
|
|
39
|
+
private _applyFileOperations;
|
|
40
|
+
private _checkInteractions;
|
|
41
|
+
private _scheduleExit;
|
|
42
|
+
private _validateExpectations;
|
|
43
|
+
private _exit;
|
|
44
|
+
private _schedule;
|
|
45
|
+
private _cleanup;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=mock-process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-process.d.ts","sourceRoot":"","sources":["../src/mock-process.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EAEd,MAAM,YAAY,CAAC;AAYpB,qBAAa,WAAY,SAAQ,YAAa,YAAW,iBAAiB;IACxE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,YAAY,CAAM;gBAEd,QAAQ,EAAE,eAAe;IAUrC,IAAI,MAAM,IAAI,OAAO,CAAyB;IAC9C,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAA2B;IAC7D,IAAI,MAAM,IAAI,MAAM,CAAyB;IAC7C,IAAI,MAAM,IAAI,MAAM,CAAyB;IAC7C,IAAI,WAAW,IAAI,aAAa,EAAE,CAAmC;IAErE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMzB,IAAI,CAAC,MAAM,SAAY,GAAG,IAAI;IAO9B,WAAW,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAuB5E;;;OAGG;IACH,KAAK,IAAI,iBAAiB;IAgC1B,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,QAAQ;CAMjB"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MockProcess — simulates a harness subprocess with configurable behavior.
|
|
3
|
+
*
|
|
4
|
+
* Emits output chunks on a schedule, handles stdin interactions,
|
|
5
|
+
* simulates file operations, and exits with the configured code/timing.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from 'node:events';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Internal state
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
let nextPid = 10000;
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// MockProcess
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export class MockProcess extends EventEmitter {
|
|
16
|
+
scenario;
|
|
17
|
+
pid;
|
|
18
|
+
_exited = false;
|
|
19
|
+
_exitCode;
|
|
20
|
+
_stdout = '';
|
|
21
|
+
_stderr = '';
|
|
22
|
+
_fileChanges = [];
|
|
23
|
+
_killed = false;
|
|
24
|
+
_timers = [];
|
|
25
|
+
_stdinBuffer = '';
|
|
26
|
+
constructor(scenario) {
|
|
27
|
+
super();
|
|
28
|
+
this.scenario = scenario;
|
|
29
|
+
this.pid = nextPid++;
|
|
30
|
+
}
|
|
31
|
+
// -----------------------------------------------------------------------
|
|
32
|
+
// MockHarnessHandle
|
|
33
|
+
// -----------------------------------------------------------------------
|
|
34
|
+
get exited() { return this._exited; }
|
|
35
|
+
get exitCode() { return this._exitCode; }
|
|
36
|
+
get stdout() { return this._stdout; }
|
|
37
|
+
get stderr() { return this._stderr; }
|
|
38
|
+
get fileChanges() { return [...this._fileChanges]; }
|
|
39
|
+
write(data) {
|
|
40
|
+
if (this._exited)
|
|
41
|
+
throw new Error('Cannot write to exited process');
|
|
42
|
+
this._stdinBuffer += data;
|
|
43
|
+
this.emit('stdin', data);
|
|
44
|
+
}
|
|
45
|
+
kill(signal = 'SIGTERM') {
|
|
46
|
+
if (this._exited)
|
|
47
|
+
return;
|
|
48
|
+
this._killed = true;
|
|
49
|
+
this._cleanup();
|
|
50
|
+
this._exit(signal === 'SIGKILL' ? 137 : 143);
|
|
51
|
+
}
|
|
52
|
+
waitForExit() {
|
|
53
|
+
if (this._exited) {
|
|
54
|
+
return Promise.resolve({
|
|
55
|
+
exitCode: this._exitCode,
|
|
56
|
+
stdout: this._stdout,
|
|
57
|
+
stderr: this._stderr,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
this.once('exit', () => {
|
|
62
|
+
resolve({
|
|
63
|
+
exitCode: this._exitCode,
|
|
64
|
+
stdout: this._stdout,
|
|
65
|
+
stderr: this._stderr,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// -----------------------------------------------------------------------
|
|
71
|
+
// Lifecycle
|
|
72
|
+
// -----------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Start the mock process. Call this after setting up event listeners.
|
|
75
|
+
* Returns the handle for chaining.
|
|
76
|
+
*/
|
|
77
|
+
start() {
|
|
78
|
+
const startDelay = this.scenario.process.startupDelayMs ?? 0;
|
|
79
|
+
this._schedule(startDelay, () => {
|
|
80
|
+
this.emit('spawn');
|
|
81
|
+
this._validateExpectations();
|
|
82
|
+
this._emitOutputChunks();
|
|
83
|
+
this._applyFileOperations();
|
|
84
|
+
this._scheduleExit();
|
|
85
|
+
});
|
|
86
|
+
if (this.scenario.process.hang) {
|
|
87
|
+
// Don't schedule exit — process hangs
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
if (this.scenario.process.crashAfterMs !== undefined) {
|
|
91
|
+
this._schedule(this.scenario.process.crashAfterMs, () => {
|
|
92
|
+
if (!this._exited) {
|
|
93
|
+
const signal = this.scenario.process.crashSignal ?? 'SIGTERM';
|
|
94
|
+
this._exit(signal === 'SIGKILL' ? 137 : 143);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
// -----------------------------------------------------------------------
|
|
101
|
+
// Private
|
|
102
|
+
// -----------------------------------------------------------------------
|
|
103
|
+
_emitOutputChunks() {
|
|
104
|
+
let cumulativeDelay = 0;
|
|
105
|
+
for (const chunk of this.scenario.output) {
|
|
106
|
+
cumulativeDelay += (chunk.delayMs ?? 0);
|
|
107
|
+
this._schedule(cumulativeDelay, () => {
|
|
108
|
+
if (this._exited)
|
|
109
|
+
return;
|
|
110
|
+
if (chunk.stream === 'stdout') {
|
|
111
|
+
this._stdout += chunk.data;
|
|
112
|
+
this.emit('stdout', chunk.data);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
this._stderr += chunk.data;
|
|
116
|
+
this.emit('stderr', chunk.data);
|
|
117
|
+
}
|
|
118
|
+
this._checkInteractions(chunk);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
_applyFileOperations() {
|
|
123
|
+
if (!this.scenario.fileOperations)
|
|
124
|
+
return;
|
|
125
|
+
let cumulativeDelay = 0;
|
|
126
|
+
for (const op of this.scenario.fileOperations) {
|
|
127
|
+
this._schedule(cumulativeDelay, () => {
|
|
128
|
+
if (this._exited)
|
|
129
|
+
return;
|
|
130
|
+
this._fileChanges.push(op);
|
|
131
|
+
this.emit('file-operation', op);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
_checkInteractions(chunk) {
|
|
136
|
+
if (!this.scenario.interactions)
|
|
137
|
+
return;
|
|
138
|
+
for (const interaction of this.scenario.interactions) {
|
|
139
|
+
const pattern = typeof interaction.triggerPattern === 'string'
|
|
140
|
+
? new RegExp(interaction.triggerPattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
141
|
+
: interaction.triggerPattern;
|
|
142
|
+
if (pattern.test(chunk.data)) {
|
|
143
|
+
const delay = interaction.delayMs ?? 0;
|
|
144
|
+
this._schedule(delay, () => {
|
|
145
|
+
if (!this._exited) {
|
|
146
|
+
this.emit('auto-response', interaction.response);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
_scheduleExit() {
|
|
153
|
+
if (this.scenario.process.hang)
|
|
154
|
+
return;
|
|
155
|
+
if (this.scenario.process.crashAfterMs !== undefined)
|
|
156
|
+
return;
|
|
157
|
+
// Calculate total output time
|
|
158
|
+
let totalOutputTime = 0;
|
|
159
|
+
for (const chunk of this.scenario.output) {
|
|
160
|
+
totalOutputTime += (chunk.delayMs ?? 0);
|
|
161
|
+
}
|
|
162
|
+
const shutdownDelay = this.scenario.process.shutdownDelayMs ?? 0;
|
|
163
|
+
this._schedule(totalOutputTime + shutdownDelay, () => {
|
|
164
|
+
if (!this._exited) {
|
|
165
|
+
this._exit(this.scenario.process.exitCode);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
_validateExpectations() {
|
|
170
|
+
// These are checked synchronously at start for test assertions
|
|
171
|
+
if (this.scenario.expectedEnv) {
|
|
172
|
+
this.emit('validate-env', this.scenario.expectedEnv);
|
|
173
|
+
}
|
|
174
|
+
if (this.scenario.expectedArgs) {
|
|
175
|
+
this.emit('validate-args', this.scenario.expectedArgs);
|
|
176
|
+
}
|
|
177
|
+
if (this.scenario.expectedCwd) {
|
|
178
|
+
this.emit('validate-cwd', this.scenario.expectedCwd);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
_exit(code) {
|
|
182
|
+
if (this._exited)
|
|
183
|
+
return;
|
|
184
|
+
this._exited = true;
|
|
185
|
+
this._exitCode = code;
|
|
186
|
+
this._cleanup();
|
|
187
|
+
this.emit('exit', code);
|
|
188
|
+
}
|
|
189
|
+
_schedule(delayMs, fn) {
|
|
190
|
+
if (delayMs <= 0) {
|
|
191
|
+
// Use setImmediate for zero-delay to maintain async semantics
|
|
192
|
+
const timer = setTimeout(fn, 0);
|
|
193
|
+
this._timers.push(timer);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const timer = setTimeout(fn, delayMs);
|
|
197
|
+
this._timers.push(timer);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
_cleanup() {
|
|
201
|
+
for (const timer of this._timers) {
|
|
202
|
+
clearTimeout(timer);
|
|
203
|
+
}
|
|
204
|
+
this._timers = [];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=mock-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-process.js","sourceRoot":"","sources":["../src/mock-process.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,MAAM,OAAO,WAAY,SAAQ,YAAY;IAClC,QAAQ,CAAkB;IAC1B,GAAG,CAAS;IAEb,OAAO,GAAG,KAAK,CAAC;IAChB,SAAS,CAAqB;IAC9B,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,GAAG,EAAE,CAAC;IACb,YAAY,GAAoB,EAAE,CAAC;IACnC,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAoC,EAAE,CAAC;IAC9C,YAAY,GAAG,EAAE,CAAC;IAE1B,YAAY,QAAyB;QACnC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,OAAO,EAAE,CAAC;IACvB,CAAC;IAED,0EAA0E;IAC1E,oBAAoB;IACpB,0EAA0E;IAE1E,IAAI,MAAM,KAAc,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAyB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,IAAI,WAAW,KAAsB,OAAO,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAErE,KAAK,CAAC,IAAY;QAChB,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpE,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,CAAC,MAAM,GAAG,SAAS;QACrB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,QAAQ,EAAE,IAAI,CAAC,SAAU;gBACzB,MAAM,EAAE,IAAI,CAAC,OAAO;gBACpB,MAAM,EAAE,IAAI,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;gBACrB,OAAO,CAAC;oBACN,QAAQ,EAAE,IAAI,CAAC,SAAU;oBACzB,MAAM,EAAE,IAAI,CAAC,OAAO;oBACpB,MAAM,EAAE,IAAI,CAAC,OAAO;iBACrB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,YAAY;IACZ,0EAA0E;IAE1E;;;OAGG;IACH,KAAK;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC;QAE7D,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE;YAC9B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC7B,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/B,sCAAsC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACrD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE;gBACtD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,IAAI,SAAS,CAAC;oBAC9D,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0EAA0E;IAC1E,UAAU;IACV,0EAA0E;IAElE,iBAAiB;QACvB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACzC,eAAe,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE;gBACnC,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO;gBACzB,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBAC9B,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC;oBAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC;oBAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,CAAC;gBACD,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc;YAAE,OAAO;QAC1C,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC9C,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE;gBACnC,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO;gBACzB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,KAAkB;QAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY;YAAE,OAAO;QACxC,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YACrD,MAAM,OAAO,GAAG,OAAO,WAAW,CAAC,cAAc,KAAK,QAAQ;gBAC5D,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;gBAC/E,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC;YAE/B,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,IAAI,CAAC,CAAC;gBACvC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE;oBACzB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;wBAClB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;oBACnD,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI;YAAE,OAAO;QACvC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS;YAAE,OAAO;QAE7D,8BAA8B;QAC9B,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACzC,eAAe,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,CAAC;QACjE,IAAI,CAAC,SAAS,CAAC,eAAe,GAAG,aAAa,EAAE,GAAG,EAAE;YACnD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,qBAAqB;QAC3B,+DAA+D;QAC/D,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAY;QACxB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAEO,SAAS,CAAC,OAAe,EAAE,EAAc;QAC/C,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACjB,8DAA8D;YAC9D,MAAM,KAAK,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;CACF"}
|