smol-symphony 0.1.0 → 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/AGENTS.md +105 -38
- package/PRODUCT.md +2 -1
- package/README.md +195 -98
- package/SPEC.md +543 -1915
- package/WORKFLOW.md +654 -179
- package/WORKFLOW.template.md +761 -121
- package/dist/acp-bridge.js +324 -0
- package/dist/acp-bridge.js.map +1 -0
- package/dist/actions/cache.js +191 -0
- package/dist/actions/cache.js.map +1 -0
- package/dist/actions/effects.js +41 -0
- package/dist/actions/effects.js.map +1 -0
- package/dist/actions/executor.js +570 -0
- package/dist/actions/executor.js.map +1 -0
- package/dist/actions/index.js +13 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/parsing.js +273 -0
- package/dist/actions/parsing.js.map +1 -0
- package/dist/actions/predicate-env.js +27 -0
- package/dist/actions/predicate-env.js.map +1 -0
- package/dist/actions/predicates.js +49 -0
- package/dist/actions/predicates.js.map +1 -0
- package/dist/actions/templating.js +66 -0
- package/dist/actions/templating.js.map +1 -0
- package/dist/actions/types.js +15 -0
- package/dist/actions/types.js.map +1 -0
- package/dist/agent/acp.js +232 -63
- package/dist/agent/acp.js.map +1 -1
- package/dist/agent/adapter-names.js +159 -0
- package/dist/agent/adapter-names.js.map +1 -0
- package/dist/agent/adapters.js +338 -102
- package/dist/agent/adapters.js.map +1 -1
- package/dist/agent/credential-extractors.js +342 -0
- package/dist/agent/credential-extractors.js.map +1 -0
- package/dist/agent/credential-secrets.js +628 -0
- package/dist/agent/credential-secrets.js.map +1 -0
- package/dist/agent/credential-ticker.js +57 -0
- package/dist/agent/credential-ticker.js.map +1 -0
- package/dist/agent/gondolin-creds-staging.js +356 -0
- package/dist/agent/gondolin-creds-staging.js.map +1 -0
- package/dist/agent/gondolin-dispatch.js +375 -0
- package/dist/agent/gondolin-dispatch.js.map +1 -0
- package/dist/agent/gondolin.js +124 -0
- package/dist/agent/gondolin.js.map +1 -0
- package/dist/agent/runner-decisions.js +134 -0
- package/dist/agent/runner-decisions.js.map +1 -0
- package/dist/agent/runner.js +1352 -290
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/tool-call-summary.js +102 -0
- package/dist/agent/tool-call-summary.js.map +1 -0
- package/dist/agent/vm-acp-mapping.js +73 -0
- package/dist/agent/vm-acp-mapping.js.map +1 -0
- package/dist/agent/vm-guards.js +262 -0
- package/dist/agent/vm-guards.js.map +1 -0
- package/dist/agent/vm-port.js +22 -0
- package/dist/agent/vm-port.js.map +1 -0
- package/dist/agent/vm-process-registry.js +79 -0
- package/dist/agent/vm-process-registry.js.map +1 -0
- package/dist/bin/cli-args.js +105 -0
- package/dist/bin/cli-args.js.map +1 -0
- package/dist/bin/symphony.js +719 -130
- package/dist/bin/symphony.js.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/http-disk.js +135 -0
- package/dist/http-disk.js.map +1 -0
- package/dist/http-handlers.js +180 -0
- package/dist/http-handlers.js.map +1 -0
- package/dist/http.js +1476 -764
- package/dist/http.js.map +1 -1
- package/dist/issues.js +178 -0
- package/dist/issues.js.map +1 -0
- package/dist/logging.js +163 -5
- package/dist/logging.js.map +1 -1
- package/dist/mcp.js +391 -163
- package/dist/mcp.js.map +1 -1
- package/dist/memory.js +85 -0
- package/dist/memory.js.map +1 -0
- package/dist/orchestrator-decisions.js +331 -0
- package/dist/orchestrator-decisions.js.map +1 -0
- package/dist/orchestrator.js +1189 -303
- package/dist/orchestrator.js.map +1 -1
- package/dist/prompt.js +5 -5
- package/dist/prompt.js.map +1 -1
- package/dist/reconciler/cache.js +65 -0
- package/dist/reconciler/cache.js.map +1 -0
- package/dist/reconciler/index.js +448 -0
- package/dist/reconciler/index.js.map +1 -0
- package/dist/reconciler/ledger.js +131 -0
- package/dist/reconciler/ledger.js.map +1 -0
- package/dist/reconciler/pr-adapters.js +174 -0
- package/dist/reconciler/pr-adapters.js.map +1 -0
- package/dist/reconciler/pr-decide.js +167 -0
- package/dist/reconciler/pr-decide.js.map +1 -0
- package/dist/reconciler/pr.js +422 -0
- package/dist/reconciler/pr.js.map +1 -0
- package/dist/reconciler/types.js +12 -0
- package/dist/reconciler/types.js.map +1 -0
- package/dist/reconciler/vm.js +243 -0
- package/dist/reconciler/vm.js.map +1 -0
- package/dist/reconciler/workspace-defaults.js +83 -0
- package/dist/reconciler/workspace-defaults.js.map +1 -0
- package/dist/reconciler/workspace.js +272 -0
- package/dist/reconciler/workspace.js.map +1 -0
- package/dist/runlog.js +403 -0
- package/dist/runlog.js.map +1 -0
- package/dist/scaffold.js +165 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/trackers/local.js +234 -133
- package/dist/trackers/local.js.map +1 -1
- package/dist/trackers/types.js +1 -1
- package/dist/trackers/types.js.map +1 -1
- package/dist/types.js +1 -1
- package/dist/util/clock.js +12 -0
- package/dist/util/clock.js.map +1 -0
- package/dist/util/crypto.js +25 -0
- package/dist/util/crypto.js.map +1 -0
- package/dist/util/frontmatter.js +70 -0
- package/dist/util/frontmatter.js.map +1 -0
- package/dist/util/fs-issues.js +22 -0
- package/dist/util/fs-issues.js.map +1 -0
- package/dist/util/process.js +152 -0
- package/dist/util/process.js.map +1 -0
- package/dist/util/workspace-key.js +10 -0
- package/dist/util/workspace-key.js.map +1 -0
- package/dist/workflow-loader.js +147 -0
- package/dist/workflow-loader.js.map +1 -0
- package/dist/workflow.js +656 -219
- package/dist/workflow.js.map +1 -1
- package/dist/workspace-types.js +8 -0
- package/dist/workspace-types.js.map +1 -0
- package/dist/workspace.js +367 -120
- package/dist/workspace.js.map +1 -1
- package/package.json +14 -6
- package/scripts/vm-agent.mjs +211 -0
- package/dist/agent/codex.js +0 -439
- package/dist/agent/codex.js.map +0 -1
- package/dist/agent/smolvm.js +0 -174
- package/dist/agent/smolvm.js.map +0 -1
- package/scripts/build-vm.sh +0 -67
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// VmProcessRegistry — tracks the backing host (qemu) process of every live
|
|
2
|
+
// Gondolin VM the orchestrator created, so a forced shutdown can SIGKILL them
|
|
3
|
+
// before `process.exit` (issue 152).
|
|
4
|
+
//
|
|
5
|
+
// WHY this exists. Symphony creates VMs *in-process* (`VM.create` runs in the
|
|
6
|
+
// orchestrator), so each qemu instance is a DIRECT CHILD of the symphony
|
|
7
|
+
// process. On `process.exit` those children are reparented to init and survive
|
|
8
|
+
// as orphaned `qemu-system-x86_64`. The Gondolin session registry can't help
|
|
9
|
+
// reap them on the forced path: it records the *creating* process's pid
|
|
10
|
+
// (symphony's own — see session-registry.js `pid: process.pid`), so a
|
|
11
|
+
// session-pid reaper either skips them (self-pid guard) or, worse, would target
|
|
12
|
+
// the orchestrator. The only reliable handle on the backing qemu is each VM's
|
|
13
|
+
// `getHostPid()` (the qemu `child.pid`), which is what this registry signals.
|
|
14
|
+
//
|
|
15
|
+
// Adapter-layer module: no domain imports. The minimal `KillableVm` shape is
|
|
16
|
+
// satisfied structurally by Gondolin's `VM`, so this stays free of the heavy
|
|
17
|
+
// Gondolin import and is unit-testable in isolation.
|
|
18
|
+
export class VmProcessRegistry {
|
|
19
|
+
live = new Set();
|
|
20
|
+
kill;
|
|
21
|
+
selfPid;
|
|
22
|
+
constructor(opts = {}) {
|
|
23
|
+
this.kill = opts.kill ?? ((pid, signal) => process.kill(pid, signal));
|
|
24
|
+
this.selfPid = opts.selfPid ?? process.pid;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register a live VM. Returns a deregister callback to invoke after a clean
|
|
28
|
+
* `close()` so the set stays bounded across many dispatches. Correctness does
|
|
29
|
+
* NOT depend on deregistration: once a VM's runner exits, `getHostPid()`
|
|
30
|
+
* returns null and {@link killAll} skips it, so a leaked entry can never
|
|
31
|
+
* signal a (possibly pid-reused) dead process.
|
|
32
|
+
*/
|
|
33
|
+
track(vm) {
|
|
34
|
+
this.live.add(vm);
|
|
35
|
+
return () => {
|
|
36
|
+
this.live.delete(vm);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* SIGKILL the backing host process of every tracked VM that still has a live
|
|
41
|
+
* runner pid. Synchronous and bounded (one signal per tracked VM, no IO), so
|
|
42
|
+
* the forced-shutdown path can call it and `process.exit` immediately without
|
|
43
|
+
* risking a hang. Best-effort: a VM with no live runner (`getHostPid → null`)
|
|
44
|
+
* is skipped, and ESRCH / any other signal failure is swallowed — a stuck pid
|
|
45
|
+
* must not wedge the forced exit. Returns the number of host pids targeted.
|
|
46
|
+
*/
|
|
47
|
+
killAll() {
|
|
48
|
+
const pids = safeKillTargets([...this.live].map((vm) => vm.getHostPid()), this.selfPid);
|
|
49
|
+
for (const pid of pids) {
|
|
50
|
+
try {
|
|
51
|
+
this.kill(pid, 'SIGKILL');
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// ESRCH (already gone) / EPERM / etc. — best-effort on the way out.
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return pids.length;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Pure: reduce candidate VM host pids (some unknown/null) to the distinct, safe
|
|
62
|
+
* set to SIGKILL — positive safe integers, never the caller's own pid (which
|
|
63
|
+
* `process.kill` would aim at the orchestrator) and never `<= 0` (which would
|
|
64
|
+
* signal a whole process group). Exported for direct testing.
|
|
65
|
+
*/
|
|
66
|
+
export function safeKillTargets(hostPids, selfPid) {
|
|
67
|
+
const out = new Set();
|
|
68
|
+
for (const pid of hostPids) {
|
|
69
|
+
if (pid === null || pid === undefined)
|
|
70
|
+
continue;
|
|
71
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
72
|
+
continue;
|
|
73
|
+
if (pid === selfPid)
|
|
74
|
+
continue;
|
|
75
|
+
out.add(pid);
|
|
76
|
+
}
|
|
77
|
+
return [...out];
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=vm-process-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-process-registry.js","sourceRoot":"","sources":["../../src/agent/vm-process-registry.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,wEAAwE;AACxE,sEAAsE;AACtE,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,qDAAqD;AAmBrD,MAAM,OAAO,iBAAiB;IACX,IAAI,GAAG,IAAI,GAAG,EAAc,CAAC;IAC7B,IAAI,CAAoD;IACxD,OAAO,CAAS;IAEjC,YAAY,OAAiC,EAAE;QAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC;IAC7C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,EAAc;QAClB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,OAAO;QACL,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,oEAAoE;YACtE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA0C,EAC1C,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,SAAS;QACrD,IAAI,GAAG,KAAK,OAAO;YAAE,SAAS;QAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// CLI argument parsing for the `symphony` binary. Lives in its own module so
|
|
2
|
+
// tests can import `parseCli` without triggering the `main()` side effects of
|
|
3
|
+
// `src/bin/symphony.ts` (HTTP/ACP listeners, tracker init, etc.) at import
|
|
4
|
+
// time.
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
export function parseCli(argv) {
|
|
8
|
+
// Detect subcommands. `reconcile` and `rerun` share the parsed-args
|
|
9
|
+
// skeleton with the default `serve` mode; the subcommand is what differs
|
|
10
|
+
// at the action layer (main() dispatches accordingly). Preserve the
|
|
11
|
+
// subcommand verbatim in the return value — collapsing `reconcile` back to
|
|
12
|
+
// `serve` would let the missing-workflow scaffold prompt fire on a
|
|
13
|
+
// `symphony reconcile` invocation, which has nothing to scaffold against.
|
|
14
|
+
let subcommand = 'serve';
|
|
15
|
+
let rest = argv;
|
|
16
|
+
if (argv[0] === 'reconcile') {
|
|
17
|
+
subcommand = 'reconcile';
|
|
18
|
+
rest = argv.slice(1);
|
|
19
|
+
}
|
|
20
|
+
else if (argv[0] === 'rerun') {
|
|
21
|
+
subcommand = 'rerun';
|
|
22
|
+
rest = argv.slice(1);
|
|
23
|
+
}
|
|
24
|
+
let workflow = null;
|
|
25
|
+
let port = null;
|
|
26
|
+
let reconcileForce = false;
|
|
27
|
+
let rerunCheck = null;
|
|
28
|
+
let verbose = false;
|
|
29
|
+
for (let i = 0; i < rest.length; i++) {
|
|
30
|
+
const a = rest[i];
|
|
31
|
+
if (a === '--port' || a === '-p') {
|
|
32
|
+
const v = rest[++i];
|
|
33
|
+
if (!v) {
|
|
34
|
+
process.stderr.write(`error: --port requires a value\n`);
|
|
35
|
+
process.exit(2);
|
|
36
|
+
}
|
|
37
|
+
const n = parseInt(v, 10);
|
|
38
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
39
|
+
process.stderr.write(`error: invalid --port value: ${v}\n`);
|
|
40
|
+
process.exit(2);
|
|
41
|
+
}
|
|
42
|
+
port = n;
|
|
43
|
+
}
|
|
44
|
+
else if (a.startsWith('--port=')) {
|
|
45
|
+
const n = parseInt(a.slice('--port='.length), 10);
|
|
46
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
47
|
+
process.stderr.write(`error: invalid --port value: ${a}\n`);
|
|
48
|
+
process.exit(2);
|
|
49
|
+
}
|
|
50
|
+
port = n;
|
|
51
|
+
}
|
|
52
|
+
else if (subcommand === 'reconcile' && a === '--force') {
|
|
53
|
+
reconcileForce = true;
|
|
54
|
+
}
|
|
55
|
+
else if (a === '--reconcile-force') {
|
|
56
|
+
// Top-level alias for `reconcile --force`. Kept so existing invocations and
|
|
57
|
+
// process-manager unit files don't need rewriting; the new canonical shape is
|
|
58
|
+
// `symphony reconcile --force [path]`.
|
|
59
|
+
reconcileForce = true;
|
|
60
|
+
}
|
|
61
|
+
else if (subcommand === 'rerun' && (a === '--check' || a === '-c')) {
|
|
62
|
+
const v = rest[++i];
|
|
63
|
+
if (!v) {
|
|
64
|
+
process.stderr.write(`error: --check requires a value\n`);
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
67
|
+
rerunCheck = v;
|
|
68
|
+
}
|
|
69
|
+
else if (subcommand === 'rerun' && a.startsWith('--check=')) {
|
|
70
|
+
rerunCheck = a.slice('--check='.length);
|
|
71
|
+
}
|
|
72
|
+
else if (a === '--verbose' || a === '-v' || a === '--foreground') {
|
|
73
|
+
verbose = true;
|
|
74
|
+
}
|
|
75
|
+
else if (a === '-h' || a === '--help') {
|
|
76
|
+
process.stdout.write(`symphony [path-to-WORKFLOW.md] [--port PORT] [--reconcile-force] [--verbose]\n` +
|
|
77
|
+
`symphony reconcile [path-to-WORKFLOW.md] [--force] [--port PORT]\n` +
|
|
78
|
+
`symphony rerun --check=<name> [path-to-WORKFLOW.md]\n\n` +
|
|
79
|
+
`If path is omitted, ./WORKFLOW.md is used.\n` +
|
|
80
|
+
`\`reconcile --force\` (or the alias \`--reconcile-force\`) requests an\n` +
|
|
81
|
+
`immediate reconcile pass (VM / workspace / PR janitors) at startup.\n` +
|
|
82
|
+
`\`rerun --check=<name>\` invalidates the named run_in_vm action's content-hash\n` +
|
|
83
|
+
`cache entry so the next dispatch into its state re-executes it.\n` +
|
|
84
|
+
`\`--verbose\` (alias \`--foreground\`, \`-v\`) mirrors structured logs to the\n` +
|
|
85
|
+
`console; by default they go to the log file only so the console stays clean.\n`);
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
else if (!workflow) {
|
|
89
|
+
workflow = a;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
process.stderr.write(`error: unexpected argument: ${a}\n`);
|
|
93
|
+
process.exit(2);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
subcommand,
|
|
98
|
+
workflow: workflow ?? path.resolve(process.cwd(), 'WORKFLOW.md'),
|
|
99
|
+
port,
|
|
100
|
+
reconcileForce,
|
|
101
|
+
rerunCheck,
|
|
102
|
+
verbose,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=cli-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-args.js","sourceRoot":"","sources":["../../src/bin/cli-args.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,QAAQ;AAER,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AAenC,MAAM,UAAU,QAAQ,CAAC,IAAc;IACrC,oEAAoE;IACpE,yEAAyE;IACzE,oEAAoE;IACpE,2EAA2E;IAC3E,mEAAmE;IACnE,0EAA0E;IAC1E,IAAI,UAAU,GAAoC,OAAO,CAAC;IAC1D,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC;QAC5B,UAAU,GAAG,WAAW,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;SAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;QAC/B,UAAU,GAAG,OAAO,CAAC;QACrB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,CAAC,EAAE,CAAC;gBACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,CAAC,CAAC;gBAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,IAAI,CAAC,CAAC;gBAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;aAAM,IAAI,UAAU,KAAK,WAAW,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACzD,cAAc,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,IAAI,CAAC,KAAK,mBAAmB,EAAE,CAAC;YACrC,4EAA4E;YAC5E,8EAA8E;YAC9E,uCAAuC;YACvC,cAAc,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,IAAI,UAAU,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,CAAC,EAAE,CAAC;gBACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,UAAU,GAAG,CAAC,CAAC;QACjB,CAAC;aAAM,IAAI,UAAU,KAAK,OAAO,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9D,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,cAAc,EAAE,CAAC;YACnE,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gFAAgF;gBAC9E,oEAAoE;gBACpE,yDAAyD;gBACzD,8CAA8C;gBAC9C,0EAA0E;gBAC1E,uEAAuE;gBACvE,kFAAkF;gBAClF,mEAAmE;gBACnE,iFAAiF;gBACjF,gFAAgF,CACnF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,GAAG,CAAC,CAAC;QACf,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,IAAI,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO;QACL,UAAU;QACV,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC;QAChE,IAAI;QACJ,cAAc;QACd,UAAU;QACV,OAAO;KACR,CAAC;AACJ,CAAC"}
|