wave-agent-sdk 0.0.7 → 0.0.8
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/dist/agent.d.ts +32 -20
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +202 -20
- package/dist/constants/events.d.ts +28 -0
- package/dist/constants/events.d.ts.map +1 -0
- package/dist/constants/events.js +27 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/managers/aiManager.d.ts +34 -1
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +243 -128
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +7 -6
- package/dist/managers/hookManager.d.ts +9 -4
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +62 -30
- package/dist/managers/liveConfigManager.d.ts +58 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -0
- package/dist/managers/liveConfigManager.js +160 -0
- package/dist/managers/messageManager.d.ts +38 -13
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +163 -30
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +4 -1
- package/dist/managers/subagentManager.d.ts +51 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +189 -18
- package/dist/services/aiService.d.ts +13 -5
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +350 -74
- package/dist/services/configurationWatcher.d.ts +120 -0
- package/dist/services/configurationWatcher.d.ts.map +1 -0
- package/dist/services/configurationWatcher.js +439 -0
- package/dist/services/fileWatcher.d.ts +69 -0
- package/dist/services/fileWatcher.d.ts.map +1 -0
- package/dist/services/fileWatcher.js +213 -0
- package/dist/services/hook.d.ts +91 -9
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +393 -43
- package/dist/services/jsonlHandler.d.ts +62 -0
- package/dist/services/jsonlHandler.d.ts.map +1 -0
- package/dist/services/jsonlHandler.js +257 -0
- package/dist/services/memory.d.ts +9 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +81 -12
- package/dist/services/memoryStore.d.ts +81 -0
- package/dist/services/memoryStore.d.ts.map +1 -0
- package/dist/services/memoryStore.js +200 -0
- package/dist/services/session.d.ts +64 -49
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +310 -132
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +5 -4
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +2 -1
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +3 -2
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +4 -3
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +2 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +5 -6
- package/dist/types/commands.d.ts +4 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/core.d.ts +35 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +42 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +21 -0
- package/dist/types/hooks.d.ts +8 -2
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +8 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/memoryStore.d.ts +82 -0
- package/dist/types/memoryStore.d.ts.map +1 -0
- package/dist/types/memoryStore.js +7 -0
- package/dist/types/messaging.d.ts +14 -2
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/session.d.ts +20 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +7 -0
- package/dist/utils/bashHistory.d.ts.map +1 -1
- package/dist/utils/bashHistory.js +27 -26
- package/dist/utils/cacheControlUtils.d.ts +121 -0
- package/dist/utils/cacheControlUtils.d.ts.map +1 -0
- package/dist/utils/cacheControlUtils.js +367 -0
- package/dist/utils/commandPathResolver.d.ts +52 -0
- package/dist/utils/commandPathResolver.d.ts.map +1 -0
- package/dist/utils/commandPathResolver.js +145 -0
- package/dist/utils/configPaths.d.ts +85 -0
- package/dist/utils/configPaths.d.ts.map +1 -0
- package/dist/utils/configPaths.js +121 -0
- package/dist/utils/configResolver.d.ts +37 -10
- package/dist/utils/configResolver.d.ts.map +1 -1
- package/dist/utils/configResolver.js +127 -23
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +7 -5
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +66 -21
- package/dist/utils/fileUtils.d.ts +15 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +61 -0
- package/dist/utils/globalLogger.d.ts +102 -0
- package/dist/utils/globalLogger.d.ts.map +1 -0
- package/dist/utils/globalLogger.js +136 -0
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +25 -3
- package/dist/utils/messageOperations.d.ts +20 -8
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +25 -16
- package/dist/utils/pathEncoder.d.ts +104 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -0
- package/dist/utils/pathEncoder.js +272 -0
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +2 -1
- package/dist/utils/tokenCalculation.d.ts +26 -0
- package/dist/utils/tokenCalculation.d.ts.map +1 -0
- package/dist/utils/tokenCalculation.js +36 -0
- package/package.json +6 -3
- package/src/agent.ts +298 -34
- package/src/constants/events.ts +38 -0
- package/src/index.ts +2 -0
- package/src/managers/aiManager.ts +323 -170
- package/src/managers/backgroundBashManager.ts +7 -6
- package/src/managers/hookManager.ts +83 -40
- package/src/managers/liveConfigManager.ts +248 -0
- package/src/managers/messageManager.ts +230 -63
- package/src/managers/slashCommandManager.ts +4 -1
- package/src/managers/subagentManager.ts +283 -21
- package/src/services/aiService.ts +474 -83
- package/src/services/configurationWatcher.ts +622 -0
- package/src/services/fileWatcher.ts +301 -0
- package/src/services/hook.ts +538 -47
- package/src/services/jsonlHandler.ts +319 -0
- package/src/services/memory.ts +92 -12
- package/src/services/memoryStore.ts +279 -0
- package/src/services/session.ts +381 -157
- package/src/tools/bashTool.ts +5 -4
- package/src/tools/deleteFileTool.ts +2 -1
- package/src/tools/editTool.ts +3 -2
- package/src/tools/multiEditTool.ts +4 -3
- package/src/tools/readTool.ts +2 -1
- package/src/tools/writeTool.ts +7 -6
- package/src/types/commands.ts +6 -0
- package/src/types/core.ts +44 -0
- package/src/types/environment.ts +60 -0
- package/src/types/hooks.ts +21 -8
- package/src/types/index.ts +2 -0
- package/src/types/memoryStore.ts +94 -0
- package/src/types/messaging.ts +14 -2
- package/src/types/session.ts +25 -0
- package/src/utils/bashHistory.ts +27 -27
- package/src/utils/cacheControlUtils.ts +540 -0
- package/src/utils/commandPathResolver.ts +189 -0
- package/src/utils/configPaths.ts +163 -0
- package/src/utils/configResolver.ts +182 -22
- package/src/utils/constants.ts +1 -1
- package/src/utils/convertMessagesForAPI.ts +7 -5
- package/src/utils/customCommands.ts +90 -22
- package/src/utils/fileUtils.ts +65 -0
- package/src/utils/globalLogger.ts +145 -0
- package/src/utils/mcpUtils.ts +34 -3
- package/src/utils/messageOperations.ts +42 -20
- package/src/utils/pathEncoder.ts +379 -0
- package/src/utils/subagentParser.ts +2 -1
- package/src/utils/tokenCalculation.ts +43 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
+
import { logger } from "../utils/globalLogger.js";
|
|
2
3
|
import type { BackgroundShell } from "../types/index.js";
|
|
3
4
|
|
|
4
5
|
export interface BackgroundBashManagerCallbacks {
|
|
@@ -127,8 +128,8 @@ export class BackgroundBashManager {
|
|
|
127
128
|
.split("\n")
|
|
128
129
|
.filter((line) => regex.test(line))
|
|
129
130
|
.join("\n");
|
|
130
|
-
} catch {
|
|
131
|
-
|
|
131
|
+
} catch (error) {
|
|
132
|
+
logger.warn(`Invalid filter regex: ${filter}`, error);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
|
|
@@ -159,8 +160,8 @@ export class BackgroundBashManager {
|
|
|
159
160
|
) {
|
|
160
161
|
try {
|
|
161
162
|
process.kill(-shell.process.pid, "SIGKILL");
|
|
162
|
-
} catch {
|
|
163
|
-
|
|
163
|
+
} catch (error) {
|
|
164
|
+
logger.error("Failed to force kill process:", error);
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
}, 1000);
|
|
@@ -183,8 +184,8 @@ export class BackgroundBashManager {
|
|
|
183
184
|
shell.runtime = Date.now() - shell.startTime;
|
|
184
185
|
this.notifyShellsChange();
|
|
185
186
|
return true;
|
|
186
|
-
} catch {
|
|
187
|
-
|
|
187
|
+
} catch (directKillError) {
|
|
188
|
+
logger.error("Failed to kill child process:", directKillError);
|
|
188
189
|
return false;
|
|
189
190
|
}
|
|
190
191
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import {
|
|
9
9
|
type HookEvent,
|
|
10
10
|
type HookEventConfig,
|
|
11
|
-
type
|
|
11
|
+
type WaveConfiguration,
|
|
12
12
|
type PartialHookConfiguration,
|
|
13
13
|
type HookExecutionContext,
|
|
14
14
|
type ExtendedHookExecutionContext,
|
|
@@ -22,7 +22,7 @@ import { HookMatcher } from "../utils/hookMatcher.js";
|
|
|
22
22
|
import {
|
|
23
23
|
executeCommand,
|
|
24
24
|
isCommandSafe,
|
|
25
|
-
|
|
25
|
+
loadMergedWaveConfig,
|
|
26
26
|
} from "../services/hook.js";
|
|
27
27
|
import type { Logger } from "../types/index.js";
|
|
28
28
|
import { MessageSource } from "../types/index.js";
|
|
@@ -30,6 +30,7 @@ import type { MessageManager } from "./messageManager.js";
|
|
|
30
30
|
|
|
31
31
|
export class HookManager {
|
|
32
32
|
private configuration: PartialHookConfiguration | undefined;
|
|
33
|
+
private environmentVars: Record<string, string> | undefined;
|
|
33
34
|
private readonly matcher: HookMatcher;
|
|
34
35
|
private readonly logger?: Logger;
|
|
35
36
|
private readonly workdir: string;
|
|
@@ -78,18 +79,25 @@ export class HookManager {
|
|
|
78
79
|
|
|
79
80
|
/**
|
|
80
81
|
* Load configuration from filesystem settings
|
|
81
|
-
* Automatically loads and merges user and project hooks
|
|
82
|
+
* Automatically loads and merges user and project Wave configuration (hooks + environment)
|
|
82
83
|
*/
|
|
83
84
|
loadConfigurationFromSettings(): void {
|
|
84
85
|
try {
|
|
85
86
|
this.logger?.debug(`[HookManager] Loading configuration...`);
|
|
86
|
-
const
|
|
87
|
-
this.logger?.debug(
|
|
88
|
-
|
|
87
|
+
const mergedWaveConfig = loadMergedWaveConfig(this.workdir);
|
|
88
|
+
this.logger?.debug(
|
|
89
|
+
`[HookManager] Merged config result:`,
|
|
90
|
+
mergedWaveConfig,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
this.configuration = mergedWaveConfig?.hooks || undefined;
|
|
94
|
+
this.environmentVars = mergedWaveConfig?.env || undefined;
|
|
89
95
|
|
|
90
96
|
// Validate the loaded configuration if it exists
|
|
91
|
-
if (
|
|
92
|
-
const validation = this.validatePartialConfiguration(
|
|
97
|
+
if (mergedWaveConfig?.hooks) {
|
|
98
|
+
const validation = this.validatePartialConfiguration(
|
|
99
|
+
mergedWaveConfig.hooks,
|
|
100
|
+
);
|
|
93
101
|
if (!validation.valid) {
|
|
94
102
|
throw new HookConfigurationError(
|
|
95
103
|
"filesystem settings",
|
|
@@ -99,11 +107,12 @@ export class HookManager {
|
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
this.logger?.debug(
|
|
102
|
-
`[HookManager] Configuration loaded successfully with ${Object.keys(
|
|
110
|
+
`[HookManager] Configuration loaded successfully with ${Object.keys(mergedWaveConfig?.hooks || {}).length} event types and ${Object.keys(this.environmentVars || {}).length} environment variables`,
|
|
103
111
|
);
|
|
104
112
|
} catch (error) {
|
|
105
113
|
// If loading fails, start with undefined configuration (no hooks)
|
|
106
114
|
this.configuration = undefined;
|
|
115
|
+
this.environmentVars = undefined;
|
|
107
116
|
|
|
108
117
|
// Re-throw configuration errors, but handle file system errors gracefully
|
|
109
118
|
if (error instanceof HookConfigurationError) {
|
|
@@ -194,7 +203,12 @@ export class HookManager {
|
|
|
194
203
|
`[HookManager] Executing command ${commandIndex + 1}/${config.hooks.length} in configuration ${configIndex + 1}`,
|
|
195
204
|
);
|
|
196
205
|
|
|
197
|
-
const result = await executeCommand(
|
|
206
|
+
const result = await executeCommand(
|
|
207
|
+
hookCommand.command,
|
|
208
|
+
context,
|
|
209
|
+
undefined,
|
|
210
|
+
this.environmentVars,
|
|
211
|
+
);
|
|
198
212
|
results.push(result);
|
|
199
213
|
|
|
200
214
|
// Report individual command result
|
|
@@ -203,7 +217,7 @@ export class HookManager {
|
|
|
203
217
|
`[HookManager] Command ${commandIndex + 1} completed successfully in ${result.duration}ms`,
|
|
204
218
|
);
|
|
205
219
|
} else {
|
|
206
|
-
this.logger?.
|
|
220
|
+
this.logger?.debug(
|
|
207
221
|
`[HookManager] Command ${commandIndex + 1} failed in ${result.duration}ms (exit code: ${result.exitCode}, timed out: ${result.timedOut})`,
|
|
208
222
|
);
|
|
209
223
|
}
|
|
@@ -344,6 +358,7 @@ export class HookManager {
|
|
|
344
358
|
result: errorMessage,
|
|
345
359
|
success: false,
|
|
346
360
|
error: "Hook blocked tool execution",
|
|
361
|
+
stage: "end", // Hook blocking results in end stage with error
|
|
347
362
|
});
|
|
348
363
|
}
|
|
349
364
|
return { shouldBlock: true };
|
|
@@ -395,46 +410,62 @@ export class HookManager {
|
|
|
395
410
|
}
|
|
396
411
|
|
|
397
412
|
/**
|
|
398
|
-
* Validate
|
|
413
|
+
* Validate Wave configuration structure and content
|
|
399
414
|
*/
|
|
400
|
-
validateConfiguration(config:
|
|
415
|
+
validateConfiguration(config: WaveConfiguration): ValidationResult {
|
|
401
416
|
const errors: string[] = [];
|
|
402
417
|
|
|
403
418
|
if (!config || typeof config !== "object") {
|
|
404
419
|
return { valid: false, errors: ["Configuration must be an object"] };
|
|
405
420
|
}
|
|
406
421
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
errors
|
|
411
|
-
}
|
|
412
|
-
|
|
422
|
+
// Validate hooks if present
|
|
423
|
+
if (config.hooks) {
|
|
424
|
+
if (typeof config.hooks !== "object") {
|
|
425
|
+
errors.push("hooks property must be an object");
|
|
426
|
+
} else {
|
|
427
|
+
// Validate each hook event
|
|
428
|
+
for (const [eventName, eventConfigs] of Object.entries(config.hooks)) {
|
|
429
|
+
// Validate event name
|
|
430
|
+
if (!isValidHookEvent(eventName)) {
|
|
431
|
+
errors.push(`Invalid hook event: ${eventName}`);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
413
434
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
435
|
+
// Validate event configurations
|
|
436
|
+
if (!Array.isArray(eventConfigs)) {
|
|
437
|
+
errors.push(
|
|
438
|
+
`Hook event ${eventName} must be an array of configurations`,
|
|
439
|
+
);
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
421
442
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
443
|
+
eventConfigs.forEach((eventConfig, index) => {
|
|
444
|
+
const configErrors = this.validateEventConfig(
|
|
445
|
+
eventName as HookEvent,
|
|
446
|
+
eventConfig,
|
|
447
|
+
index,
|
|
448
|
+
);
|
|
449
|
+
errors.push(...configErrors);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
428
452
|
}
|
|
453
|
+
}
|
|
429
454
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
)
|
|
436
|
-
|
|
437
|
-
|
|
455
|
+
// Validate environment variables if present
|
|
456
|
+
if (config.env) {
|
|
457
|
+
if (typeof config.env !== "object" || Array.isArray(config.env)) {
|
|
458
|
+
errors.push("env property must be an object");
|
|
459
|
+
} else {
|
|
460
|
+
for (const [key, value] of Object.entries(config.env)) {
|
|
461
|
+
if (typeof key !== "string" || key.trim() === "") {
|
|
462
|
+
errors.push(`Invalid environment variable key: ${key}`);
|
|
463
|
+
}
|
|
464
|
+
if (typeof value !== "string") {
|
|
465
|
+
errors.push(`Environment variable ${key} must have a string value`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
438
469
|
}
|
|
439
470
|
|
|
440
471
|
return {
|
|
@@ -497,6 +528,16 @@ export class HookManager {
|
|
|
497
528
|
return JSON.parse(JSON.stringify(this.configuration));
|
|
498
529
|
}
|
|
499
530
|
|
|
531
|
+
/**
|
|
532
|
+
* Get current environment variables
|
|
533
|
+
*/
|
|
534
|
+
getEnvironmentVars(): Record<string, string> | undefined {
|
|
535
|
+
if (!this.environmentVars) return undefined;
|
|
536
|
+
|
|
537
|
+
// Deep clone to prevent external modification
|
|
538
|
+
return JSON.parse(JSON.stringify(this.environmentVars));
|
|
539
|
+
}
|
|
540
|
+
|
|
500
541
|
/**
|
|
501
542
|
* Clear current configuration
|
|
502
543
|
*/
|
|
@@ -697,6 +738,7 @@ export class HookManager {
|
|
|
697
738
|
PostToolUse: 0,
|
|
698
739
|
UserPromptSubmit: 0,
|
|
699
740
|
Stop: 0,
|
|
741
|
+
SubagentStop: 0,
|
|
700
742
|
},
|
|
701
743
|
};
|
|
702
744
|
}
|
|
@@ -706,6 +748,7 @@ export class HookManager {
|
|
|
706
748
|
PostToolUse: 0,
|
|
707
749
|
UserPromptSubmit: 0,
|
|
708
750
|
Stop: 0,
|
|
751
|
+
SubagentStop: 0,
|
|
709
752
|
};
|
|
710
753
|
|
|
711
754
|
let totalConfigs = 0;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live Configuration Manager
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates live configuration reload functionality including:
|
|
5
|
+
* - Hook configuration watching and reloading
|
|
6
|
+
* - Memory store management for AGENTS.md files
|
|
7
|
+
* - Coordination between file watchers and configuration updates
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Logger } from "../types/index.js";
|
|
11
|
+
import {
|
|
12
|
+
ConfigurationWatcher,
|
|
13
|
+
type ConfigurationChangeEvent,
|
|
14
|
+
} from "../services/configurationWatcher.js";
|
|
15
|
+
|
|
16
|
+
import { type FileWatchEvent } from "../services/fileWatcher.js";
|
|
17
|
+
import { configResolver } from "../utils/configResolver.js";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import {
|
|
20
|
+
getUserConfigPaths,
|
|
21
|
+
getProjectConfigPaths,
|
|
22
|
+
} from "../utils/configPaths.js";
|
|
23
|
+
import { CONFIGURATION_EVENTS } from "../constants/events.js";
|
|
24
|
+
|
|
25
|
+
export interface LiveConfigManagerOptions {
|
|
26
|
+
workdir: string;
|
|
27
|
+
logger?: Logger;
|
|
28
|
+
onConfigurationChanged?: () => void; // Callback for when configuration changes
|
|
29
|
+
onMemoryStoreFileChanged?: (
|
|
30
|
+
filePath: string,
|
|
31
|
+
changeType: "add" | "change" | "unlink",
|
|
32
|
+
) => Promise<void>; // Callback for memory store file changes
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class LiveConfigManager {
|
|
36
|
+
private readonly workdir: string;
|
|
37
|
+
private readonly logger?: Logger;
|
|
38
|
+
private readonly onConfigurationChanged?: () => void;
|
|
39
|
+
private readonly onMemoryStoreFileChanged?: (
|
|
40
|
+
filePath: string,
|
|
41
|
+
changeType: "add" | "change" | "unlink",
|
|
42
|
+
) => Promise<void>;
|
|
43
|
+
private configurationWatcher?: ConfigurationWatcher;
|
|
44
|
+
private isInitialized: boolean = false;
|
|
45
|
+
|
|
46
|
+
constructor(options: LiveConfigManagerOptions) {
|
|
47
|
+
this.workdir = options.workdir;
|
|
48
|
+
this.logger = options.logger;
|
|
49
|
+
this.onConfigurationChanged = options.onConfigurationChanged;
|
|
50
|
+
this.onMemoryStoreFileChanged = options.onMemoryStoreFileChanged;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Initialize live configuration management
|
|
55
|
+
*/
|
|
56
|
+
async initialize(): Promise<void> {
|
|
57
|
+
if (this.isInitialized) {
|
|
58
|
+
this.logger?.debug("[LiveConfigManager] Already initialized");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Initialize configuration watcher for hook settings
|
|
64
|
+
await this.initializeConfigurationWatcher();
|
|
65
|
+
|
|
66
|
+
// Initialize memory store watching for AGENTS.md if callback is available
|
|
67
|
+
if (this.onMemoryStoreFileChanged) {
|
|
68
|
+
await this.initializeMemoryStoreWatching();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.isInitialized = true;
|
|
72
|
+
this.logger?.info(
|
|
73
|
+
"Live Config: Live configuration management initialized successfully",
|
|
74
|
+
);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logger?.error(
|
|
77
|
+
`Live Config: Failed to initialize: ${(error as Error).message}`,
|
|
78
|
+
);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Shutdown live configuration management
|
|
85
|
+
*/
|
|
86
|
+
async shutdown(): Promise<void> {
|
|
87
|
+
if (!this.isInitialized) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
if (this.configurationWatcher) {
|
|
93
|
+
await this.configurationWatcher.shutdown();
|
|
94
|
+
this.configurationWatcher = undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.isInitialized = false;
|
|
98
|
+
this.logger?.info(
|
|
99
|
+
"Live Config: Live configuration management shutdown completed",
|
|
100
|
+
);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
this.logger?.error(
|
|
103
|
+
`Live Config: Error during shutdown: ${(error as Error).message}`,
|
|
104
|
+
);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Initialize configuration watcher for hook settings
|
|
111
|
+
*/
|
|
112
|
+
private async initializeConfigurationWatcher(): Promise<void> {
|
|
113
|
+
this.configurationWatcher = new ConfigurationWatcher(
|
|
114
|
+
this.workdir,
|
|
115
|
+
this.logger,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Set up configuration change handler using EventEmitter pattern
|
|
119
|
+
this.configurationWatcher.on(
|
|
120
|
+
CONFIGURATION_EVENTS.CONFIGURATION_CHANGE,
|
|
121
|
+
(event: ConfigurationChangeEvent) => {
|
|
122
|
+
this.handleConfigurationChange(event);
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Initialize watching for user and project settings
|
|
127
|
+
const { userPaths, projectPaths } = this.getConfigurationPaths();
|
|
128
|
+
await this.configurationWatcher.initializeWatching(userPaths, projectPaths);
|
|
129
|
+
this.logger?.info("Live Config: Configuration watching initialized");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initialize memory store watching for AGENTS.md files
|
|
134
|
+
*/
|
|
135
|
+
private async initializeMemoryStoreWatching(): Promise<void> {
|
|
136
|
+
if (!this.onMemoryStoreFileChanged || !this.configurationWatcher) {
|
|
137
|
+
this.logger?.debug(
|
|
138
|
+
"Live Config: Memory store callback or configuration watcher not available, skipping AGENTS.md watching",
|
|
139
|
+
);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const agentsFilePath = join(this.workdir, "AGENTS.md");
|
|
145
|
+
|
|
146
|
+
// Add AGENTS.md to file watcher
|
|
147
|
+
await this.configurationWatcher.watchAdditionalFile(
|
|
148
|
+
agentsFilePath,
|
|
149
|
+
async (event: FileWatchEvent) => {
|
|
150
|
+
await this.handleMemoryStoreFileChange(event);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
this.logger?.info("Live Config: AGENTS.md file watching initialized");
|
|
155
|
+
} catch (error) {
|
|
156
|
+
this.logger?.warn(
|
|
157
|
+
`Live Config: Failed to initialize AGENTS.md watching: ${(error as Error).message}`,
|
|
158
|
+
);
|
|
159
|
+
// Don't throw - memory optimization is not critical for core functionality
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Handle configuration change events
|
|
165
|
+
*/
|
|
166
|
+
private handleConfigurationChange(event: ConfigurationChangeEvent): void {
|
|
167
|
+
this.logger?.info(
|
|
168
|
+
`Live Config: Configuration change detected: ${event.type} at ${event.path}`,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Invalidate and refresh configuration cache for live environment variable updates
|
|
172
|
+
configResolver.invalidateCache(this.workdir);
|
|
173
|
+
configResolver.refreshCache(this.workdir);
|
|
174
|
+
|
|
175
|
+
// Trigger Agent configuration update callback if provided
|
|
176
|
+
if (this.onConfigurationChanged) {
|
|
177
|
+
try {
|
|
178
|
+
this.logger?.info("Live Config: Triggering Agent configuration update");
|
|
179
|
+
this.onConfigurationChanged();
|
|
180
|
+
} catch (error) {
|
|
181
|
+
this.logger?.error(
|
|
182
|
+
`Live Config: Error in configuration change callback: ${(error as Error).message}`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Log cache status after refresh
|
|
188
|
+
const cacheStatus = configResolver.getCacheStatus();
|
|
189
|
+
if (cacheStatus) {
|
|
190
|
+
this.logger?.info(
|
|
191
|
+
`Live Config: Configuration cache refreshed - ${cacheStatus.envVarCount} environment variables loaded`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Handle AGENTS.md file change events
|
|
198
|
+
*/
|
|
199
|
+
private async handleMemoryStoreFileChange(
|
|
200
|
+
event: FileWatchEvent,
|
|
201
|
+
): Promise<void> {
|
|
202
|
+
if (!this.onMemoryStoreFileChanged) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
this.logger?.info(
|
|
208
|
+
`Live Config: AGENTS.md ${event.type} detected: ${event.path}`,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const changeType: "add" | "change" | "unlink" =
|
|
212
|
+
event.type === "delete"
|
|
213
|
+
? "unlink"
|
|
214
|
+
: event.type === "create"
|
|
215
|
+
? "add"
|
|
216
|
+
: "change";
|
|
217
|
+
await this.onMemoryStoreFileChanged(event.path, changeType);
|
|
218
|
+
|
|
219
|
+
this.logger?.info(
|
|
220
|
+
`Live Config: Memory store updated for AGENTS.md ${event.type}`,
|
|
221
|
+
);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
this.logger?.error(
|
|
224
|
+
`Live Config: Failed to handle AGENTS.md file change: ${(error as Error).message}`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get initialization status
|
|
231
|
+
*/
|
|
232
|
+
get initialized(): boolean {
|
|
233
|
+
return this.isInitialized;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get configuration file paths for user and project settings
|
|
238
|
+
* Returns paths in priority order (local.json first, then .json)
|
|
239
|
+
*/
|
|
240
|
+
private getConfigurationPaths(): {
|
|
241
|
+
userPaths: string[];
|
|
242
|
+
projectPaths: string[];
|
|
243
|
+
} {
|
|
244
|
+
const userPaths = getUserConfigPaths();
|
|
245
|
+
const projectPaths = getProjectConfigPaths(this.workdir);
|
|
246
|
+
return { userPaths, projectPaths };
|
|
247
|
+
}
|
|
248
|
+
}
|