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.
- package/README.md +3 -3
- package/assets/agent-files/json/antigravity-hooks.fragment.json +11 -0
- package/assets/agent-files/scripts/antigravity-hook.mjs +133 -0
- package/dist/application/context/project/init/AgentSelection.d.ts +1 -1
- package/dist/application/context/project/init/AgentSelection.d.ts.map +1 -1
- package/dist/infrastructure/agents/AgentCliGateway.d.ts +1 -1
- package/dist/infrastructure/agents/AgentCliGateway.d.ts.map +1 -1
- package/dist/infrastructure/agents/AgentCliGateway.js +2 -2
- package/dist/infrastructure/agents/AgentCliGateway.js.map +1 -1
- package/dist/infrastructure/context/project/init/AgentFileProtocol.js +2 -2
- package/dist/infrastructure/context/project/init/AgentFileProtocol.js.map +1 -1
- package/dist/infrastructure/context/project/init/AntigravityConfigurer.d.ts +44 -0
- package/dist/infrastructure/context/project/init/AntigravityConfigurer.d.ts.map +1 -0
- package/dist/infrastructure/context/project/init/AntigravityConfigurer.js +280 -0
- package/dist/infrastructure/context/project/init/AntigravityConfigurer.js.map +1 -0
- package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.d.ts +35 -0
- package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.d.ts.map +1 -0
- package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.js +105 -0
- package/dist/infrastructure/context/project/init/SafeAntigravityHooksMerger.js.map +1 -0
- package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.d.ts.map +1 -1
- package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.js +6 -0
- package/dist/presentation/cli/commands/goals/start/GoalStartOutputBuilder.js.map +1 -1
- package/dist/presentation/cli/commands/work/shared/AgentSpawner.d.ts +1 -1
- package/dist/presentation/cli/commands/work/shared/AgentSpawner.d.ts.map +1 -1
- package/dist/presentation/cli/commands/work/shared/AgentSpawner.js +2 -2
- package/dist/presentation/cli/commands/work/shared/AgentSpawner.js.map +1 -1
- package/dist/presentation/cli/output/HookOutput.d.ts +1 -1
- package/dist/presentation/tui/cockpit/CockpitDaemonAgentConfigCycler.js +1 -1
- package/dist/presentation/tui/cockpit/CockpitDaemonAgentConfigCycler.js.map +1 -1
- package/dist/presentation/tui/project-initialization/Constants.d.ts +1 -1
- package/dist/presentation/tui/project-initialization/Constants.js +1 -1
- package/dist/presentation/tui/project-initialization/Constants.js.map +1 -1
- package/dist/presentation/tui/project-initialization/InitFlow.js +3 -3
- package/dist/presentation/tui/project-initialization/InitFlow.js.map +1 -1
- package/package.json +1 -1
- package/assets/agent-files/json/gemini-settings.fragment.json +0 -41
- package/assets/gemini-logo.svg +0 -1
- package/dist/infrastructure/context/project/init/GeminiConfigurer.d.ts +0 -45
- package/dist/infrastructure/context/project/init/GeminiConfigurer.d.ts.map +0 -1
- package/dist/infrastructure/context/project/init/GeminiConfigurer.js +0 -126
- package/dist/infrastructure/context/project/init/GeminiConfigurer.js.map +0 -1
- package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.d.ts +0 -75
- package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.d.ts.map +0 -1
- package/dist/infrastructure/context/project/init/SafeGeminiSettingsMerger.js +0 -150
- 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":"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"}
|