memento-mcp-server 1.16.0 → 1.16.1
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/shared/utils/procedural-memory-change-detector.d.ts +142 -0
- package/dist/shared/utils/procedural-memory-change-detector.d.ts.map +1 -0
- package/dist/shared/utils/procedural-memory-change-detector.js +401 -0
- package/dist/shared/utils/procedural-memory-change-detector.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural Memory 변경 감지 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* 이 유틸리티는 Procedural Memory의 변경 사항을 감지하고 분류합니다.
|
|
5
|
+
* PRD FR4: 판정 기준 구현을 위한 유틸리티 함수 제공
|
|
6
|
+
*
|
|
7
|
+
* 주요 기능:
|
|
8
|
+
* - Procedural Memory 스냅샷 생성
|
|
9
|
+
* - 변경 타입 분류 (version_created, steps_modified, metadata_modified, content_modified, reflection_added, deleted, none)
|
|
10
|
+
* - JSON 정규화 및 해시 계산
|
|
11
|
+
*/
|
|
12
|
+
import Database from 'better-sqlite3';
|
|
13
|
+
/**
|
|
14
|
+
* Procedural Memory 스냅샷 인터페이스
|
|
15
|
+
*
|
|
16
|
+
* 변경 감지를 위해 필요한 모든 필드를 포함합니다.
|
|
17
|
+
* memory_item 테이블과 memory_link 테이블의 version_of 관계를 조합하여 생성됩니다.
|
|
18
|
+
*/
|
|
19
|
+
export interface ProceduralMemorySnapshot {
|
|
20
|
+
/** 메모리 ID */
|
|
21
|
+
id: string | null;
|
|
22
|
+
/** 메모리 내용 */
|
|
23
|
+
content: string | null;
|
|
24
|
+
/** 중요도 (0-1) */
|
|
25
|
+
importance: number | null;
|
|
26
|
+
/** 프라이버시 범위 */
|
|
27
|
+
privacy_scope: string | null;
|
|
28
|
+
/** 프로세스 이름 */
|
|
29
|
+
workflow_name: string | null;
|
|
30
|
+
/** 기술/능력 이름 */
|
|
31
|
+
skill_name: string | null;
|
|
32
|
+
/** steps JSON 배열의 해시값 */
|
|
33
|
+
steps_hash: string | null;
|
|
34
|
+
/** trigger_conditions JSON 객체의 해시값 */
|
|
35
|
+
trigger_conditions_hash: string | null;
|
|
36
|
+
/** 작업 목표 */
|
|
37
|
+
task_goal: string | null;
|
|
38
|
+
/** reflection_notes 배열의 길이 (JSON 파싱 후) */
|
|
39
|
+
reflection_notes_count: number | null;
|
|
40
|
+
/** 편집 횟수 */
|
|
41
|
+
edit_count: number | null;
|
|
42
|
+
/** version_of 관계의 target_id (memory_link에서 조회) */
|
|
43
|
+
version_of_target_id: string | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 변경 타입 열거형
|
|
47
|
+
*
|
|
48
|
+
* PRD FR4 기반 판정 기준:
|
|
49
|
+
* - version_created: versioned 모드로 새 버전 생성
|
|
50
|
+
* - steps_modified: steps JSON 배열 변경
|
|
51
|
+
* - metadata_modified: workflow_name, skill_name, trigger_conditions_hash, task_goal, edit_count 변경
|
|
52
|
+
* - content_modified: content 필드 변경
|
|
53
|
+
* - reflection_added: reflection_notes 배열 길이 증가
|
|
54
|
+
* - deleted: 메모리 삭제
|
|
55
|
+
* - none: 변경 없음
|
|
56
|
+
*/
|
|
57
|
+
export type ChangeType = 'version_created' | 'steps_modified' | 'metadata_modified' | 'content_modified' | 'reflection_added' | 'deleted' | 'none';
|
|
58
|
+
/**
|
|
59
|
+
* 변경 감지 결과 인터페이스
|
|
60
|
+
*
|
|
61
|
+
* 변경 여부와 변경 타입, 상세 변경 내역을 포함합니다.
|
|
62
|
+
*/
|
|
63
|
+
export interface ChangeDetectionResult {
|
|
64
|
+
/** 변경 여부 */
|
|
65
|
+
hasChanged: boolean;
|
|
66
|
+
/** 변경 타입 */
|
|
67
|
+
changeType: ChangeType;
|
|
68
|
+
/** 변경된 필드 목록 (디버깅 및 로깅용) */
|
|
69
|
+
changedFields: string[];
|
|
70
|
+
/** 변경 전 스냅샷 */
|
|
71
|
+
before: ProceduralMemorySnapshot | null;
|
|
72
|
+
/** 변경 후 스냅샷 */
|
|
73
|
+
after: ProceduralMemorySnapshot | null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* JSON 정규화 유틸리티 함수
|
|
77
|
+
*
|
|
78
|
+
* 해시 계산을 위해 일관된 JSON 문자열을 생성합니다.
|
|
79
|
+
*
|
|
80
|
+
* 정규화 규칙:
|
|
81
|
+
* - 객체의 키를 알파벳 순서로 정렬
|
|
82
|
+
* - 숫자는 일관된 형식으로 직렬화 (JSON.stringify의 기본 동작 사용)
|
|
83
|
+
* - 배열의 순서는 유지 (배열은 순서가 중요하므로 정렬하지 않음)
|
|
84
|
+
* - null 값은 "null" 문자열로 처리
|
|
85
|
+
* - undefined는 제외 (객체에서 undefined 필드는 제외됨)
|
|
86
|
+
*
|
|
87
|
+
* @param value - 정규화할 값 (객체, 배열, 원시 타입)
|
|
88
|
+
* @returns 정규화된 JSON 문자열
|
|
89
|
+
*/
|
|
90
|
+
export declare function normalizeJson(value: unknown): string;
|
|
91
|
+
/**
|
|
92
|
+
* JSON 문자열의 SHA-256 해시 계산
|
|
93
|
+
*
|
|
94
|
+
* 해시 계산 전에 JSON을 정규화하여 일관된 해시값을 생성합니다.
|
|
95
|
+
*
|
|
96
|
+
* 처리 규칙:
|
|
97
|
+
* - `jsonString === null`: `"null"` 문자열을 해시 (SHA-256 hash of `"null"`)
|
|
98
|
+
* - `jsonString === ""` (빈 문자열): 빈 문자열을 해시 (SHA-256 hash of `""`)
|
|
99
|
+
* - `jsonString === "null"` (문자열 "null"): JSON 파싱 시도 → `null`로 파싱되면 정규화 후 해시, 실패 시 원문 해시
|
|
100
|
+
* - 일반 JSON 문자열: JSON 파싱 → 정규화 → 해시
|
|
101
|
+
* - 파싱 실패 시: 원문 문자열을 해시 (fallback)
|
|
102
|
+
*
|
|
103
|
+
* **일관성**: null 입력과 "null" 문자열 입력은 다른 해시값을 반환
|
|
104
|
+
* - null → "null" 문자열 해시
|
|
105
|
+
* - "null" → JSON 파싱 후 정규화된 해시
|
|
106
|
+
*
|
|
107
|
+
* @param jsonString - 해시할 JSON 문자열 (또는 null)
|
|
108
|
+
* @returns SHA-256 해시값 (hex 문자열)
|
|
109
|
+
*/
|
|
110
|
+
export declare function computeJsonHash(jsonString: string | null): string;
|
|
111
|
+
/**
|
|
112
|
+
* Procedural Memory 스냅샷 생성
|
|
113
|
+
*
|
|
114
|
+
* memory_item 테이블에서 메모리를 조회하고, memory_link 테이블에서 version_of 관계를 조회하여
|
|
115
|
+
* 변경 감지에 필요한 모든 정보를 포함한 스냅샷을 생성합니다.
|
|
116
|
+
*
|
|
117
|
+
* @param db - 데이터베이스 인스턴스
|
|
118
|
+
* @param memoryId - 메모리 ID
|
|
119
|
+
* @returns ProceduralMemorySnapshot 또는 null (메모리가 없거나 procedural 타입이 아닌 경우)
|
|
120
|
+
*/
|
|
121
|
+
export declare function createProceduralMemorySnapshot(db: Database.Database, memoryId: string): ProceduralMemorySnapshot | null;
|
|
122
|
+
/**
|
|
123
|
+
* Procedural Memory 변경 감지
|
|
124
|
+
*
|
|
125
|
+
* PRD FR4 기반 판정 기준에 따라 변경 여부와 변경 타입을 판정합니다.
|
|
126
|
+
*
|
|
127
|
+
* 판정 우선순위:
|
|
128
|
+
* 1. 경계값 처리 (null 체크)
|
|
129
|
+
* 2. version_created
|
|
130
|
+
* 3. steps_modified
|
|
131
|
+
* 4. metadata_modified
|
|
132
|
+
* 5. content_modified
|
|
133
|
+
* 6. reflection_added
|
|
134
|
+
* 7. deleted (경계값 처리에서 이미 처리됨)
|
|
135
|
+
* 8. none
|
|
136
|
+
*
|
|
137
|
+
* @param before - 변경 전 스냅샷 (또는 null)
|
|
138
|
+
* @param after - 변경 후 스냅샷 (또는 null)
|
|
139
|
+
* @returns 변경 감지 결과
|
|
140
|
+
*/
|
|
141
|
+
export declare function hasProceduralMemoryChanged(before: ProceduralMemorySnapshot | null, after: ProceduralMemorySnapshot | null): ChangeDetectionResult;
|
|
142
|
+
//# sourceMappingURL=procedural-memory-change-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedural-memory-change-detector.d.ts","sourceRoot":"","sources":["../../../src/shared/utils/procedural-memory-change-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,aAAa;IACb,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,aAAa;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gBAAgB;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe;IACf,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,yBAAyB;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sCAAsC;IACtC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,YAAY;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,0CAA0C;IAC1C,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,YAAY;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kDAAkD;IAClD,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAClB,iBAAiB,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,SAAS,GACT,MAAM,CAAC;AAEX;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY;IACZ,UAAU,EAAE,UAAU,CAAC;IACvB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe;IACf,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACxC,eAAe;IACf,KAAK,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACxC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2CpD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA6CjE;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,GACf,wBAAwB,GAAG,IAAI,CA+DjC;AAkBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,wBAAwB,GAAG,IAAI,EACvC,KAAK,EAAE,wBAAwB,GAAG,IAAI,GACrC,qBAAqB,CAkLvB"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural Memory 변경 감지 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* 이 유틸리티는 Procedural Memory의 변경 사항을 감지하고 분류합니다.
|
|
5
|
+
* PRD FR4: 판정 기준 구현을 위한 유틸리티 함수 제공
|
|
6
|
+
*
|
|
7
|
+
* 주요 기능:
|
|
8
|
+
* - Procedural Memory 스냅샷 생성
|
|
9
|
+
* - 변경 타입 분류 (version_created, steps_modified, metadata_modified, content_modified, reflection_added, deleted, none)
|
|
10
|
+
* - JSON 정규화 및 해시 계산
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from 'crypto';
|
|
13
|
+
import Database from 'better-sqlite3';
|
|
14
|
+
import { DatabaseUtils } from './database.js';
|
|
15
|
+
/**
|
|
16
|
+
* JSON 정규화 유틸리티 함수
|
|
17
|
+
*
|
|
18
|
+
* 해시 계산을 위해 일관된 JSON 문자열을 생성합니다.
|
|
19
|
+
*
|
|
20
|
+
* 정규화 규칙:
|
|
21
|
+
* - 객체의 키를 알파벳 순서로 정렬
|
|
22
|
+
* - 숫자는 일관된 형식으로 직렬화 (JSON.stringify의 기본 동작 사용)
|
|
23
|
+
* - 배열의 순서는 유지 (배열은 순서가 중요하므로 정렬하지 않음)
|
|
24
|
+
* - null 값은 "null" 문자열로 처리
|
|
25
|
+
* - undefined는 제외 (객체에서 undefined 필드는 제외됨)
|
|
26
|
+
*
|
|
27
|
+
* @param value - 정규화할 값 (객체, 배열, 원시 타입)
|
|
28
|
+
* @returns 정규화된 JSON 문자열
|
|
29
|
+
*/
|
|
30
|
+
export function normalizeJson(value) {
|
|
31
|
+
// null 처리
|
|
32
|
+
if (value === null) {
|
|
33
|
+
return 'null';
|
|
34
|
+
}
|
|
35
|
+
// undefined 처리 (null로 변환)
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
return 'null';
|
|
38
|
+
}
|
|
39
|
+
// 원시 타입 처리 (JSON.stringify 사용)
|
|
40
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
41
|
+
return JSON.stringify(value);
|
|
42
|
+
}
|
|
43
|
+
// 배열 처리 (순서 유지, 재귀적으로 정규화)
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
const normalizedItems = value.map(item => normalizeJson(item));
|
|
46
|
+
return `[${normalizedItems.join(',')}]`;
|
|
47
|
+
}
|
|
48
|
+
// 객체 처리 (키 정렬, 재귀적으로 정규화)
|
|
49
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
50
|
+
const obj = value;
|
|
51
|
+
const sortedKeys = Object.keys(obj).sort();
|
|
52
|
+
const normalizedPairs = [];
|
|
53
|
+
for (const key of sortedKeys) {
|
|
54
|
+
const val = obj[key];
|
|
55
|
+
// undefined 필드는 제외 (일관된 해시를 위해)
|
|
56
|
+
if (val !== undefined) {
|
|
57
|
+
const normalizedValue = normalizeJson(val);
|
|
58
|
+
// 키와 값을 JSON 형식으로 직렬화
|
|
59
|
+
normalizedPairs.push(`${JSON.stringify(key)}:${normalizedValue}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return `{${normalizedPairs.join(',')}}`;
|
|
63
|
+
}
|
|
64
|
+
// 예상치 못한 타입은 null로 처리
|
|
65
|
+
return 'null';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* JSON 문자열의 SHA-256 해시 계산
|
|
69
|
+
*
|
|
70
|
+
* 해시 계산 전에 JSON을 정규화하여 일관된 해시값을 생성합니다.
|
|
71
|
+
*
|
|
72
|
+
* 처리 규칙:
|
|
73
|
+
* - `jsonString === null`: `"null"` 문자열을 해시 (SHA-256 hash of `"null"`)
|
|
74
|
+
* - `jsonString === ""` (빈 문자열): 빈 문자열을 해시 (SHA-256 hash of `""`)
|
|
75
|
+
* - `jsonString === "null"` (문자열 "null"): JSON 파싱 시도 → `null`로 파싱되면 정규화 후 해시, 실패 시 원문 해시
|
|
76
|
+
* - 일반 JSON 문자열: JSON 파싱 → 정규화 → 해시
|
|
77
|
+
* - 파싱 실패 시: 원문 문자열을 해시 (fallback)
|
|
78
|
+
*
|
|
79
|
+
* **일관성**: null 입력과 "null" 문자열 입력은 다른 해시값을 반환
|
|
80
|
+
* - null → "null" 문자열 해시
|
|
81
|
+
* - "null" → JSON 파싱 후 정규화된 해시
|
|
82
|
+
*
|
|
83
|
+
* @param jsonString - 해시할 JSON 문자열 (또는 null)
|
|
84
|
+
* @returns SHA-256 해시값 (hex 문자열)
|
|
85
|
+
*/
|
|
86
|
+
export function computeJsonHash(jsonString) {
|
|
87
|
+
// null 처리: "null" 문자열을 해시
|
|
88
|
+
if (jsonString === null) {
|
|
89
|
+
const hash = createHash('sha256');
|
|
90
|
+
hash.update('null');
|
|
91
|
+
return hash.digest('hex');
|
|
92
|
+
}
|
|
93
|
+
// 빈 문자열 처리: 빈 문자열을 해시
|
|
94
|
+
if (jsonString === '') {
|
|
95
|
+
const hash = createHash('sha256');
|
|
96
|
+
hash.update('');
|
|
97
|
+
return hash.digest('hex');
|
|
98
|
+
}
|
|
99
|
+
// 문자열 "null" 처리: JSON 파싱 시도
|
|
100
|
+
if (jsonString === 'null') {
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(jsonString);
|
|
103
|
+
// null로 파싱되면 정규화 후 해시
|
|
104
|
+
const normalized = normalizeJson(parsed);
|
|
105
|
+
const hash = createHash('sha256');
|
|
106
|
+
hash.update(normalized);
|
|
107
|
+
return hash.digest('hex');
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// 파싱 실패 시 원문 해시 (fallback)
|
|
111
|
+
const hash = createHash('sha256');
|
|
112
|
+
hash.update(jsonString);
|
|
113
|
+
return hash.digest('hex');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// 일반 JSON 문자열 처리: JSON 파싱 → 정규화 → 해시
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(jsonString);
|
|
119
|
+
const normalized = normalizeJson(parsed);
|
|
120
|
+
const hash = createHash('sha256');
|
|
121
|
+
hash.update(normalized);
|
|
122
|
+
return hash.digest('hex');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// 파싱 실패 시 원문 문자열을 해시 (fallback)
|
|
126
|
+
const hash = createHash('sha256');
|
|
127
|
+
hash.update(jsonString);
|
|
128
|
+
return hash.digest('hex');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* reflection_notes JSON 문자열의 배열 길이 계산
|
|
133
|
+
*
|
|
134
|
+
* @param reflectionNotes - reflection_notes JSON 문자열 (또는 null)
|
|
135
|
+
* @returns 배열 길이 (파싱 실패 시 null)
|
|
136
|
+
*/
|
|
137
|
+
function computeReflectionNotesCount(reflectionNotes) {
|
|
138
|
+
if (reflectionNotes === null || reflectionNotes === '') {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(reflectionNotes);
|
|
143
|
+
// 배열인 경우 길이 반환
|
|
144
|
+
if (Array.isArray(parsed)) {
|
|
145
|
+
return parsed.length;
|
|
146
|
+
}
|
|
147
|
+
// 단일 객체인 경우 1 반환 (Phase 1 호환성)
|
|
148
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
// 예상치 못한 타입
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// 파싱 실패 시 null 반환
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Procedural Memory 스냅샷 생성
|
|
161
|
+
*
|
|
162
|
+
* memory_item 테이블에서 메모리를 조회하고, memory_link 테이블에서 version_of 관계를 조회하여
|
|
163
|
+
* 변경 감지에 필요한 모든 정보를 포함한 스냅샷을 생성합니다.
|
|
164
|
+
*
|
|
165
|
+
* @param db - 데이터베이스 인스턴스
|
|
166
|
+
* @param memoryId - 메모리 ID
|
|
167
|
+
* @returns ProceduralMemorySnapshot 또는 null (메모리가 없거나 procedural 타입이 아닌 경우)
|
|
168
|
+
*/
|
|
169
|
+
export function createProceduralMemorySnapshot(db, memoryId) {
|
|
170
|
+
// memory_item 테이블에서 메모리 조회
|
|
171
|
+
const memory = DatabaseUtils.get(db, `SELECT
|
|
172
|
+
id, content, importance, privacy_scope, workflow_name, skill_name,
|
|
173
|
+
steps, trigger_conditions, task_goal, reflection_notes, edit_count, last_accessed
|
|
174
|
+
FROM memory_item
|
|
175
|
+
WHERE id = ? AND type = 'procedural'`, [memoryId]);
|
|
176
|
+
// 메모리가 없거나 procedural 타입이 아닌 경우 null 반환
|
|
177
|
+
if (!memory) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
// memory_link 테이블에서 version_of 관계 조회
|
|
181
|
+
// source_id가 현재 메모리 id이고 relation_type이 'version_of'인 경우
|
|
182
|
+
const versionLink = DatabaseUtils.get(db, `SELECT target_id
|
|
183
|
+
FROM memory_link
|
|
184
|
+
WHERE source_id = ? AND relation_type = 'version_of'
|
|
185
|
+
LIMIT 1`, [memoryId]);
|
|
186
|
+
// steps와 trigger_conditions 해시 계산
|
|
187
|
+
const stepsHash = computeJsonHash(memory.steps);
|
|
188
|
+
const triggerConditionsHash = computeJsonHash(memory.trigger_conditions);
|
|
189
|
+
// reflection_notes 배열 길이 계산
|
|
190
|
+
const reflectionNotesCount = computeReflectionNotesCount(memory.reflection_notes);
|
|
191
|
+
// 스냅샷 생성
|
|
192
|
+
return {
|
|
193
|
+
id: memory.id,
|
|
194
|
+
content: memory.content,
|
|
195
|
+
importance: memory.importance,
|
|
196
|
+
privacy_scope: memory.privacy_scope,
|
|
197
|
+
workflow_name: memory.workflow_name,
|
|
198
|
+
skill_name: memory.skill_name,
|
|
199
|
+
steps_hash: stepsHash,
|
|
200
|
+
trigger_conditions_hash: triggerConditionsHash,
|
|
201
|
+
task_goal: memory.task_goal,
|
|
202
|
+
reflection_notes_count: reflectionNotesCount,
|
|
203
|
+
edit_count: memory.edit_count ?? 0,
|
|
204
|
+
version_of_target_id: versionLink?.target_id ?? null,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* 두 값가 같은지 비교 (null 처리 포함)
|
|
209
|
+
*/
|
|
210
|
+
function isEqual(a, b) {
|
|
211
|
+
// 둘 다 null이거나 undefined인 경우
|
|
212
|
+
if ((a === null || a === undefined) && (b === null || b === undefined)) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
// 하나만 null이거나 undefined인 경우
|
|
216
|
+
if ((a === null || a === undefined) || (b === null || b === undefined)) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
// 값 비교
|
|
220
|
+
return a === b;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Procedural Memory 변경 감지
|
|
224
|
+
*
|
|
225
|
+
* PRD FR4 기반 판정 기준에 따라 변경 여부와 변경 타입을 판정합니다.
|
|
226
|
+
*
|
|
227
|
+
* 판정 우선순위:
|
|
228
|
+
* 1. 경계값 처리 (null 체크)
|
|
229
|
+
* 2. version_created
|
|
230
|
+
* 3. steps_modified
|
|
231
|
+
* 4. metadata_modified
|
|
232
|
+
* 5. content_modified
|
|
233
|
+
* 6. reflection_added
|
|
234
|
+
* 7. deleted (경계값 처리에서 이미 처리됨)
|
|
235
|
+
* 8. none
|
|
236
|
+
*
|
|
237
|
+
* @param before - 변경 전 스냅샷 (또는 null)
|
|
238
|
+
* @param after - 변경 후 스냅샷 (또는 null)
|
|
239
|
+
* @returns 변경 감지 결과
|
|
240
|
+
*/
|
|
241
|
+
export function hasProceduralMemoryChanged(before, after) {
|
|
242
|
+
// 경계값 처리: 둘 다 null
|
|
243
|
+
if (before === null && after === null) {
|
|
244
|
+
return {
|
|
245
|
+
hasChanged: false,
|
|
246
|
+
changeType: 'none',
|
|
247
|
+
changedFields: [],
|
|
248
|
+
before: null,
|
|
249
|
+
after: null,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
// 경계값 처리: 신규 생성 (before === null && after !== null)
|
|
253
|
+
if (before === null && after !== null) {
|
|
254
|
+
// versioned 모드로 생성된 경우
|
|
255
|
+
if (after.version_of_target_id !== null) {
|
|
256
|
+
return {
|
|
257
|
+
hasChanged: true,
|
|
258
|
+
changeType: 'version_created',
|
|
259
|
+
changedFields: ['id', 'version_of_target_id'],
|
|
260
|
+
before: null,
|
|
261
|
+
after,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// 단순 신규 생성 (메타데이터 변경으로 간주)
|
|
265
|
+
return {
|
|
266
|
+
hasChanged: true,
|
|
267
|
+
changeType: 'metadata_modified',
|
|
268
|
+
changedFields: ['id'],
|
|
269
|
+
before: null,
|
|
270
|
+
after,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// 경계값 처리: 삭제 (before !== null && after === null)
|
|
274
|
+
if (before !== null && after === null) {
|
|
275
|
+
return {
|
|
276
|
+
hasChanged: true,
|
|
277
|
+
changeType: 'deleted',
|
|
278
|
+
changedFields: ['id'],
|
|
279
|
+
before,
|
|
280
|
+
after: null,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// 이제 before와 after가 모두 null이 아님을 보장
|
|
284
|
+
// TypeScript 타입 가드를 위해 명시적 체크
|
|
285
|
+
if (before === null || after === null) {
|
|
286
|
+
// 이 경우는 발생하지 않아야 하지만 타입 안전성을 위해
|
|
287
|
+
return {
|
|
288
|
+
hasChanged: false,
|
|
289
|
+
changeType: 'none',
|
|
290
|
+
changedFields: [],
|
|
291
|
+
before,
|
|
292
|
+
after,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
// 변경된 필드 추적
|
|
296
|
+
const changedFields = [];
|
|
297
|
+
// version_created 체크: versioned 모드로 새 버전 생성
|
|
298
|
+
if (before.version_of_target_id === null &&
|
|
299
|
+
after.version_of_target_id !== null) {
|
|
300
|
+
changedFields.push('version_of_target_id');
|
|
301
|
+
return {
|
|
302
|
+
hasChanged: true,
|
|
303
|
+
changeType: 'version_created',
|
|
304
|
+
changedFields,
|
|
305
|
+
before,
|
|
306
|
+
after,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
// steps_modified 체크: steps_hash 변경
|
|
310
|
+
if (!isEqual(before.steps_hash, after.steps_hash)) {
|
|
311
|
+
changedFields.push('steps_hash');
|
|
312
|
+
return {
|
|
313
|
+
hasChanged: true,
|
|
314
|
+
changeType: 'steps_modified',
|
|
315
|
+
changedFields,
|
|
316
|
+
before,
|
|
317
|
+
after,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
// metadata_modified 체크: workflow_name, skill_name, trigger_conditions_hash, task_goal, edit_count 변경
|
|
321
|
+
const metadataFields = [
|
|
322
|
+
'workflow_name',
|
|
323
|
+
'skill_name',
|
|
324
|
+
'trigger_conditions_hash',
|
|
325
|
+
'task_goal',
|
|
326
|
+
'edit_count',
|
|
327
|
+
];
|
|
328
|
+
const metadataChanged = metadataFields.some((field) => {
|
|
329
|
+
if (!isEqual(before[field], after[field])) {
|
|
330
|
+
changedFields.push(field);
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
});
|
|
335
|
+
if (metadataChanged) {
|
|
336
|
+
return {
|
|
337
|
+
hasChanged: true,
|
|
338
|
+
changeType: 'metadata_modified',
|
|
339
|
+
changedFields,
|
|
340
|
+
before,
|
|
341
|
+
after,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
// content_modified 체크: content 변경
|
|
345
|
+
if (!isEqual(before.content, after.content)) {
|
|
346
|
+
changedFields.push('content');
|
|
347
|
+
return {
|
|
348
|
+
hasChanged: true,
|
|
349
|
+
changeType: 'content_modified',
|
|
350
|
+
changedFields,
|
|
351
|
+
before,
|
|
352
|
+
after,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
// reflection_added 체크: reflection_notes_count 증가
|
|
356
|
+
if (before.reflection_notes_count !== null &&
|
|
357
|
+
after.reflection_notes_count !== null &&
|
|
358
|
+
after.reflection_notes_count > before.reflection_notes_count) {
|
|
359
|
+
changedFields.push('reflection_notes_count');
|
|
360
|
+
return {
|
|
361
|
+
hasChanged: true,
|
|
362
|
+
changeType: 'reflection_added',
|
|
363
|
+
changedFields,
|
|
364
|
+
before,
|
|
365
|
+
after,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
// 모든 필드 비교 (나머지 필드들도 확인)
|
|
369
|
+
const allFields = [
|
|
370
|
+
'id',
|
|
371
|
+
'importance',
|
|
372
|
+
'privacy_scope',
|
|
373
|
+
'reflection_notes_count',
|
|
374
|
+
'version_of_target_id',
|
|
375
|
+
];
|
|
376
|
+
allFields.forEach((field) => {
|
|
377
|
+
if (!isEqual(before[field], after[field])) {
|
|
378
|
+
changedFields.push(field);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
// 변경이 감지되지 않은 경우
|
|
382
|
+
if (changedFields.length === 0) {
|
|
383
|
+
return {
|
|
384
|
+
hasChanged: false,
|
|
385
|
+
changeType: 'none',
|
|
386
|
+
changedFields: [],
|
|
387
|
+
before,
|
|
388
|
+
after,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
// 예상치 못한 경우: 변경이 감지되었지만 위의 조건에 해당하지 않음
|
|
392
|
+
// metadata_modified로 처리 (안전한 기본값)
|
|
393
|
+
return {
|
|
394
|
+
hasChanged: true,
|
|
395
|
+
changeType: 'metadata_modified',
|
|
396
|
+
changedFields,
|
|
397
|
+
before,
|
|
398
|
+
after,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=procedural-memory-change-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedural-memory-change-detector.js","sourceRoot":"","sources":["../../../src/shared/utils/procedural-memory-change-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA0E9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,UAAU;IACV,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0BAA0B;IAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+BAA+B;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QACzF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,2BAA2B;IAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,CAAC;IAED,0BAA0B;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,eAAe,GAAa,EAAE,CAAC;QAErC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YACrB,gCAAgC;YAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,eAAe,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBAC3C,sBAAsB;gBACtB,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QAED,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,CAAC;IAED,sBAAsB;IACtB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,eAAe,CAAC,UAAyB;IACvD,0BAA0B;IAC1B,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,sBAAsB;IACtB,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,4BAA4B;IAC5B,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACtC,sBAAsB;YACtB,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;YAC3B,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,2BAA2B,CAAC,eAA8B;IACjE,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,KAAK,EAAE,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC3C,eAAe;QACf,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;QACD,+BAA+B;QAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,YAAY;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAC5C,EAAqB,EACrB,QAAgB;IAEhB,2BAA2B;IAC3B,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAC9B,EAAE,EACF;;;;yCAIqC,EACrC,CAAC,QAAQ,CAAC,CAcC,CAAC;IAEd,wCAAwC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qCAAqC;IACrC,yDAAyD;IACzD,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CACnC,EAAE,EACF;;;YAGQ,EACR,CAAC,QAAQ,CAAC,CAC0B,CAAC;IAEvC,kCAAkC;IAClC,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,qBAAqB,GAAG,eAAe,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAEzE,4BAA4B;IAC5B,MAAM,oBAAoB,GAAG,2BAA2B,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAElF,SAAS;IACT,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,SAAS;QACrB,uBAAuB,EAAE,qBAAqB;QAC9C,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,sBAAsB,EAAE,oBAAoB;QAC5C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;QAClC,oBAAoB,EAAE,WAAW,EAAE,SAAS,IAAI,IAAI;KACrD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,CAAU,EAAE,CAAU;IACrC,4BAA4B;IAC5B,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,4BAA4B;IAC5B,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO;IACP,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAuC,EACvC,KAAsC;IAEtC,mBAAmB;IACnB,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,MAAM;YAClB,aAAa,EAAE,EAAE;YACjB,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED,oDAAoD;IACpD,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACtC,uBAAuB;QACvB,IAAI,KAAK,CAAC,oBAAoB,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO;gBACL,UAAU,EAAE,IAAI;gBAChB,UAAU,EAAE,iBAAiB;gBAC7B,aAAa,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC;gBAC7C,MAAM,EAAE,IAAI;gBACZ,KAAK;aACN,CAAC;QACJ,CAAC;QACD,2BAA2B;QAC3B,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,mBAAmB;YAC/B,aAAa,EAAE,CAAC,IAAI,CAAC;YACrB,MAAM,EAAE,IAAI;YACZ,KAAK;SACN,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,SAAS;YACrB,aAAa,EAAE,CAAC,IAAI,CAAC;YACrB,MAAM;YACN,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,8BAA8B;IAC9B,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACtC,gCAAgC;QAChC,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,MAAM;YAClB,aAAa,EAAE,EAAE;YACjB,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,YAAY;IACZ,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,4CAA4C;IAC5C,IACE,MAAM,CAAC,oBAAoB,KAAK,IAAI;QACpC,KAAK,CAAC,oBAAoB,KAAK,IAAI,EACnC,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC3C,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,iBAAiB;YAC7B,aAAa;YACb,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAClD,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjC,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,gBAAgB;YAC5B,aAAa;YACb,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,qGAAqG;IACrG,MAAM,cAAc,GAA0C;QAC5D,eAAe;QACf,YAAY;QACZ,yBAAyB;QACzB,WAAW;QACX,YAAY;KACb,CAAC;IAEF,MAAM,eAAe,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACpD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1C,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,mBAAmB;YAC/B,aAAa;YACb,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,kBAAkB;YAC9B,aAAa;YACb,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,IACE,MAAM,CAAC,sBAAsB,KAAK,IAAI;QACtC,KAAK,CAAC,sBAAsB,KAAK,IAAI;QACrC,KAAK,CAAC,sBAAsB,GAAG,MAAM,CAAC,sBAAsB,EAC5D,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC7C,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,kBAAkB;YAC9B,aAAa;YACb,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,MAAM,SAAS,GAA0C;QACvD,IAAI;QACJ,YAAY;QACZ,eAAe;QACf,wBAAwB;QACxB,sBAAsB;KACvB,CAAC;IAEF,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1C,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,iBAAiB;IACjB,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,MAAM;YAClB,aAAa,EAAE,EAAE;YACjB,MAAM;YACN,KAAK;SACN,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,kCAAkC;IAClC,OAAO;QACL,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,mBAAmB;QAC/B,aAAa;QACb,MAAM;QACN,KAAK;KACN,CAAC;AACJ,CAAC"}
|