jumbo-cli 3.14.0 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +3 -3
  2. package/assets/agent-files/json/antigravity-hooks.fragment.json +11 -0
  3. package/assets/agent-files/scripts/antigravity-hook.mjs +133 -0
  4. package/dist/application/context/project/init/AgentSelection.d.ts +1 -1
  5. package/dist/application/context/project/init/AgentSelection.d.ts.map +1 -1
  6. package/dist/infrastructure/agents/AgentCliGateway.d.ts +1 -1
  7. package/dist/infrastructure/agents/AgentCliGateway.d.ts.map +1 -1
  8. package/dist/infrastructure/agents/AgentCliGateway.js +2 -2
  9. package/dist/infrastructure/agents/AgentCliGateway.js.map +1 -1
  10. package/dist/infrastructure/context/project/init/AgentFileProtocol.js +2 -2
  11. package/dist/infrastructure/context/project/init/AgentFileProtocol.js.map +1 -1
  12. package/dist/infrastructure/context/project/init/AntigravityConfigurer.d.ts +44 -0
  13. package/dist/infrastructure/context/project/init/AntigravityConfigurer.d.ts.map +1 -0
  14. package/dist/infrastructure/context/project/init/AntigravityConfigurer.js +280 -0
  15. package/dist/infrastructure/context/project/init/AntigravityConfigurer.js.map +1 -0
  16. package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.d.ts +35 -0
  17. package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.d.ts.map +1 -0
  18. package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.js +105 -0
  19. package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.js.map +1 -0
  20. package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.d.ts.map +1 -1
  21. package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.js +6 -0
  22. package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.js.map +1 -1
  23. package/dist/presentation/cli/commands/work/shared/AgentSpawner.d.ts +1 -1
  24. package/dist/presentation/cli/commands/work/shared/AgentSpawner.d.ts.map +1 -1
  25. package/dist/presentation/cli/commands/work/shared/AgentSpawner.js +2 -2
  26. package/dist/presentation/cli/commands/work/shared/AgentSpawner.js.map +1 -1
  27. package/dist/presentation/cli/output/HookOutput.d.ts +1 -1
  28. package/dist/presentation/tui/cockpit/CockpitDaemonAgentConfigCycler.js +1 -1
  29. package/dist/presentation/tui/cockpit/CockpitDaemonAgentConfigCycler.js.map +1 -1
  30. package/dist/presentation/tui/project-initialization/Constants.d.ts +1 -1
  31. package/dist/presentation/tui/project-initialization/Constants.js +1 -1
  32. package/dist/presentation/tui/project-initialization/Constants.js.map +1 -1
  33. package/dist/presentation/tui/project-initialization/InitFlow.js +3 -3
  34. package/dist/presentation/tui/project-initialization/InitFlow.js.map +1 -1
  35. package/package.json +1 -1
  36. package/assets/agent-files/json/gemini-settings.fragment.json +0 -41
  37. package/assets/gemini-logo.svg +0 -1
  38. package/dist/infrastructure/context/project/init/GeminiConfigurer.d.ts +0 -45
  39. package/dist/infrastructure/context/project/init/GeminiConfigurer.d.ts.map +0 -1
  40. package/dist/infrastructure/context/project/init/GeminiConfigurer.js +0 -126
  41. package/dist/infrastructure/context/project/init/GeminiConfigurer.js.map +0 -1
  42. package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.d.ts +0 -75
  43. package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.d.ts.map +0 -1
  44. package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.js +0 -150
  45. package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.js.map +0 -1
@@ -1,126 +0,0 @@
1
- /**
2
- * Infrastructure: Gemini CLI Configurer
3
- *
4
- * Encapsulates all knowledge about Gemini CLI configuration:
5
- * - GEMINI.md with thin reference to JUMBO.md
6
- * - .gemini/settings.json with SessionStart hooks
7
- *
8
- * Operations are idempotent and gracefully handle errors.
9
- */
10
- import path from "path";
11
- import fs from "fs-extra";
12
- import { AgentFileReferenceContent } from "../../../../domain/project/AgentFileReferenceContent.js";
13
- import { AgentFileAssetContent } from "../../../../domain/project/AgentFileAssetContent.js";
14
- import { SafeGeminiSettingsMerger } from "./SafeGeminiSettingsMerger.js";
15
- export class GeminiConfigurer {
16
- constructor() {
17
- this.agent = {
18
- id: "gemini",
19
- name: "Gemini",
20
- };
21
- this.skillPlatforms = [".gemini/skills"];
22
- }
23
- /**
24
- * Configure all Gemini CLI requirements for Jumbo
25
- *
26
- * @param projectRoot Absolute path to project root directory
27
- */
28
- async configure(projectRoot) {
29
- await this.ensureGeminiMd(projectRoot);
30
- await this.ensureGeminiSettings(projectRoot);
31
- }
32
- /**
33
- * Ensure GEMINI.md exists with thin reference to JUMBO.md
34
- */
35
- async ensureGeminiMd(projectRoot) {
36
- const geminiMdPath = path.join(projectRoot, "GEMINI.md");
37
- const reference = AgentFileReferenceContent.getAgentFileReference("GEMINI.md");
38
- try {
39
- const exists = await fs.pathExists(geminiMdPath);
40
- if (!exists) {
41
- await fs.writeFile(geminiMdPath, reference, "utf-8");
42
- return;
43
- }
44
- // File exists - check if reference is present
45
- const content = await fs.readFile(geminiMdPath, "utf-8");
46
- if (!content.includes("JUMBO.md")) {
47
- // Reference missing - append it
48
- const updatedContent = content.trimEnd() + "\n\n" + reference;
49
- await fs.writeFile(geminiMdPath, updatedContent, "utf-8");
50
- }
51
- // else: Reference already present - no-op
52
- }
53
- catch (error) {
54
- // Graceful degradation - log but don't throw
55
- console.warn(`Warning: Failed to update GEMINI.md: ${error instanceof Error ? error.message : String(error)}`);
56
- }
57
- }
58
- /**
59
- * Ensure Gemini CLI hooks are configured in .gemini/settings.json
60
- */
61
- async ensureGeminiSettings(projectRoot) {
62
- try {
63
- const jumboSettings = AgentFileAssetContent.readJson("gemini-settings.fragment.json");
64
- await SafeGeminiSettingsMerger.mergeSettings(projectRoot, jumboSettings);
65
- }
66
- catch (error) {
67
- // Graceful degradation - log but don't throw
68
- console.warn(`Warning: Failed to configure Gemini CLI hooks: ${error instanceof Error ? error.message : String(error)}`);
69
- }
70
- }
71
- /**
72
- * Repair Gemini CLI configuration by replacing stale content
73
- */
74
- async repair(projectRoot) {
75
- await this.repairGeminiMd(projectRoot);
76
- await this.ensureGeminiSettings(projectRoot);
77
- }
78
- /**
79
- * Repair GEMINI.md by replacing the reference with the current thin reference
80
- */
81
- async repairGeminiMd(projectRoot) {
82
- const geminiMdPath = path.join(projectRoot, "GEMINI.md");
83
- const reference = AgentFileReferenceContent.getAgentFileReference("GEMINI.md");
84
- try {
85
- const exists = await fs.pathExists(geminiMdPath);
86
- if (!exists) {
87
- await fs.writeFile(geminiMdPath, reference, "utf-8");
88
- return;
89
- }
90
- const content = await fs.readFile(geminiMdPath, "utf-8");
91
- const replaced = AgentFileReferenceContent.replaceAgentFileReference(content, "GEMINI.md");
92
- if (replaced !== null) {
93
- // Legacy reference block found - replace entire file with new thin reference
94
- await fs.writeFile(geminiMdPath, replaced, "utf-8");
95
- }
96
- else if (!content.includes("JUMBO.md")) {
97
- // No reference at all - append
98
- const updatedContent = content.trimEnd() + "\n\n" + reference;
99
- await fs.writeFile(geminiMdPath, updatedContent, "utf-8");
100
- }
101
- }
102
- catch (error) {
103
- console.warn(`Warning: Failed to repair GEMINI.md: ${error instanceof Error ? error.message : String(error)}`);
104
- }
105
- }
106
- /**
107
- * Return what changes this configurer will make without executing.
108
- */
109
- async getPlannedFileChanges(projectRoot) {
110
- const changes = [];
111
- const geminiMdPath = path.join(projectRoot, "GEMINI.md");
112
- changes.push({
113
- path: "GEMINI.md",
114
- action: (await fs.pathExists(geminiMdPath)) ? "modify" : "create",
115
- description: "Add Jumbo instructions",
116
- });
117
- const settingsPath = path.join(projectRoot, ".gemini/settings.json");
118
- changes.push({
119
- path: ".gemini/settings.json",
120
- action: (await fs.pathExists(settingsPath)) ? "modify" : "create",
121
- description: "Add hook configuration and permissions",
122
- });
123
- return changes;
124
- }
125
- }
126
- //# sourceMappingURL=GeminiConfigurer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"GeminiConfigurer.js","sourceRoot":"","sources":["../../../../../src/infrastructure/context/project/init/GeminiConfigurer.ts"],"names":[],"mappings":"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"}
@@ -1,75 +0,0 @@
1
- /**
2
- * Gemini CLI settings structure
3
- * Based on Gemini CLI hooks configuration
4
- */
5
- export interface GeminiCommandHook {
6
- type: "command";
7
- command: string;
8
- }
9
- export interface GeminiPromptHook {
10
- type: "prompt";
11
- prompt: string;
12
- }
13
- export type GeminiHook = GeminiCommandHook | GeminiPromptHook;
14
- export interface GeminiHookMatcher {
15
- matcher: string;
16
- hooks: GeminiHook[];
17
- }
18
- export interface GeminiSettings {
19
- hooks?: {
20
- SessionStart?: GeminiHookMatcher[];
21
- PreCompress?: GeminiHookMatcher[];
22
- SessionEnd?: GeminiHookMatcher[];
23
- [key: string]: GeminiHookMatcher[] | undefined;
24
- };
25
- tools?: {
26
- allowed?: string[];
27
- };
28
- }
29
- /**
30
- * Safe merger for Gemini CLI settings.json files
31
- *
32
- * Strategy:
33
- * - Creates backup before modification
34
- * - Deep merges objects, deduplicates arrays
35
- * - Lenient with existing user config (may have extensions or typos)
36
- * - Rolls back on error
37
- * - Idempotent (safe to run multiple times)
38
- *
39
- * @example
40
- * await SafeGeminiSettingsMerger.mergeSettings(projectRoot, {
41
- * hooks: {
42
- * SessionStart: [{
43
- * matcher: "startup",
44
- * hooks: [{ type: "command", command: "jumbo session start" }]
45
- * }]
46
- * }
47
- * });
48
- */
49
- export declare class SafeGeminiSettingsMerger {
50
- /**
51
- * Merges new settings into existing .gemini/settings.json
52
- *
53
- * @param projectRoot - Root directory of the project
54
- * @param newSettings - Settings to merge in
55
- * @throws Error if JSON is malformed
56
- */
57
- static mergeSettings(projectRoot: string, newSettings: GeminiSettings): Promise<void>;
58
- /**
59
- * Deep merges two settings objects
60
- * - Objects are merged recursively
61
- * - Arrays are deduplicated based on content
62
- * - Existing user settings are preserved
63
- */
64
- private static deepMerge;
65
- /**
66
- * Merges hook matcher arrays, deduplicating by hook content
67
- */
68
- private static mergeHookMatchers;
69
- /**
70
- * Generate a unique key for a hook based on its type and content
71
- * Handles malformed hooks gracefully by including all available properties
72
- */
73
- private static getHookKey;
74
- }
75
- //# sourceMappingURL=SafeGeminiSettingsMerger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SafeGeminiSettingsMerger.d.ts","sourceRoot":"","sources":["../../../../../src/infrastructure/context/project/init/SafeGeminiSettingsMerger.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACnC,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAClC,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACjC,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;KAChD,CAAC;IACF,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,wBAAwB;IACnC;;;;;;OAMG;WACU,aAAa,CACxB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,GAC1B,OAAO,CAAC,IAAI,CAAC;IA+ChB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAqCxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAwChC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAY1B"}
@@ -1,150 +0,0 @@
1
- import fs from "fs-extra";
2
- import * as path from "path";
3
- /**
4
- * Safe merger for Gemini CLI settings.json files
5
- *
6
- * Strategy:
7
- * - Creates backup before modification
8
- * - Deep merges objects, deduplicates arrays
9
- * - Lenient with existing user config (may have extensions or typos)
10
- * - Rolls back on error
11
- * - Idempotent (safe to run multiple times)
12
- *
13
- * @example
14
- * await SafeGeminiSettingsMerger.mergeSettings(projectRoot, {
15
- * hooks: {
16
- * SessionStart: [{
17
- * matcher: "startup",
18
- * hooks: [{ type: "command", command: "jumbo session start" }]
19
- * }]
20
- * }
21
- * });
22
- */
23
- export class SafeGeminiSettingsMerger {
24
- /**
25
- * Merges new settings into existing .gemini/settings.json
26
- *
27
- * @param projectRoot - Root directory of the project
28
- * @param newSettings - Settings to merge in
29
- * @throws Error if JSON is malformed
30
- */
31
- static async mergeSettings(projectRoot, newSettings) {
32
- const settingsPath = path.join(projectRoot, ".gemini", "settings.json");
33
- const backupPath = `${settingsPath}.backup.${Date.now()}`;
34
- // Ensure .gemini directory exists
35
- await fs.ensureDir(path.join(projectRoot, ".gemini"));
36
- // STEP 1: Create backup if file exists
37
- if (await fs.pathExists(settingsPath)) {
38
- await fs.copy(settingsPath, backupPath);
39
- }
40
- try {
41
- // STEP 2: Read existing or use empty object
42
- // Be lenient with existing user content - only parse JSON, don't validate structure
43
- // User's config may have extensions or typos we shouldn't reject
44
- let existing = {};
45
- if (await fs.pathExists(settingsPath)) {
46
- const content = await fs.readFile(settingsPath, "utf-8");
47
- // Handle empty file case - treat as empty config
48
- if (content.trim()) {
49
- existing = JSON.parse(content);
50
- }
51
- }
52
- // STEP 3: Merge safely
53
- const merged = this.deepMerge(existing, newSettings);
54
- // STEP 4: Write back with formatting
55
- // Skip validation - user's config may have extensions or typos we should preserve
56
- await fs.writeFile(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
57
- // STEP 5: Cleanup backup on success (optional - keep for audit trail)
58
- // await fs.remove(backupPath);
59
- }
60
- catch (error) {
61
- // STEP 6: Rollback on error
62
- if (await fs.pathExists(backupPath)) {
63
- await fs.copy(backupPath, settingsPath, { overwrite: true });
64
- }
65
- throw error;
66
- }
67
- }
68
- /**
69
- * Deep merges two settings objects
70
- * - Objects are merged recursively
71
- * - Arrays are deduplicated based on content
72
- * - Existing user settings are preserved
73
- */
74
- static deepMerge(existing, newSettings) {
75
- const result = { ...existing };
76
- // Merge hooks - handle all event types generically
77
- if (newSettings.hooks) {
78
- result.hooks = result.hooks ?? {};
79
- for (const eventType of Object.keys(newSettings.hooks)) {
80
- const newHooks = newSettings.hooks[eventType];
81
- if (newHooks) {
82
- const existingHooks = existing.hooks?.[eventType] ?? [];
83
- result.hooks[eventType] = this.mergeHookMatchers(existingHooks, newHooks);
84
- }
85
- }
86
- }
87
- // Merge tools
88
- if (newSettings.tools) {
89
- result.tools = result.tools ?? {};
90
- // Merge allowed array (unique values)
91
- if (newSettings.tools.allowed) {
92
- const existingAllowed = existing.tools?.allowed ?? [];
93
- const newAllowed = newSettings.tools.allowed;
94
- result.tools.allowed = Array.from(new Set([...existingAllowed, ...newAllowed]));
95
- }
96
- }
97
- return result;
98
- }
99
- /**
100
- * Merges hook matcher arrays, deduplicating by hook content
101
- */
102
- static mergeHookMatchers(existing, additions) {
103
- const merged = [...existing];
104
- for (const newMatcher of additions) {
105
- // Find existing matcher with same matcher type
106
- const existingIndex = merged.findIndex((m) => m.matcher === newMatcher.matcher);
107
- if (existingIndex >= 0) {
108
- // Merge hooks within the same matcher, deduplicating by content
109
- const existingMatcher = merged[existingIndex];
110
- const hookMap = new Map();
111
- // Add existing hooks - key by unique content
112
- for (const hook of existingMatcher.hooks) {
113
- hookMap.set(this.getHookKey(hook), hook);
114
- }
115
- // Add new hooks (overwrites if same key)
116
- for (const hook of newMatcher.hooks) {
117
- hookMap.set(this.getHookKey(hook), hook);
118
- }
119
- merged[existingIndex] = {
120
- ...existingMatcher,
121
- hooks: Array.from(hookMap.values()),
122
- };
123
- }
124
- else {
125
- // No existing matcher with this type, add it
126
- merged.push(newMatcher);
127
- }
128
- }
129
- return merged;
130
- }
131
- /**
132
- * Generate a unique key for a hook based on its type and content
133
- * Handles malformed hooks gracefully by including all available properties
134
- */
135
- static getHookKey(hook) {
136
- // Handle malformed hooks that might have mismatched type/content
137
- const anyHook = hook;
138
- if (hook.type === "command" && typeof anyHook.command === "string") {
139
- return `command:${anyHook.command}`;
140
- }
141
- else if (hook.type === "prompt" && typeof anyHook.prompt === "string") {
142
- return `prompt:${anyHook.prompt}`;
143
- }
144
- else {
145
- // Fallback for malformed hooks - use JSON serialization for uniqueness
146
- return `unknown:${JSON.stringify(hook)}`;
147
- }
148
- }
149
- }
150
- //# sourceMappingURL=SafeGeminiSettingsMerger.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SafeGeminiSettingsMerger.js","sourceRoot":"","sources":["../../../../../src/infrastructure/context/project/init/SafeGeminiSettingsMerger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAmC7B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,wBAAwB;IACnC;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CACxB,WAAmB,EACnB,WAA2B;QAE3B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QACxE,MAAM,UAAU,GAAG,GAAG,YAAY,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAE1D,kCAAkC;QAClC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;QAEtD,uCAAuC;QACvC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACtC,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,CAAC;YACH,4CAA4C;YAC5C,oFAAoF;YACpF,iEAAiE;YACjE,IAAI,QAAQ,GAAmB,EAAE,CAAC;YAClC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACzD,iDAAiD;gBACjD,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;oBACnB,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACjC,CAAC;YACH,CAAC;YAED,uBAAuB;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAErD,qCAAqC;YACrC,kFAAkF;YAClF,MAAM,EAAE,CAAC,SAAS,CAChB,YAAY,EACZ,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,OAAO,CACR,CAAC;YAEF,sEAAsE;YACtE,+BAA+B;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,4BAA4B;YAC5B,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAC,SAAS,CACtB,QAAwB,EACxB,WAA2B;QAE3B,MAAM,MAAM,GAAmB,EAAE,GAAG,QAAQ,EAAE,CAAC;QAE/C,mDAAmD;QACnD,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAElC,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvD,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBAC9C,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;oBACxD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAC9C,aAAa,EACb,QAAQ,CACT,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAElC,sCAAsC;YACtC,IAAI,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC9B,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;gBACtD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;gBAC7C,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,iBAAiB,CAC9B,QAA6B,EAC7B,SAA8B;QAE9B,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;QAE7B,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;YACnC,+CAA+C;YAC/C,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,CACxC,CAAC;YAEF,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;gBACvB,gEAAgE;gBAChE,MAAM,eAAe,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;gBAC9C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;gBAE9C,6CAA6C;gBAC7C,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC;oBACzC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC3C,CAAC;gBAED,yCAAyC;gBACzC,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;oBACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC3C,CAAC;gBAED,MAAM,CAAC,aAAa,CAAC,GAAG;oBACtB,GAAG,eAAe;oBAClB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;iBACpC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,6CAA6C;gBAC7C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,UAAU,CAAC,IAAgB;QACxC,iEAAiE;QACjE,MAAM,OAAO,GAAG,IAA0C,CAAC;QAC3D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACnE,OAAO,WAAW,OAAO,CAAC,OAAO,EAAE,CAAC;QACtC,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxE,OAAO,UAAU,OAAO,CAAC,MAAM,EAAE,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,uEAAuE;YACvE,OAAO,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,CAAC;IACH,CAAC;CACF"}