@stackmemoryai/stackmemory 0.3.8 → 0.3.10
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 +53 -0
- package/dist/agents/core/agent-task-manager.js +12 -1
- package/dist/agents/core/agent-task-manager.js.map +3 -3
- package/dist/agents/testing-agent.js +610 -0
- package/dist/agents/testing-agent.js.map +7 -0
- package/dist/cli/claude-sm.js +2 -2
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +2 -2
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/handoff.js +65 -18
- package/dist/cli/commands/handoff.js.map +3 -3
- package/dist/cli/commands/onboard.js +3 -3
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js +2 -2
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/skills.js +113 -28
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/test.js +282 -0
- package/dist/cli/commands/test.js.map +7 -0
- package/dist/cli/commands/worktree.js +28 -10
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js +26 -0
- package/dist/core/config/config-manager.js.map +3 -3
- package/dist/core/context/frame-manager.js +139 -0
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +582 -0
- package/dist/core/context/recursive-context-manager.js.map +7 -0
- package/dist/core/context/refactored-frame-manager.js +180 -1
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/execution/parallel-executor.js +254 -0
- package/dist/core/execution/parallel-executor.js.map +7 -0
- package/dist/core/utils/update-checker.js +2 -2
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/integrations/anthropic/client.js +259 -0
- package/dist/integrations/anthropic/client.js.map +7 -0
- package/dist/integrations/claude-code/subagent-client-stub.js +16 -0
- package/dist/integrations/claude-code/subagent-client-stub.js.map +7 -0
- package/dist/integrations/claude-code/subagent-client.js +404 -0
- package/dist/integrations/claude-code/subagent-client.js.map +7 -0
- package/dist/skills/claude-skills.js +191 -0
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +559 -0
- package/dist/skills/recursive-agent-orchestrator.js.map +7 -0
- package/dist/skills/security-secrets-scanner.js +280 -0
- package/dist/skills/security-secrets-scanner.js.map +7 -0
- package/dist/skills/unified-rlm-orchestrator.js +400 -0
- package/dist/skills/unified-rlm-orchestrator.js.map +7 -0
- package/package.json +3 -2
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
ErrorCode
|
|
8
8
|
} from "../errors/index.js";
|
|
9
9
|
import { FrameQueryMode } from "../session/index.js";
|
|
10
|
+
const MAX_FRAME_DEPTH = 100;
|
|
11
|
+
const DEFAULT_MAX_DEPTH = 100;
|
|
10
12
|
import { FrameDatabase } from "./frame-database.js";
|
|
11
13
|
import { FrameStack } from "./frame-stack.js";
|
|
12
14
|
import { FrameDigestGenerator } from "./frame-digest.js";
|
|
@@ -19,6 +21,7 @@ class RefactoredFrameManager {
|
|
|
19
21
|
projectId;
|
|
20
22
|
queryMode = FrameQueryMode.PROJECT_ACTIVE;
|
|
21
23
|
config;
|
|
24
|
+
maxFrameDepth = DEFAULT_MAX_DEPTH;
|
|
22
25
|
constructor(db, projectId, config) {
|
|
23
26
|
this.projectId = projectId;
|
|
24
27
|
this.config = {
|
|
@@ -27,6 +30,7 @@ class RefactoredFrameManager {
|
|
|
27
30
|
sessionId: config?.sessionId || uuidv4(),
|
|
28
31
|
maxStackDepth: config?.maxStackDepth || 50
|
|
29
32
|
};
|
|
33
|
+
this.maxFrameDepth = config?.maxStackDepth || DEFAULT_MAX_DEPTH;
|
|
30
34
|
this.currentRunId = this.config.runId;
|
|
31
35
|
this.sessionId = this.config.sessionId;
|
|
32
36
|
this.frameDb = new FrameDatabase(db);
|
|
@@ -96,7 +100,37 @@ class RefactoredFrameManager {
|
|
|
96
100
|
);
|
|
97
101
|
}
|
|
98
102
|
const resolvedParentId = frameOptions.parentFrameId || this.frameStack.getCurrentFrameId();
|
|
99
|
-
|
|
103
|
+
let depth = 0;
|
|
104
|
+
if (resolvedParentId) {
|
|
105
|
+
const parentFrame = this.frameDb.getFrame(resolvedParentId);
|
|
106
|
+
depth = parentFrame ? parentFrame.depth + 1 : 0;
|
|
107
|
+
}
|
|
108
|
+
if (depth > this.maxFrameDepth) {
|
|
109
|
+
throw new FrameError(
|
|
110
|
+
`Maximum frame depth exceeded: ${depth} > ${this.maxFrameDepth}`,
|
|
111
|
+
ErrorCode.FRAME_STACK_OVERFLOW,
|
|
112
|
+
{
|
|
113
|
+
currentDepth: depth,
|
|
114
|
+
maxDepth: this.maxFrameDepth,
|
|
115
|
+
frameName: frameOptions.name,
|
|
116
|
+
parentFrameId: resolvedParentId
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (resolvedParentId) {
|
|
121
|
+
const cycle = this.detectCycle(uuidv4(), resolvedParentId);
|
|
122
|
+
if (cycle) {
|
|
123
|
+
throw new FrameError(
|
|
124
|
+
`Circular reference detected in frame hierarchy`,
|
|
125
|
+
ErrorCode.FRAME_CYCLE_DETECTED,
|
|
126
|
+
{
|
|
127
|
+
parentFrameId: resolvedParentId,
|
|
128
|
+
cycle,
|
|
129
|
+
frameName: frameOptions.name
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
100
134
|
const frameId = uuidv4();
|
|
101
135
|
const frame = {
|
|
102
136
|
frame_id: frameId,
|
|
@@ -375,6 +409,151 @@ class RefactoredFrameManager {
|
|
|
375
409
|
}
|
|
376
410
|
return constraints;
|
|
377
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Detect if setting a parent frame would create a cycle in the frame hierarchy.
|
|
414
|
+
* Returns the cycle path if detected, or null if no cycle.
|
|
415
|
+
* @param childFrameId - The frame that would be the child
|
|
416
|
+
* @param parentFrameId - The proposed parent frame
|
|
417
|
+
* @returns Array of frame IDs forming the cycle, or null if no cycle
|
|
418
|
+
*/
|
|
419
|
+
detectCycle(childFrameId, parentFrameId) {
|
|
420
|
+
const visited = /* @__PURE__ */ new Set();
|
|
421
|
+
const path = [];
|
|
422
|
+
let currentId = parentFrameId;
|
|
423
|
+
while (currentId) {
|
|
424
|
+
if (visited.has(currentId)) {
|
|
425
|
+
const cycleStart = path.indexOf(currentId);
|
|
426
|
+
return path.slice(cycleStart).concat(currentId);
|
|
427
|
+
}
|
|
428
|
+
if (currentId === childFrameId) {
|
|
429
|
+
return path.concat([currentId, childFrameId]);
|
|
430
|
+
}
|
|
431
|
+
visited.add(currentId);
|
|
432
|
+
path.push(currentId);
|
|
433
|
+
const frame = this.frameDb.getFrame(currentId);
|
|
434
|
+
if (!frame) {
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
currentId = frame.parent_frame_id;
|
|
438
|
+
if (path.length > this.maxFrameDepth) {
|
|
439
|
+
throw new FrameError(
|
|
440
|
+
`Frame hierarchy traversal exceeded maximum depth during cycle detection`,
|
|
441
|
+
ErrorCode.FRAME_STACK_OVERFLOW,
|
|
442
|
+
{
|
|
443
|
+
depth: path.length,
|
|
444
|
+
maxDepth: this.maxFrameDepth,
|
|
445
|
+
path
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Update parent frame of an existing frame (with cycle detection)
|
|
454
|
+
* @param frameId - The frame to update
|
|
455
|
+
* @param newParentFrameId - The new parent frame ID (null to make it a root frame)
|
|
456
|
+
*/
|
|
457
|
+
updateParentFrame(frameId, newParentFrameId) {
|
|
458
|
+
const frame = this.frameDb.getFrame(frameId);
|
|
459
|
+
if (!frame) {
|
|
460
|
+
throw new FrameError(
|
|
461
|
+
`Frame not found: ${frameId}`,
|
|
462
|
+
ErrorCode.FRAME_NOT_FOUND,
|
|
463
|
+
{ frameId }
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
if (newParentFrameId) {
|
|
467
|
+
const cycle = this.detectCycle(frameId, newParentFrameId);
|
|
468
|
+
if (cycle) {
|
|
469
|
+
throw new FrameError(
|
|
470
|
+
`Cannot set parent: would create circular reference`,
|
|
471
|
+
ErrorCode.FRAME_CYCLE_DETECTED,
|
|
472
|
+
{
|
|
473
|
+
frameId,
|
|
474
|
+
newParentFrameId,
|
|
475
|
+
cycle,
|
|
476
|
+
currentParentId: frame.parent_frame_id
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
const newParentFrame = this.frameDb.getFrame(newParentFrameId);
|
|
481
|
+
if (newParentFrame) {
|
|
482
|
+
const newDepth = newParentFrame.depth + 1;
|
|
483
|
+
if (newDepth > this.maxFrameDepth) {
|
|
484
|
+
throw new FrameError(
|
|
485
|
+
`Cannot set parent: would exceed maximum frame depth`,
|
|
486
|
+
ErrorCode.FRAME_STACK_OVERFLOW,
|
|
487
|
+
{
|
|
488
|
+
frameId,
|
|
489
|
+
newParentFrameId,
|
|
490
|
+
newDepth,
|
|
491
|
+
maxDepth: this.maxFrameDepth
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
this.frameDb.updateFrame(frameId, {
|
|
498
|
+
parent_frame_id: newParentFrameId
|
|
499
|
+
});
|
|
500
|
+
logger.info("Updated parent frame", {
|
|
501
|
+
frameId,
|
|
502
|
+
oldParentId: frame.parent_frame_id,
|
|
503
|
+
newParentId: newParentFrameId
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Validate the entire frame hierarchy for cycles and depth violations
|
|
508
|
+
* @returns Validation result with any detected issues
|
|
509
|
+
*/
|
|
510
|
+
validateFrameHierarchy() {
|
|
511
|
+
const errors = [];
|
|
512
|
+
const warnings = [];
|
|
513
|
+
const allFrames = this.frameDb.getFramesByProject(this.projectId);
|
|
514
|
+
for (const frame of allFrames) {
|
|
515
|
+
if (frame.depth > this.maxFrameDepth) {
|
|
516
|
+
errors.push(
|
|
517
|
+
`Frame ${frame.frame_id} exceeds max depth: ${frame.depth} > ${this.maxFrameDepth}`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
if (frame.depth > this.maxFrameDepth * 0.8) {
|
|
521
|
+
warnings.push(
|
|
522
|
+
`Frame ${frame.frame_id} is deep in hierarchy: ${frame.depth}/${this.maxFrameDepth}`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const rootFrames = allFrames.filter((f) => !f.parent_frame_id);
|
|
527
|
+
const visited = /* @__PURE__ */ new Set();
|
|
528
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
529
|
+
const checkForCycle = (frameId) => {
|
|
530
|
+
if (visiting.has(frameId)) {
|
|
531
|
+
errors.push(`Cycle detected involving frame ${frameId}`);
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
if (visited.has(frameId)) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
visiting.add(frameId);
|
|
538
|
+
const children = allFrames.filter((f) => f.parent_frame_id === frameId);
|
|
539
|
+
for (const child of children) {
|
|
540
|
+
if (checkForCycle(child.frame_id)) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
visiting.delete(frameId);
|
|
545
|
+
visited.add(frameId);
|
|
546
|
+
return false;
|
|
547
|
+
};
|
|
548
|
+
for (const root of rootFrames) {
|
|
549
|
+
checkForCycle(root.frame_id);
|
|
550
|
+
}
|
|
551
|
+
return {
|
|
552
|
+
isValid: errors.length === 0,
|
|
553
|
+
errors,
|
|
554
|
+
warnings
|
|
555
|
+
};
|
|
556
|
+
}
|
|
378
557
|
}
|
|
379
558
|
import {
|
|
380
559
|
Frame as Frame2,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/refactored-frame-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Refactored Frame Manager - Modular Implementation\n * Main orchestrator that uses focused modules for frame management\n */\n\nimport Database from 'better-sqlite3';\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../monitoring/logger.js';\nimport { trace } from '../trace/index.js';\nimport {\n FrameError,\n SystemError,\n ErrorCode,\n wrapError,\n createErrorHandler,\n} from '../errors/index.js';\nimport { retry, withTimeout } from '../errors/recovery.js';\nimport { sessionManager, FrameQueryMode } from '../session/index.js';\n\n// Import refactored modules\nimport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { FrameStack } from './frame-stack.js';\nimport { FrameDigestGenerator } from './frame-digest.js';\n\nexport class RefactoredFrameManager {\n private frameDb: FrameDatabase;\n private frameStack: FrameStack;\n private digestGenerator: FrameDigestGenerator;\n\n private currentRunId: string;\n private sessionId: string;\n private projectId: string;\n private queryMode: FrameQueryMode = FrameQueryMode.PROJECT_ACTIVE;\n private config: FrameManagerConfig;\n\n constructor(\n db: Database.Database,\n projectId: string,\n config?: Partial<FrameManagerConfig>\n ) {\n this.projectId = projectId;\n this.config = {\n projectId,\n runId: config?.runId || uuidv4(),\n sessionId: config?.sessionId || uuidv4(),\n maxStackDepth: config?.maxStackDepth || 50,\n };\n\n this.currentRunId = this.config.runId!;\n this.sessionId = this.config.sessionId!;\n\n // Initialize modules\n this.frameDb = new FrameDatabase(db);\n this.frameStack = new FrameStack(\n this.frameDb,\n projectId,\n this.currentRunId\n );\n this.digestGenerator = new FrameDigestGenerator(this.frameDb);\n\n // Initialize database schema\n this.frameDb.initSchema();\n\n logger.info('RefactoredFrameManager initialized', {\n projectId: this.projectId,\n runId: this.currentRunId,\n sessionId: this.sessionId,\n });\n }\n\n /**\n * Initialize the frame manager\n */\n async initialize(): Promise<void> {\n try {\n await this.frameStack.initialize();\n\n logger.info('Frame manager initialization completed', {\n stackDepth: this.frameStack.getDepth(),\n });\n } catch (error: unknown) {\n throw new SystemError(\n 'Failed to initialize frame manager',\n ErrorCode.SYSTEM_INIT_FAILED,\n { projectId: this.projectId },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new frame\n */\n createFrame(options: FrameCreationOptions): string;\n createFrame(\n type: FrameType,\n name: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string;\n createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.createFrame',\n { typeOrOptions, name },\n () => this._createFrame(typeOrOptions, name, inputs, parentFrameId)\n );\n }\n\n private _createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n let frameOptions: FrameCreationOptions;\n\n // Handle both function signatures\n if (typeof typeOrOptions === 'string') {\n frameOptions = {\n type: typeOrOptions,\n name: name!,\n inputs: inputs || {},\n parentFrameId,\n };\n } else {\n frameOptions = typeOrOptions;\n }\n\n // Validate inputs\n if (!frameOptions.name || frameOptions.name.trim().length === 0) {\n throw new FrameError(\n 'Frame name is required',\n ErrorCode.FRAME_INVALID_INPUT,\n { frameOptions }\n );\n }\n\n // Check stack depth limit\n if (this.frameStack.getDepth() >= this.config.maxStackDepth!) {\n throw new FrameError(\n `Maximum stack depth reached: ${this.config.maxStackDepth}`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n { currentDepth: this.frameStack.getDepth() }\n );\n }\n\n // Determine parent frame\n const resolvedParentId =\n frameOptions.parentFrameId || this.frameStack.getCurrentFrameId();\n const depth = resolvedParentId\n ? this.frameStack.getFrameStackDepth(resolvedParentId) + 1\n : 0;\n\n // Create frame data\n const frameId = uuidv4();\n const frame: Omit<Frame, 'created_at' | 'closed_at'> = {\n frame_id: frameId,\n run_id: this.currentRunId,\n project_id: this.projectId,\n parent_frame_id: resolvedParentId,\n depth,\n type: frameOptions.type,\n name: frameOptions.name,\n state: 'active',\n inputs: frameOptions.inputs || {},\n outputs: {},\n digest_json: {},\n };\n\n // Insert into database\n const createdFrame = this.frameDb.insertFrame(frame);\n\n // Add to stack\n this.frameStack.pushFrame(frameId);\n\n logger.info('Created frame', {\n frameId,\n name: frameOptions.name,\n type: frameOptions.type,\n parentFrameId: resolvedParentId,\n stackDepth: this.frameStack.getDepth(),\n });\n\n return frameId;\n }\n\n /**\n * Close a frame and generate digest\n */\n closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n trace.traceSync(\n 'function',\n 'FrameManager.closeFrame',\n { frameId, outputs },\n () => this._closeFrame(frameId, outputs)\n );\n }\n\n private _closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame to close',\n ErrorCode.FRAME_INVALID_STATE,\n {\n operation: 'closeFrame',\n stackDepth: this.frameStack.getDepth(),\n }\n );\n }\n\n // Get frame details\n const frame = this.frameDb.getFrame(targetFrameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${targetFrameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n {\n frameId: targetFrameId,\n operation: 'closeFrame',\n runId: this.currentRunId,\n }\n );\n }\n\n if (frame.state === 'closed') {\n logger.warn('Attempted to close already closed frame', {\n frameId: targetFrameId,\n });\n return;\n }\n\n // Generate digest before closing\n const digest = this.digestGenerator.generateDigest(targetFrameId);\n const finalOutputs = { ...outputs, ...digest.structured };\n\n // Update frame to closed state\n this.frameDb.updateFrame(targetFrameId, {\n state: 'closed',\n outputs: finalOutputs,\n digest_text: digest.text,\n digest_json: digest.structured,\n closed_at: Math.floor(Date.now() / 1000),\n });\n\n // Remove from stack (this will also remove any child frames)\n this.frameStack.popFrame(targetFrameId);\n\n // Close all child frames recursively\n this.closeChildFrames(targetFrameId);\n\n logger.info('Closed frame', {\n frameId: targetFrameId,\n name: frame.name,\n duration: Math.floor(Date.now() / 1000) - frame.created_at,\n digestLength: digest.text.length,\n stackDepth: this.frameStack.getDepth(),\n });\n }\n\n /**\n * Add an event to the current frame\n */\n addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.addEvent',\n { eventType, frameId },\n () => this._addEvent(eventType, payload, frameId)\n );\n }\n\n private _addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for event',\n ErrorCode.FRAME_INVALID_STATE,\n {\n eventType,\n operation: 'addEvent',\n }\n );\n }\n\n const eventId = uuidv4();\n const sequence = this.frameDb.getNextEventSequence(targetFrameId);\n\n const event: Omit<Event, 'ts'> = {\n event_id: eventId,\n frame_id: targetFrameId,\n run_id: this.currentRunId,\n seq: sequence,\n event_type: eventType,\n payload,\n };\n\n const createdEvent = this.frameDb.insertEvent(event);\n\n logger.debug('Added event', {\n eventId,\n frameId: targetFrameId,\n eventType,\n sequence,\n });\n\n return eventId;\n }\n\n /**\n * Add an anchor (important fact) to current frame\n */\n addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number = 5,\n metadata: Record<string, any> = {},\n frameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.addAnchor',\n { type, frameId },\n () => this._addAnchor(type, text, priority, metadata, frameId)\n );\n }\n\n private _addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number,\n metadata: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for anchor',\n ErrorCode.FRAME_INVALID_STATE,\n {\n anchorType: type,\n operation: 'addAnchor',\n }\n );\n }\n\n const anchorId = uuidv4();\n const anchor: Omit<Anchor, 'created_at'> = {\n anchor_id: anchorId,\n frame_id: targetFrameId,\n type,\n text,\n priority,\n metadata,\n };\n\n const createdAnchor = this.frameDb.insertAnchor(anchor);\n\n logger.debug('Added anchor', {\n anchorId,\n frameId: targetFrameId,\n type,\n priority,\n });\n\n return anchorId;\n }\n\n /**\n * Get hot stack context\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.frameStack.getHotStackContext(maxEvents);\n }\n\n /**\n * Get active frame path (root to current)\n */\n getActiveFramePath(): Frame[] {\n return this.frameStack.getStackFrames();\n }\n\n /**\n * Get current frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.frameStack.getCurrentFrameId();\n }\n\n /**\n * Get stack depth\n */\n getStackDepth(): number {\n return this.frameStack.getDepth();\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n return this.frameDb.getFrame(frameId);\n }\n\n /**\n * Get frame events\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n return this.frameDb.getFrameEvents(frameId, limit);\n }\n\n /**\n * Get frame anchors\n */\n getFrameAnchors(frameId: string): Anchor[] {\n return this.frameDb.getFrameAnchors(frameId);\n }\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n return this.digestGenerator.generateDigest(frameId);\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n return this.frameStack.validateStack();\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n return this.frameDb.getStatistics();\n }\n\n /**\n * Close all child frames recursively\n */\n private closeChildFrames(parentFrameId: string): void {\n try {\n const activeFrames = this.frameDb.getFramesByProject(\n this.projectId,\n 'active'\n );\n const childFrames = activeFrames.filter(\n (f: any) => f.parent_frame_id === parentFrameId\n );\n\n for (const childFrame of childFrames) {\n if (this.frameStack.isFrameActive(childFrame.frame_id)) {\n this.closeFrame(childFrame.frame_id);\n }\n }\n } catch (error: unknown) {\n logger.warn('Failed to close child frames', { parentFrameId, error });\n }\n }\n\n /**\n * Extract active artifacts from frame events\n */\n getActiveArtifacts(frameId: string): string[] {\n const events = this.frameDb.getFrameEvents(frameId);\n const artifacts: string[] = [];\n\n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload.path) {\n artifacts.push(event.payload.path);\n }\n }\n\n return [...new Set(artifacts)];\n }\n\n /**\n * Extract constraints from frame inputs\n */\n extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n\n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n\n if (inputs.requirements && Array.isArray(inputs.requirements)) {\n constraints.push(...inputs.requirements);\n }\n\n if (inputs.limitations && Array.isArray(inputs.limitations)) {\n constraints.push(...inputs.limitations);\n }\n\n return constraints;\n }\n}\n\n// Re-export types for compatibility\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\n"],
|
|
5
|
-
"mappings": "AAMA,SAAS,MAAM,cAAc;AAC7B,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAEP,SAAyB,sBAAsB;
|
|
4
|
+
"sourcesContent": ["/**\n * Refactored Frame Manager - Modular Implementation\n * Main orchestrator that uses focused modules for frame management\n */\n\nimport Database from 'better-sqlite3';\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../monitoring/logger.js';\nimport { trace } from '../trace/index.js';\nimport {\n FrameError,\n SystemError,\n ErrorCode,\n wrapError,\n createErrorHandler,\n} from '../errors/index.js';\nimport { retry, withTimeout } from '../errors/recovery.js';\nimport { sessionManager, FrameQueryMode } from '../session/index.js';\n\n// Constants for frame validation\nconst MAX_FRAME_DEPTH = 100; // Maximum allowed frame depth\nconst DEFAULT_MAX_DEPTH = 100; // Default if not configured\n\n// Import refactored modules\nimport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { FrameStack } from './frame-stack.js';\nimport { FrameDigestGenerator } from './frame-digest.js';\n\nexport class RefactoredFrameManager {\n private frameDb: FrameDatabase;\n private frameStack: FrameStack;\n private digestGenerator: FrameDigestGenerator;\n\n private currentRunId: string;\n private sessionId: string;\n private projectId: string;\n private queryMode: FrameQueryMode = FrameQueryMode.PROJECT_ACTIVE;\n private config: FrameManagerConfig;\n private maxFrameDepth: number = DEFAULT_MAX_DEPTH;\n\n constructor(\n db: Database.Database,\n projectId: string,\n config?: Partial<FrameManagerConfig>\n ) {\n this.projectId = projectId;\n this.config = {\n projectId,\n runId: config?.runId || uuidv4(),\n sessionId: config?.sessionId || uuidv4(),\n maxStackDepth: config?.maxStackDepth || 50,\n };\n \n // Set max frame depth from config if provided\n this.maxFrameDepth = config?.maxStackDepth || DEFAULT_MAX_DEPTH;\n\n this.currentRunId = this.config.runId!;\n this.sessionId = this.config.sessionId!;\n\n // Initialize modules\n this.frameDb = new FrameDatabase(db);\n this.frameStack = new FrameStack(\n this.frameDb,\n projectId,\n this.currentRunId\n );\n this.digestGenerator = new FrameDigestGenerator(this.frameDb);\n\n // Initialize database schema\n this.frameDb.initSchema();\n\n logger.info('RefactoredFrameManager initialized', {\n projectId: this.projectId,\n runId: this.currentRunId,\n sessionId: this.sessionId,\n });\n }\n\n /**\n * Initialize the frame manager\n */\n async initialize(): Promise<void> {\n try {\n await this.frameStack.initialize();\n\n logger.info('Frame manager initialization completed', {\n stackDepth: this.frameStack.getDepth(),\n });\n } catch (error: unknown) {\n throw new SystemError(\n 'Failed to initialize frame manager',\n ErrorCode.SYSTEM_INIT_FAILED,\n { projectId: this.projectId },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new frame\n */\n createFrame(options: FrameCreationOptions): string;\n createFrame(\n type: FrameType,\n name: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string;\n createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.createFrame',\n { typeOrOptions, name },\n () => this._createFrame(typeOrOptions, name, inputs, parentFrameId)\n );\n }\n\n private _createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n let frameOptions: FrameCreationOptions;\n\n // Handle both function signatures\n if (typeof typeOrOptions === 'string') {\n frameOptions = {\n type: typeOrOptions,\n name: name!,\n inputs: inputs || {},\n parentFrameId,\n };\n } else {\n frameOptions = typeOrOptions;\n }\n\n // Validate inputs\n if (!frameOptions.name || frameOptions.name.trim().length === 0) {\n throw new FrameError(\n 'Frame name is required',\n ErrorCode.FRAME_INVALID_INPUT,\n { frameOptions }\n );\n }\n\n // Check stack depth limit\n if (this.frameStack.getDepth() >= this.config.maxStackDepth!) {\n throw new FrameError(\n `Maximum stack depth reached: ${this.config.maxStackDepth}`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n { currentDepth: this.frameStack.getDepth() }\n );\n }\n\n // Determine parent frame\n const resolvedParentId =\n frameOptions.parentFrameId || this.frameStack.getCurrentFrameId();\n \n // Get depth from parent frame, not from stack position\n let depth = 0;\n if (resolvedParentId) {\n const parentFrame = this.frameDb.getFrame(resolvedParentId);\n depth = parentFrame ? parentFrame.depth + 1 : 0;\n }\n\n // Check for depth limit\n if (depth > this.maxFrameDepth) {\n throw new FrameError(\n `Maximum frame depth exceeded: ${depth} > ${this.maxFrameDepth}`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n {\n currentDepth: depth,\n maxDepth: this.maxFrameDepth,\n frameName: frameOptions.name,\n parentFrameId: resolvedParentId,\n }\n );\n }\n\n // Check for circular reference before creating frame\n if (resolvedParentId) {\n const cycle = this.detectCycle(uuidv4(), resolvedParentId);\n if (cycle) {\n throw new FrameError(\n `Circular reference detected in frame hierarchy`,\n ErrorCode.FRAME_CYCLE_DETECTED,\n {\n parentFrameId: resolvedParentId,\n cycle,\n frameName: frameOptions.name,\n }\n );\n }\n }\n\n // Create frame data\n const frameId = uuidv4();\n const frame: Omit<Frame, 'created_at' | 'closed_at'> = {\n frame_id: frameId,\n run_id: this.currentRunId,\n project_id: this.projectId,\n parent_frame_id: resolvedParentId,\n depth,\n type: frameOptions.type,\n name: frameOptions.name,\n state: 'active',\n inputs: frameOptions.inputs || {},\n outputs: {},\n digest_json: {},\n };\n\n // Insert into database\n const createdFrame = this.frameDb.insertFrame(frame);\n\n // Add to stack\n this.frameStack.pushFrame(frameId);\n\n logger.info('Created frame', {\n frameId,\n name: frameOptions.name,\n type: frameOptions.type,\n parentFrameId: resolvedParentId,\n stackDepth: this.frameStack.getDepth(),\n });\n\n return frameId;\n }\n\n /**\n * Close a frame and generate digest\n */\n closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n trace.traceSync(\n 'function',\n 'FrameManager.closeFrame',\n { frameId, outputs },\n () => this._closeFrame(frameId, outputs)\n );\n }\n\n private _closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame to close',\n ErrorCode.FRAME_INVALID_STATE,\n {\n operation: 'closeFrame',\n stackDepth: this.frameStack.getDepth(),\n }\n );\n }\n\n // Get frame details\n const frame = this.frameDb.getFrame(targetFrameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${targetFrameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n {\n frameId: targetFrameId,\n operation: 'closeFrame',\n runId: this.currentRunId,\n }\n );\n }\n\n if (frame.state === 'closed') {\n logger.warn('Attempted to close already closed frame', {\n frameId: targetFrameId,\n });\n return;\n }\n\n // Generate digest before closing\n const digest = this.digestGenerator.generateDigest(targetFrameId);\n const finalOutputs = { ...outputs, ...digest.structured };\n\n // Update frame to closed state\n this.frameDb.updateFrame(targetFrameId, {\n state: 'closed',\n outputs: finalOutputs,\n digest_text: digest.text,\n digest_json: digest.structured,\n closed_at: Math.floor(Date.now() / 1000),\n });\n\n // Remove from stack (this will also remove any child frames)\n this.frameStack.popFrame(targetFrameId);\n\n // Close all child frames recursively\n this.closeChildFrames(targetFrameId);\n\n logger.info('Closed frame', {\n frameId: targetFrameId,\n name: frame.name,\n duration: Math.floor(Date.now() / 1000) - frame.created_at,\n digestLength: digest.text.length,\n stackDepth: this.frameStack.getDepth(),\n });\n }\n\n /**\n * Add an event to the current frame\n */\n addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.addEvent',\n { eventType, frameId },\n () => this._addEvent(eventType, payload, frameId)\n );\n }\n\n private _addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for event',\n ErrorCode.FRAME_INVALID_STATE,\n {\n eventType,\n operation: 'addEvent',\n }\n );\n }\n\n const eventId = uuidv4();\n const sequence = this.frameDb.getNextEventSequence(targetFrameId);\n\n const event: Omit<Event, 'ts'> = {\n event_id: eventId,\n frame_id: targetFrameId,\n run_id: this.currentRunId,\n seq: sequence,\n event_type: eventType,\n payload,\n };\n\n const createdEvent = this.frameDb.insertEvent(event);\n\n logger.debug('Added event', {\n eventId,\n frameId: targetFrameId,\n eventType,\n sequence,\n });\n\n return eventId;\n }\n\n /**\n * Add an anchor (important fact) to current frame\n */\n addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number = 5,\n metadata: Record<string, any> = {},\n frameId?: string\n ): string {\n return trace.traceSync(\n 'function',\n 'FrameManager.addAnchor',\n { type, frameId },\n () => this._addAnchor(type, text, priority, metadata, frameId)\n );\n }\n\n private _addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number,\n metadata: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for anchor',\n ErrorCode.FRAME_INVALID_STATE,\n {\n anchorType: type,\n operation: 'addAnchor',\n }\n );\n }\n\n const anchorId = uuidv4();\n const anchor: Omit<Anchor, 'created_at'> = {\n anchor_id: anchorId,\n frame_id: targetFrameId,\n type,\n text,\n priority,\n metadata,\n };\n\n const createdAnchor = this.frameDb.insertAnchor(anchor);\n\n logger.debug('Added anchor', {\n anchorId,\n frameId: targetFrameId,\n type,\n priority,\n });\n\n return anchorId;\n }\n\n /**\n * Get hot stack context\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.frameStack.getHotStackContext(maxEvents);\n }\n\n /**\n * Get active frame path (root to current)\n */\n getActiveFramePath(): Frame[] {\n return this.frameStack.getStackFrames();\n }\n\n /**\n * Get current frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.frameStack.getCurrentFrameId();\n }\n\n /**\n * Get stack depth\n */\n getStackDepth(): number {\n return this.frameStack.getDepth();\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n return this.frameDb.getFrame(frameId);\n }\n\n /**\n * Get frame events\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n return this.frameDb.getFrameEvents(frameId, limit);\n }\n\n /**\n * Get frame anchors\n */\n getFrameAnchors(frameId: string): Anchor[] {\n return this.frameDb.getFrameAnchors(frameId);\n }\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n return this.digestGenerator.generateDigest(frameId);\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n return this.frameStack.validateStack();\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n return this.frameDb.getStatistics();\n }\n\n /**\n * Close all child frames recursively\n */\n private closeChildFrames(parentFrameId: string): void {\n try {\n const activeFrames = this.frameDb.getFramesByProject(\n this.projectId,\n 'active'\n );\n const childFrames = activeFrames.filter(\n (f: any) => f.parent_frame_id === parentFrameId\n );\n\n for (const childFrame of childFrames) {\n if (this.frameStack.isFrameActive(childFrame.frame_id)) {\n this.closeFrame(childFrame.frame_id);\n }\n }\n } catch (error: unknown) {\n logger.warn('Failed to close child frames', { parentFrameId, error });\n }\n }\n\n /**\n * Extract active artifacts from frame events\n */\n getActiveArtifacts(frameId: string): string[] {\n const events = this.frameDb.getFrameEvents(frameId);\n const artifacts: string[] = [];\n\n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload.path) {\n artifacts.push(event.payload.path);\n }\n }\n\n return [...new Set(artifacts)];\n }\n\n /**\n * Extract constraints from frame inputs\n */\n extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n\n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n\n if (inputs.requirements && Array.isArray(inputs.requirements)) {\n constraints.push(...inputs.requirements);\n }\n\n if (inputs.limitations && Array.isArray(inputs.limitations)) {\n constraints.push(...inputs.limitations);\n }\n\n return constraints;\n }\n\n /**\n * Detect if setting a parent frame would create a cycle in the frame hierarchy.\n * Returns the cycle path if detected, or null if no cycle.\n * @param childFrameId - The frame that would be the child\n * @param parentFrameId - The proposed parent frame\n * @returns Array of frame IDs forming the cycle, or null if no cycle\n */\n private detectCycle(\n childFrameId: string,\n parentFrameId: string\n ): string[] | null {\n const visited = new Set<string>();\n const path: string[] = [];\n\n // Start from the proposed parent and traverse up the hierarchy\n let currentId: string | undefined = parentFrameId;\n \n while (currentId) {\n // If we've seen this frame before, we have a cycle\n if (visited.has(currentId)) {\n // Build the cycle path\n const cycleStart = path.indexOf(currentId);\n return path.slice(cycleStart).concat(currentId);\n }\n\n // If the current frame is the child we're trying to add, it's a cycle\n if (currentId === childFrameId) {\n return path.concat([currentId, childFrameId]);\n }\n\n visited.add(currentId);\n path.push(currentId);\n\n // Move to the parent of current frame\n const frame = this.frameDb.getFrame(currentId);\n if (!frame) {\n // Frame not found, no cycle possible through this path\n break;\n }\n currentId = frame.parent_frame_id;\n\n // Safety check: if we've traversed too many levels, something is wrong\n if (path.length > this.maxFrameDepth) {\n throw new FrameError(\n `Frame hierarchy traversal exceeded maximum depth during cycle detection`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n {\n depth: path.length,\n maxDepth: this.maxFrameDepth,\n path,\n }\n );\n }\n }\n\n return null; // No cycle detected\n }\n\n /**\n * Update parent frame of an existing frame (with cycle detection)\n * @param frameId - The frame to update\n * @param newParentFrameId - The new parent frame ID (null to make it a root frame)\n */\n public updateParentFrame(frameId: string, newParentFrameId: string | null): void {\n // Check if frame exists\n const frame = this.frameDb.getFrame(frameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${frameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n { frameId }\n );\n }\n\n // If setting a parent, check for cycles\n if (newParentFrameId) {\n const cycle = this.detectCycle(frameId, newParentFrameId);\n if (cycle) {\n throw new FrameError(\n `Cannot set parent: would create circular reference`,\n ErrorCode.FRAME_CYCLE_DETECTED,\n {\n frameId,\n newParentFrameId,\n cycle,\n currentParentId: frame.parent_frame_id,\n }\n );\n }\n\n // Check depth after parent change\n const newParentFrame = this.frameDb.getFrame(newParentFrameId);\n if (newParentFrame) {\n const newDepth = newParentFrame.depth + 1;\n if (newDepth > this.maxFrameDepth) {\n throw new FrameError(\n `Cannot set parent: would exceed maximum frame depth`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n {\n frameId,\n newParentFrameId,\n newDepth,\n maxDepth: this.maxFrameDepth,\n }\n );\n }\n }\n }\n\n // Update the frame's parent (this would need to be implemented in FrameDatabase)\n this.frameDb.updateFrame(frameId, {\n parent_frame_id: newParentFrameId,\n });\n\n logger.info('Updated parent frame', {\n frameId,\n oldParentId: frame.parent_frame_id,\n newParentId: newParentFrameId,\n });\n }\n\n /**\n * Validate the entire frame hierarchy for cycles and depth violations\n * @returns Validation result with any detected issues\n */\n public validateFrameHierarchy(): {\n isValid: boolean;\n errors: string[];\n warnings: string[];\n } {\n const errors: string[] = [];\n const warnings: string[] = [];\n const allFrames = this.frameDb.getFramesByProject(this.projectId);\n \n // Check each frame for depth violations\n for (const frame of allFrames) {\n if (frame.depth > this.maxFrameDepth) {\n errors.push(\n `Frame ${frame.frame_id} exceeds max depth: ${frame.depth} > ${this.maxFrameDepth}`\n );\n }\n \n // Warn about deep frames approaching the limit\n if (frame.depth > this.maxFrameDepth * 0.8) {\n warnings.push(\n `Frame ${frame.frame_id} is deep in hierarchy: ${frame.depth}/${this.maxFrameDepth}`\n );\n }\n }\n \n // Check for cycles by traversing from each root\n const rootFrames = allFrames.filter(f => !f.parent_frame_id);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n \n const checkForCycle = (frameId: string): boolean => {\n if (visiting.has(frameId)) {\n errors.push(`Cycle detected involving frame ${frameId}`);\n return true;\n }\n \n if (visited.has(frameId)) {\n return false;\n }\n \n visiting.add(frameId);\n \n // Check all children\n const children = allFrames.filter(f => f.parent_frame_id === frameId);\n for (const child of children) {\n if (checkForCycle(child.frame_id)) {\n return true;\n }\n }\n \n visiting.delete(frameId);\n visited.add(frameId);\n return false;\n };\n \n // Check from each root\n for (const root of rootFrames) {\n checkForCycle(root.frame_id);\n }\n \n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n }\n}\n\n// Re-export types for compatibility\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Frame", "FrameContext", "Anchor", "Event", "FrameType", "FrameState", "FrameCreationOptions", "FrameManagerConfig", "DigestResult"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { logger } from "../monitoring/logger.js";
|
|
3
|
+
class ParallelExecutor extends EventEmitter {
|
|
4
|
+
maxConcurrency;
|
|
5
|
+
queueSize;
|
|
6
|
+
defaultTimeout;
|
|
7
|
+
defaultRetries;
|
|
8
|
+
rateLimitPerMinute;
|
|
9
|
+
activeCount = 0;
|
|
10
|
+
queue = [];
|
|
11
|
+
rateLimitTokens;
|
|
12
|
+
lastRateLimitReset;
|
|
13
|
+
// Metrics
|
|
14
|
+
totalExecuted = 0;
|
|
15
|
+
totalSucceeded = 0;
|
|
16
|
+
totalFailed = 0;
|
|
17
|
+
totalDuration = 0;
|
|
18
|
+
constructor(maxConcurrency = 5, options = {}) {
|
|
19
|
+
super();
|
|
20
|
+
this.maxConcurrency = maxConcurrency;
|
|
21
|
+
this.queueSize = options.queueSize || 100;
|
|
22
|
+
this.defaultTimeout = options.defaultTimeout || 3e5;
|
|
23
|
+
this.defaultRetries = options.defaultRetries || 3;
|
|
24
|
+
this.rateLimitPerMinute = options.rateLimitPerMinute || 60;
|
|
25
|
+
this.rateLimitTokens = this.rateLimitPerMinute;
|
|
26
|
+
this.lastRateLimitReset = Date.now();
|
|
27
|
+
logger.info("Parallel Executor initialized", {
|
|
28
|
+
maxConcurrency,
|
|
29
|
+
queueSize: this.queueSize,
|
|
30
|
+
rateLimitPerMinute: this.rateLimitPerMinute
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Execute multiple tasks in parallel
|
|
35
|
+
*/
|
|
36
|
+
async executeParallel(items, executor, options) {
|
|
37
|
+
const results = [];
|
|
38
|
+
const batchSize = options?.batchSize || this.maxConcurrency;
|
|
39
|
+
const delayBetweenBatches = options?.delayBetweenBatches || 0;
|
|
40
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
41
|
+
const batch = items.slice(i, i + batchSize);
|
|
42
|
+
const batchPromises = batch.map(
|
|
43
|
+
(item, index) => this.executeWithTracking(
|
|
44
|
+
`parallel-${i + index}`,
|
|
45
|
+
() => executor(item, i + index)
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
49
|
+
batchResults.forEach((result, index) => {
|
|
50
|
+
if (result.status === "fulfilled") {
|
|
51
|
+
results.push(result.value);
|
|
52
|
+
} else {
|
|
53
|
+
results.push({
|
|
54
|
+
taskId: `parallel-${i + index}`,
|
|
55
|
+
success: false,
|
|
56
|
+
error: result.reason,
|
|
57
|
+
duration: 0,
|
|
58
|
+
attempts: 1
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (delayBetweenBatches > 0 && i + batchSize < items.length) {
|
|
63
|
+
await this.delay(delayBetweenBatches);
|
|
64
|
+
}
|
|
65
|
+
logger.debug("Batch completed", {
|
|
66
|
+
batchNumber: Math.floor(i / batchSize) + 1,
|
|
67
|
+
totalBatches: Math.ceil(items.length / batchSize),
|
|
68
|
+
successRate: results.filter((r) => r.success).length / results.length
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Execute a single task with tracking and retries
|
|
75
|
+
*/
|
|
76
|
+
async executeWithTracking(taskId, executor, options) {
|
|
77
|
+
const timeout = options?.timeout || this.defaultTimeout;
|
|
78
|
+
const maxRetries = options?.retries || this.defaultRetries;
|
|
79
|
+
let attempts = 0;
|
|
80
|
+
let lastError;
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
while (attempts < maxRetries) {
|
|
83
|
+
attempts++;
|
|
84
|
+
try {
|
|
85
|
+
await this.checkRateLimit();
|
|
86
|
+
await this.waitForSlot();
|
|
87
|
+
this.activeCount++;
|
|
88
|
+
this.emit("task-start", { taskId, attempt: attempts });
|
|
89
|
+
const result = await this.executeWithTimeout(executor, timeout);
|
|
90
|
+
this.totalSucceeded++;
|
|
91
|
+
this.emit("task-success", { taskId, attempts });
|
|
92
|
+
return {
|
|
93
|
+
taskId,
|
|
94
|
+
success: true,
|
|
95
|
+
result,
|
|
96
|
+
duration: Date.now() - startTime,
|
|
97
|
+
attempts
|
|
98
|
+
};
|
|
99
|
+
} catch (error) {
|
|
100
|
+
lastError = error;
|
|
101
|
+
logger.warn(`Task failed (attempt ${attempts}/${maxRetries})`, {
|
|
102
|
+
taskId,
|
|
103
|
+
error: lastError.message
|
|
104
|
+
});
|
|
105
|
+
this.emit("task-retry", { taskId, attempt: attempts, error: lastError });
|
|
106
|
+
if (attempts < maxRetries) {
|
|
107
|
+
await this.delay(Math.pow(2, attempts) * 1e3);
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
this.activeCount--;
|
|
111
|
+
this.totalExecuted++;
|
|
112
|
+
this.totalDuration += Date.now() - startTime;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
this.totalFailed++;
|
|
116
|
+
this.emit("task-failed", { taskId, attempts, error: lastError });
|
|
117
|
+
return {
|
|
118
|
+
taskId,
|
|
119
|
+
success: false,
|
|
120
|
+
error: lastError,
|
|
121
|
+
duration: Date.now() - startTime,
|
|
122
|
+
attempts
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Execute task with timeout
|
|
127
|
+
*/
|
|
128
|
+
async executeWithTimeout(executor, timeout) {
|
|
129
|
+
return Promise.race([
|
|
130
|
+
executor(),
|
|
131
|
+
new Promise(
|
|
132
|
+
(_, reject) => setTimeout(() => reject(new Error("Task timeout")), timeout)
|
|
133
|
+
)
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check and enforce rate limiting
|
|
138
|
+
*/
|
|
139
|
+
async checkRateLimit() {
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const timeSinceReset = now - this.lastRateLimitReset;
|
|
142
|
+
if (timeSinceReset >= 6e4) {
|
|
143
|
+
this.rateLimitTokens = this.rateLimitPerMinute;
|
|
144
|
+
this.lastRateLimitReset = now;
|
|
145
|
+
}
|
|
146
|
+
if (this.rateLimitTokens <= 0) {
|
|
147
|
+
const waitTime = 6e4 - timeSinceReset;
|
|
148
|
+
logger.debug(`Rate limit reached, waiting ${waitTime}ms`);
|
|
149
|
+
await this.delay(waitTime);
|
|
150
|
+
this.rateLimitTokens = this.rateLimitPerMinute;
|
|
151
|
+
this.lastRateLimitReset = Date.now();
|
|
152
|
+
}
|
|
153
|
+
this.rateLimitTokens--;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Wait for an available execution slot
|
|
157
|
+
*/
|
|
158
|
+
async waitForSlot() {
|
|
159
|
+
while (this.activeCount >= this.maxConcurrency) {
|
|
160
|
+
await this.delay(100);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Queue a task for execution
|
|
165
|
+
*/
|
|
166
|
+
async queueTask(task) {
|
|
167
|
+
if (this.queue.length >= this.queueSize) {
|
|
168
|
+
throw new Error("Execution queue is full");
|
|
169
|
+
}
|
|
170
|
+
return new Promise((resolve) => {
|
|
171
|
+
this.queue.push({
|
|
172
|
+
...task,
|
|
173
|
+
execute: async () => {
|
|
174
|
+
const result = await task.execute();
|
|
175
|
+
resolve({
|
|
176
|
+
taskId: task.id,
|
|
177
|
+
success: true,
|
|
178
|
+
result,
|
|
179
|
+
duration: 0,
|
|
180
|
+
attempts: 1
|
|
181
|
+
});
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
this.processQueue();
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Process queued tasks
|
|
190
|
+
*/
|
|
191
|
+
async processQueue() {
|
|
192
|
+
if (this.activeCount >= this.maxConcurrency || this.queue.length === 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
this.queue.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
196
|
+
const task = this.queue.shift();
|
|
197
|
+
if (task) {
|
|
198
|
+
this.executeWithTracking(task.id, task.execute, {
|
|
199
|
+
timeout: task.timeout,
|
|
200
|
+
retries: task.retries
|
|
201
|
+
}).then(() => {
|
|
202
|
+
this.processQueue();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Utility delay function
|
|
208
|
+
*/
|
|
209
|
+
delay(ms) {
|
|
210
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get execution metrics
|
|
214
|
+
*/
|
|
215
|
+
getMetrics() {
|
|
216
|
+
return {
|
|
217
|
+
activeCount: this.activeCount,
|
|
218
|
+
queueLength: this.queue.length,
|
|
219
|
+
totalExecuted: this.totalExecuted,
|
|
220
|
+
totalSucceeded: this.totalSucceeded,
|
|
221
|
+
totalFailed: this.totalFailed,
|
|
222
|
+
successRate: this.totalExecuted > 0 ? this.totalSucceeded / this.totalExecuted : 0,
|
|
223
|
+
averageDuration: this.totalExecuted > 0 ? this.totalDuration / this.totalExecuted : 0,
|
|
224
|
+
rateLimitTokens: this.rateLimitTokens
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Reset all metrics
|
|
229
|
+
*/
|
|
230
|
+
resetMetrics() {
|
|
231
|
+
this.totalExecuted = 0;
|
|
232
|
+
this.totalSucceeded = 0;
|
|
233
|
+
this.totalFailed = 0;
|
|
234
|
+
this.totalDuration = 0;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Gracefully shutdown executor
|
|
238
|
+
*/
|
|
239
|
+
async shutdown() {
|
|
240
|
+
logger.info("Shutting down Parallel Executor", {
|
|
241
|
+
activeCount: this.activeCount,
|
|
242
|
+
queueLength: this.queue.length
|
|
243
|
+
});
|
|
244
|
+
this.queue = [];
|
|
245
|
+
while (this.activeCount > 0) {
|
|
246
|
+
await this.delay(100);
|
|
247
|
+
}
|
|
248
|
+
logger.info("Parallel Executor shutdown complete");
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
export {
|
|
252
|
+
ParallelExecutor
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=parallel-executor.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/core/execution/parallel-executor.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Parallel Execution Engine for RLM\n * \n * Manages concurrent execution of multiple Claude API calls\n * with rate limiting, resource pooling, and failure recovery\n */\n\nimport { EventEmitter } from 'events';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface ExecutionTask<T> {\n id: string;\n execute: () => Promise<T>;\n priority?: number;\n timeout?: number;\n retries?: number;\n}\n\nexport interface ExecutionResult<T> {\n taskId: string;\n success: boolean;\n result?: T;\n error?: Error;\n duration: number;\n attempts: number;\n}\n\nexport interface ParallelExecutorOptions {\n maxConcurrency?: number;\n queueSize?: number;\n defaultTimeout?: number;\n defaultRetries?: number;\n rateLimitPerMinute?: number;\n}\n\n/**\n * Parallel Executor for managing concurrent operations\n */\nexport class ParallelExecutor extends EventEmitter {\n private maxConcurrency: number;\n private queueSize: number;\n private defaultTimeout: number;\n private defaultRetries: number;\n private rateLimitPerMinute: number;\n \n private activeCount: number = 0;\n private queue: ExecutionTask<any>[] = [];\n private rateLimitTokens: number;\n private lastRateLimitReset: number;\n \n // Metrics\n private totalExecuted: number = 0;\n private totalSucceeded: number = 0;\n private totalFailed: number = 0;\n private totalDuration: number = 0;\n\n constructor(maxConcurrency: number = 5, options: ParallelExecutorOptions = {}) {\n super();\n \n this.maxConcurrency = maxConcurrency;\n this.queueSize = options.queueSize || 100;\n this.defaultTimeout = options.defaultTimeout || 300000; // 5 minutes\n this.defaultRetries = options.defaultRetries || 3;\n this.rateLimitPerMinute = options.rateLimitPerMinute || 60;\n \n this.rateLimitTokens = this.rateLimitPerMinute;\n this.lastRateLimitReset = Date.now();\n \n logger.info('Parallel Executor initialized', {\n maxConcurrency,\n queueSize: this.queueSize,\n rateLimitPerMinute: this.rateLimitPerMinute,\n });\n }\n \n /**\n * Execute multiple tasks in parallel\n */\n async executeParallel<T>(\n items: T[],\n executor: (item: T, index: number) => Promise<void>,\n options?: {\n batchSize?: number;\n delayBetweenBatches?: number;\n }\n ): Promise<ExecutionResult<void>[]> {\n const results: ExecutionResult<void>[] = [];\n const batchSize = options?.batchSize || this.maxConcurrency;\n const delayBetweenBatches = options?.delayBetweenBatches || 0;\n \n // Process items in batches\n for (let i = 0; i < items.length; i += batchSize) {\n const batch = items.slice(i, i + batchSize);\n const batchPromises = batch.map((item, index) => \n this.executeWithTracking(\n `parallel-${i + index}`,\n () => executor(item, i + index)\n )\n );\n \n const batchResults = await Promise.allSettled(batchPromises);\n \n // Convert to ExecutionResult format\n batchResults.forEach((result, index) => {\n if (result.status === 'fulfilled') {\n results.push(result.value);\n } else {\n results.push({\n taskId: `parallel-${i + index}`,\n success: false,\n error: result.reason,\n duration: 0,\n attempts: 1,\n });\n }\n });\n \n // Delay between batches if specified\n if (delayBetweenBatches > 0 && i + batchSize < items.length) {\n await this.delay(delayBetweenBatches);\n }\n \n // Log batch progress\n logger.debug('Batch completed', {\n batchNumber: Math.floor(i / batchSize) + 1,\n totalBatches: Math.ceil(items.length / batchSize),\n successRate: results.filter(r => r.success).length / results.length,\n });\n }\n \n return results;\n }\n \n /**\n * Execute a single task with tracking and retries\n */\n async executeWithTracking<T>(\n taskId: string,\n executor: () => Promise<T>,\n options?: {\n timeout?: number;\n retries?: number;\n }\n ): Promise<ExecutionResult<T>> {\n const timeout = options?.timeout || this.defaultTimeout;\n const maxRetries = options?.retries || this.defaultRetries;\n \n let attempts = 0;\n let lastError: Error | undefined;\n const startTime = Date.now();\n \n while (attempts < maxRetries) {\n attempts++;\n \n try {\n // Check rate limit\n await this.checkRateLimit();\n \n // Wait for available slot\n await this.waitForSlot();\n \n this.activeCount++;\n this.emit('task-start', { taskId, attempt: attempts });\n \n // Execute with timeout\n const result = await this.executeWithTimeout(executor, timeout);\n \n // Success\n this.totalSucceeded++;\n this.emit('task-success', { taskId, attempts });\n \n return {\n taskId,\n success: true,\n result,\n duration: Date.now() - startTime,\n attempts,\n };\n \n } catch (error) {\n lastError = error as Error;\n \n logger.warn(`Task failed (attempt ${attempts}/${maxRetries})`, {\n taskId,\n error: lastError.message,\n });\n \n this.emit('task-retry', { taskId, attempt: attempts, error: lastError });\n \n // Exponential backoff for retries\n if (attempts < maxRetries) {\n await this.delay(Math.pow(2, attempts) * 1000);\n }\n \n } finally {\n this.activeCount--;\n this.totalExecuted++;\n this.totalDuration += Date.now() - startTime;\n }\n }\n \n // All retries exhausted\n this.totalFailed++;\n this.emit('task-failed', { taskId, attempts, error: lastError });\n \n return {\n taskId,\n success: false,\n error: lastError,\n duration: Date.now() - startTime,\n attempts,\n };\n }\n \n /**\n * Execute task with timeout\n */\n private async executeWithTimeout<T>(\n executor: () => Promise<T>,\n timeout: number\n ): Promise<T> {\n return Promise.race([\n executor(),\n new Promise<T>((_, reject) => \n setTimeout(() => reject(new Error('Task timeout')), timeout)\n ),\n ]);\n }\n \n /**\n * Check and enforce rate limiting\n */\n private async checkRateLimit(): Promise<void> {\n const now = Date.now();\n const timeSinceReset = now - this.lastRateLimitReset;\n \n // Reset tokens if a minute has passed\n if (timeSinceReset >= 60000) {\n this.rateLimitTokens = this.rateLimitPerMinute;\n this.lastRateLimitReset = now;\n }\n \n // Wait if no tokens available\n if (this.rateLimitTokens <= 0) {\n const waitTime = 60000 - timeSinceReset;\n logger.debug(`Rate limit reached, waiting ${waitTime}ms`);\n await this.delay(waitTime);\n \n // Reset after waiting\n this.rateLimitTokens = this.rateLimitPerMinute;\n this.lastRateLimitReset = Date.now();\n }\n \n this.rateLimitTokens--;\n }\n \n /**\n * Wait for an available execution slot\n */\n private async waitForSlot(): Promise<void> {\n while (this.activeCount >= this.maxConcurrency) {\n await this.delay(100); // Check every 100ms\n }\n }\n \n /**\n * Queue a task for execution\n */\n async queueTask<T>(task: ExecutionTask<T>): Promise<ExecutionResult<T>> {\n if (this.queue.length >= this.queueSize) {\n throw new Error('Execution queue is full');\n }\n \n return new Promise((resolve) => {\n this.queue.push({\n ...task,\n execute: async () => {\n const result = await task.execute();\n resolve({\n taskId: task.id,\n success: true,\n result,\n duration: 0,\n attempts: 1,\n });\n return result;\n },\n });\n \n this.processQueue();\n });\n }\n \n /**\n * Process queued tasks\n */\n private async processQueue(): Promise<void> {\n if (this.activeCount >= this.maxConcurrency || this.queue.length === 0) {\n return;\n }\n \n // Sort by priority (higher first)\n this.queue.sort((a, b) => (b.priority || 0) - (a.priority || 0));\n \n const task = this.queue.shift();\n if (task) {\n this.executeWithTracking(task.id, task.execute, {\n timeout: task.timeout,\n retries: task.retries,\n }).then(() => {\n this.processQueue(); // Process next task\n });\n }\n }\n \n /**\n * Utility delay function\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n \n /**\n * Get execution metrics\n */\n getMetrics() {\n return {\n activeCount: this.activeCount,\n queueLength: this.queue.length,\n totalExecuted: this.totalExecuted,\n totalSucceeded: this.totalSucceeded,\n totalFailed: this.totalFailed,\n successRate: this.totalExecuted > 0 ? this.totalSucceeded / this.totalExecuted : 0,\n averageDuration: this.totalExecuted > 0 ? this.totalDuration / this.totalExecuted : 0,\n rateLimitTokens: this.rateLimitTokens,\n };\n }\n \n /**\n * Reset all metrics\n */\n resetMetrics(): void {\n this.totalExecuted = 0;\n this.totalSucceeded = 0;\n this.totalFailed = 0;\n this.totalDuration = 0;\n }\n \n /**\n * Gracefully shutdown executor\n */\n async shutdown(): Promise<void> {\n logger.info('Shutting down Parallel Executor', {\n activeCount: this.activeCount,\n queueLength: this.queue.length,\n });\n \n // Clear queue\n this.queue = [];\n \n // Wait for active tasks to complete\n while (this.activeCount > 0) {\n await this.delay(100);\n }\n \n logger.info('Parallel Executor shutdown complete');\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
@@ -59,7 +59,7 @@ class UpdateChecker {
|
|
|
59
59
|
static async fetchLatestVersion() {
|
|
60
60
|
try {
|
|
61
61
|
const fetchVersion = async () => {
|
|
62
|
-
const output =
|
|
62
|
+
const output = execFileSync("npm", ["view", this.PACKAGE_NAME, "version"], {
|
|
63
63
|
encoding: "utf-8",
|
|
64
64
|
stdio: ["pipe", "pipe", "ignore"],
|
|
65
65
|
timeout: 5e3
|