synapse-kit 0.0.0-stage → 0.3.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/LICENSE +21 -0
- package/README.ko.md +129 -0
- package/README.md +127 -2
- package/dist/causal-memory.json +4581 -0
- package/dist/cli-memory.d.ts +5 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +3474 -0
- package/dist/compiler/causal-build.d.ts +51 -0
- package/dist/compiler/causal-graph.d.ts +6 -0
- package/dist/compiler/cli.d.ts +2 -0
- package/dist/compiler/cli.js +1299 -0
- package/dist/compiler/core/config.d.ts +16 -0
- package/dist/compiler/core/engine.d.ts +17 -0
- package/dist/compiler/core/reporter.d.ts +5 -0
- package/dist/compiler/i18n.d.ts +281 -0
- package/dist/compiler/index.d.ts +21 -0
- package/dist/compiler/index.js +1983 -0
- package/dist/compiler/plugins/cpp.d.ts +19 -0
- package/dist/compiler/plugins/csharp.d.ts +13 -0
- package/dist/compiler/plugins/go.d.ts +15 -0
- package/dist/compiler/plugins/java.d.ts +16 -0
- package/dist/compiler/plugins/native.d.ts +12 -0
- package/dist/compiler/plugins/nsis.d.ts +8 -0
- package/dist/compiler/plugins/python.d.ts +21 -0
- package/dist/compiler/plugins/rust.d.ts +9 -0
- package/dist/compiler/plugins/schema.d.ts +12 -0
- package/dist/compiler/plugins/svelte.d.ts +10 -0
- package/dist/compiler/plugins/typescript.d.ts +23 -0
- package/dist/compiler/types.d.ts +72 -0
- package/dist/compiler/virtual_120b_types.d.ts +18 -0
- package/dist/core/config.d.ts +16 -0
- package/dist/core/engine.d.ts +17 -0
- package/dist/core/reporter.d.ts +5 -0
- package/dist/db/index.js +1910 -0
- package/dist/i18n.d.ts +281 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8282 -0
- package/dist/memory/causal-benchmark.d.ts +29 -0
- package/dist/memory/causal-branch.d.ts +79 -0
- package/dist/memory/causal-build.d.ts +51 -0
- package/dist/memory/causal-config.d.ts +38 -0
- package/dist/memory/causal-context.d.ts +113 -0
- package/dist/memory/causal-contexts.json +316 -0
- package/dist/memory/causal-graph.d.ts +6 -0
- package/dist/memory/causal-graveyard.d.ts +94 -0
- package/dist/memory/causal-lens.d.ts +133 -0
- package/dist/memory/causal-memory.json +5054 -0
- package/dist/memory/causal-migrator.d.ts +11 -0
- package/dist/memory/causal-peer.d.ts +53 -0
- package/dist/memory/causal-predictor.d.ts +42 -0
- package/dist/memory/causal-query.d.ts +21 -0
- package/dist/memory/causal-server.d.ts +578 -0
- package/dist/memory/causal-store.d.ts +280 -0
- package/dist/memory/causal-synthesizer.d.ts +96 -0
- package/dist/memory/causal-timeseries.d.ts +92 -0
- package/dist/memory/cli.d.ts +13 -0
- package/dist/memory/cli.js +5668 -0
- package/dist/memory/index.d.ts +13 -0
- package/dist/memory/index.js +4451 -0
- package/dist/plugins/cpp.d.ts +19 -0
- package/dist/plugins/csharp.d.ts +13 -0
- package/dist/plugins/go.d.ts +15 -0
- package/dist/plugins/java.d.ts +16 -0
- package/dist/plugins/native.d.ts +12 -0
- package/dist/plugins/nsis.d.ts +8 -0
- package/dist/plugins/python.d.ts +21 -0
- package/dist/plugins/rust.d.ts +9 -0
- package/dist/plugins/schema.d.ts +12 -0
- package/dist/plugins/svelte.d.ts +10 -0
- package/dist/plugins/typescript.d.ts +23 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/core/config.d.ts +12 -0
- package/dist/src/core/engine.d.ts +9 -0
- package/dist/src/core/reporter.d.ts +5 -0
- package/dist/src/index.d.ts +13 -0
- package/dist/src/memory/causal-graph.d.ts +6 -0
- package/dist/src/plugins/native.d.ts +12 -0
- package/dist/src/plugins/nsis.d.ts +8 -0
- package/dist/src/plugins/rust.d.ts +9 -0
- package/dist/src/plugins/schema.d.ts +12 -0
- package/dist/src/plugins/svelte.d.ts +10 -0
- package/dist/src/types.d.ts +55 -0
- package/dist/types.d.ts +72 -0
- package/package.json +87 -4
package/dist/cli.js
ADDED
|
@@ -0,0 +1,3474 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
var __esm = (fn, res, err) => () => {
|
|
4
|
+
if (fn)
|
|
5
|
+
try {
|
|
6
|
+
res = fn(fn = 0);
|
|
7
|
+
} catch (e) {
|
|
8
|
+
err = [e];
|
|
9
|
+
}
|
|
10
|
+
if (err)
|
|
11
|
+
throw err[0];
|
|
12
|
+
return res;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/memory/causal-config.ts
|
|
16
|
+
import { homedir } from "os";
|
|
17
|
+
import { resolve as resolve4 } from "path";
|
|
18
|
+
var CAUSAL_MEMORY_CONFIG;
|
|
19
|
+
var init_causal_config = __esm(() => {
|
|
20
|
+
CAUSAL_MEMORY_CONFIG = {
|
|
21
|
+
SCHEMA_VERSION: process.env.SYNAPSE_MEMORY_VERSION || "2.1.0",
|
|
22
|
+
GLOBAL_DB_PATH: process.env.SYNAPSE_MEMORY_PATH || resolve4(homedir(), ".gemini", "antigravity", "causal_memory.json"),
|
|
23
|
+
LEGACY_BACKUP_PATH: process.env.SYNAPSE_MEMORY_BACKUP_PATH || resolve4(homedir(), ".gemini", "antigravity", "memory_backup_20261101.json"),
|
|
24
|
+
LOCAL_DB_PATH: resolve4(import.meta.dir, "causal-memory.json"),
|
|
25
|
+
DEFAULT_HOST: process.env.SYNAPSE_MEMORY_HOST || "127.0.0.1",
|
|
26
|
+
DEFAULT_PORT: parseInt(process.env.SYNAPSE_MEMORY_PORT || "4242", 10),
|
|
27
|
+
MCP_PROTOCOL_VERSION: process.env.SYNAPSE_MCP_VERSION || "2024-11-05",
|
|
28
|
+
MCP_SERVER_NAME: "synapse-causal-memory",
|
|
29
|
+
MAX_CONTEXT_PREVIEW_LINES: parseInt(process.env.SYNAPSE_MEMORY_MAX_PREVIEW || "5", 10)
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// src/memory/causal-store.ts
|
|
34
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, statSync as statSync2 } from "fs";
|
|
35
|
+
import { dirname } from "path";
|
|
36
|
+
|
|
37
|
+
class CausalMemoryStore {
|
|
38
|
+
dbPath;
|
|
39
|
+
database;
|
|
40
|
+
lastMtimeMs = 0;
|
|
41
|
+
alwaysActiveRules = [];
|
|
42
|
+
domainIndex = new Map;
|
|
43
|
+
commandIndex = new Map;
|
|
44
|
+
exactKeywordIndex = new Map;
|
|
45
|
+
exactFileIndex = new Map;
|
|
46
|
+
prefixFileRules = [];
|
|
47
|
+
compiledSearchRules = [];
|
|
48
|
+
titleToRuleMap = new Map;
|
|
49
|
+
idToRuleMap = new Map;
|
|
50
|
+
relationAdjacency = new Map;
|
|
51
|
+
constructor(customPath, initialDatabase) {
|
|
52
|
+
this.dbPath = customPath || (existsSync4(CAUSAL_MEMORY_CONFIG.GLOBAL_DB_PATH) ? CAUSAL_MEMORY_CONFIG.GLOBAL_DB_PATH : CAUSAL_MEMORY_CONFIG.LOCAL_DB_PATH);
|
|
53
|
+
if (initialDatabase) {
|
|
54
|
+
this.database = initialDatabase;
|
|
55
|
+
this.rebuildIndices();
|
|
56
|
+
} else {
|
|
57
|
+
this.database = this.loadDatabase();
|
|
58
|
+
this.rebuildIndices();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
reloadIfNeeded() {
|
|
62
|
+
try {
|
|
63
|
+
if (!existsSync4(this.dbPath))
|
|
64
|
+
return false;
|
|
65
|
+
const stat = statSync2(this.dbPath);
|
|
66
|
+
if (stat.mtimeMs > this.lastMtimeMs) {
|
|
67
|
+
this.database = this.loadDatabase();
|
|
68
|
+
this.rebuildIndices();
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
} catch {}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
reload() {
|
|
75
|
+
this.database = this.loadDatabase();
|
|
76
|
+
this.rebuildIndices();
|
|
77
|
+
}
|
|
78
|
+
loadFromMemory(db) {
|
|
79
|
+
this.database = db;
|
|
80
|
+
this.rebuildIndices();
|
|
81
|
+
}
|
|
82
|
+
rebuildIndices() {
|
|
83
|
+
this.alwaysActiveRules = [];
|
|
84
|
+
this.domainIndex.clear();
|
|
85
|
+
this.commandIndex.clear();
|
|
86
|
+
this.exactKeywordIndex.clear();
|
|
87
|
+
this.exactFileIndex.clear();
|
|
88
|
+
this.prefixFileRules = [];
|
|
89
|
+
this.compiledSearchRules = [];
|
|
90
|
+
this.titleToRuleMap.clear();
|
|
91
|
+
this.idToRuleMap.clear();
|
|
92
|
+
this.relationAdjacency.clear();
|
|
93
|
+
const addTokenToKeywordIndex = (token, rule) => {
|
|
94
|
+
if (!token)
|
|
95
|
+
return;
|
|
96
|
+
let list = this.exactKeywordIndex.get(token);
|
|
97
|
+
if (!list) {
|
|
98
|
+
list = [];
|
|
99
|
+
this.exactKeywordIndex.set(token, list);
|
|
100
|
+
}
|
|
101
|
+
if (list[list.length - 1] !== rule) {
|
|
102
|
+
list.push(rule);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
for (const rule of this.database.rules) {
|
|
106
|
+
const domainLower = rule.domain.toLowerCase();
|
|
107
|
+
const titleLower = rule.title.toLowerCase();
|
|
108
|
+
const idLower = rule.id.toLowerCase();
|
|
109
|
+
this.titleToRuleMap.set(titleLower, rule);
|
|
110
|
+
this.idToRuleMap.set(idLower, rule);
|
|
111
|
+
let domList = this.domainIndex.get(domainLower);
|
|
112
|
+
if (!domList) {
|
|
113
|
+
domList = [];
|
|
114
|
+
this.domainIndex.set(domainLower, domList);
|
|
115
|
+
}
|
|
116
|
+
domList.push(rule);
|
|
117
|
+
if (rule.triggers.alwaysActive) {
|
|
118
|
+
this.alwaysActiveRules.push(rule);
|
|
119
|
+
}
|
|
120
|
+
if (rule.triggers.commands) {
|
|
121
|
+
for (const cmd of rule.triggers.commands) {
|
|
122
|
+
const cmdLower = cmd.toLowerCase();
|
|
123
|
+
let cmdList = this.commandIndex.get(cmdLower);
|
|
124
|
+
if (!cmdList) {
|
|
125
|
+
cmdList = [];
|
|
126
|
+
this.commandIndex.set(cmdLower, cmdList);
|
|
127
|
+
}
|
|
128
|
+
cmdList.push(rule);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
addTokenToKeywordIndex(titleLower, rule);
|
|
132
|
+
addTokenToKeywordIndex(domainLower, rule);
|
|
133
|
+
for (const part of titleLower.split(/[\s_-]+/)) {
|
|
134
|
+
addTokenToKeywordIndex(part, rule);
|
|
135
|
+
}
|
|
136
|
+
if (rule.triggers.keywords) {
|
|
137
|
+
for (const kw of rule.triggers.keywords) {
|
|
138
|
+
const kwLower = kw.toLowerCase();
|
|
139
|
+
addTokenToKeywordIndex(kwLower, rule);
|
|
140
|
+
for (const sub of kwLower.split(/[\s_-]+/)) {
|
|
141
|
+
addTokenToKeywordIndex(sub, rule);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (rule.triggers.files && rule.triggers.files.length > 0) {
|
|
146
|
+
const prefixPatterns = [];
|
|
147
|
+
for (const pattern of rule.triggers.files) {
|
|
148
|
+
const cleaned = (pattern.includes("\\") ? pattern.replaceAll("\\", "/") : pattern).replace(/^\*\*\/|\*\*$|\*$/g, "").replace(/\/+$/, "").toLowerCase();
|
|
149
|
+
if (!cleaned)
|
|
150
|
+
continue;
|
|
151
|
+
let fList = this.exactFileIndex.get(cleaned);
|
|
152
|
+
if (!fList) {
|
|
153
|
+
fList = [];
|
|
154
|
+
this.exactFileIndex.set(cleaned, fList);
|
|
155
|
+
}
|
|
156
|
+
fList.push(rule);
|
|
157
|
+
if (cleaned.endsWith("-") || cleaned.endsWith("_") || cleaned.includes(":")) {
|
|
158
|
+
prefixPatterns.push(cleaned);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (prefixPatterns.length > 0) {
|
|
162
|
+
this.prefixFileRules.push({ rule, domainLower, cleanPatterns: prefixPatterns });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const rel of this.database.relations) {
|
|
167
|
+
const fromLower = rel.from.toLowerCase();
|
|
168
|
+
const toLower = rel.to.toLowerCase();
|
|
169
|
+
let fromAdj = this.relationAdjacency.get(fromLower);
|
|
170
|
+
if (!fromAdj) {
|
|
171
|
+
fromAdj = [];
|
|
172
|
+
this.relationAdjacency.set(fromLower, fromAdj);
|
|
173
|
+
}
|
|
174
|
+
fromAdj.push(rel);
|
|
175
|
+
if (toLower !== fromLower) {
|
|
176
|
+
let toAdj = this.relationAdjacency.get(toLower);
|
|
177
|
+
if (!toAdj) {
|
|
178
|
+
toAdj = [];
|
|
179
|
+
this.relationAdjacency.set(toLower, toAdj);
|
|
180
|
+
}
|
|
181
|
+
toAdj.push(rel);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
loadDatabase() {
|
|
186
|
+
try {
|
|
187
|
+
if (existsSync4(this.dbPath)) {
|
|
188
|
+
const stat = statSync2(this.dbPath);
|
|
189
|
+
this.lastMtimeMs = stat.mtimeMs;
|
|
190
|
+
const raw = readFileSync2(this.dbPath, "utf-8");
|
|
191
|
+
const parsed = JSON.parse(raw);
|
|
192
|
+
const rules = Array.isArray(parsed.rules) ? parsed.rules : [];
|
|
193
|
+
const relations = Array.isArray(parsed.relations) ? parsed.relations : [];
|
|
194
|
+
return {
|
|
195
|
+
version: parsed.version || CAUSAL_MEMORY_CONFIG.SCHEMA_VERSION,
|
|
196
|
+
updatedAt: parsed.updatedAt || new Date().toISOString(),
|
|
197
|
+
totalRules: rules.length,
|
|
198
|
+
totalRelations: relations.length,
|
|
199
|
+
rules,
|
|
200
|
+
relations
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
} catch {}
|
|
204
|
+
return {
|
|
205
|
+
version: CAUSAL_MEMORY_CONFIG.SCHEMA_VERSION,
|
|
206
|
+
updatedAt: new Date().toISOString(),
|
|
207
|
+
totalRules: 0,
|
|
208
|
+
totalRelations: 0,
|
|
209
|
+
rules: [],
|
|
210
|
+
relations: []
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
saveDatabase() {
|
|
214
|
+
try {
|
|
215
|
+
const dir = dirname(this.dbPath);
|
|
216
|
+
if (!existsSync4(dir)) {
|
|
217
|
+
mkdirSync2(dir, { recursive: true });
|
|
218
|
+
}
|
|
219
|
+
const serialized = JSON.stringify(this.database, null, 2);
|
|
220
|
+
writeFileSync2(this.dbPath, serialized, "utf-8");
|
|
221
|
+
this.lastMtimeMs = statSync2(this.dbPath).mtimeMs;
|
|
222
|
+
if (this.dbPath === CAUSAL_MEMORY_CONFIG.GLOBAL_DB_PATH && existsSync4(dirname(CAUSAL_MEMORY_CONFIG.LOCAL_DB_PATH))) {
|
|
223
|
+
writeFileSync2(CAUSAL_MEMORY_CONFIG.LOCAL_DB_PATH, serialized, "utf-8");
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
throw new Error(`\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB514\uC2A4\uD06C \uC800\uC7A5 \uC2E4\uD328: ${error instanceof Error ? error.message : String(error)}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
getAllRules() {
|
|
230
|
+
return this.database.rules;
|
|
231
|
+
}
|
|
232
|
+
getAllRelations() {
|
|
233
|
+
return this.database.relations;
|
|
234
|
+
}
|
|
235
|
+
getStatus() {
|
|
236
|
+
const domainCounts = {};
|
|
237
|
+
for (const [dom, list] of this.domainIndex.entries()) {
|
|
238
|
+
const originalDomainName = list[0]?.domain || dom;
|
|
239
|
+
domainCounts[originalDomainName] = list.length;
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
version: this.database.version,
|
|
243
|
+
updatedAt: this.database.updatedAt,
|
|
244
|
+
totalRules: this.database.rules.length,
|
|
245
|
+
totalRelations: this.database.relations.length,
|
|
246
|
+
dbPath: this.dbPath,
|
|
247
|
+
domains: Object.keys(domainCounts),
|
|
248
|
+
domainCounts
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
getCompiledSearchRules() {
|
|
252
|
+
if (this.compiledSearchRules.length === 0 && this.database.rules.length > 0) {
|
|
253
|
+
for (const rule of this.database.rules) {
|
|
254
|
+
const domainLower = rule.domain.toLowerCase();
|
|
255
|
+
const searchableText = [
|
|
256
|
+
rule.title,
|
|
257
|
+
rule.domain,
|
|
258
|
+
...rule.triggers.keywords || [],
|
|
259
|
+
...rule.invariants,
|
|
260
|
+
...rule.actions,
|
|
261
|
+
...rule.context
|
|
262
|
+
].join(" ").toLowerCase();
|
|
263
|
+
this.compiledSearchRules.push({ rule, domainLower, searchableText });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return this.compiledSearchRules;
|
|
267
|
+
}
|
|
268
|
+
queryResonance(options) {
|
|
269
|
+
const startTime = performance.now();
|
|
270
|
+
const targetDomain = options.domain ? options.domain.toLowerCase() : undefined;
|
|
271
|
+
const queryCommand = options.command ? options.command.toLowerCase() : undefined;
|
|
272
|
+
const propagate = options.propagateRelations ?? true;
|
|
273
|
+
const maxHops = options.maxHops ?? 1;
|
|
274
|
+
const matchedRulesMap = new Map;
|
|
275
|
+
const nonAlwaysMatchedTitles = new Set;
|
|
276
|
+
for (const rule of this.alwaysActiveRules) {
|
|
277
|
+
if (targetDomain && rule.domain.toLowerCase() !== targetDomain)
|
|
278
|
+
continue;
|
|
279
|
+
matchedRulesMap.set(rule.id, rule);
|
|
280
|
+
}
|
|
281
|
+
if (queryCommand) {
|
|
282
|
+
const cmdRules = this.commandIndex.get(queryCommand);
|
|
283
|
+
if (cmdRules) {
|
|
284
|
+
for (const rule of cmdRules) {
|
|
285
|
+
if (targetDomain && rule.domain.toLowerCase() !== targetDomain)
|
|
286
|
+
continue;
|
|
287
|
+
matchedRulesMap.set(rule.id, rule);
|
|
288
|
+
nonAlwaysMatchedTitles.add(rule.title.toLowerCase());
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (options.files && options.files.length > 0 && this.exactFileIndex.size > 0) {
|
|
293
|
+
const hasPrefixRules = this.prefixFileRules.length > 0;
|
|
294
|
+
const checkedDirs = new Set;
|
|
295
|
+
const registerHits = (hits) => {
|
|
296
|
+
if (!hits)
|
|
297
|
+
return;
|
|
298
|
+
for (let i = 0;i < hits.length; i++) {
|
|
299
|
+
const rule = hits[i];
|
|
300
|
+
if (targetDomain && rule.domain.toLowerCase() !== targetDomain)
|
|
301
|
+
continue;
|
|
302
|
+
matchedRulesMap.set(rule.id, rule);
|
|
303
|
+
nonAlwaysMatchedTitles.add(rule.title.toLowerCase());
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
let lastTwoSeg = "";
|
|
307
|
+
for (let i = 0;i < options.files.length; i++) {
|
|
308
|
+
const rawFile = options.files[i];
|
|
309
|
+
const nf = (rawFile.includes("\\") ? rawFile.replaceAll("\\", "/") : rawFile).toLowerCase();
|
|
310
|
+
registerHits(this.exactFileIndex.get(nf));
|
|
311
|
+
const firstSlash = nf.indexOf("/");
|
|
312
|
+
if (firstSlash > 0) {
|
|
313
|
+
const secondSlash = nf.indexOf("/", firstSlash + 1);
|
|
314
|
+
const twoSeg = secondSlash > 0 ? nf.slice(0, secondSlash) : nf.slice(0, firstSlash);
|
|
315
|
+
if (twoSeg !== lastTwoSeg) {
|
|
316
|
+
lastTwoSeg = twoSeg;
|
|
317
|
+
if (!checkedDirs.has(twoSeg)) {
|
|
318
|
+
checkedDirs.add(twoSeg);
|
|
319
|
+
registerHits(this.exactFileIndex.get(twoSeg));
|
|
320
|
+
const oneSeg = nf.slice(0, firstSlash);
|
|
321
|
+
if (oneSeg !== twoSeg && !checkedDirs.has(oneSeg)) {
|
|
322
|
+
checkedDirs.add(oneSeg);
|
|
323
|
+
registerHits(this.exactFileIndex.get(oneSeg));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const lastSlash = nf.lastIndexOf("/");
|
|
328
|
+
registerHits(this.exactFileIndex.get(nf.slice(lastSlash + 1)));
|
|
329
|
+
} else {
|
|
330
|
+
checkedDirs.add(nf);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (hasPrefixRules && checkedDirs.size > 0) {
|
|
334
|
+
const prefixArr = Array.from(checkedDirs);
|
|
335
|
+
for (const entry of this.prefixFileRules) {
|
|
336
|
+
if (targetDomain && entry.domainLower !== targetDomain)
|
|
337
|
+
continue;
|
|
338
|
+
if (matchedRulesMap.has(entry.rule.id))
|
|
339
|
+
continue;
|
|
340
|
+
for (const pattern of entry.cleanPatterns) {
|
|
341
|
+
if (prefixArr.some((p) => p.includes(pattern) || pattern.includes(p))) {
|
|
342
|
+
matchedRulesMap.set(entry.rule.id, entry.rule);
|
|
343
|
+
nonAlwaysMatchedTitles.add(entry.rule.title.toLowerCase());
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const queryKeywords = (options.keywords || []).flatMap((k) => k.toLowerCase().split(/\s+/)).filter((k) => k.length > 0);
|
|
351
|
+
if (queryKeywords.length > 0) {
|
|
352
|
+
const unindexedKeywords = [];
|
|
353
|
+
for (const qk of queryKeywords) {
|
|
354
|
+
const exactHits = this.exactKeywordIndex.get(qk);
|
|
355
|
+
if (exactHits && exactHits.length > 0) {
|
|
356
|
+
for (const rule of exactHits) {
|
|
357
|
+
if (targetDomain && rule.domain.toLowerCase() !== targetDomain)
|
|
358
|
+
continue;
|
|
359
|
+
matchedRulesMap.set(rule.id, rule);
|
|
360
|
+
nonAlwaysMatchedTitles.add(rule.title.toLowerCase());
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
unindexedKeywords.push(qk);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (unindexedKeywords.length > 0) {
|
|
367
|
+
const searchPool = this.getCompiledSearchRules();
|
|
368
|
+
for (const entry of searchPool) {
|
|
369
|
+
if (targetDomain && entry.domainLower !== targetDomain)
|
|
370
|
+
continue;
|
|
371
|
+
if (matchedRulesMap.has(entry.rule.id))
|
|
372
|
+
continue;
|
|
373
|
+
for (const qk of unindexedKeywords) {
|
|
374
|
+
if (entry.searchableText.includes(qk)) {
|
|
375
|
+
matchedRulesMap.set(entry.rule.id, entry.rule);
|
|
376
|
+
nonAlwaysMatchedTitles.add(entry.rule.title.toLowerCase());
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const activeRelationsSet = new Set;
|
|
384
|
+
const visitedTitles = new Set(Array.from(matchedRulesMap.values()).map((r) => r.title.toLowerCase()));
|
|
385
|
+
let currentFrontier = new Set(nonAlwaysMatchedTitles.size > 0 ? nonAlwaysMatchedTitles : visitedTitles);
|
|
386
|
+
const effectiveHops = propagate ? Math.max(1, maxHops) : 1;
|
|
387
|
+
for (let hop = 0;hop < effectiveHops; hop++) {
|
|
388
|
+
const nextFrontier = new Set;
|
|
389
|
+
for (const titleLower of currentFrontier) {
|
|
390
|
+
const adjRelations = this.relationAdjacency.get(titleLower);
|
|
391
|
+
if (!adjRelations)
|
|
392
|
+
continue;
|
|
393
|
+
for (const rel of adjRelations) {
|
|
394
|
+
activeRelationsSet.add(rel);
|
|
395
|
+
if (propagate && nonAlwaysMatchedTitles.size > 0) {
|
|
396
|
+
const neighborLower = rel.from.toLowerCase() === titleLower ? rel.to.toLowerCase() : rel.from.toLowerCase();
|
|
397
|
+
if (!visitedTitles.has(neighborLower)) {
|
|
398
|
+
visitedTitles.add(neighborLower);
|
|
399
|
+
nextFrontier.add(neighborLower);
|
|
400
|
+
const neighborRule = this.titleToRuleMap.get(neighborLower);
|
|
401
|
+
if (neighborRule && (!targetDomain || neighborRule.domain.toLowerCase() === targetDomain)) {
|
|
402
|
+
matchedRulesMap.set(neighborRule.id, neighborRule);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (nextFrontier.size === 0)
|
|
409
|
+
break;
|
|
410
|
+
currentFrontier = nextFrontier;
|
|
411
|
+
}
|
|
412
|
+
const matchedRules = Array.from(matchedRulesMap.values());
|
|
413
|
+
const activeRelations = Array.from(activeRelationsSet);
|
|
414
|
+
const duration = performance.now() - startTime;
|
|
415
|
+
const totalCount = this.database.rules.length;
|
|
416
|
+
const savings = totalCount > 0 ? ((totalCount - matchedRules.length) / totalCount * 100).toFixed(1) + "%" : "0.0%";
|
|
417
|
+
return {
|
|
418
|
+
queryDurationMs: Math.round(duration * 100) / 100,
|
|
419
|
+
matchedCount: matchedRules.length,
|
|
420
|
+
totalDatabaseRules: totalCount,
|
|
421
|
+
resonanceRules: matchedRules,
|
|
422
|
+
activeRelations,
|
|
423
|
+
tokenDietSavingsRatio: savings
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
assertRule(rule, persistToDisk = true) {
|
|
427
|
+
const existingIndex = this.database.rules.findIndex((r) => r.id === rule.id || r.title.toLowerCase() === rule.title.toLowerCase());
|
|
428
|
+
const updatedRules = [...this.database.rules];
|
|
429
|
+
const today = new Date().toISOString().split("T")[0];
|
|
430
|
+
if (existingIndex >= 0) {
|
|
431
|
+
updatedRules[existingIndex] = {
|
|
432
|
+
...rule,
|
|
433
|
+
id: rule.id || updatedRules[existingIndex].id,
|
|
434
|
+
lastVerified: today
|
|
435
|
+
};
|
|
436
|
+
} else {
|
|
437
|
+
updatedRules.push({
|
|
438
|
+
...rule,
|
|
439
|
+
lastVerified: today
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
this.database = {
|
|
443
|
+
...this.database,
|
|
444
|
+
updatedAt: new Date().toISOString(),
|
|
445
|
+
totalRules: updatedRules.length,
|
|
446
|
+
rules: updatedRules
|
|
447
|
+
};
|
|
448
|
+
this.rebuildIndices();
|
|
449
|
+
if (persistToDisk) {
|
|
450
|
+
this.saveDatabase();
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
readSmartGraph(files = []) {
|
|
454
|
+
const resonance = this.queryResonance({ files });
|
|
455
|
+
const status = this.getStatus();
|
|
456
|
+
const entities = resonance.resonanceRules.map((r) => ({
|
|
457
|
+
name: r.title,
|
|
458
|
+
entityType: r.entityType || r.domain,
|
|
459
|
+
domain: r.domain,
|
|
460
|
+
invariants: r.invariants,
|
|
461
|
+
actions: r.actions,
|
|
462
|
+
observations: [
|
|
463
|
+
...r.invariants.map((i) => `[\uBD88\uBCC0\uADDC\uCE59] ${i}`),
|
|
464
|
+
...r.actions.map((a) => `[\uC2E4\uD589\uC9C0\uCE68] ${a}`),
|
|
465
|
+
...r.context
|
|
466
|
+
]
|
|
467
|
+
}));
|
|
468
|
+
return {
|
|
469
|
+
causalMemoryEngine: `v${status.version} (Active Resonance Mode)`,
|
|
470
|
+
tokenDietSavings: resonance.tokenDietSavingsRatio,
|
|
471
|
+
queryDurationMs: resonance.queryDurationMs,
|
|
472
|
+
activeEntitiesCount: entities.length,
|
|
473
|
+
totalIndexedRules: status.totalRules,
|
|
474
|
+
totalIndexedRelations: status.totalRelations,
|
|
475
|
+
availableDomains: status.domainCounts,
|
|
476
|
+
hint: "\uBB34\uAD00\uD55C \uB3C4\uBA54\uC778 \uC9C0\uC2DD\uC740 \uD1A0\uD070 \uC808\uAC10\uC744 \uC704\uD574 0ms \uC2A4\uD0B5\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD2B9\uC815 \uB3C4\uBA54\uC778 \uC0C1\uC138 \uC870\uD68C\uB294 search_nodes \uB610\uB294 query_causal_memory\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
477
|
+
entities,
|
|
478
|
+
relations: resonance.activeRelations
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
searchNodes(query) {
|
|
482
|
+
const trimmed = query.trim();
|
|
483
|
+
if (!trimmed) {
|
|
484
|
+
return this.readSmartGraph();
|
|
485
|
+
}
|
|
486
|
+
const tokens = trimmed.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
487
|
+
const matchedRules = [];
|
|
488
|
+
const matchedTitles = new Set;
|
|
489
|
+
const searchPool = this.getCompiledSearchRules();
|
|
490
|
+
for (const entry of searchPool) {
|
|
491
|
+
const ruleIdLower = entry.rule.id.toLowerCase();
|
|
492
|
+
if (tokens.some((tok) => entry.searchableText.includes(tok) || ruleIdLower.includes(tok))) {
|
|
493
|
+
matchedRules.push(entry.rule);
|
|
494
|
+
matchedTitles.add(entry.rule.title.toLowerCase());
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const relationsSet = new Set;
|
|
498
|
+
for (const titleLower of matchedTitles) {
|
|
499
|
+
const adj = this.relationAdjacency.get(titleLower);
|
|
500
|
+
if (adj) {
|
|
501
|
+
for (const r of adj)
|
|
502
|
+
relationsSet.add(r);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
entities: matchedRules.map((r) => ({
|
|
507
|
+
name: r.title,
|
|
508
|
+
entityType: r.entityType || r.domain,
|
|
509
|
+
observations: [...r.invariants, ...r.actions, ...r.context]
|
|
510
|
+
})),
|
|
511
|
+
relations: Array.from(relationsSet)
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
openNodes(names) {
|
|
515
|
+
const matchedRules = [];
|
|
516
|
+
const matchedTitles = new Set;
|
|
517
|
+
for (const name of names) {
|
|
518
|
+
const lower = name.toLowerCase();
|
|
519
|
+
const rule = this.titleToRuleMap.get(lower) || this.idToRuleMap.get(lower);
|
|
520
|
+
if (rule && !matchedTitles.has(rule.title.toLowerCase())) {
|
|
521
|
+
matchedRules.push(rule);
|
|
522
|
+
matchedTitles.add(rule.title.toLowerCase());
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const relationsSet = new Set;
|
|
526
|
+
for (const titleLower of matchedTitles) {
|
|
527
|
+
const adj = this.relationAdjacency.get(titleLower);
|
|
528
|
+
if (adj) {
|
|
529
|
+
for (const r of adj)
|
|
530
|
+
relationsSet.add(r);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
entities: matchedRules.map((r) => ({
|
|
535
|
+
name: r.title,
|
|
536
|
+
entityType: r.entityType || r.domain,
|
|
537
|
+
observations: [...r.invariants, ...r.actions, ...r.context]
|
|
538
|
+
})),
|
|
539
|
+
relations: Array.from(relationsSet)
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
createEntities(entities, persistToDisk = true) {
|
|
543
|
+
const created = [];
|
|
544
|
+
const updatedRules = [...this.database.rules];
|
|
545
|
+
const today = new Date().toISOString().split("T")[0];
|
|
546
|
+
for (const ent of entities) {
|
|
547
|
+
if (this.titleToRuleMap.has(ent.name.toLowerCase()))
|
|
548
|
+
continue;
|
|
549
|
+
const inferred = CausalMemoryStore.inferRuleFromEntity(ent, today);
|
|
550
|
+
updatedRules.push(inferred);
|
|
551
|
+
created.push(ent);
|
|
552
|
+
}
|
|
553
|
+
if (created.length > 0) {
|
|
554
|
+
this.database = {
|
|
555
|
+
...this.database,
|
|
556
|
+
updatedAt: new Date().toISOString(),
|
|
557
|
+
totalRules: updatedRules.length,
|
|
558
|
+
rules: updatedRules
|
|
559
|
+
};
|
|
560
|
+
this.rebuildIndices();
|
|
561
|
+
if (persistToDisk) {
|
|
562
|
+
this.saveDatabase();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return created;
|
|
566
|
+
}
|
|
567
|
+
addObservations(observations, persistToDisk = true) {
|
|
568
|
+
const updatedRules = [...this.database.rules];
|
|
569
|
+
const results = [];
|
|
570
|
+
let changed = false;
|
|
571
|
+
for (const item of observations) {
|
|
572
|
+
const idx = updatedRules.findIndex((r) => r.title.toLowerCase() === item.entityName.toLowerCase());
|
|
573
|
+
if (idx < 0)
|
|
574
|
+
continue;
|
|
575
|
+
const rule = updatedRules[idx];
|
|
576
|
+
const existingObs = new Set([...rule.invariants, ...rule.actions, ...rule.context]);
|
|
577
|
+
const added = [];
|
|
578
|
+
const newInvariants = [...rule.invariants];
|
|
579
|
+
const newActions = [...rule.actions];
|
|
580
|
+
const newContext = [...rule.context];
|
|
581
|
+
for (const content of item.contents) {
|
|
582
|
+
if (existingObs.has(content))
|
|
583
|
+
continue;
|
|
584
|
+
added.push(content);
|
|
585
|
+
existingObs.add(content);
|
|
586
|
+
changed = true;
|
|
587
|
+
if (content.includes("\uAE08\uC9C0") || content.includes("\uC808\uB300") || content.includes("\uD544\uC218") || content.includes("\uC8FC\uC758")) {
|
|
588
|
+
newInvariants.push(content);
|
|
589
|
+
} else if (/^\d+\.|\uB2E8\uACC4|Step/i.test(content)) {
|
|
590
|
+
newActions.push(content);
|
|
591
|
+
} else {
|
|
592
|
+
newContext.push(content);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
updatedRules[idx] = {
|
|
596
|
+
...rule,
|
|
597
|
+
invariants: newInvariants,
|
|
598
|
+
actions: newActions,
|
|
599
|
+
context: newContext,
|
|
600
|
+
lastVerified: new Date().toISOString().split("T")[0]
|
|
601
|
+
};
|
|
602
|
+
results.push({ entityName: item.entityName, addedObservations: added });
|
|
603
|
+
}
|
|
604
|
+
if (changed) {
|
|
605
|
+
this.database = {
|
|
606
|
+
...this.database,
|
|
607
|
+
updatedAt: new Date().toISOString(),
|
|
608
|
+
rules: updatedRules
|
|
609
|
+
};
|
|
610
|
+
this.rebuildIndices();
|
|
611
|
+
if (persistToDisk) {
|
|
612
|
+
this.saveDatabase();
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return results;
|
|
616
|
+
}
|
|
617
|
+
createRelations(relations, persistToDisk = true) {
|
|
618
|
+
const updatedRelations = [...this.database.relations];
|
|
619
|
+
const created = [];
|
|
620
|
+
for (const rel of relations) {
|
|
621
|
+
const exists = updatedRelations.some((r) => r.from === rel.from && r.to === rel.to && r.relationType === rel.relationType);
|
|
622
|
+
if (!exists) {
|
|
623
|
+
updatedRelations.push(rel);
|
|
624
|
+
created.push(rel);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (created.length > 0) {
|
|
628
|
+
this.database = {
|
|
629
|
+
...this.database,
|
|
630
|
+
updatedAt: new Date().toISOString(),
|
|
631
|
+
totalRelations: updatedRelations.length,
|
|
632
|
+
relations: updatedRelations
|
|
633
|
+
};
|
|
634
|
+
this.rebuildIndices();
|
|
635
|
+
if (persistToDisk) {
|
|
636
|
+
this.saveDatabase();
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return created;
|
|
640
|
+
}
|
|
641
|
+
deleteEntities(entityNames, persistToDisk = true) {
|
|
642
|
+
const nameSet = new Set(entityNames.map((n) => n.toLowerCase()));
|
|
643
|
+
const filteredRules = this.database.rules.filter((r) => !nameSet.has(r.title.toLowerCase()) && !nameSet.has(r.id.toLowerCase()));
|
|
644
|
+
const filteredRelations = this.database.relations.filter((rel) => !nameSet.has(rel.from.toLowerCase()) && !nameSet.has(rel.to.toLowerCase()));
|
|
645
|
+
this.database = {
|
|
646
|
+
...this.database,
|
|
647
|
+
updatedAt: new Date().toISOString(),
|
|
648
|
+
totalRules: filteredRules.length,
|
|
649
|
+
totalRelations: filteredRelations.length,
|
|
650
|
+
rules: filteredRules,
|
|
651
|
+
relations: filteredRelations
|
|
652
|
+
};
|
|
653
|
+
this.rebuildIndices();
|
|
654
|
+
if (persistToDisk) {
|
|
655
|
+
this.saveDatabase();
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
deleteObservations(deletions, persistToDisk = true) {
|
|
659
|
+
const updatedRules = [...this.database.rules];
|
|
660
|
+
for (const del of deletions) {
|
|
661
|
+
const idx = updatedRules.findIndex((r) => r.title.toLowerCase() === del.entityName.toLowerCase());
|
|
662
|
+
if (idx < 0)
|
|
663
|
+
continue;
|
|
664
|
+
const toDelete = new Set(del.observations);
|
|
665
|
+
const rule = updatedRules[idx];
|
|
666
|
+
updatedRules[idx] = {
|
|
667
|
+
...rule,
|
|
668
|
+
invariants: rule.invariants.filter((x) => !toDelete.has(x)),
|
|
669
|
+
actions: rule.actions.filter((x) => !toDelete.has(x)),
|
|
670
|
+
context: rule.context.filter((x) => !toDelete.has(x))
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
this.database = {
|
|
674
|
+
...this.database,
|
|
675
|
+
updatedAt: new Date().toISOString(),
|
|
676
|
+
rules: updatedRules
|
|
677
|
+
};
|
|
678
|
+
this.rebuildIndices();
|
|
679
|
+
if (persistToDisk) {
|
|
680
|
+
this.saveDatabase();
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
deleteRelations(relations, persistToDisk = true) {
|
|
684
|
+
const filtered = this.database.relations.filter((existing) => !relations.some((del) => del.from === existing.from && del.to === existing.to && del.relationType === existing.relationType));
|
|
685
|
+
this.database = {
|
|
686
|
+
...this.database,
|
|
687
|
+
updatedAt: new Date().toISOString(),
|
|
688
|
+
totalRelations: filtered.length,
|
|
689
|
+
relations: filtered
|
|
690
|
+
};
|
|
691
|
+
this.rebuildIndices();
|
|
692
|
+
if (persistToDisk) {
|
|
693
|
+
this.saveDatabase();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
static inferRuleFromEntity(ent, today) {
|
|
697
|
+
const nameLower = ent.name.toLowerCase();
|
|
698
|
+
const typeLower = ent.entityType.toLowerCase();
|
|
699
|
+
const obsJoined = ent.observations.join(" ").toLowerCase();
|
|
700
|
+
let domain = "Knowledge_Base";
|
|
701
|
+
const triggers = {};
|
|
702
|
+
const invariants = [];
|
|
703
|
+
const actions = [];
|
|
704
|
+
const context = [];
|
|
705
|
+
const isTrueUserPreference = typeLower === "preference" || typeLower === "user_constraint" || typeLower === "forbidden_rules" || nameLower === "userpreferences" || nameLower === "user_web_navigation_preference" || nameLower === "python_strictly_forbidden" || nameLower === "forbidden_topics_until_mentioned";
|
|
706
|
+
if (isTrueUserPreference) {
|
|
707
|
+
domain = "User_Preferences_And_Rules";
|
|
708
|
+
triggers.alwaysActive = true;
|
|
709
|
+
triggers.keywords = ["\uD658\uACBD\uC124\uC815", "\uADDC\uCE59", "\uD130\uBBF8\uB110", "\uCD9C\uB825", "\uBCF4\uC548", "\uC120\uD638\uB3C4"];
|
|
710
|
+
} else if (nameLower.includes("poe2") || nameLower.includes("noble-babbage") || nameLower.includes("release_workflow") || obsJoined.includes("poe2filter-releases") || obsJoined.includes("noble-babbage")) {
|
|
711
|
+
domain = "Project_POE2_AutoFilter";
|
|
712
|
+
triggers.files = [
|
|
713
|
+
"noble-babbage",
|
|
714
|
+
"poe2filter-releases",
|
|
715
|
+
"updater.json",
|
|
716
|
+
"post_download_button.js"
|
|
717
|
+
];
|
|
718
|
+
triggers.keywords = ["poe2", "autofilter", "\uD544\uD130", "\uC624\uD1A0\uD544\uD130", "updater", "discord", "\uB9B4\uB9AC\uC988", "\uBC30\uD3EC"];
|
|
719
|
+
triggers.commands = ["release", "updater", "build", "sign"];
|
|
720
|
+
} else if (nameLower.includes("vesper") || nameLower.includes("dsp") || nameLower.includes("neurospatial audio") || typeLower.includes("audio_architecture")) {
|
|
721
|
+
domain = "Project_Vesper_DSP";
|
|
722
|
+
triggers.files = ["vesper", "crates/vesper-", "vesper-apo"];
|
|
723
|
+
triggers.keywords = ["vesper", "dsp", "\uC624\uB514\uC624", "audio", "mmcss", "virtuallock", "apo", "eq", "\uC0AC\uC6B4\uB4DC"];
|
|
724
|
+
triggers.commands = ["check", "build", "test"];
|
|
725
|
+
} else if (nameLower.includes("synapse") && !nameLower.includes("biophys")) {
|
|
726
|
+
domain = "Project_Synapse_Kit";
|
|
727
|
+
triggers.files = ["synapse", "synapse.config.ts"];
|
|
728
|
+
triggers.keywords = ["synapse", "synapse-kit", "\uC2DC\uB0C5\uC2A4", "\uC778\uACFC\uC728", "causal", "\uCEF4\uD30C\uC77C\uB7EC", "\uCCB4\uCEE4"];
|
|
729
|
+
triggers.commands = ["check", "build", "package", "sign", "init", "memory"];
|
|
730
|
+
} else if (nameLower.includes("hardware") || nameLower.includes("pcb") || nameLower.includes("jlcpcb") || nameLower.includes("m2_2230") || nameLower.includes("pocket_orange") || typeLower.includes("hardware")) {
|
|
731
|
+
domain = "Hardware_And_PCB";
|
|
732
|
+
triggers.files = ["hardware", "pcb", "kicad"];
|
|
733
|
+
triggers.keywords = ["pcb", "hardware", "\uD558\uB4DC\uC6E8\uC5B4", "\uD68C\uB85C", "jlcpcb", "kicad", "m2"];
|
|
734
|
+
} else if (nameLower.includes("biophys") || nameLower.includes("connectome") || nameLower.includes("drosophila") || nameLower.includes("cortex") || typeLower.includes("whitepaper")) {
|
|
735
|
+
domain = "BioPhys_Research_And_Architecture";
|
|
736
|
+
triggers.files = ["biophys", "whitepaper"];
|
|
737
|
+
triggers.keywords = ["biophys", "connectome", "\uC2DC\uB0C5\uC2A4\uC2E0\uACBD\uB9DD", "\uD000\uD0C0\uC774\uC81C\uC774\uC158", "\uBC31\uC11C", "\uC544\uD0A4\uD14D\uCC98"];
|
|
738
|
+
} else {
|
|
739
|
+
domain = "Knowledge_Base";
|
|
740
|
+
triggers.keywords = [ent.name.toLowerCase().replace(/_/g, " ")];
|
|
741
|
+
}
|
|
742
|
+
for (const obs of ent.observations) {
|
|
743
|
+
if (obs.includes("\uAE08\uC9C0") || obs.includes("\uC808\uB300") || obs.includes("\uD544\uC218") || obs.includes("\uC8FC\uC758") || obs.includes("VirtualLock") || obs.includes("MMCSS")) {
|
|
744
|
+
invariants.push(obs);
|
|
745
|
+
} else if (/^\d+\.|\uB2E8\uACC4|Step/i.test(obs)) {
|
|
746
|
+
actions.push(obs);
|
|
747
|
+
} else {
|
|
748
|
+
context.push(obs);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const baseSlug = ent.name.trim().toLowerCase().replace(/[^\w\uAC00-\uD7A30-9-]+/g, "-").replace(/^-+|-+$/g, "") || "item";
|
|
752
|
+
return {
|
|
753
|
+
id: `rule-${domain.toLowerCase()}-${baseSlug}`,
|
|
754
|
+
domain,
|
|
755
|
+
title: ent.name,
|
|
756
|
+
entityType: ent.entityType,
|
|
757
|
+
triggers,
|
|
758
|
+
invariants,
|
|
759
|
+
actions,
|
|
760
|
+
context,
|
|
761
|
+
lastVerified: today
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
audit() {
|
|
765
|
+
const issues = [];
|
|
766
|
+
const seenIds = new Set;
|
|
767
|
+
let alwaysActiveCount = 0;
|
|
768
|
+
for (const rule of this.database.rules) {
|
|
769
|
+
if (rule.triggers.alwaysActive) {
|
|
770
|
+
alwaysActiveCount++;
|
|
771
|
+
}
|
|
772
|
+
if (!rule.id || rule.id.trim().length === 0) {
|
|
773
|
+
issues.push(`ID \uB204\uB77D \uADDC\uCE59 \uBC1C\uACAC: ${rule.title}`);
|
|
774
|
+
} else if (seenIds.has(rule.id)) {
|
|
775
|
+
issues.push(`\uC911\uBCF5 ID \uBC1C\uACAC: ${rule.id}`);
|
|
776
|
+
} else {
|
|
777
|
+
seenIds.add(rule.id);
|
|
778
|
+
}
|
|
779
|
+
if (!rule.domain) {
|
|
780
|
+
issues.push(`\uB3C4\uBA54\uC778 \uB204\uB77D \uADDC\uCE59: ${rule.id}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (alwaysActiveCount > 10) {
|
|
784
|
+
issues.push(`\uC0C1\uC2DC \uD65C\uC131(alwaysActive) \uADDC\uCE59 \uACFC\uB2E4 (${alwaysActiveCount}\uAC1C): \uD1A0\uD070 \uC808\uAC10 \uD6A8\uC728\uC774 \uC800\uD558\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
|
|
785
|
+
}
|
|
786
|
+
return {
|
|
787
|
+
ok: issues.length === 0,
|
|
788
|
+
totalRules: this.database.rules.length,
|
|
789
|
+
totalRelations: this.database.relations.length,
|
|
790
|
+
alwaysActiveCount,
|
|
791
|
+
issues
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
var init_causal_store = __esm(() => {
|
|
796
|
+
init_causal_config();
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
// src/memory/causal-query.ts
|
|
800
|
+
var {spawn: spawn3 } = globalThis.Bun;
|
|
801
|
+
async function detectModifiedFiles(cwd = process.cwd()) {
|
|
802
|
+
try {
|
|
803
|
+
const gitProc = spawn3(["git", "status", "--porcelain", "-uall"], {
|
|
804
|
+
cwd,
|
|
805
|
+
stdout: "pipe",
|
|
806
|
+
stderr: "pipe"
|
|
807
|
+
});
|
|
808
|
+
const output = await new Response(gitProc.stdout).text();
|
|
809
|
+
await gitProc.exited;
|
|
810
|
+
return output.split(`
|
|
811
|
+
`).map((line) => line.slice(3).trim().replaceAll("\\", "/")).filter((line) => line.length > 0 && !line.startsWith(".synapse/") && !line.includes("/.synapse/"));
|
|
812
|
+
} catch {
|
|
813
|
+
return [];
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
async function runCausalQuery(rawOptions, storeCustomPath) {
|
|
817
|
+
const store = new CausalMemoryStore(storeCustomPath);
|
|
818
|
+
let targetFiles = rawOptions.files ? [...rawOptions.files] : [];
|
|
819
|
+
if (rawOptions.autoGit || targetFiles.length === 0) {
|
|
820
|
+
const gitFiles = await detectModifiedFiles(rawOptions.cwd || process.cwd());
|
|
821
|
+
if (gitFiles.length > 0) {
|
|
822
|
+
targetFiles = Array.from(new Set([...targetFiles, ...gitFiles]));
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const queryOptions = {
|
|
826
|
+
files: targetFiles,
|
|
827
|
+
keywords: rawOptions.keywords,
|
|
828
|
+
command: rawOptions.command,
|
|
829
|
+
domain: rawOptions.domain,
|
|
830
|
+
propagateRelations: rawOptions.propagateRelations
|
|
831
|
+
};
|
|
832
|
+
return store.queryResonance(queryOptions);
|
|
833
|
+
}
|
|
834
|
+
function formatResonanceForAgent(result, compact = false) {
|
|
835
|
+
if (result.matchedCount === 0) {
|
|
836
|
+
return `[Causal-Memory] \uACF5\uBA85 \uADDC\uCE59 0\uAC74 (\uD1A0\uD070 \uC808\uAC10\uB960: ${result.tokenDietSavingsRatio}, \uC18C\uC694: ${result.queryDurationMs}ms)`;
|
|
837
|
+
}
|
|
838
|
+
if (compact) {
|
|
839
|
+
return JSON.stringify({
|
|
840
|
+
ok: true,
|
|
841
|
+
durationMs: result.queryDurationMs,
|
|
842
|
+
matchedCount: result.matchedCount,
|
|
843
|
+
totalDatabaseRules: result.totalDatabaseRules,
|
|
844
|
+
savings: result.tokenDietSavingsRatio,
|
|
845
|
+
rules: result.resonanceRules.map((r) => ({
|
|
846
|
+
id: r.id,
|
|
847
|
+
domain: r.domain,
|
|
848
|
+
title: r.title,
|
|
849
|
+
invariants: r.invariants,
|
|
850
|
+
actions: r.actions
|
|
851
|
+
})),
|
|
852
|
+
relations: result.activeRelations
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
const lines = [
|
|
856
|
+
`### \uD83E\uDDE0 \uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uACF5\uBA85 \uC8FC\uC785 (${result.matchedCount}/${result.totalDatabaseRules}\uAC1C \uADDC\uCE59 \uD65C\uC131\uD654, \uC808\uAC10\uB960: ${result.tokenDietSavingsRatio}, ${result.queryDurationMs}ms)`
|
|
857
|
+
];
|
|
858
|
+
for (const rule of result.resonanceRules) {
|
|
859
|
+
lines.push(`
|
|
860
|
+
**[${rule.domain}] ${rule.title}**`);
|
|
861
|
+
if (rule.invariants.length > 0) {
|
|
862
|
+
lines.push(" - **\uBD88\uBCC0 \uADDC\uCE59(Invariants)**:");
|
|
863
|
+
for (const inv of rule.invariants) {
|
|
864
|
+
lines.push(` \u2022 ${inv}`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (rule.actions.length > 0) {
|
|
868
|
+
lines.push(" - **\uC2E4\uD589 \uC808\uCC28(Actions)**:");
|
|
869
|
+
for (const act of rule.actions) {
|
|
870
|
+
lines.push(` \u2022 ${act}`);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (rule.context.length > 0) {
|
|
874
|
+
lines.push(" - **\uD575\uC2EC \uB9E5\uB77D(Context)**:");
|
|
875
|
+
for (const ctx of rule.context.slice(0, CAUSAL_MEMORY_CONFIG.MAX_CONTEXT_PREVIEW_LINES)) {
|
|
876
|
+
lines.push(` \u2022 ${ctx}`);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (result.activeRelations.length > 0) {
|
|
881
|
+
lines.push(`
|
|
882
|
+
### \uD83D\uDD17 \uD65C\uC131 \uC778\uACFC \uAC04\uC120 (Active Causal Relations)`);
|
|
883
|
+
for (const rel of result.activeRelations) {
|
|
884
|
+
lines.push(` \u2022 \`${rel.from}\` \u2500\u2500[${rel.relationType}]\u2500\u2500\u25B6 \`${rel.to}\``);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return lines.join(`
|
|
888
|
+
`);
|
|
889
|
+
}
|
|
890
|
+
var init_causal_query = __esm(() => {
|
|
891
|
+
init_causal_config();
|
|
892
|
+
init_causal_store();
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
// src/memory/causal-server.ts
|
|
896
|
+
import { createInterface } from "readline";
|
|
897
|
+
async function handleMcpJsonRpcRequest(rpc, store, dbPath) {
|
|
898
|
+
const { id, method, params } = rpc;
|
|
899
|
+
if (method.startsWith("notifications/")) {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
if (method === "initialize") {
|
|
903
|
+
return {
|
|
904
|
+
jsonrpc: "2.0",
|
|
905
|
+
id: id ?? null,
|
|
906
|
+
result: {
|
|
907
|
+
protocolVersion: params?.protocolVersion || CAUSAL_MEMORY_CONFIG.MCP_PROTOCOL_VERSION,
|
|
908
|
+
capabilities: {
|
|
909
|
+
tools: {}
|
|
910
|
+
},
|
|
911
|
+
serverInfo: {
|
|
912
|
+
name: CAUSAL_MEMORY_CONFIG.MCP_SERVER_NAME,
|
|
913
|
+
version: CAUSAL_MEMORY_CONFIG.SCHEMA_VERSION
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
if (method === "ping") {
|
|
919
|
+
return {
|
|
920
|
+
jsonrpc: "2.0",
|
|
921
|
+
id: id ?? null,
|
|
922
|
+
result: {}
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
if (method === "tools/list") {
|
|
926
|
+
return {
|
|
927
|
+
jsonrpc: "2.0",
|
|
928
|
+
id: id ?? null,
|
|
929
|
+
result: {
|
|
930
|
+
tools: CAUSAL_MCP_TOOLS
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
if (method === "tools/call") {
|
|
935
|
+
store.reloadIfNeeded();
|
|
936
|
+
const toolName = params?.name;
|
|
937
|
+
const args = params?.arguments || {};
|
|
938
|
+
try {
|
|
939
|
+
let payloadText = "";
|
|
940
|
+
switch (toolName) {
|
|
941
|
+
case "query_causal_memory": {
|
|
942
|
+
let files = Array.isArray(args.files) ? args.files : [];
|
|
943
|
+
if (files.length === 0 && args.autoGit !== false) {
|
|
944
|
+
files = await detectModifiedFiles();
|
|
945
|
+
}
|
|
946
|
+
const res = store.queryResonance({
|
|
947
|
+
files,
|
|
948
|
+
keywords: args.keywords,
|
|
949
|
+
command: args.command,
|
|
950
|
+
domain: args.domain,
|
|
951
|
+
propagateRelations: args.propagateRelations,
|
|
952
|
+
maxHops: args.maxHops
|
|
953
|
+
});
|
|
954
|
+
payloadText = formatResonanceForAgent(res, Boolean(args.compact));
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
case "assert_causal_rule": {
|
|
958
|
+
store.assertRule(args);
|
|
959
|
+
payloadText = JSON.stringify({
|
|
960
|
+
ok: true,
|
|
961
|
+
message: `\uC778\uACFC\uC728 \uADDC\uCE59 \uB4F1\uB85D/\uAC31\uC2E0 \uC644\uB8CC: ${args.id}`,
|
|
962
|
+
id: args.id
|
|
963
|
+
});
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
case "audit_causal_memory": {
|
|
967
|
+
const audit = store.audit();
|
|
968
|
+
const status = store.getStatus();
|
|
969
|
+
payloadText = JSON.stringify({ ...audit, status }, null, 2);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
case "read_graph": {
|
|
973
|
+
const gitFiles = await detectModifiedFiles();
|
|
974
|
+
const smartGraph = store.readSmartGraph(gitFiles);
|
|
975
|
+
payloadText = JSON.stringify(smartGraph, null, 2);
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
case "search_nodes": {
|
|
979
|
+
const searchResult = store.searchNodes(String(args.query || ""));
|
|
980
|
+
payloadText = JSON.stringify(searchResult, null, 2);
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
case "open_nodes": {
|
|
984
|
+
const names = Array.isArray(args.names) ? args.names : [];
|
|
985
|
+
const openResult = store.openNodes(names);
|
|
986
|
+
payloadText = JSON.stringify(openResult, null, 2);
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
case "create_entities": {
|
|
990
|
+
const entities = Array.isArray(args.entities) ? args.entities : [];
|
|
991
|
+
const created = store.createEntities(entities);
|
|
992
|
+
payloadText = JSON.stringify(created, null, 2);
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
case "create_relations": {
|
|
996
|
+
const relations = Array.isArray(args.relations) ? args.relations : [];
|
|
997
|
+
const created = store.createRelations(relations);
|
|
998
|
+
payloadText = JSON.stringify(created, null, 2);
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
case "add_observations": {
|
|
1002
|
+
const observations = Array.isArray(args.observations) ? args.observations : [];
|
|
1003
|
+
const added = store.addObservations(observations);
|
|
1004
|
+
payloadText = JSON.stringify(added, null, 2);
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
case "delete_entities": {
|
|
1008
|
+
const entityNames = Array.isArray(args.entityNames) ? args.entityNames : [];
|
|
1009
|
+
store.deleteEntities(entityNames);
|
|
1010
|
+
payloadText = "Entities deleted successfully";
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
case "delete_observations": {
|
|
1014
|
+
const deletions = Array.isArray(args.deletions) ? args.deletions : [];
|
|
1015
|
+
store.deleteObservations(deletions);
|
|
1016
|
+
payloadText = "Observations deleted successfully";
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
case "delete_relations": {
|
|
1020
|
+
const relations = Array.isArray(args.relations) ? args.relations : [];
|
|
1021
|
+
store.deleteRelations(relations);
|
|
1022
|
+
payloadText = "Relations deleted successfully";
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
default:
|
|
1026
|
+
return {
|
|
1027
|
+
jsonrpc: "2.0",
|
|
1028
|
+
id: id ?? null,
|
|
1029
|
+
error: {
|
|
1030
|
+
code: -32601,
|
|
1031
|
+
message: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB3C4\uAD6C\uC785\uB2C8\uB2E4: ${toolName}`
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
return {
|
|
1036
|
+
jsonrpc: "2.0",
|
|
1037
|
+
id: id ?? null,
|
|
1038
|
+
result: {
|
|
1039
|
+
content: [{ type: "text", text: payloadText }]
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
return {
|
|
1044
|
+
jsonrpc: "2.0",
|
|
1045
|
+
id: id ?? null,
|
|
1046
|
+
result: {
|
|
1047
|
+
content: [
|
|
1048
|
+
{
|
|
1049
|
+
type: "text",
|
|
1050
|
+
text: `\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB3C4\uAD6C \uC2E4\uD589 \uC624\uB958: ${error instanceof Error ? error.message : String(error)}`
|
|
1051
|
+
}
|
|
1052
|
+
],
|
|
1053
|
+
isError: true
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return {
|
|
1059
|
+
jsonrpc: "2.0",
|
|
1060
|
+
id: id ?? null,
|
|
1061
|
+
error: { code: -32601, message: `Method not found: ${method}` }
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
function startCausalServer(options = {}) {
|
|
1065
|
+
const port = options.port || CAUSAL_MEMORY_CONFIG.DEFAULT_PORT;
|
|
1066
|
+
const host = options.host || CAUSAL_MEMORY_CONFIG.DEFAULT_HOST;
|
|
1067
|
+
const store = new CausalMemoryStore(options.dbPath);
|
|
1068
|
+
const server = Bun.serve({
|
|
1069
|
+
port,
|
|
1070
|
+
hostname: host,
|
|
1071
|
+
async fetch(req) {
|
|
1072
|
+
const url = new URL(req.url);
|
|
1073
|
+
const headers = {
|
|
1074
|
+
"Content-Type": "application/json",
|
|
1075
|
+
"Access-Control-Allow-Origin": "*",
|
|
1076
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
1077
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
1078
|
+
};
|
|
1079
|
+
if (req.method === "OPTIONS") {
|
|
1080
|
+
return new Response(null, { headers });
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
if (url.pathname === "/health" || url.pathname === "/status") {
|
|
1084
|
+
store.reloadIfNeeded();
|
|
1085
|
+
return new Response(JSON.stringify({ ok: true, status: store.getStatus() }), { headers });
|
|
1086
|
+
}
|
|
1087
|
+
if (url.pathname === "/query" && req.method === "GET") {
|
|
1088
|
+
store.reloadIfNeeded();
|
|
1089
|
+
const files = url.searchParams.getAll("files");
|
|
1090
|
+
const keywords = url.searchParams.getAll("keywords");
|
|
1091
|
+
const command = url.searchParams.get("command") || undefined;
|
|
1092
|
+
const domain = url.searchParams.get("domain") || undefined;
|
|
1093
|
+
const result = store.queryResonance({ files, keywords, command, domain });
|
|
1094
|
+
return new Response(JSON.stringify(result), { headers });
|
|
1095
|
+
}
|
|
1096
|
+
if (url.pathname === "/query" && req.method === "POST") {
|
|
1097
|
+
store.reloadIfNeeded();
|
|
1098
|
+
const body = await req.json();
|
|
1099
|
+
let files = Array.isArray(body.files) ? body.files : [];
|
|
1100
|
+
if (body.autoGit === true && files.length === 0) {
|
|
1101
|
+
files = await detectModifiedFiles(body.cwd);
|
|
1102
|
+
}
|
|
1103
|
+
const result = store.queryResonance({
|
|
1104
|
+
files,
|
|
1105
|
+
keywords: body.keywords,
|
|
1106
|
+
command: body.command,
|
|
1107
|
+
domain: body.domain,
|
|
1108
|
+
propagateRelations: body.propagateRelations,
|
|
1109
|
+
maxHops: body.maxHops
|
|
1110
|
+
});
|
|
1111
|
+
const format = url.searchParams.get("format") || body.format;
|
|
1112
|
+
if (format === "markdown" || format === "md") {
|
|
1113
|
+
return new Response(formatResonanceForAgent(result, false), {
|
|
1114
|
+
headers: { ...headers, "Content-Type": "text/markdown; charset=utf-8" }
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
if (format === "compact") {
|
|
1118
|
+
return new Response(formatResonanceForAgent(result, true), { headers });
|
|
1119
|
+
}
|
|
1120
|
+
return new Response(JSON.stringify(result), { headers });
|
|
1121
|
+
}
|
|
1122
|
+
if (url.pathname === "/assert" && req.method === "POST") {
|
|
1123
|
+
store.reloadIfNeeded();
|
|
1124
|
+
const body = await req.json();
|
|
1125
|
+
store.assertRule(body);
|
|
1126
|
+
return new Response(JSON.stringify({ ok: true, id: body.id }), { headers });
|
|
1127
|
+
}
|
|
1128
|
+
if (url.pathname === "/audit") {
|
|
1129
|
+
store.reloadIfNeeded();
|
|
1130
|
+
const auditResult = store.audit();
|
|
1131
|
+
return new Response(JSON.stringify(auditResult), { headers });
|
|
1132
|
+
}
|
|
1133
|
+
if (url.pathname === "/mcp" && req.method === "POST") {
|
|
1134
|
+
const rpc = await req.json();
|
|
1135
|
+
const responseObj = await handleMcpJsonRpcRequest(rpc, store, options.dbPath);
|
|
1136
|
+
if (!responseObj) {
|
|
1137
|
+
return new Response(null, { status: 204, headers });
|
|
1138
|
+
}
|
|
1139
|
+
return new Response(JSON.stringify(responseObj), { headers });
|
|
1140
|
+
}
|
|
1141
|
+
return new Response(JSON.stringify({ error: "Not Found" }), { status: 404, headers });
|
|
1142
|
+
} catch (err) {
|
|
1143
|
+
return new Response(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }), { status: 500, headers });
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
return server;
|
|
1148
|
+
}
|
|
1149
|
+
async function startCausalMcpStdioServer(dbPath) {
|
|
1150
|
+
const store = new CausalMemoryStore(dbPath);
|
|
1151
|
+
const daemonUrl = `http://${CAUSAL_MEMORY_CONFIG.DEFAULT_HOST}:${CAUSAL_MEMORY_CONFIG.DEFAULT_PORT}/mcp`;
|
|
1152
|
+
const rl = createInterface({
|
|
1153
|
+
input: process.stdin,
|
|
1154
|
+
terminal: false
|
|
1155
|
+
});
|
|
1156
|
+
for await (const line of rl) {
|
|
1157
|
+
const trimmed = line.trim();
|
|
1158
|
+
if (!trimmed)
|
|
1159
|
+
continue;
|
|
1160
|
+
try {
|
|
1161
|
+
const rpc = JSON.parse(trimmed);
|
|
1162
|
+
let responseObj = null;
|
|
1163
|
+
if (rpc.method === "tools/call") {
|
|
1164
|
+
try {
|
|
1165
|
+
const daemonRes = await fetch(daemonUrl, {
|
|
1166
|
+
method: "POST",
|
|
1167
|
+
headers: { "Content-Type": "application/json" },
|
|
1168
|
+
body: trimmed,
|
|
1169
|
+
signal: AbortSignal.timeout(150)
|
|
1170
|
+
});
|
|
1171
|
+
if (daemonRes.ok) {
|
|
1172
|
+
responseObj = await daemonRes.json();
|
|
1173
|
+
}
|
|
1174
|
+
} catch {}
|
|
1175
|
+
}
|
|
1176
|
+
if (!responseObj) {
|
|
1177
|
+
responseObj = await handleMcpJsonRpcRequest(rpc, store, dbPath);
|
|
1178
|
+
}
|
|
1179
|
+
if (responseObj) {
|
|
1180
|
+
process.stdout.write(JSON.stringify(responseObj) + `
|
|
1181
|
+
`);
|
|
1182
|
+
}
|
|
1183
|
+
} catch (error) {
|
|
1184
|
+
const errResp = {
|
|
1185
|
+
jsonrpc: "2.0",
|
|
1186
|
+
id: null,
|
|
1187
|
+
error: {
|
|
1188
|
+
code: -32700,
|
|
1189
|
+
message: `JSON Parse error: ${error instanceof Error ? error.message : String(error)}`
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
process.stdout.write(JSON.stringify(errResp) + `
|
|
1193
|
+
`);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
var CAUSAL_MCP_TOOLS;
|
|
1198
|
+
var init_causal_server = __esm(() => {
|
|
1199
|
+
init_causal_config();
|
|
1200
|
+
init_causal_store();
|
|
1201
|
+
init_causal_query();
|
|
1202
|
+
CAUSAL_MCP_TOOLS = [
|
|
1203
|
+
{
|
|
1204
|
+
name: "query_causal_memory",
|
|
1205
|
+
description: "\uC791\uC5C5 \uCEE8\uD14D\uC2A4\uD2B8(\uC218\uC815\uB41C \uD30C\uC77C, \uD0A4\uC6CC\uB4DC, \uBA85\uB839\uC5B4, \uB3C4\uBA54\uC778)\uC5D0 \uB9E4\uCE6D\uB418\uB294 \uC778\uACFC\uC728 \uC9C0\uC2DD\uACFC \uBD88\uBCC0 \uADDC\uCE59\uB9CC 0ms \uCD08\uACBD\uB7C9\uC73C\uB85C \uACF5\uBA85 \uCFFC\uB9AC\uD569\uB2C8\uB2E4.",
|
|
1206
|
+
inputSchema: {
|
|
1207
|
+
type: "object",
|
|
1208
|
+
properties: {
|
|
1209
|
+
files: {
|
|
1210
|
+
type: "array",
|
|
1211
|
+
items: { type: "string" },
|
|
1212
|
+
description: "\uAC10\uC9C0\uD560 \uB300\uC0C1 \uD30C\uC77C \uACBD\uB85C \uBAA9\uB85D (\uC0DD\uB7B5 \uC2DC Git \uBCC0\uACBD \uD30C\uC77C \uC790\uB3D9 \uAC10\uC9C0)"
|
|
1213
|
+
},
|
|
1214
|
+
keywords: {
|
|
1215
|
+
type: "array",
|
|
1216
|
+
items: { type: "string" },
|
|
1217
|
+
description: "\uAC80\uC0C9\uD560 \uB3C4\uBA54\uC778/\uC791\uC5C5 \uD0A4\uC6CC\uB4DC \uBAA9\uB85D"
|
|
1218
|
+
},
|
|
1219
|
+
command: {
|
|
1220
|
+
type: "string",
|
|
1221
|
+
description: "\uC5F0\uB3D9 \uBA85\uB839\uC5B4 (\uC608: check, build, release, sign)"
|
|
1222
|
+
},
|
|
1223
|
+
domain: {
|
|
1224
|
+
type: "string",
|
|
1225
|
+
description: "\uD2B9\uC815 \uB3C4\uBA54\uC778 \uD544\uD130"
|
|
1226
|
+
},
|
|
1227
|
+
compact: {
|
|
1228
|
+
type: "boolean",
|
|
1229
|
+
description: "\uCD08\uC18C\uD615 JSON \uD3EC\uB9F7 \uBC18\uD658 \uC5EC\uBD80"
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
name: "assert_causal_rule",
|
|
1236
|
+
description: "\uC2E0\uADDC \uC778\uACFC\uC728 \uADDC\uCE59(\uC6D0\uC778 \uD2B8\uB9AC\uAC70 \u2794 \uBD88\uBCC0 \uACC4\uC57D \u2794 \uC2E4\uD589 \uC9C0\uCE68)\uC744 \uBA54\uBAA8\uB9AC\uC5D0 \uB4F1\uB85D\uD558\uAC70\uB098 \uAC31\uC2E0\uD569\uB2C8\uB2E4.",
|
|
1237
|
+
inputSchema: {
|
|
1238
|
+
type: "object",
|
|
1239
|
+
required: ["id", "domain", "title", "triggers"],
|
|
1240
|
+
properties: {
|
|
1241
|
+
id: { type: "string" },
|
|
1242
|
+
domain: { type: "string" },
|
|
1243
|
+
title: { type: "string" },
|
|
1244
|
+
triggers: { type: "object" },
|
|
1245
|
+
invariants: { type: "array", items: { type: "string" } },
|
|
1246
|
+
actions: { type: "array", items: { type: "string" } },
|
|
1247
|
+
context: { type: "array", items: { type: "string" } }
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
name: "audit_causal_memory",
|
|
1253
|
+
description: "\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uC758 \uBB34\uACB0\uC131, \uB3C4\uBA54\uC778 \uBD84\uD3EC, \uD1A0\uD070 \uC808\uAC10 \uC0C1\uD0DC\uB97C \uAC10\uC0AC(Audit)\uD569\uB2C8\uB2E4.",
|
|
1254
|
+
inputSchema: {
|
|
1255
|
+
type: "object",
|
|
1256
|
+
properties: {}
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
name: "read_graph",
|
|
1261
|
+
description: "Read the active causal resonance knowledge graph (automatically filters out unrelated noise for 90%+ token savings)",
|
|
1262
|
+
inputSchema: {
|
|
1263
|
+
type: "object",
|
|
1264
|
+
properties: {}
|
|
1265
|
+
}
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
name: "search_nodes",
|
|
1269
|
+
description: "Search for causal rules and nodes in the knowledge graph based on a query and traverse causal relations",
|
|
1270
|
+
inputSchema: {
|
|
1271
|
+
type: "object",
|
|
1272
|
+
required: ["query"],
|
|
1273
|
+
properties: {
|
|
1274
|
+
query: {
|
|
1275
|
+
type: "string",
|
|
1276
|
+
description: "The search query to match against rule titles, domains, triggers, and invariants"
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
},
|
|
1281
|
+
{
|
|
1282
|
+
name: "open_nodes",
|
|
1283
|
+
description: "Open specific causal rule nodes in the knowledge graph by their names or IDs",
|
|
1284
|
+
inputSchema: {
|
|
1285
|
+
type: "object",
|
|
1286
|
+
required: ["names"],
|
|
1287
|
+
properties: {
|
|
1288
|
+
names: {
|
|
1289
|
+
type: "array",
|
|
1290
|
+
items: { type: "string" },
|
|
1291
|
+
description: "An array of entity names or rule IDs to retrieve"
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
name: "create_entities",
|
|
1298
|
+
description: "Create multiple new entities (automatically converted into structured Causal Rules)",
|
|
1299
|
+
inputSchema: {
|
|
1300
|
+
type: "object",
|
|
1301
|
+
required: ["entities"],
|
|
1302
|
+
properties: {
|
|
1303
|
+
entities: {
|
|
1304
|
+
type: "array",
|
|
1305
|
+
items: {
|
|
1306
|
+
type: "object",
|
|
1307
|
+
required: ["name", "entityType", "observations"],
|
|
1308
|
+
properties: {
|
|
1309
|
+
name: { type: "string" },
|
|
1310
|
+
entityType: { type: "string" },
|
|
1311
|
+
observations: { type: "array", items: { type: "string" } }
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
name: "create_relations",
|
|
1320
|
+
description: "Create multiple new causal relations between nodes in the knowledge graph",
|
|
1321
|
+
inputSchema: {
|
|
1322
|
+
type: "object",
|
|
1323
|
+
required: ["relations"],
|
|
1324
|
+
properties: {
|
|
1325
|
+
relations: {
|
|
1326
|
+
type: "array",
|
|
1327
|
+
items: {
|
|
1328
|
+
type: "object",
|
|
1329
|
+
required: ["from", "to", "relationType"],
|
|
1330
|
+
properties: {
|
|
1331
|
+
from: { type: "string" },
|
|
1332
|
+
to: { type: "string" },
|
|
1333
|
+
relationType: { type: "string" }
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
name: "add_observations",
|
|
1342
|
+
description: "Add new invariants, actions, or context observations to existing causal rules",
|
|
1343
|
+
inputSchema: {
|
|
1344
|
+
type: "object",
|
|
1345
|
+
required: ["observations"],
|
|
1346
|
+
properties: {
|
|
1347
|
+
observations: {
|
|
1348
|
+
type: "array",
|
|
1349
|
+
items: {
|
|
1350
|
+
type: "object",
|
|
1351
|
+
required: ["entityName", "contents"],
|
|
1352
|
+
properties: {
|
|
1353
|
+
entityName: { type: "string" },
|
|
1354
|
+
contents: { type: "array", items: { type: "string" } }
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
name: "delete_entities",
|
|
1363
|
+
description: "Delete multiple entities/rules and their associated causal relations",
|
|
1364
|
+
inputSchema: {
|
|
1365
|
+
type: "object",
|
|
1366
|
+
required: ["entityNames"],
|
|
1367
|
+
properties: {
|
|
1368
|
+
entityNames: {
|
|
1369
|
+
type: "array",
|
|
1370
|
+
items: { type: "string" }
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
{
|
|
1376
|
+
name: "delete_observations",
|
|
1377
|
+
description: "Delete specific observations from entities/rules in the causal memory",
|
|
1378
|
+
inputSchema: {
|
|
1379
|
+
type: "object",
|
|
1380
|
+
required: ["deletions"],
|
|
1381
|
+
properties: {
|
|
1382
|
+
deletions: {
|
|
1383
|
+
type: "array",
|
|
1384
|
+
items: {
|
|
1385
|
+
type: "object",
|
|
1386
|
+
required: ["entityName", "observations"],
|
|
1387
|
+
properties: {
|
|
1388
|
+
entityName: { type: "string" },
|
|
1389
|
+
observations: { type: "array", items: { type: "string" } }
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
name: "delete_relations",
|
|
1398
|
+
description: "Delete multiple causal relations from the knowledge graph",
|
|
1399
|
+
inputSchema: {
|
|
1400
|
+
type: "object",
|
|
1401
|
+
required: ["relations"],
|
|
1402
|
+
properties: {
|
|
1403
|
+
relations: {
|
|
1404
|
+
type: "array",
|
|
1405
|
+
items: {
|
|
1406
|
+
type: "object",
|
|
1407
|
+
required: ["from", "to", "relationType"],
|
|
1408
|
+
properties: {
|
|
1409
|
+
from: { type: "string" },
|
|
1410
|
+
to: { type: "string" },
|
|
1411
|
+
relationType: { type: "string" }
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
];
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
// src/memory/causal-benchmark.ts
|
|
1422
|
+
function calcPercentile(sorted, p) {
|
|
1423
|
+
if (sorted.length === 0)
|
|
1424
|
+
return 0;
|
|
1425
|
+
const idx = Math.min(sorted.length - 1, Math.floor(p / 100 * sorted.length));
|
|
1426
|
+
return Math.round(sorted[idx] * 1000) / 1000;
|
|
1427
|
+
}
|
|
1428
|
+
function generateSyntheticDatabase(ruleCount, relationCount) {
|
|
1429
|
+
const domains = [
|
|
1430
|
+
"Project_POE2_AutoFilter",
|
|
1431
|
+
"Project_Vesper_DSP",
|
|
1432
|
+
"Project_Synapse_Kit",
|
|
1433
|
+
"BioPhys_Research_And_Architecture",
|
|
1434
|
+
"Hardware_And_PCB",
|
|
1435
|
+
"Knowledge_Base"
|
|
1436
|
+
];
|
|
1437
|
+
const rules = [
|
|
1438
|
+
{
|
|
1439
|
+
id: "rule-always-1",
|
|
1440
|
+
domain: "User_Preferences_And_Rules",
|
|
1441
|
+
title: "Global_Preference_1",
|
|
1442
|
+
triggers: { alwaysActive: true },
|
|
1443
|
+
invariants: ["\uD56D\uC0C1 \uD55C\uAD6D\uC5B4 \uC6B0\uC120 \uCD9C\uB825", "bun \uD544\uC218 \uC0AC\uC6A9"],
|
|
1444
|
+
actions: [],
|
|
1445
|
+
context: []
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
id: "rule-always-2",
|
|
1449
|
+
domain: "User_Preferences_And_Rules",
|
|
1450
|
+
title: "Global_Preference_2",
|
|
1451
|
+
triggers: { alwaysActive: true },
|
|
1452
|
+
invariants: ["console.log \uB514\uBC84\uADF8 \uCF54\uB4DC \uAE08\uC9C0", "\uD558\uB4DC\uCF54\uB529 \uAE08\uC9C0"],
|
|
1453
|
+
actions: [],
|
|
1454
|
+
context: []
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
id: "rule-always-3",
|
|
1458
|
+
domain: "User_Preferences_And_Rules",
|
|
1459
|
+
title: "Global_Preference_3",
|
|
1460
|
+
triggers: { alwaysActive: true },
|
|
1461
|
+
invariants: ["100% \uC21C\uC218 Rust \uBC31\uC5D4\uB4DC \uC6D0\uCE59"],
|
|
1462
|
+
actions: [],
|
|
1463
|
+
context: []
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
id: "rule-always-4",
|
|
1467
|
+
domain: "User_Preferences_And_Rules",
|
|
1468
|
+
title: "Global_Preference_4",
|
|
1469
|
+
triggers: { alwaysActive: true },
|
|
1470
|
+
invariants: ["\uAC80\uC99D \uCD5C\uC6B0\uC120 \uC6D0\uCE59 \uC900\uC218"],
|
|
1471
|
+
actions: [],
|
|
1472
|
+
context: []
|
|
1473
|
+
}
|
|
1474
|
+
];
|
|
1475
|
+
for (let i = 4;i < ruleCount; i++) {
|
|
1476
|
+
const dom = domains[i % domains.length];
|
|
1477
|
+
const moduleIdx = i % 500;
|
|
1478
|
+
rules.push({
|
|
1479
|
+
id: `rule-synth-${i}`,
|
|
1480
|
+
domain: dom,
|
|
1481
|
+
title: `Synth_Node_${i}`,
|
|
1482
|
+
triggers: {
|
|
1483
|
+
files: [`packages/mod_${moduleIdx}/src/file_${i}.rs`],
|
|
1484
|
+
keywords: [`kw_${i}`, `topic_${i % 250}`],
|
|
1485
|
+
commands: i % 20 === 0 ? ["build"] : i % 20 === 1 ? ["release"] : ["check"]
|
|
1486
|
+
},
|
|
1487
|
+
invariants: [`\uBD88\uBCC0 \uACC4\uC57D #${i}: \uBA54\uBAA8\uB9AC \uC548\uC804\uC131 \uBC0F \uD0C0\uC785 \uACBD\uACC4 \uBCF4\uC7A5`],
|
|
1488
|
+
actions: [`1. \uBAA8\uB4C8 ${moduleIdx} \uC815\uC801 \uAC80\uC99D \uC218\uD589`],
|
|
1489
|
+
context: [`\uD569\uC131 \uBCA4\uCE58\uB9C8\uD06C \uB178\uB4DC \uCEE8\uD14D\uC2A4\uD2B8 \uB370\uC774\uD130 #${i}`],
|
|
1490
|
+
lastVerified: "2026-11-01"
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
const relations = [];
|
|
1494
|
+
relations.push({ from: "Synth_Node_10", to: "Synth_Node_11", relationType: "triggers_hop_1" }, { from: "Synth_Node_11", to: "Synth_Node_12", relationType: "triggers_hop_2" }, { from: "Synth_Node_12", to: "Synth_Node_13", relationType: "triggers_hop_3" }, { from: "Synth_Node_13", to: "Synth_Node_14", relationType: "triggers_hop_4" }, { from: "Synth_Node_14", to: "Synth_Node_15", relationType: "triggers_hop_5" }, { from: "Synth_Node_15", to: "Synth_Node_10", relationType: "circular_feedback_edge" });
|
|
1495
|
+
for (let j = relations.length;j < relationCount; j++) {
|
|
1496
|
+
const fromIdx = 4 + j % (ruleCount - 10);
|
|
1497
|
+
const toIdx = fromIdx + 1 + j % 5;
|
|
1498
|
+
relations.push({
|
|
1499
|
+
from: `Synth_Node_${fromIdx}`,
|
|
1500
|
+
to: `Synth_Node_${toIdx}`,
|
|
1501
|
+
relationType: "causal_impact_on"
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
version: "2.1.0",
|
|
1506
|
+
updatedAt: new Date().toISOString(),
|
|
1507
|
+
totalRules: rules.length,
|
|
1508
|
+
totalRelations: relations.length,
|
|
1509
|
+
rules,
|
|
1510
|
+
relations
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
async function executeOverloadBenchmark(customConfig, silent = false) {
|
|
1514
|
+
const config = {
|
|
1515
|
+
ruleScale: customConfig?.ruleScale ?? 1e4,
|
|
1516
|
+
relationScale: customConfig?.relationScale ?? 20000,
|
|
1517
|
+
concurrency: customConfig?.concurrency ?? 50,
|
|
1518
|
+
totalRequests: customConfig?.totalRequests ?? 5000,
|
|
1519
|
+
fileInputScale: customConfig?.fileInputScale ?? 1e4,
|
|
1520
|
+
crudIterations: customConfig?.crudIterations ?? 5000
|
|
1521
|
+
};
|
|
1522
|
+
const log = (msg) => {
|
|
1523
|
+
if (!silent)
|
|
1524
|
+
process.stdout.write(msg);
|
|
1525
|
+
};
|
|
1526
|
+
const benchStart = performance.now();
|
|
1527
|
+
const scenarios = [];
|
|
1528
|
+
const isExtreme = config.ruleScale >= 1e5;
|
|
1529
|
+
const modeTitle = isExtreme ? "\uC635\uC158 2 \uADF9\uD55C \uD55C\uACC4 \uB3CC\uD30C \uC2A4\uD2B8\uB808\uC2A4 \uBCA4\uCE58\uB9C8\uD06C (Stress Max)" : "\uC635\uC158 1 \uD45C\uC900 \uACFC\uBD80\uD558 \uC2A4\uD2B8\uB808\uC2A4 \uBCA4\uCE58\uB9C8\uD06C";
|
|
1530
|
+
const sloP50Ms = isExtreme ? 2 : 0.8;
|
|
1531
|
+
const sloP99Ms = isExtreme ? 5 : 1.5;
|
|
1532
|
+
const sloRps = isExtreme ? 3000 : 5000;
|
|
1533
|
+
const sloHopMs = isExtreme ? 100 : 30;
|
|
1534
|
+
const sloHeapDeltaMB = isExtreme ? 8 : 3;
|
|
1535
|
+
log(`
|
|
1536
|
+
${BOLD3}${CYAN3}\uD83D\uDD25 [Causal Memory 2.1] ${modeTitle} \uAC00\uB3D9${RESET3}
|
|
1537
|
+
`);
|
|
1538
|
+
log(`${GRAY3}\u2022 \uC2A4\uD399: \uADDC\uCE59 ${config.ruleScale.toLocaleString()}\uAC1C | \uAC04\uC120 ${config.relationScale.toLocaleString()}\uAC1C | \uB3D9\uC2DC\uC131 ${config.concurrency} \uC6CC\uCEE4 | \uC694\uCCAD ${config.totalRequests.toLocaleString()}\uD68C | \uBCC0\uACBD\uD30C\uC77C ${config.fileInputScale.toLocaleString()}\uAC1C${RESET3}
|
|
1539
|
+
`);
|
|
1540
|
+
log(`${GRAY3}${"\u2501".repeat(84)}${RESET3}
|
|
1541
|
+
|
|
1542
|
+
`);
|
|
1543
|
+
log(`${BOLD3}${YELLOW3}\uD83D\uDCCC [\uC2DC\uB098\uB9AC\uC624 1] ${config.ruleScale.toLocaleString()}\uAC1C \uADDC\uCE59 & ${config.relationScale.toLocaleString()}\uAC1C \uAC04\uC120 \uC801\uC7AC \uBC0F O(1) \uC5ED\uC778\uB371\uC2A4 \uACF5\uBA85 \uD14C\uC2A4\uD2B8${RESET3}
|
|
1544
|
+
`);
|
|
1545
|
+
const genStart = performance.now();
|
|
1546
|
+
const synthDb = generateSyntheticDatabase(config.ruleScale, config.relationScale);
|
|
1547
|
+
const genDurationMs = Math.round((performance.now() - genStart) * 100) / 100;
|
|
1548
|
+
const indexStart = performance.now();
|
|
1549
|
+
const scaleStore = new CausalMemoryStore(undefined, synthDb);
|
|
1550
|
+
const indexBuildMs = Math.round((performance.now() - indexStart) * 100) / 100;
|
|
1551
|
+
const queryLatencies = [];
|
|
1552
|
+
let lastResonance = scaleStore.queryResonance({ keywords: ["kw_10"] });
|
|
1553
|
+
for (let i = 0;i < 1000; i++) {
|
|
1554
|
+
const targetKw = `kw_${10 + i % 5000}`;
|
|
1555
|
+
const qStart = performance.now();
|
|
1556
|
+
lastResonance = scaleStore.queryResonance({ keywords: [targetKw] });
|
|
1557
|
+
queryLatencies.push(performance.now() - qStart);
|
|
1558
|
+
}
|
|
1559
|
+
queryLatencies.sort((a, b) => a - b);
|
|
1560
|
+
const s1P50 = calcPercentile(queryLatencies, 50);
|
|
1561
|
+
const s1P95 = calcPercentile(queryLatencies, 95);
|
|
1562
|
+
const s1P99 = calcPercentile(queryLatencies, 99);
|
|
1563
|
+
const s1Passed = s1P50 <= sloP50Ms && s1P99 <= sloP99Ms && parseFloat(lastResonance.tokenDietSavingsRatio) >= 99;
|
|
1564
|
+
scenarios.push({
|
|
1565
|
+
name: "\uC2DC\uB098\uB9AC\uC624 1: \uB300\uADDC\uBAA8 \uBCFC\uB968 \uC801\uC7AC \uBC0F O(1) \uACF5\uBA85 \uCFFC\uB9AC",
|
|
1566
|
+
passed: s1Passed,
|
|
1567
|
+
details: {
|
|
1568
|
+
totalRules: config.ruleScale,
|
|
1569
|
+
totalRelations: config.relationScale,
|
|
1570
|
+
syntheticGenMs: genDurationMs,
|
|
1571
|
+
indexBuildMs,
|
|
1572
|
+
p50Ms: s1P50,
|
|
1573
|
+
p95Ms: s1P95,
|
|
1574
|
+
p99Ms: s1P99,
|
|
1575
|
+
tokenSavings: lastResonance.tokenDietSavingsRatio
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
log(` \u2022 \uC5ED\uC778\uB371\uC2A4 \uAD6C\uCD95 \uC2DC\uAC04 : ${BOLD3}${GREEN3}${indexBuildMs}ms${RESET3} (${config.ruleScale.toLocaleString()} Rules + ${config.relationScale.toLocaleString()} Relations)
|
|
1579
|
+
`);
|
|
1580
|
+
log(` \u2022 \uACF5\uBA85 \uCFFC\uB9AC \uB808\uC774\uD134\uC2DC : ${BOLD3}p50=${s1P50}ms | p95=${s1P95}ms | p99=${s1P99}ms${RESET3} (\uBAA9\uD45C: p50\u2264${sloP50Ms}ms, p99\u2264${sloP99Ms}ms)
|
|
1581
|
+
`);
|
|
1582
|
+
log(` \u2022 \uD1A0\uD070 \uC808\uAC10\uB960 : ${BOLD3}${GREEN3}${lastResonance.tokenDietSavingsRatio}${RESET3} (${lastResonance.matchedCount}/${config.ruleScale}\uAC1C\uB9CC \uC815\uBC00 \uACF5\uBA85)
|
|
1583
|
+
`);
|
|
1584
|
+
log(` \u2022 \uD310\uC815 : ${s1Passed ? `${BOLD3}${GREEN3}\u2705 PASS${RESET3}` : `${BOLD3}${RED3}\u274C FAIL${RESET3}`}
|
|
1585
|
+
|
|
1586
|
+
`);
|
|
1587
|
+
log(`${BOLD3}${YELLOW3}\uD83D\uDCCC [\uC2DC\uB098\uB9AC\uC624 2] \uB3D9\uC2DC ${config.concurrency} \uD074\uB77C\uC774\uC5B8\uD2B8 \xD7 ${config.totalRequests.toLocaleString()}\uD68C HTTP/MCP \uB370\uBAAC \uD3ED\uACA9 \uD14C\uC2A4\uD2B8${RESET3}
|
|
1588
|
+
`);
|
|
1589
|
+
const benchPort = 4288;
|
|
1590
|
+
const server = startCausalServer({ port: benchPort });
|
|
1591
|
+
let successCount = 0;
|
|
1592
|
+
let errorCount = 0;
|
|
1593
|
+
const httpLatencies = [];
|
|
1594
|
+
const requestsPerWorker = Math.floor(config.totalRequests / config.concurrency);
|
|
1595
|
+
for (let w = 0;w < 10; w++) {
|
|
1596
|
+
await fetch(`http://127.0.0.1:${benchPort}/query`, {
|
|
1597
|
+
method: "POST",
|
|
1598
|
+
headers: { "Content-Type": "application/json" },
|
|
1599
|
+
body: JSON.stringify({ keywords: ["poe2"], format: "compact" })
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
const concStart = performance.now();
|
|
1603
|
+
try {
|
|
1604
|
+
const workerPromises = Array.from({ length: config.concurrency }, async (_, workerId) => {
|
|
1605
|
+
const sampleQueries = [
|
|
1606
|
+
{ keywords: ["poe2", "updater"], format: "compact" },
|
|
1607
|
+
{ files: ["crates/vesper-audio-core/src/lib.rs"], format: "compact" },
|
|
1608
|
+
{ keywords: ["synapse", "causal"], format: "compact" },
|
|
1609
|
+
{ keywords: ["pcb", "kicad"], format: "compact" }
|
|
1610
|
+
];
|
|
1611
|
+
for (let r = 0;r < requestsPerWorker; r++) {
|
|
1612
|
+
const qPayload = sampleQueries[(workerId + r) % sampleQueries.length];
|
|
1613
|
+
const reqT0 = performance.now();
|
|
1614
|
+
try {
|
|
1615
|
+
const resp = await fetch(`http://127.0.0.1:${benchPort}/query`, {
|
|
1616
|
+
method: "POST",
|
|
1617
|
+
headers: { "Content-Type": "application/json" },
|
|
1618
|
+
body: JSON.stringify(qPayload)
|
|
1619
|
+
});
|
|
1620
|
+
if (resp.ok) {
|
|
1621
|
+
await resp.text();
|
|
1622
|
+
successCount++;
|
|
1623
|
+
} else {
|
|
1624
|
+
errorCount++;
|
|
1625
|
+
}
|
|
1626
|
+
} catch {
|
|
1627
|
+
errorCount++;
|
|
1628
|
+
}
|
|
1629
|
+
httpLatencies.push(performance.now() - reqT0);
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
await Promise.all(workerPromises);
|
|
1633
|
+
} finally {
|
|
1634
|
+
server.stop();
|
|
1635
|
+
}
|
|
1636
|
+
const concTotalSec = (performance.now() - concStart) / 1000;
|
|
1637
|
+
const rps = Math.round(successCount / concTotalSec);
|
|
1638
|
+
httpLatencies.sort((a, b) => a - b);
|
|
1639
|
+
const s2P50 = calcPercentile(httpLatencies, 50);
|
|
1640
|
+
const s2P95 = calcPercentile(httpLatencies, 95);
|
|
1641
|
+
const s2P99 = calcPercentile(httpLatencies, 99);
|
|
1642
|
+
const s2Passed = errorCount === 0 && successCount === config.totalRequests && rps >= sloRps;
|
|
1643
|
+
scenarios.push({
|
|
1644
|
+
name: "\uC2DC\uB098\uB9AC\uC624 2: \uACE0\uB3D9\uC2DC\uC131 \uB370\uBAAC \uCC98\uB9AC\uB7C9",
|
|
1645
|
+
passed: s2Passed,
|
|
1646
|
+
details: {
|
|
1647
|
+
concurrency: config.concurrency,
|
|
1648
|
+
totalRequests: config.totalRequests,
|
|
1649
|
+
successCount,
|
|
1650
|
+
errorCount,
|
|
1651
|
+
durationSec: Math.round(concTotalSec * 100) / 100,
|
|
1652
|
+
rps,
|
|
1653
|
+
httpP50Ms: s2P50,
|
|
1654
|
+
httpP95Ms: s2P95,
|
|
1655
|
+
httpP99Ms: s2P99
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
log(` \u2022 \uCD1D \uCC98\uB9AC \uC694\uCCAD : ${BOLD3}${GREEN3}${successCount.toLocaleString()} / ${config.totalRequests.toLocaleString()} \uC131\uACF5${RESET3} (\uC624\uB958\uC728: ${errorCount === 0 ? "0.00%" : errorCount})
|
|
1659
|
+
`);
|
|
1660
|
+
log(` \u2022 \uCD08\uB2F9 \uCC98\uB9AC\uB7C9 (RPS) : ${BOLD3}${CYAN3}${rps.toLocaleString()} req/sec${RESET3} (\uCD1D \uC18C\uC694: ${concTotalSec.toFixed(2)}s, \uBAA9\uD45C: \u2265${sloRps.toLocaleString()} req/s)
|
|
1661
|
+
`);
|
|
1662
|
+
log(` \u2022 HTTP \uC655\uBCF5 \uB808\uC774\uD134\uC2DC : ${BOLD3}p50=${s2P50}ms | p95=${s2P95}ms | p99=${s2P99}ms${RESET3}
|
|
1663
|
+
`);
|
|
1664
|
+
log(` \u2022 \uD310\uC815 : ${s2Passed ? `${BOLD3}${GREEN3}\u2705 PASS${RESET3}` : `${BOLD3}${RED3}\u274C FAIL${RESET3}`}
|
|
1665
|
+
|
|
1666
|
+
`);
|
|
1667
|
+
log(`${BOLD3}${YELLOW3}\uD83D\uDCCC [\uC2DC\uB098\uB9AC\uC624 3] ${config.fileInputScale.toLocaleString()}\uAC1C \uBCC0\uACBD \uD30C\uC77C \uB3D9\uC2DC \uC785\uB825 & 5-Hop \uB2E4\uC911 \uCCB4\uC778/\uC21C\uD658 \uCC38\uC870 \uC2A4\uD2B8\uB808\uC2A4${RESET3}
|
|
1668
|
+
`);
|
|
1669
|
+
const massiveFiles = [];
|
|
1670
|
+
for (let f = 0;f < config.fileInputScale; f++) {
|
|
1671
|
+
massiveFiles.push(`services/microservice_${f % 100}/src/handler_${f}.ts`);
|
|
1672
|
+
}
|
|
1673
|
+
massiveFiles[Math.floor(config.fileInputScale / 2)] = "packages/mod_10/src/file_10.rs";
|
|
1674
|
+
const hopStart = performance.now();
|
|
1675
|
+
const multiHopRes = scaleStore.queryResonance({
|
|
1676
|
+
files: massiveFiles,
|
|
1677
|
+
propagateRelations: true,
|
|
1678
|
+
maxHops: 5
|
|
1679
|
+
});
|
|
1680
|
+
const hopDurationMs = Math.round((performance.now() - hopStart) * 100) / 100;
|
|
1681
|
+
const matchedTitles = new Set(multiHopRes.resonanceRules.map((r) => r.title));
|
|
1682
|
+
const all5HopsPropagated = matchedTitles.has("Synth_Node_10") && matchedTitles.has("Synth_Node_11") && matchedTitles.has("Synth_Node_12") && matchedTitles.has("Synth_Node_13") && matchedTitles.has("Synth_Node_14") && matchedTitles.has("Synth_Node_15");
|
|
1683
|
+
const s3Passed = all5HopsPropagated && hopDurationMs <= sloHopMs;
|
|
1684
|
+
scenarios.push({
|
|
1685
|
+
name: "\uC2DC\uB098\uB9AC\uC624 3: \uB300\uADDC\uBAA8 \uD30C\uC77C & 5-Hop \uB2E4\uC911 \uC778\uACFC \uC804\uD30C",
|
|
1686
|
+
passed: s3Passed,
|
|
1687
|
+
details: {
|
|
1688
|
+
inputFilesCount: config.fileInputScale,
|
|
1689
|
+
maxHops: 5,
|
|
1690
|
+
traversalDurationMs: hopDurationMs,
|
|
1691
|
+
matchedRulesCount: multiHopRes.matchedCount,
|
|
1692
|
+
activeRelationsCount: multiHopRes.activeRelations.length,
|
|
1693
|
+
all5HopsResolved: all5HopsPropagated ? "YES (Circular Loop Safe)" : "NO",
|
|
1694
|
+
tokenSavings: multiHopRes.tokenDietSavingsRatio
|
|
1695
|
+
}
|
|
1696
|
+
});
|
|
1697
|
+
log(` \u2022 \uB300\uB7C9 \uD30C\uC77C + 5-Hop \uC18C\uC694 : ${BOLD3}${GREEN3}${hopDurationMs}ms${RESET3} (\uBAA9\uD45C: \u2264${sloHopMs}ms)
|
|
1698
|
+
`);
|
|
1699
|
+
log(` \u2022 5\uB2E8\uACC4 \uC5F0\uC1C4 \uC804\uD30C \uAC80\uC99D : ${BOLD3}${all5HopsPropagated ? `${GREEN3}Node_10 \u2794 Node_15 (5-Hop) \uBC0F \uC21C\uD658 \uCC38\uC870 \uBC29\uC5B4 100% \uC131\uACF5` : `${RED3}\uC2E4\uD328`}${RESET3}
|
|
1700
|
+
`);
|
|
1701
|
+
log(` \u2022 \uC815\uBC00 \uACA9\uB9AC \uC808\uAC10\uB960 : ${BOLD3}${GREEN3}${multiHopRes.tokenDietSavingsRatio}${RESET3} (${multiHopRes.matchedCount}/${config.ruleScale}\uAC1C\uB9CC \uD65C\uC131\uD654)
|
|
1702
|
+
`);
|
|
1703
|
+
log(` \u2022 \uD310\uC815 : ${s3Passed ? `${BOLD3}${GREEN3}\u2705 PASS${RESET3}` : `${BOLD3}${RED3}\u274C FAIL${RESET3}`}
|
|
1704
|
+
|
|
1705
|
+
`);
|
|
1706
|
+
log(`${BOLD3}${YELLOW3}\uD83D\uDCCC [\uC2DC\uB098\uB9AC\uC624 4] ${config.crudIterations.toLocaleString()}\uD68C \uC5F0\uC18D CRUD \uD2B8\uB79C\uC7AD\uC158 & \uD799 \uBA54\uBAA8\uB9AC \uB204\uC218 \uAC10\uC0AC (Zero-Leak Audit)${RESET3}
|
|
1707
|
+
`);
|
|
1708
|
+
if (typeof Bun !== "undefined" && typeof Bun.gc === "function") {
|
|
1709
|
+
Bun.gc(true);
|
|
1710
|
+
}
|
|
1711
|
+
const baseMem = process.memoryUsage();
|
|
1712
|
+
const baseHeapMB = baseMem.heapUsed / (1024 * 1024);
|
|
1713
|
+
const crudStore = new CausalMemoryStore(undefined, {
|
|
1714
|
+
version: "2.1.0",
|
|
1715
|
+
updatedAt: new Date().toISOString(),
|
|
1716
|
+
totalRules: 0,
|
|
1717
|
+
totalRelations: 0,
|
|
1718
|
+
rules: [],
|
|
1719
|
+
relations: []
|
|
1720
|
+
});
|
|
1721
|
+
const crudStart = performance.now();
|
|
1722
|
+
for (let c = 0;c < config.crudIterations; c++) {
|
|
1723
|
+
const tempName = `Ephemeral_Entity_${c % 50}`;
|
|
1724
|
+
crudStore.createEntities([
|
|
1725
|
+
{
|
|
1726
|
+
name: tempName,
|
|
1727
|
+
entityType: "StressTest",
|
|
1728
|
+
observations: [`\uC808\uB300 \uADDC\uCE59 #${c}`, `1. \uC2E4\uD589 \uB2E8\uACC4 #${c}`]
|
|
1729
|
+
}
|
|
1730
|
+
], false);
|
|
1731
|
+
crudStore.addObservations([{ entityName: tempName, contents: [`\uCD94\uAC00 \uAD00\uCC30 #${c}`] }], false);
|
|
1732
|
+
crudStore.queryResonance({ keywords: [tempName] });
|
|
1733
|
+
crudStore.deleteEntities([tempName], false);
|
|
1734
|
+
}
|
|
1735
|
+
const crudDurationMs = Math.round((performance.now() - crudStart) * 100) / 100;
|
|
1736
|
+
if (typeof Bun !== "undefined" && typeof Bun.gc === "function") {
|
|
1737
|
+
Bun.gc(true);
|
|
1738
|
+
}
|
|
1739
|
+
const afterMem = process.memoryUsage();
|
|
1740
|
+
const afterHeapMB = afterMem.heapUsed / (1024 * 1024);
|
|
1741
|
+
const rssMB = Math.round(afterMem.rss / (1024 * 1024) * 100) / 100;
|
|
1742
|
+
const heapDeltaMB = Math.round(Math.max(0, afterHeapMB - baseHeapMB) * 100) / 100;
|
|
1743
|
+
const s4Passed = heapDeltaMB <= sloHeapDeltaMB && crudStore.getAllRules().length === 0;
|
|
1744
|
+
scenarios.push({
|
|
1745
|
+
name: "\uC2DC\uB098\uB9AC\uC624 4: \uC5F0\uC18D CRUD \uB0B4\uAD6C\uB3C4 \uBC0F \uD799 \uB204\uC218 \uAC10\uC0AC",
|
|
1746
|
+
passed: s4Passed,
|
|
1747
|
+
details: {
|
|
1748
|
+
crudCycles: config.crudIterations,
|
|
1749
|
+
totalOperations: config.crudIterations * 4,
|
|
1750
|
+
durationMs: crudDurationMs,
|
|
1751
|
+
baseHeapMB: Math.round(baseHeapMB * 100) / 100,
|
|
1752
|
+
afterHeapMB: Math.round(afterHeapMB * 100) / 100,
|
|
1753
|
+
heapDeltaMB,
|
|
1754
|
+
rssMB,
|
|
1755
|
+
residualRules: crudStore.getAllRules().length
|
|
1756
|
+
}
|
|
1757
|
+
});
|
|
1758
|
+
log(` \u2022 \uCD1D \uC218\uD589 \uC5F0\uC0B0 \uC218 : ${BOLD3}${(config.crudIterations * 4).toLocaleString()}\uD68C CRUD \uC5F0\uC0B0${RESET3} (\uC18C\uC694: ${crudDurationMs}ms)
|
|
1759
|
+
`);
|
|
1760
|
+
log(` \u2022 \uD799 \uBA54\uBAA8\uB9AC \uBCC0\uD654\uB7C9 : ${BOLD3}${GREEN3}\u0394 ${heapDeltaMB} MB${RESET3} (\uC2DC\uC791: ${baseHeapMB.toFixed(2)}MB \u2794 \uC885\uB8CC: ${afterHeapMB.toFixed(2)}MB, \uBAA9\uD45C: \u2264${sloHeapDeltaMB.toFixed(1)}MB)
|
|
1761
|
+
`);
|
|
1762
|
+
log(` \u2022 \uD504\uB85C\uC138\uC2A4 RSS \uC810\uC720 : ${BOLD3}${rssMB} MB${RESET3}
|
|
1763
|
+
`);
|
|
1764
|
+
log(` \u2022 \uD310\uC815 : ${s4Passed ? `${BOLD3}${GREEN3}\u2705 PASS${RESET3}` : `${BOLD3}${RED3}\u274C FAIL${RESET3}`}
|
|
1765
|
+
|
|
1766
|
+
`);
|
|
1767
|
+
const totalDurationMs = Math.round((performance.now() - benchStart) * 100) / 100;
|
|
1768
|
+
const allPassed = scenarios.every((s) => s.passed);
|
|
1769
|
+
log(`${GRAY3}${"\u2501".repeat(84)}${RESET3}
|
|
1770
|
+
`);
|
|
1771
|
+
log(`${BOLD3}${allPassed ? GREEN3 : RED3}\uD83C\uDFC6 [\uCD5C\uC885 \uBCA4\uCE58\uB9C8\uD06C \uACB0\uACFC] 4\uB300 \uACFC\uBD80\uD558 \uCC28\uC6D0 \uC804\uC218 ${allPassed ? "ALL PASS (100% \uD569\uACA9)" : "\uC77C\uBD80 \uBBF8\uB2EC"} (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${(totalDurationMs / 1000).toFixed(2)}s)${RESET3}
|
|
1772
|
+
|
|
1773
|
+
`);
|
|
1774
|
+
return {
|
|
1775
|
+
timestamp: new Date().toISOString(),
|
|
1776
|
+
config,
|
|
1777
|
+
allPassed,
|
|
1778
|
+
totalDurationMs,
|
|
1779
|
+
scenarios
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
var RESET3 = "\x1B[0m", BOLD3 = "\x1B[1m", CYAN3 = "\x1B[36m", GREEN3 = "\x1B[32m", YELLOW3 = "\x1B[33m", RED3 = "\x1B[31m", GRAY3 = "\x1B[90m";
|
|
1783
|
+
var init_causal_benchmark = __esm(() => {
|
|
1784
|
+
init_causal_store();
|
|
1785
|
+
init_causal_server();
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
// src/cli.ts
|
|
1789
|
+
import { resolve as resolve5 } from "path";
|
|
1790
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1791
|
+
import { writeFile } from "fs/promises";
|
|
1792
|
+
// package.json
|
|
1793
|
+
var package_default = {
|
|
1794
|
+
name: "synapse-kit",
|
|
1795
|
+
version: "0.2.2",
|
|
1796
|
+
private: false,
|
|
1797
|
+
publishConfig: {
|
|
1798
|
+
access: "public"
|
|
1799
|
+
},
|
|
1800
|
+
description: "AI-Native Unified Compiler, Linter & Verification Framework for Tauri and Full-Stack Apps",
|
|
1801
|
+
type: "module",
|
|
1802
|
+
main: "dist/index.js",
|
|
1803
|
+
types: "dist/index.d.ts",
|
|
1804
|
+
bin: {
|
|
1805
|
+
synapse: "./dist/cli.js",
|
|
1806
|
+
"synapse-kit": "./dist/cli.js"
|
|
1807
|
+
},
|
|
1808
|
+
files: [
|
|
1809
|
+
"dist",
|
|
1810
|
+
"README.md",
|
|
1811
|
+
"README.ko.md",
|
|
1812
|
+
"LICENSE"
|
|
1813
|
+
],
|
|
1814
|
+
scripts: {
|
|
1815
|
+
"build:bundle": "bun build src/cli.ts --outfile dist/cli.js --target bun && bun build src/index.ts --outfile dist/index.js --target bun",
|
|
1816
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
1817
|
+
build: "bun run build:bundle && bun run build:types",
|
|
1818
|
+
prepublishOnly: "bun run build",
|
|
1819
|
+
start: "bun run src/cli.ts",
|
|
1820
|
+
check: "bun run src/cli.ts check",
|
|
1821
|
+
test: "bun test"
|
|
1822
|
+
},
|
|
1823
|
+
repository: {
|
|
1824
|
+
type: "git",
|
|
1825
|
+
url: "git+https://github.com/minseokk77/synapse-kit.git"
|
|
1826
|
+
},
|
|
1827
|
+
homepage: "https://github.com/minseokk77/synapse-kit#readme",
|
|
1828
|
+
bugs: {
|
|
1829
|
+
url: "https://github.com/minseokk77/synapse-kit/issues"
|
|
1830
|
+
},
|
|
1831
|
+
keywords: [
|
|
1832
|
+
"tauri",
|
|
1833
|
+
"compiler",
|
|
1834
|
+
"verification",
|
|
1835
|
+
"rust",
|
|
1836
|
+
"svelte",
|
|
1837
|
+
"typescript",
|
|
1838
|
+
"ai-native",
|
|
1839
|
+
"bun"
|
|
1840
|
+
],
|
|
1841
|
+
author: "Vesper",
|
|
1842
|
+
license: "MIT",
|
|
1843
|
+
devDependencies: {
|
|
1844
|
+
"@types/bun": "^1.4.4",
|
|
1845
|
+
typescript: "^5.6.3"
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
// src/core/config.ts
|
|
1850
|
+
import { resolve } from "path";
|
|
1851
|
+
import { existsSync } from "fs";
|
|
1852
|
+
var CONFIG_FILENAMES = [
|
|
1853
|
+
"synapse.config.ts",
|
|
1854
|
+
"synapse.config.js",
|
|
1855
|
+
"synapse.config.mjs"
|
|
1856
|
+
];
|
|
1857
|
+
async function loadSynapseConfig(targetDir = process.cwd()) {
|
|
1858
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
1859
|
+
const candidate = resolve(targetDir, filename);
|
|
1860
|
+
if (existsSync(candidate)) {
|
|
1861
|
+
try {
|
|
1862
|
+
const imported = await import(candidate);
|
|
1863
|
+
const config = imported.default || imported;
|
|
1864
|
+
return {
|
|
1865
|
+
config: {
|
|
1866
|
+
...config,
|
|
1867
|
+
rootDir: config.rootDir ? resolve(targetDir, config.rootDir) : targetDir
|
|
1868
|
+
},
|
|
1869
|
+
configPath: candidate
|
|
1870
|
+
};
|
|
1871
|
+
} catch (error) {
|
|
1872
|
+
throw new Error(`\uC124\uC815 \uD30C\uC77C(${candidate}) \uB85C\uB529 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4: ${error instanceof Error ? error.message : String(error)}`);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
throw new Error(`\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8(${targetDir})\uC5D0\uC11C synapse.config.ts \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
|
|
1877
|
+
` + `'synapse init' \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD558\uC5EC \uAE30\uBCF8 \uC124\uC815 \uD30C\uC77C\uC744 \uC0DD\uC131\uD574 \uC8FC\uC138\uC694.`);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// src/core/engine.ts
|
|
1881
|
+
var {spawn: spawn2 } = globalThis.Bun;
|
|
1882
|
+
import { existsSync as existsSync3, readdirSync, watch } from "fs";
|
|
1883
|
+
import { resolve as resolve3 } from "path";
|
|
1884
|
+
|
|
1885
|
+
// src/memory/causal-build.ts
|
|
1886
|
+
var {spawn } = globalThis.Bun;
|
|
1887
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, statSync } from "fs";
|
|
1888
|
+
import { resolve as resolve2 } from "path";
|
|
1889
|
+
import { createHash } from "crypto";
|
|
1890
|
+
function loadBuildCache(rootDir) {
|
|
1891
|
+
const cacheFile = resolve2(rootDir, ".synapse/build-cache.json");
|
|
1892
|
+
try {
|
|
1893
|
+
if (existsSync2(cacheFile)) {
|
|
1894
|
+
const content = readFileSync(cacheFile, "utf-8");
|
|
1895
|
+
const parsed = JSON.parse(content);
|
|
1896
|
+
return {
|
|
1897
|
+
lastVerifiedHead: parsed.lastVerifiedHead,
|
|
1898
|
+
tracks: parsed.tracks || {},
|
|
1899
|
+
sign: parsed.sign
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
} catch {}
|
|
1903
|
+
return { tracks: {} };
|
|
1904
|
+
}
|
|
1905
|
+
function saveBuildCache(rootDir, cache) {
|
|
1906
|
+
const cacheDir = resolve2(rootDir, ".synapse");
|
|
1907
|
+
const cacheFile = resolve2(cacheDir, "build-cache.json");
|
|
1908
|
+
try {
|
|
1909
|
+
if (!existsSync2(cacheDir)) {
|
|
1910
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
1911
|
+
}
|
|
1912
|
+
writeFileSync(cacheFile, JSON.stringify(cache, null, 2), "utf-8");
|
|
1913
|
+
} catch {}
|
|
1914
|
+
}
|
|
1915
|
+
async function getGitState(rootDir) {
|
|
1916
|
+
try {
|
|
1917
|
+
const rootProc = spawn(["git", "rev-parse", "--show-toplevel"], { cwd: rootDir, stdout: "pipe" });
|
|
1918
|
+
const repoRoot = (await new Response(rootProc.stdout).text()).trim().replaceAll("\\", "/");
|
|
1919
|
+
await rootProc.exited;
|
|
1920
|
+
const headProc = spawn(["git", "rev-parse", "HEAD"], { cwd: rootDir, stdout: "pipe" });
|
|
1921
|
+
const head = (await new Response(headProc.stdout).text()).trim();
|
|
1922
|
+
await headProc.exited;
|
|
1923
|
+
const statusProc = spawn(["git", "status", "--porcelain", "-uall"], { cwd: rootDir, stdout: "pipe" });
|
|
1924
|
+
const statusText = await new Response(statusProc.stdout).text();
|
|
1925
|
+
await statusProc.exited;
|
|
1926
|
+
const modifiedFiles = statusText.split(`
|
|
1927
|
+
`).map((line) => line.slice(3).trim().replaceAll("\\", "/")).filter((line) => line.length > 0 && !line.startsWith(".synapse/") && !line.includes("/.synapse/"));
|
|
1928
|
+
return { head, modifiedFiles, repoRoot: repoRoot || rootDir };
|
|
1929
|
+
} catch {
|
|
1930
|
+
return { head: "unknown", modifiedFiles: [], repoRoot: rootDir };
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
function shouldSkipBuildTrack(track, rootDir, repoRoot, cache, modifiedFiles, isForce) {
|
|
1934
|
+
if (isForce) {
|
|
1935
|
+
return { skip: false, reason: "\uAC15\uC81C \uBE4C\uB4DC \uBAA8\uB4DC(--force)" };
|
|
1936
|
+
}
|
|
1937
|
+
const artifacts = track.artifacts || [];
|
|
1938
|
+
if (artifacts.length > 0) {
|
|
1939
|
+
for (const art of artifacts) {
|
|
1940
|
+
const fullPath = resolve2(track.cwd || rootDir, art);
|
|
1941
|
+
if (!existsSync2(fullPath)) {
|
|
1942
|
+
return { skip: false, reason: `\uC0B0\uCD9C\uBB3C \uB204\uB77D: ${art}` };
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
const record = cache.tracks[track.name];
|
|
1947
|
+
if (!record) {
|
|
1948
|
+
return { skip: false, reason: "\uCD08\uAE30 \uBE4C\uB4DC \uAE30\uB85D \uC5C6\uC74C" };
|
|
1949
|
+
}
|
|
1950
|
+
const sources = track.sources || [];
|
|
1951
|
+
if (sources.length > 0) {
|
|
1952
|
+
const lastBuildEpoch = new Date(record.lastBuildTime).getTime();
|
|
1953
|
+
const hasModifiedSource = modifiedFiles.some((file) => {
|
|
1954
|
+
const isMatch = sources.some((src) => file.includes(src.replaceAll("\\", "/")));
|
|
1955
|
+
if (!isMatch)
|
|
1956
|
+
return false;
|
|
1957
|
+
const fullPath = resolve2(repoRoot, file);
|
|
1958
|
+
if (existsSync2(fullPath)) {
|
|
1959
|
+
try {
|
|
1960
|
+
const stat = statSync(fullPath);
|
|
1961
|
+
return stat.mtimeMs > lastBuildEpoch;
|
|
1962
|
+
} catch {
|
|
1963
|
+
return true;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return true;
|
|
1967
|
+
});
|
|
1968
|
+
if (hasModifiedSource) {
|
|
1969
|
+
return { skip: false, reason: "\uB9C8\uC9C0\uB9C9 \uBE4C\uB4DC \uC774\uD6C4 \uC18C\uC2A4 \uCF54\uB4DC \uBCC0\uACBD \uAC10\uC9C0" };
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
return { skip: true, reason: "\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uC77C\uCE58 (\uC18C\uC2A4 \uBCC0\uACBD \uC5C6\uC74C)" };
|
|
1973
|
+
}
|
|
1974
|
+
function computeFileHash(filePath) {
|
|
1975
|
+
try {
|
|
1976
|
+
const buffer = readFileSync(filePath);
|
|
1977
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
1978
|
+
} catch {
|
|
1979
|
+
return "";
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
function shouldSkipSign(installerPath, signaturePath, cache, isForce) {
|
|
1983
|
+
if (isForce) {
|
|
1984
|
+
return { skip: false, reason: "\uAC15\uC81C \uC11C\uBA85 \uBAA8\uB4DC(--force)", currentHash: "" };
|
|
1985
|
+
}
|
|
1986
|
+
if (!existsSync2(installerPath)) {
|
|
1987
|
+
return { skip: false, reason: "\uC11C\uBA85 \uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC \uBBF8\uC874\uC7AC", currentHash: "" };
|
|
1988
|
+
}
|
|
1989
|
+
if (!existsSync2(signaturePath)) {
|
|
1990
|
+
return { skip: false, reason: "\uAE30\uC874 \uC11C\uBA85(.sig) \uD30C\uC77C \uBBF8\uC874\uC7AC", currentHash: "" };
|
|
1991
|
+
}
|
|
1992
|
+
const currentHash = computeFileHash(installerPath);
|
|
1993
|
+
if (!currentHash) {
|
|
1994
|
+
return { skip: false, reason: "\uC778\uC2A4\uD1A8\uB7EC \uD574\uC2DC \uACC4\uC0B0 \uBD88\uAC00", currentHash: "" };
|
|
1995
|
+
}
|
|
1996
|
+
const record = cache.sign;
|
|
1997
|
+
if (record && record.installerHash === currentHash && record.signaturePath === signaturePath) {
|
|
1998
|
+
return { skip: true, reason: "\uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uBD88\uBCC0 (\uC11C\uBA85 \uCE90\uC2DC \uC801\uC911)", currentHash };
|
|
1999
|
+
}
|
|
2000
|
+
return { skip: false, reason: "\uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uBCC0\uACBD \uAC10\uC9C0", currentHash };
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// src/i18n.ts
|
|
2004
|
+
var currentLocale = "en";
|
|
2005
|
+
var MESSAGES = {
|
|
2006
|
+
ko: {
|
|
2007
|
+
cliTitle: "\uD83E\uDDE0 Synapse Kit - AI-Native \uD1B5\uD569 \uCEF4\uD30C\uC77C, \uBE4C\uB4DC & \uD328\uD0A4\uC9D5 \uD504\uB808\uC784\uC6CC\uD06C",
|
|
2008
|
+
cliUsage: "\uC0AC\uC6A9\uBC95:",
|
|
2009
|
+
cliCommands: "\uD575\uC2EC \uBA85\uB839\uC5B4:",
|
|
2010
|
+
cmdCheck: "\uB4F1\uB85D\uB41C \uD50C\uB7EC\uADF8\uC778 \uBB34\uACB0\uC131 \uAC80\uC99D (\uAE30\uBCF8: AI \uC778\uACFC\uC728 \uC2A4\uB9C8\uD2B8 \uAC80\uC0AC)",
|
|
2011
|
+
cmdBuild: "\uB4F1\uB85D\uB41C buildTracks \uCD08\uACE0\uC18D \uC778\uACFC\uC728 \uBCD1\uB82C \uC99D\uBD84 \uBE4C\uB4DC (0\uCD08\uB300 \uCE90\uC2DC)",
|
|
2012
|
+
cmdPackage: "\uB2E8\uC77C NSIS + zlib \uACE0\uC18D \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uBC88\uB4E4\uB7EC",
|
|
2013
|
+
cmdSign: "\uC778\uACFC\uC728 \uC554\uD638\uD654 \uC11C\uBA85 \uC5D4\uC9C4 (Minisign / Ed25519)",
|
|
2014
|
+
cmdInit: "\uD604\uC7AC \uB514\uB809\uD130\uB9AC\uC5D0 \uCD5C\uC801\uD654\uB41C synapse.config.ts \uC0DD\uC131",
|
|
2015
|
+
cmdMemory: "\uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC(Causal Memory) \uCD08\uACBD\uB7C9 \uACF5\uBA85 \uC870\uD68C, \uAD00\uB9AC \uBC0F \uB85C\uCEEC \uB370\uBAAC \uAD6C\uB3D9",
|
|
2016
|
+
cliOptions: "\uC635\uC158:",
|
|
2017
|
+
optAll: "\uC778\uACFC\uC728 \uC2A4\uD0B5\uC744 \uB044\uACE0 \uC804\uBC29\uC704 \uAC15\uC81C \uAC80\uC0AC",
|
|
2018
|
+
optForce: "\uBE4C\uB4DC/\uC11C\uBA85 \uC2DC \uC778\uACFC\uC728 \uCE90\uC2DC\uB97C \uBB34\uC2DC\uD558\uACE0 \uAC15\uC81C \uC7AC\uC2E4\uD589",
|
|
2019
|
+
optAgent: "AI \uC5D0\uC774\uC804\uD2B8(Claude Code, Antigravity \uB4F1) \uC5F0\uB3D9\uC6A9 \uAD6C\uC870\uD654\uB41C JSON \uCD9C\uB825",
|
|
2020
|
+
optCompact: "AI \uD1A0\uD070 \uADF9\uB2E8\uC801 \uCD5C\uC18C\uD654 \uBAA8\uB4DC (\uC131\uACF5 \uC2DC \uB2E8 11 \uD1A0\uD070)",
|
|
2021
|
+
optInteractive: "\uC624\uB958 \uBC1C\uC0DD \uC2DC \uD504\uB85C\uC138\uC2A4\uB97C \uC77C\uC2DC\uC815\uC9C0\uD558\uACE0 \uC2E4\uC2DC\uAC04 \uCF54\uB4DC \uC218\uC815 \uB300\uAE30 (\uC778\uACFC \uD56B\uD53D\uC2A4)",
|
|
2022
|
+
optWatch: "\uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0 \uBC31\uADF8\uB77C\uC6B4\uB4DC \uBAA8\uB4DC",
|
|
2023
|
+
optLang: "\uCD9C\uB825 \uC5B8\uC5B4 \uAC15\uC81C \uC9C0\uC815 (ko | en)",
|
|
2024
|
+
optHelp: "\uB3C4\uC6C0\uB9D0 \uD45C\uC2DC",
|
|
2025
|
+
optVersion: "\uBC84\uC804 \uC815\uBCF4 \uD45C\uC2DC",
|
|
2026
|
+
unknownCmd: "\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4:",
|
|
2027
|
+
errPrefix: "\uD83D\uDEA8 \uC624\uB958:",
|
|
2028
|
+
configExists: "\uC774\uBBF8 \uC124\uC815 \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4:",
|
|
2029
|
+
configCreated: "synapse.config.ts \uD15C\uD50C\uB9BF\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
2030
|
+
checkHeader: "\uD83E\uDDE0 [Synapse Kit] AI-Native \uD1B5\uD569 \uCEF4\uD30C\uC77C & \uAC80\uC0AC \uD504\uB808\uC784\uC6CC\uD06C",
|
|
2031
|
+
causalAll: "\uC804\uCCB4 \uAC80\uC0AC \uBAA8\uB4DC(--all) \uC694\uCCAD: \uBAA8\uB4E0 \uD50C\uB7EC\uADF8\uC778 \uAC80\uC0AC\uAE30\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.",
|
|
2032
|
+
causalDirty: (count, plugins) => `\uBCC0\uACBD\uB41C ${count}\uAC1C \uD30C\uC77C \uC778\uACFC \uBD84\uC11D \uC644\uB8CC: [${plugins}] \uD50C\uB7EC\uADF8\uC778\uB9CC \uC120\uBCC4 \uC2E4\uD589\uD569\uB2C8\uB2E4.`,
|
|
2033
|
+
causalClean: "\uBCC0\uACBD\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBAA8\uB4E0 \uAC80\uC99D \uD50C\uB7EC\uADF8\uC778\uC744 0.00\uCD08 \uC2A4\uD0B5\uD569\uB2C8\uB2E4.",
|
|
2034
|
+
causalCleanCacheHit: "\uC791\uC5C5 \uD2B8\uB9AC\uC5D0 \uBCC0\uACBD \uD30C\uC77C\uC774 \uC5C6\uC73C\uBA70 \uC774\uC804 \uAC80\uC99D \uD1B5\uACFC \uCEE4\uBC0B\uACFC \uC77C\uCE58\uD558\uC5EC 0.00\uCD08 \uC2A4\uD0B5\uD569\uB2C8\uB2E4.",
|
|
2035
|
+
causalBaseline: "\uC791\uC5C5 \uD2B8\uB9AC\uC5D0 \uBCC0\uACBD\uB41C \uD30C\uC77C\uC774 \uC5C6\uC5B4 \uC804\uCCB4 \uBCA0\uC774\uC2A4\uB77C\uC778 \uAC80\uC99D\uC744 \uC218\uD589\uD569\uB2C8\uB2E4.",
|
|
2036
|
+
causalUnrelated: (count) => `\uBCC0\uACBD\uB41C ${count}\uAC1C \uD30C\uC77C\uC774 \uB4F1\uB85D\uB41C \uAC80\uC0AC \uD50C\uB7EC\uADF8\uC778\uC758 \uC601\uD5A5 \uBC94\uC704\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC544 \uC804\uCCB4 \uAC80\uC0AC\uB97C \uC2A4\uD0B5\uD569\uB2C8\uB2E4.`,
|
|
2037
|
+
causalGitFail: "Git \uBCC0\uACBD \uCD94\uC801 \uBD88\uAC00\uB85C \uC548\uC804 \uBAA8\uB4DC(\uC804\uCCB4 \uAC80\uC0AC)\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.",
|
|
2038
|
+
checkPassed: "\uD1B5\uACFC",
|
|
2039
|
+
checkSkipped: "\uC0DD\uB7B5 (\uC778\uACFC\uC728 0\uCD08 \uC2A4\uD0B5)",
|
|
2040
|
+
checkFailed: "\uC2E4\uD328",
|
|
2041
|
+
checkSuccessSummary: (errs, warns, skips, sec) => `\u2728 \uC2DC\uB0C5\uC2A4 \uAC80\uC99D \uC131\uACF5: ${errs} Errors, ${warns} Warnings, ${skips} Skipped (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2042
|
+
checkFailureSummary: (errs, warns, sec) => `\u274C \uC2DC\uB0C5\uC2A4 \uAC80\uC99D \uC2E4\uD328: ${errs}\uAC1C \uAC80\uC0AC\uAE30 \uC624\uB958 \uBC1C\uC0DD (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2043
|
+
interactivePause: "\u23F8\uFE0F \uC5D0\uB7EC \uBC1C\uC0DD\uC73C\uB85C \uC77C\uC2DC\uC815\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC744 \uC218\uC815\uD55C \uB4A4 \uC800\uC7A5\uD558\uBA74 0.05\uCD08 \uB9CC\uC5D0 \uD56B \uC7AC\uAC80\uC99D\uD569\uB2C8\uB2E4. (\uC885\uB8CC: Ctrl+C)",
|
|
2044
|
+
interactiveReload: "\u26A1 \uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0! \uC778\uBA54\uBAA8\uB9AC \uD56B \uC7AC\uAC80\uC99D\uC744 \uC989\uC2DC \uAC00\uB3D9\uD569\uB2C8\uB2E4...",
|
|
2045
|
+
interactiveTitle: "\u23F8\uFE0F [\uB300\uD654\uD615 \uC778\uACFC \uD56B\uD53D\uC2A4 \uBAA8\uB4DC] \uC624\uB958 \uBC1C\uC0DD\uC73C\uB85C \uD504\uB85C\uC138\uC2A4\uB97C \uC77C\uC2DC\uC815\uC9C0\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2046
|
+
interactiveTarget: "\uB300\uC0C1 \uD50C\uB7EC\uADF8\uC778",
|
|
2047
|
+
interactiveWatching: "\uAC10\uC2DC \uC0C1\uD0DC : \uD83D\uDC40 \uC18C\uC2A4 \uCF54\uB4DC \uC218\uC815 \uB300\uAE30 \uC911... (\uC800\uC7A5 \uC2DC 0.05\uCD08 \uB9CC\uC5D0 \uD56B \uC7AC\uCEF4\uD30C\uC77C)",
|
|
2048
|
+
interactiveExit: "\uC138\uC158 \uC885\uB8CC : \uD130\uBBF8\uB110\uC5D0\uC11C Ctrl+C \uC785\uB825",
|
|
2049
|
+
interactiveDetected: (time, file) => `\u26A1 [\uC800\uC7A5 \uAC10\uC9C0 ${time}] ${file} \uC218\uC815 \uAC10\uC9C0 \u279C \uD56B \uC7AC\uCEF4\uD30C\uC77C \uC2E4\uD589 \uC911...`,
|
|
2050
|
+
interactivePassed: (sec) => `\u2728 [\uD56B \uC7AC\uCEF4\uD30C\uC77C \uD1B5\uACFC] (${sec}s) \uACB0\uD568\uC774 \uC644\uC804\uD788 \uD574\uACB0\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`,
|
|
2051
|
+
interactiveResumed: "\u25B6\uFE0F [\uD30C\uC774\uD504\uB77C\uC778 \uC7AC\uAC1C] \uBAA8\uB4E0 \uAC80\uC99D \uD1B5\uACFC \uC644\uB8CC. \uD504\uB85C\uC138\uC2A4\uB97C \uC815\uC0C1 \uC885\uB8CC\uD569\uB2C8\uB2E4.",
|
|
2052
|
+
interactiveFailed: "\u274C [\uC7AC\uAC80\uC99D \uC2E4\uD328] \uC5EC\uC804\uD788 \uC624\uB958\uAC00 \uB0A8\uC544\uC788\uC2B5\uB2C8\uB2E4. \uCF54\uB4DC\uB97C \uB2E4\uC2DC \uC218\uC815\uD558\uACE0 \uC800\uC7A5\uD574 \uC8FC\uC138\uC694.",
|
|
2053
|
+
buildHeader: "\u26A1 [Synapse Build] \uC778\uACFC\uC728 \uBA40\uD2F0\uD2B8\uB799 \uBCD1\uB82C \uC99D\uBD84 \uBE4C\uB354",
|
|
2054
|
+
buildSkipped: "\u23ED\uFE0F \uC18C\uC2A4 \uBBF8\uBCC0\uACBD \uAC10\uC9C0: 0.00\uCD08 \uC2A4\uD0B5",
|
|
2055
|
+
buildSuccess: "\u2705 \uBE4C\uB4DC \uC644\uACB0",
|
|
2056
|
+
buildFailed: "\u274C \uBE4C\uB4DC \uC2E4\uD328",
|
|
2057
|
+
buildAllUpToDate: "\u2728 \uBAA8\uB4E0 \uBE4C\uB4DC \uD2B8\uB799\uC774 \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4. (\uC804\uCCB4 \uBE4C\uB4DC \uC0DD\uB7B5: 0.00\uCD08)",
|
|
2058
|
+
buildComplete: (sec) => `\u2728 \uC804\uCCB4 \uC778\uACFC\uC728 \uC99D\uBD84 \uBE4C\uB4DC \uC644\uACB0 (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2059
|
+
packageHeader: "\uD83D\uDCE6 [Synapse Package] \uCD08\uACE0\uC18D \uC778\uC2A4\uD1A8\uB7EC \uBC88\uB4E4\uB7EC",
|
|
2060
|
+
packageSuccess: (sec) => `\u2728 \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uC131\uACF5 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2061
|
+
packageFailed: (sec) => `\u274C \uC778\uC2A4\uD1A8\uB7EC \uD328\uD0A4\uC9D5 \uC2E4\uD328 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2062
|
+
signHeader: "\uD83D\uDD10 [Synapse Sign] \uC778\uACFC\uC728 \uC554\uD638\uD654 \uC11C\uBA85 \uD30C\uC774\uD504\uB77C\uC778",
|
|
2063
|
+
signSkipped: "\u23ED\uFE0F \uC778\uC2A4\uD1A8\uB7EC \uBC14\uC774\uB108\uB9AC \uD574\uC2DC \uBD88\uBCC0: \uC11C\uBA85 0.00\uCD08 \uC2A4\uD0B5",
|
|
2064
|
+
signSuccess: (sec) => `\u2728 \uC778\uC2A4\uD1A8\uB7EC Ed25519 \uB514\uC9C0\uD138 \uC11C\uBA85 \uBC1C\uD589 \uC644\uB8CC (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2065
|
+
signFailed: (sec) => `\u274C \uC11C\uBA85 \uC0DD\uC131 \uC2E4\uD328 (\uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2066
|
+
signNoConfig: "\u274C \uC11C\uBA85 \uC124\uC815(sign.privateKeyPath)\uC774 synapse.config.ts\uC5D0 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
|
|
2067
|
+
signNoKey: (p) => `\u274C \uC11C\uBA85 \uAC1C\uC778\uD0A4 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${p}`,
|
|
2068
|
+
signNoInstaller: "\u274C \uC11C\uBA85 \uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC(.exe) \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2069
|
+
signTarget: "\uB300\uC0C1 \uC778\uC2A4\uD1A8\uB7EC",
|
|
2070
|
+
signStatus: "\uC11C\uBA85 \uC0C1\uD0DC",
|
|
2071
|
+
signFile: "\uC11C\uBA85 \uD30C\uC77C",
|
|
2072
|
+
signReasonLabel: "\uC11C\uBA85 \uC0AC\uC720",
|
|
2073
|
+
signEngineLabel: "\uC11C\uBA85 \uC5D4\uC9C4",
|
|
2074
|
+
signCacheHit: "\uC2A4\uD0B5 [\uC778\uACFC\uC728 \uCE90\uC2DC \uC801\uC911: \uBC14\uC774\uB108\uB9AC \uD574\uC2DC \uBD88\uBCC0]",
|
|
2075
|
+
signExistingKeep: (p) => `\uAE30\uC874 \uC11C\uBA85 \uD30C\uC77C \uC720\uC9C0 (${p})`,
|
|
2076
|
+
signIntegrityPass: "\u2728 \uC11C\uBA85 \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC (0.00\uCD08)",
|
|
2077
|
+
statusSuccess: "\uD1B5\uACFC",
|
|
2078
|
+
statusSkipped: "\uC2A4\uD0B5 (\uC778\uACFC\uC728 \uC0DD\uB7B5)",
|
|
2079
|
+
statusWarning: "\uACBD\uACE0",
|
|
2080
|
+
statusError: "\uC2E4\uD328",
|
|
2081
|
+
causalAnalysis: "\uC778\uACFC \uBA54\uBAA8\uB9AC \uBD84\uC11D",
|
|
2082
|
+
trackSkipped: "\uC2A4\uD0B5 [\uC778\uACFC\uC728 \uCE90\uC2DC \uC801\uC911]",
|
|
2083
|
+
trackComplete: "\uBE4C\uB4DC \uC644\uB8CC",
|
|
2084
|
+
trackFailed: "\uBE4C\uB4DC \uC2E4\uD328",
|
|
2085
|
+
noBuildTracks: "\u274C \uB4F1\uB85D\uB41C \uBE4C\uB4DC \uD2B8\uB799(buildTracks)\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. synapse.config.ts\uB97C \uD655\uC778\uD574 \uC8FC\uC138\uC694.",
|
|
2086
|
+
buildSuccessSummary: (tracks, sec) => `\u2728 \uC778\uACFC\uC728 \uBCD1\uB82C \uBE4C\uB4DC \uC131\uACF5: \uC804\uCCB4 ${tracks}\uAC1C \uD2B8\uB799 \uC644\uB8CC (\uCD1D \uC18C\uC694 \uC2DC\uAC04: ${sec}\uCD08)`,
|
|
2087
|
+
buildFailureSummary: "\uD83D\uDEA8 \uBCD1\uB82C \uBE4C\uB4DC \uC2E4\uD328: \uD558\uB098 \uC774\uC0C1\uC758 \uD2B8\uB799\uC5D0\uC11C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2088
|
+
packagingPreBuild: "\u2139\uFE0F \uC0AC\uC804 \uC544\uD2F0\uD329\uD2B8 \uC778\uACFC\uC728 \uBE4C\uB4DC \uD655\uC778 \uC911...",
|
|
2089
|
+
packagingStart: "\uD83D\uDE80 Tauri \uC778\uC2A4\uD1A8\uB7EC \uBC88\uB4E4\uB9C1 \uC2DC\uC791...",
|
|
2090
|
+
packagingGuide: `\u26A0\uFE0F [\uD328\uD0A4\uC9D5 \uAC00\uC774\uB4DC] tauri.conf.json\uC758 targets\uAC00 "all"\uB85C \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.
|
|
2091
|
+
\u21B3 WiX MSI \uC911\uBCF5 \uBE4C\uB4DC\uB85C \uC2DC\uAC04\uC774 \uC18C\uC694\uB429\uB2C8\uB2E4. targets: ["nsis"] \uC124\uC815\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.`,
|
|
2092
|
+
pluginRustTitle: "Rust \uBC31\uC5D4\uB4DC \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 (Check & Clippy)",
|
|
2093
|
+
pluginRustSuccess: "Rust \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uCEF4\uD30C\uC77C \uBC0F Clippy \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC (0 Warnings, 0 Errors)",
|
|
2094
|
+
pluginRustClippyWarn: (count) => `\uCEF4\uD30C\uC77C \uD1B5\uACFC \uC644\uB8CC (${count}\uAC1C Clippy \uAD8C\uC7A5\uC0AC\uD56D \uAC10\uC9C0\uB428)`,
|
|
2095
|
+
pluginRustCompileFail: "Rust \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uCEF4\uD30C\uC77C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2096
|
+
pluginRustExecFail: (msg) => `Rust \uAC80\uC0AC \uB3C4\uAD6C \uC2E4\uD589 \uC2E4\uD328: ${msg}`,
|
|
2097
|
+
pluginSvelteTitle: "Svelte 5 & TypeScript (svelte-check)",
|
|
2098
|
+
pluginSvelteSuccess: "Svelte 5 Runes \uBC0F TS \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC (0 Errors, 0 Warnings)",
|
|
2099
|
+
pluginSvelteError: "Svelte \uD15C\uD50C\uB9BF \uB610\uB294 TypeScript \uD0C0\uC785 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2100
|
+
pluginSvelteExecFail: (msg) => `Svelte \uAC80\uC0AC \uB3C4\uAD6C \uC2E4\uD589 \uC2E4\uD328: ${msg}`,
|
|
2101
|
+
pluginJavaTitle: "Java \uC5D4\uD130\uD504\uB77C\uC774\uC988 \uCEF4\uD30C\uC77C\uB7EC (javac)",
|
|
2102
|
+
pluginJavaSuccess: (count) => `Java ${count}\uAC1C \uC18C\uC2A4 \uD30C\uC77C \uBC14\uC774\uD2B8\uCF54\uB4DC \uCEF4\uD30C\uC77C \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
2103
|
+
pluginJavaNoFiles: "\uAC80\uC99D\uD560 Java \uC18C\uC2A4 \uD30C\uC77C(.java)\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
2104
|
+
pluginJavaError: "javac \uCEF4\uD30C\uC77C \uC2E4\uD328",
|
|
2105
|
+
pluginCppTitle: "C/C++ \uB124\uC774\uD2F0\uBE0C \uCEE4\uB110 \uAC80\uC99D\uAE30 (g++/clang++)",
|
|
2106
|
+
pluginCppSuccess: (count) => `C/C++ ${count}\uAC1C \uC18C\uC2A4 \uD30C\uC77C \uAD6C\uBB38 \uBC0F \uD5E4\uB354 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
2107
|
+
pluginCppNoFiles: "\uAC80\uC99D\uD560 C/C++ \uC18C\uC2A4 \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
2108
|
+
pluginCppError: "C/C++ \uAD6C\uBB38 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2109
|
+
pluginCsharpTitle: "C# .NET \uC194\uB8E8\uC158 \uAC80\uC99D\uAE30 (dotnet build)",
|
|
2110
|
+
pluginCsharpSuccess: "C# .NET \uD504\uB85C\uC81D\uD2B8 \uBE4C\uB4DC \uBC0F \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC",
|
|
2111
|
+
pluginCsharpError: "C# .NET \uBE4C\uB4DC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2112
|
+
pluginGoTitle: "Go \uBC31\uC5D4\uB4DC \uD328\uD0A4\uC9C0 \uAC80\uC99D\uAE30 (go vet)",
|
|
2113
|
+
pluginGoSuccess: "Go \uB3D9\uC2DC\uC131 \uB8E8\uD2F4 \uBC0F \uD328\uD0A4\uC9C0 \uC815\uC801 \uBD84\uC11D \uD1B5\uACFC",
|
|
2114
|
+
pluginGoError: "Go \uC815\uC801 \uBD84\uC11D \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2115
|
+
pluginPythonTitle: "Python \uBC14\uC774\uD2B8\uCF54\uB4DC \uAC80\uC99D\uAE30 (py_compile)",
|
|
2116
|
+
pluginPythonSuccess: (count) => `Python ${count}\uAC1C \uBAA8\uB4C8 \uBC14\uC774\uD2B8\uCF54\uB4DC \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC`,
|
|
2117
|
+
pluginPythonNoFiles: "\uAC80\uC99D\uD560 Python \uC18C\uC2A4 \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
2118
|
+
pluginPythonError: "Python \uAD6C\uBB38 \uBD84\uC11D \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2119
|
+
pluginTypescriptTitlePure: "\uC21C\uC218 TypeScript \uACF5\uC2DD \uCEF4\uD30C\uC77C\uB7EC (tsc)",
|
|
2120
|
+
pluginTypescriptTitleNative: "TypeScript \uB124\uC774\uD2F0\uBE0C Rust Oxc (tsrs)",
|
|
2121
|
+
pluginTypescriptSuccess: (mode) => `TypeScript \uD0C0\uC785 \uBB34\uACB0\uC131 \uAC80\uC99D \uC644\uB8CC (${mode})`,
|
|
2122
|
+
pluginTypescriptError: "TypeScript \uD0C0\uC785 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2123
|
+
pluginSchemaTitle: "\uB370\uC774\uD130 \uBC0F \uC124\uC815 \uC2A4\uD0A4\uB9C8 \uBB34\uACB0\uC131 \uAC80\uC0AC",
|
|
2124
|
+
pluginSchemaSuccess: (count) => `${count}\uAC1C \uC2A4\uD0A4\uB9C8/\uB370\uC774\uD130 \uD30C\uC77C \uC815\uC0C1 \uD655\uC778 \uC644\uB8CC`,
|
|
2125
|
+
pluginSchemaParseFail: (path, err) => `${path} \uD30C\uC2F1 \uC2E4\uD328: ${err}`,
|
|
2126
|
+
pluginNativeTitle: "\uB124\uC774\uD2F0\uBE0C \uBC14\uC774\uB108\uB9AC & \uC5D0\uC14B \uAC80\uC0AC",
|
|
2127
|
+
pluginNativeSuccess: (count) => `${count}\uAC1C \uBC14\uC774\uB108\uB9AC \uBC0F \uB9AC\uC18C\uC2A4 \uBB34\uACB0\uC131 \uD655\uC778 \uC644\uB8CC`,
|
|
2128
|
+
pluginNativeMissing: (path) => `\uD544\uC218 \uBC14\uC774\uB108\uB9AC\uAC00 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${path}`,
|
|
2129
|
+
pluginNativeNotPe: (path) => `${path}: \uC62C\uBC14\uB978 PE \uD3EC\uB9F7(MZ \uC2DC\uADF8\uB2C8\uCC98 \uB204\uB77D)\uC774 \uC544\uB2D9\uB2C8\uB2E4.`,
|
|
2130
|
+
pluginNativeInvalidPe: (path) => `${path}: \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PE \uC2DC\uADF8\uB2C8\uCC98\uC785\uB2C8\uB2E4.`,
|
|
2131
|
+
pluginNativeInvalidArch: (path, code) => `${path}: 64\uBE44\uD2B8(x64) \uBC14\uC774\uB108\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4 (\uBA38\uC2E0 \uCF54\uB4DC: 0x${code}).`,
|
|
2132
|
+
pluginNsisTitle: "NSIS \uC778\uC2A4\uD1A8\uB7EC \uD15C\uD50C\uB9BF \uAD6C\uBB38 \uAC80\uC0AC",
|
|
2133
|
+
pluginNsisSuccess: (path) => `${path} \uAD6C\uBB38 \uBC0F \uD544\uC218 \uC9C0\uC2DC\uBB38 \uD655\uC778 \uC644\uB8CC`,
|
|
2134
|
+
pluginNsisMissing: (path) => `NSIS \uD15C\uD50C\uB9BF \uD30C\uC77C\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${path}`,
|
|
2135
|
+
pluginNsisCorrupt: "NSIS \uD15C\uD50C\uB9BF \uD30C\uC77C \uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uAC70\uB098 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
2136
|
+
pluginNsisDirectiveMissing: (dir) => `NSIS \uD544\uC218 \uC9C0\uC2DC\uBB38 \uB204\uB77D: '${dir}' \uAD6C\uBB38\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`
|
|
2137
|
+
},
|
|
2138
|
+
en: {
|
|
2139
|
+
cliTitle: "\uD83E\uDDE0 Synapse Kit - AI-Native Unified Compiler, Build & Packaging Framework",
|
|
2140
|
+
cliUsage: "Usage:",
|
|
2141
|
+
cliCommands: "Core Commands:",
|
|
2142
|
+
cmdCheck: "Run multi-track verification with AI causal smart skipping",
|
|
2143
|
+
cmdBuild: "Fast incremental multi-track build (0.00s skip on unchanged sources)",
|
|
2144
|
+
cmdPackage: "Single NSIS + zlib high-speed installer packager",
|
|
2145
|
+
cmdSign: "Causal cryptographic signing engine (Minisign / Ed25519)",
|
|
2146
|
+
cmdInit: "Generate optimized synapse.config.ts template in current directory",
|
|
2147
|
+
cmdMemory: "Query, manage and serve zero-cost Causal Memory & Local Daemon",
|
|
2148
|
+
cliOptions: "Options:",
|
|
2149
|
+
optAll: "Disable causal skipping and force full verification",
|
|
2150
|
+
optForce: "Ignore cache and force re-execution of build and signing",
|
|
2151
|
+
optAgent: "Structured JSON output for AI coding agents (Claude, Cursor, Antigravity)",
|
|
2152
|
+
optCompact: "Extreme token-diet mode for AI agents (only 11 tokens on pass)",
|
|
2153
|
+
optInteractive: "Pause on error and wait for live code modification (0.05s live-fix)",
|
|
2154
|
+
optWatch: "Background file-watcher mode",
|
|
2155
|
+
optLang: "Force display language (ko | en)",
|
|
2156
|
+
optHelp: "Display help information",
|
|
2157
|
+
optVersion: "Display version information",
|
|
2158
|
+
unknownCmd: "Unknown command:",
|
|
2159
|
+
errPrefix: "\uD83D\uDEA8 Error:",
|
|
2160
|
+
configExists: "Configuration file already exists:",
|
|
2161
|
+
configCreated: "synapse.config.ts template created successfully.",
|
|
2162
|
+
checkHeader: "\uD83E\uDDE0 [Synapse Kit] AI-Native Unified Compiler & Verification Framework",
|
|
2163
|
+
causalAll: "Full check requested (--all): Executing all registered checkers.",
|
|
2164
|
+
causalDirty: (count, plugins) => `${count} modified files detected: Running [${plugins}] plugins only.`,
|
|
2165
|
+
causalClean: "No source changes detected. All checkers skipped in 0.00s.",
|
|
2166
|
+
causalCleanCacheHit: "No file changes and matches last verified commit. Skipped in 0.00s.",
|
|
2167
|
+
causalBaseline: "No changes detected; performing baseline verification for initial state.",
|
|
2168
|
+
causalUnrelated: (count) => `${count} modified files do not affect registered plugins. Skipping all checkers.`,
|
|
2169
|
+
causalGitFail: "Cannot track Git changes; running full verification in safe mode.",
|
|
2170
|
+
checkPassed: "PASSED",
|
|
2171
|
+
checkSkipped: "SKIPPED (Causal 0.00s)",
|
|
2172
|
+
checkFailed: "FAILED",
|
|
2173
|
+
checkSuccessSummary: (errs, warns, skips, sec) => `\u2728 Verification Passed: ${errs} Errors, ${warns} Warnings, ${skips} Skipped (Total: ${sec}s)`,
|
|
2174
|
+
checkFailureSummary: (errs, warns, sec) => `\u274C Verification Failed: ${errs} check failures (Total: ${sec}s)`,
|
|
2175
|
+
interactivePause: "\u23F8\uFE0F Paused due to errors. Save modified files to hot-recheck in 0.05s. (Exit: Ctrl+C)",
|
|
2176
|
+
interactiveReload: "\u26A1 File changes detected! Launching in-memory hot-recheck...",
|
|
2177
|
+
interactiveTitle: "\u23F8\uFE0F [Interactive Causal Hotfix] Process paused due to verification errors.",
|
|
2178
|
+
interactiveTarget: "Target Plugins",
|
|
2179
|
+
interactiveWatching: "Watch Status : \uD83D\uDC40 Waiting for code changes... (hot-rechecks in 0.05s on save)",
|
|
2180
|
+
interactiveExit: "Exit Session : Press Ctrl+C in terminal",
|
|
2181
|
+
interactiveDetected: (time, file) => `\u26A1 [Save Detected ${time}] ${file} changed \u279C Running hot-recheck...`,
|
|
2182
|
+
interactivePassed: (sec) => `\u2728 [Hot-recheck Passed] (${sec}s) All issues resolved!`,
|
|
2183
|
+
interactiveResumed: "\u25B6\uFE0F [Pipeline Resumed] All verifications passed. Exiting cleanly.",
|
|
2184
|
+
interactiveFailed: "\u274C [Hot-recheck Failed] Errors remain. Please edit and save again.",
|
|
2185
|
+
buildHeader: "\u26A1 [Synapse Build] Causal Multi-Track Parallel Incremental Builder",
|
|
2186
|
+
buildSkipped: "\u23ED\uFE0F Unchanged source detected: 0.00s skipped",
|
|
2187
|
+
buildSuccess: "\u2705 Build completed",
|
|
2188
|
+
buildFailed: "\u274C Build failed",
|
|
2189
|
+
buildAllUpToDate: "\u2728 All build tracks are up-to-date. (Skipped all tracks: 0.00s)",
|
|
2190
|
+
buildComplete: (sec) => `\u2728 Causal incremental build completed (Total: ${sec}s)`,
|
|
2191
|
+
packageHeader: "\uD83D\uDCE6 [Synapse Package] High-Speed Installer Bundler",
|
|
2192
|
+
packageSuccess: (sec) => `\u2728 Installer package bundled successfully (Elapsed: ${sec}s)`,
|
|
2193
|
+
packageFailed: (sec) => `\u274C Installer packaging failed (Elapsed: ${sec}s)`,
|
|
2194
|
+
signHeader: "\uD83D\uDD10 [Synapse Sign] Causal Cryptographic Signing Pipeline",
|
|
2195
|
+
signSkipped: "\u23ED\uFE0F Binary SHA-256 unchanged: Signature skipped in 0.00s",
|
|
2196
|
+
signSuccess: (sec) => `\u2728 Ed25519 digital signature generated (Elapsed: ${sec}s)`,
|
|
2197
|
+
signFailed: (sec) => `\u274C Signature generation failed (Elapsed: ${sec}s)`,
|
|
2198
|
+
signNoConfig: "\u274C Signing configuration (sign.privateKeyPath) is missing in synapse.config.ts.",
|
|
2199
|
+
signNoKey: (p) => `\u274C Signing private key not found: ${p}`,
|
|
2200
|
+
signNoInstaller: "\u274C Target installer (.exe) not found for signing.",
|
|
2201
|
+
signTarget: "Target Installer",
|
|
2202
|
+
signStatus: "Signing Status",
|
|
2203
|
+
signFile: "Signature File",
|
|
2204
|
+
signReasonLabel: "Reason",
|
|
2205
|
+
signEngineLabel: "Signing Engine",
|
|
2206
|
+
signCacheHit: "SKIPPED [Causal Cache Hit: Binary hash identical]",
|
|
2207
|
+
signExistingKeep: (p) => `Keeping existing signature file (${p})`,
|
|
2208
|
+
signIntegrityPass: "\u2728 Signature integrity verified (0.00s)",
|
|
2209
|
+
statusSuccess: "PASSED",
|
|
2210
|
+
statusSkipped: "SKIPPED (Causal skip)",
|
|
2211
|
+
statusWarning: "WARNING",
|
|
2212
|
+
statusError: "FAILED",
|
|
2213
|
+
causalAnalysis: "Causal Analysis",
|
|
2214
|
+
trackSkipped: "SKIPPED [Causal Cache Hit]",
|
|
2215
|
+
trackComplete: "Build Passed",
|
|
2216
|
+
trackFailed: "Build Failed",
|
|
2217
|
+
noBuildTracks: "\u274C No buildTracks found in synapse.config.ts.",
|
|
2218
|
+
buildSuccessSummary: (tracks, sec) => `\u2728 Causal Parallel Build Passed: All ${tracks} tracks completed (Total: ${sec}s)`,
|
|
2219
|
+
buildFailureSummary: "\uD83D\uDEA8 Parallel Build Failed: Errors occurred in one or more tracks.",
|
|
2220
|
+
packagingPreBuild: "\u2139\uFE0F Verifying prerequisite artifact causal builds...",
|
|
2221
|
+
packagingStart: "\uD83D\uDE80 Starting Tauri installer bundling...",
|
|
2222
|
+
packagingGuide: `\u26A0\uFE0F [Packaging Notice] tauri.conf.json has targets set to "all".
|
|
2223
|
+
\u21B3 WiX MSI adds redundant delay. Recommended setting: targets: ["nsis"].`,
|
|
2224
|
+
pluginRustTitle: "Rust Backend Workspace (Check & Clippy)",
|
|
2225
|
+
pluginRustSuccess: "Rust workspace compilation & Clippy integrity verified (0 Warnings, 0 Errors)",
|
|
2226
|
+
pluginRustClippyWarn: (count) => `Compilation passed (${count} Clippy recommendations detected)`,
|
|
2227
|
+
pluginRustCompileFail: "Rust workspace compilation failed.",
|
|
2228
|
+
pluginRustExecFail: (msg) => `Failed to execute Rust checker tool: ${msg}`,
|
|
2229
|
+
pluginSvelteTitle: "Svelte 5 & TypeScript (svelte-check)",
|
|
2230
|
+
pluginSvelteSuccess: "Svelte 5 Runes & TS type integrity verified (0 Errors, 0 Warnings)",
|
|
2231
|
+
pluginSvelteError: "Errors detected in Svelte template or TypeScript types.",
|
|
2232
|
+
pluginSvelteExecFail: (msg) => `Failed to execute Svelte checker tool: ${msg}`,
|
|
2233
|
+
pluginJavaTitle: "Java Enterprise Compiler (javac)",
|
|
2234
|
+
pluginJavaSuccess: (count) => `Java bytecode compilation verified for ${count} source files`,
|
|
2235
|
+
pluginJavaNoFiles: "No Java source files (*.java) found to verify.",
|
|
2236
|
+
pluginJavaError: "javac compilation failed",
|
|
2237
|
+
pluginCppTitle: "C/C++ Native Kernel Checker (g++/clang++)",
|
|
2238
|
+
pluginCppSuccess: (count) => `C/C++ syntax & header integrity verified for ${count} files`,
|
|
2239
|
+
pluginCppNoFiles: "No C/C++ source files found to verify.",
|
|
2240
|
+
pluginCppError: "C/C++ compilation syntax errors detected.",
|
|
2241
|
+
pluginCsharpTitle: "C# .NET Solution Checker (dotnet build)",
|
|
2242
|
+
pluginCsharpSuccess: "C# .NET project build and type integrity verified",
|
|
2243
|
+
pluginCsharpError: "Errors detected during C# .NET build.",
|
|
2244
|
+
pluginGoTitle: "Go Backend Package Checker (go vet)",
|
|
2245
|
+
pluginGoSuccess: "Go concurrency routines and packages passed static analysis",
|
|
2246
|
+
pluginGoError: "Errors detected during Go static analysis.",
|
|
2247
|
+
pluginPythonTitle: "Python Bytecode Checker (py_compile)",
|
|
2248
|
+
pluginPythonSuccess: (count) => `Python bytecode integrity verified for ${count} modules`,
|
|
2249
|
+
pluginPythonNoFiles: "No Python source files found to verify.",
|
|
2250
|
+
pluginPythonError: "Syntax errors detected in Python source.",
|
|
2251
|
+
pluginTypescriptTitlePure: "Pure TypeScript Official Compiler (tsc)",
|
|
2252
|
+
pluginTypescriptTitleNative: "TypeScript Native Rust Oxc (tsrs)",
|
|
2253
|
+
pluginTypescriptSuccess: (mode) => `TypeScript type integrity verified (${mode})`,
|
|
2254
|
+
pluginTypescriptError: "TypeScript type errors detected.",
|
|
2255
|
+
pluginSchemaTitle: "Data & Config Schema Integrity Checker",
|
|
2256
|
+
pluginSchemaSuccess: (count) => `Verified ${count} schema/data files successfully`,
|
|
2257
|
+
pluginSchemaParseFail: (path, err) => `${path} parse failure: ${err}`,
|
|
2258
|
+
pluginNativeTitle: "Native Binary & Asset Checker",
|
|
2259
|
+
pluginNativeSuccess: (count) => `Verified ${count} binaries & resources successfully`,
|
|
2260
|
+
pluginNativeMissing: (path) => `Required binary is missing: ${path}`,
|
|
2261
|
+
pluginNativeNotPe: (path) => `${path}: Not a valid PE format (MZ signature missing).`,
|
|
2262
|
+
pluginNativeInvalidPe: (path) => `${path}: Invalid PE signature.`,
|
|
2263
|
+
pluginNativeInvalidArch: (path, code) => `${path}: Not a 64-bit (x64) binary (Machine code: 0x${code}).`,
|
|
2264
|
+
pluginNsisTitle: "NSIS Installer Template Checker",
|
|
2265
|
+
pluginNsisSuccess: (path) => `${path} syntax & required directives verified`,
|
|
2266
|
+
pluginNsisMissing: (path) => `NSIS template file is missing: ${path}`,
|
|
2267
|
+
pluginNsisCorrupt: "NSIS template content is empty or corrupted.",
|
|
2268
|
+
pluginNsisDirectiveMissing: (dir) => `Required NSIS directive missing: '${dir}'.`
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
function detectLocale(explicitLang) {
|
|
2272
|
+
if (explicitLang === "ko" || explicitLang === "en") {
|
|
2273
|
+
currentLocale = explicitLang;
|
|
2274
|
+
return currentLocale;
|
|
2275
|
+
}
|
|
2276
|
+
const envLang = process.env.SYNAPSE_LANG || process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || "";
|
|
2277
|
+
if (envLang.toLowerCase().includes("ko")) {
|
|
2278
|
+
currentLocale = "ko";
|
|
2279
|
+
return "ko";
|
|
2280
|
+
}
|
|
2281
|
+
try {
|
|
2282
|
+
const sysLocale = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
|
|
2283
|
+
if (sysLocale.startsWith("ko")) {
|
|
2284
|
+
currentLocale = "ko";
|
|
2285
|
+
return "ko";
|
|
2286
|
+
}
|
|
2287
|
+
} catch {}
|
|
2288
|
+
currentLocale = "en";
|
|
2289
|
+
return "en";
|
|
2290
|
+
}
|
|
2291
|
+
function t(key, ...args) {
|
|
2292
|
+
const dict = MESSAGES[currentLocale] || MESSAGES.en;
|
|
2293
|
+
const val = dict[key] ?? MESSAGES.en[key] ?? key;
|
|
2294
|
+
if (typeof val === "function") {
|
|
2295
|
+
return val(...args);
|
|
2296
|
+
}
|
|
2297
|
+
return val;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
// src/memory/causal-graph.ts
|
|
2301
|
+
async function analyzeCausalGraph(rootDir, plugins, options) {
|
|
2302
|
+
const allPluginNames = new Set(plugins.map((p) => p.name));
|
|
2303
|
+
if (options.mode === "all") {
|
|
2304
|
+
return {
|
|
2305
|
+
runAll: true,
|
|
2306
|
+
activePluginNames: allPluginNames,
|
|
2307
|
+
reason: t("causalAll"),
|
|
2308
|
+
modifiedFiles: []
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2311
|
+
try {
|
|
2312
|
+
const { head, modifiedFiles } = await getGitState(rootDir);
|
|
2313
|
+
if (modifiedFiles.length === 0) {
|
|
2314
|
+
const cache = loadBuildCache(rootDir);
|
|
2315
|
+
if (cache.lastVerifiedHead && cache.lastVerifiedHead === head && head !== "unknown") {
|
|
2316
|
+
return {
|
|
2317
|
+
runAll: false,
|
|
2318
|
+
activePluginNames: new Set,
|
|
2319
|
+
reason: t("causalCleanCacheHit"),
|
|
2320
|
+
modifiedFiles: []
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
return {
|
|
2324
|
+
runAll: true,
|
|
2325
|
+
activePluginNames: allPluginNames,
|
|
2326
|
+
reason: t("causalBaseline"),
|
|
2327
|
+
modifiedFiles: []
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
const activePluginNames = new Set;
|
|
2331
|
+
for (const plugin of plugins) {
|
|
2332
|
+
const isTriggered = plugin.triggers.some((pattern) => {
|
|
2333
|
+
const cleanPattern = pattern.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
2334
|
+
const isExtension = cleanPattern.startsWith(".");
|
|
2335
|
+
return modifiedFiles.some((file) => {
|
|
2336
|
+
if (isExtension) {
|
|
2337
|
+
return file.endsWith(cleanPattern);
|
|
2338
|
+
}
|
|
2339
|
+
return file.includes(cleanPattern);
|
|
2340
|
+
});
|
|
2341
|
+
});
|
|
2342
|
+
if (isTriggered) {
|
|
2343
|
+
activePluginNames.add(plugin.name);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
if (activePluginNames.size === 0) {
|
|
2347
|
+
return {
|
|
2348
|
+
runAll: false,
|
|
2349
|
+
activePluginNames: new Set,
|
|
2350
|
+
reason: t("causalUnrelated", modifiedFiles.length),
|
|
2351
|
+
modifiedFiles
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
return {
|
|
2355
|
+
runAll: false,
|
|
2356
|
+
activePluginNames,
|
|
2357
|
+
reason: t("causalDirty", modifiedFiles.length, Array.from(activePluginNames).join(", ")),
|
|
2358
|
+
modifiedFiles
|
|
2359
|
+
};
|
|
2360
|
+
} catch {
|
|
2361
|
+
return {
|
|
2362
|
+
runAll: true,
|
|
2363
|
+
activePluginNames: allPluginNames,
|
|
2364
|
+
reason: t("causalGitFail"),
|
|
2365
|
+
modifiedFiles: []
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/core/reporter.ts
|
|
2371
|
+
var RESET = "\x1B[0m";
|
|
2372
|
+
var BOLD = "\x1B[1m";
|
|
2373
|
+
var GREEN = "\x1B[32m";
|
|
2374
|
+
var RED = "\x1B[31m";
|
|
2375
|
+
var YELLOW = "\x1B[33m";
|
|
2376
|
+
var CYAN = "\x1B[36m";
|
|
2377
|
+
var GRAY = "\x1B[90m";
|
|
2378
|
+
function reportResults(decision, results, totalDurationMs, options) {
|
|
2379
|
+
const totalSeconds = (totalDurationMs / 1000).toFixed(2);
|
|
2380
|
+
const errorResults = results.filter((r) => r.status === "error");
|
|
2381
|
+
const warningResults = results.filter((r) => r.status === "warning");
|
|
2382
|
+
const skippedResults = results.filter((r) => r.status === "skipped");
|
|
2383
|
+
const successResults = results.filter((r) => r.status === "success");
|
|
2384
|
+
if (options.agentMode || options.compactMode) {
|
|
2385
|
+
const isCleanPass = errorResults.length === 0 && warningResults.length === 0;
|
|
2386
|
+
if (isCleanPass && options.compactMode) {
|
|
2387
|
+
const minimalPayload = {
|
|
2388
|
+
ok: true,
|
|
2389
|
+
duration: `${totalSeconds}s`,
|
|
2390
|
+
skipped: skippedResults.map((r) => r.name)
|
|
2391
|
+
};
|
|
2392
|
+
process.stdout.write(`${JSON.stringify(minimalPayload)}
|
|
2393
|
+
`);
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
const payload = {
|
|
2397
|
+
ok: errorResults.length === 0,
|
|
2398
|
+
duration: `${totalSeconds}s`,
|
|
2399
|
+
summary: {
|
|
2400
|
+
pass: successResults.length,
|
|
2401
|
+
warn: warningResults.length,
|
|
2402
|
+
err: errorResults.length,
|
|
2403
|
+
skip: skippedResults.length
|
|
2404
|
+
}
|
|
2405
|
+
};
|
|
2406
|
+
if (errorResults.length > 0) {
|
|
2407
|
+
payload.errors = errorResults.map((r) => ({
|
|
2408
|
+
plugin: r.name,
|
|
2409
|
+
details: r.details,
|
|
2410
|
+
diagnostics: r.diagnostics
|
|
2411
|
+
}));
|
|
2412
|
+
}
|
|
2413
|
+
if (warningResults.length > 0) {
|
|
2414
|
+
payload.warnings = warningResults.map((r) => ({
|
|
2415
|
+
plugin: r.name,
|
|
2416
|
+
details: r.details,
|
|
2417
|
+
diagnostics: r.diagnostics
|
|
2418
|
+
}));
|
|
2419
|
+
}
|
|
2420
|
+
if (skippedResults.length > 0) {
|
|
2421
|
+
payload.skipped = skippedResults.map((r) => r.name);
|
|
2422
|
+
}
|
|
2423
|
+
const outputString = options.compactMode ? JSON.stringify(payload) : JSON.stringify(payload, null, 2);
|
|
2424
|
+
process.stdout.write(`${outputString}
|
|
2425
|
+
`);
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
const line = "\u2501".repeat(68);
|
|
2429
|
+
process.stdout.write(`
|
|
2430
|
+
${BOLD}${CYAN}${t("checkHeader")}${RESET}
|
|
2431
|
+
`);
|
|
2432
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
2433
|
+
`);
|
|
2434
|
+
process.stdout.write(`${GRAY}\uD83D\uDCA1 ${t("causalAnalysis")}: ${decision.reason}${RESET}
|
|
2435
|
+
`);
|
|
2436
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
2437
|
+
`);
|
|
2438
|
+
for (const result of results) {
|
|
2439
|
+
const duration = (result.durationMs / 1000).toFixed(2);
|
|
2440
|
+
let statusBadge = "";
|
|
2441
|
+
switch (result.status) {
|
|
2442
|
+
case "success":
|
|
2443
|
+
statusBadge = `${GREEN}\u2705 ${t("statusSuccess")} (${duration}s)${RESET}`;
|
|
2444
|
+
break;
|
|
2445
|
+
case "skipped":
|
|
2446
|
+
statusBadge = `${GRAY}\u23ED\uFE0F ${t("statusSkipped")}${RESET}`;
|
|
2447
|
+
break;
|
|
2448
|
+
case "warning":
|
|
2449
|
+
statusBadge = `${YELLOW}\u26A0\uFE0F ${t("statusWarning")} (${duration}s)${RESET}`;
|
|
2450
|
+
break;
|
|
2451
|
+
case "error":
|
|
2452
|
+
statusBadge = `${RED}\u274C ${t("statusError")} (${duration}s)${RESET}`;
|
|
2453
|
+
break;
|
|
2454
|
+
}
|
|
2455
|
+
const titlePadded = result.title.padEnd(36, " ");
|
|
2456
|
+
process.stdout.write(` \u2022 ${BOLD}${titlePadded}${RESET} : ${statusBadge}
|
|
2457
|
+
`);
|
|
2458
|
+
if (result.status !== "skipped" && result.details) {
|
|
2459
|
+
process.stdout.write(` ${GRAY}\u2514\u2500 ${result.details}${RESET}
|
|
2460
|
+
`);
|
|
2461
|
+
}
|
|
2462
|
+
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
2463
|
+
for (const diag of result.diagnostics) {
|
|
2464
|
+
process.stdout.write(` ${RED}\u25B6 ${diag.message}${RESET}
|
|
2465
|
+
`);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
process.stdout.write(`${GRAY}${line}${RESET}
|
|
2470
|
+
`);
|
|
2471
|
+
if (errorResults.length === 0) {
|
|
2472
|
+
process.stdout.write(`${BOLD}${GREEN}${t("checkSuccessSummary", 0, warningResults.length, skippedResults.length, totalSeconds)}${RESET}
|
|
2473
|
+
|
|
2474
|
+
`);
|
|
2475
|
+
} else {
|
|
2476
|
+
process.stdout.write(`${BOLD}${RED}${t("checkFailureSummary", errorResults.length, warningResults.length, totalSeconds)}${RESET}
|
|
2477
|
+
|
|
2478
|
+
`);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// src/core/engine.ts
|
|
2483
|
+
var RESET2 = "\x1B[0m";
|
|
2484
|
+
var BOLD2 = "\x1B[1m";
|
|
2485
|
+
var GREEN2 = "\x1B[32m";
|
|
2486
|
+
var RED2 = "\x1B[31m";
|
|
2487
|
+
var YELLOW2 = "\x1B[33m";
|
|
2488
|
+
var CYAN2 = "\x1B[36m";
|
|
2489
|
+
var GRAY2 = "\x1B[90m";
|
|
2490
|
+
async function runPluginChecker(plugin, isActive, rootDir, options) {
|
|
2491
|
+
if (!isActive) {
|
|
2492
|
+
return {
|
|
2493
|
+
name: plugin.name,
|
|
2494
|
+
title: plugin.title,
|
|
2495
|
+
status: "skipped",
|
|
2496
|
+
durationMs: 0,
|
|
2497
|
+
details: t("checkSkipped")
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
try {
|
|
2501
|
+
return await plugin.check({ rootDir, options });
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
return {
|
|
2504
|
+
name: plugin.name,
|
|
2505
|
+
title: plugin.title,
|
|
2506
|
+
status: "error",
|
|
2507
|
+
durationMs: 0,
|
|
2508
|
+
details: `Critical plugin execution failure: ${error instanceof Error ? error.message : String(error)}`
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
async function executeChecks(config, options) {
|
|
2513
|
+
const rootDir = config.rootDir || process.cwd();
|
|
2514
|
+
const startTime = performance.now();
|
|
2515
|
+
const decision = await analyzeCausalGraph(rootDir, config.plugins, options);
|
|
2516
|
+
const results = await Promise.all(config.plugins.map((plugin) => runPluginChecker(plugin, decision.activePluginNames.has(plugin.name), rootDir, options)));
|
|
2517
|
+
const totalDurationMs = performance.now() - startTime;
|
|
2518
|
+
reportResults(decision, results, totalDurationMs, options);
|
|
2519
|
+
const hasError = results.some((r) => r.status === "error");
|
|
2520
|
+
if (!hasError) {
|
|
2521
|
+
const cache = loadBuildCache(rootDir);
|
|
2522
|
+
const { head } = await getGitState(rootDir);
|
|
2523
|
+
if (head && head !== "unknown") {
|
|
2524
|
+
cache.lastVerifiedHead = head;
|
|
2525
|
+
saveBuildCache(rootDir, cache);
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
if (hasError && options.interactive) {
|
|
2529
|
+
const failedNames = new Set(results.filter((r) => r.status === "error").map((r) => r.name));
|
|
2530
|
+
const failedPlugins = config.plugins.filter((p) => failedNames.has(p.name));
|
|
2531
|
+
return await runInteractiveLoop(failedPlugins, rootDir, options);
|
|
2532
|
+
}
|
|
2533
|
+
return hasError ? 1 : 0;
|
|
2534
|
+
}
|
|
2535
|
+
async function runInteractiveLoop(failedPlugins, rootDir, options) {
|
|
2536
|
+
const line = "\u2501".repeat(68);
|
|
2537
|
+
process.stdout.write(`
|
|
2538
|
+
${BOLD2}${CYAN2}${t("interactiveTitle")}${RESET2}
|
|
2539
|
+
`);
|
|
2540
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2541
|
+
`);
|
|
2542
|
+
process.stdout.write(` \u2022 ${t("interactiveTarget")} : ${BOLD2}${failedPlugins.map((p) => p.name).join(", ")}${RESET2}
|
|
2543
|
+
`);
|
|
2544
|
+
process.stdout.write(` \u2022 ${t("interactiveWatching")}
|
|
2545
|
+
`);
|
|
2546
|
+
process.stdout.write(` \u2022 ${t("interactiveExit")}
|
|
2547
|
+
`);
|
|
2548
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2549
|
+
|
|
2550
|
+
`);
|
|
2551
|
+
return new Promise((resolve) => {
|
|
2552
|
+
let isChecking = false;
|
|
2553
|
+
let debounceTimer = null;
|
|
2554
|
+
const watcher = watch(rootDir, { recursive: true }, async (_eventType, filename) => {
|
|
2555
|
+
if (!filename)
|
|
2556
|
+
return;
|
|
2557
|
+
const normalized = filename.replace(/\\/g, "/");
|
|
2558
|
+
if (normalized.includes("target/") || normalized.includes("node_modules/") || normalized.includes(".git/") || normalized.includes(".svelte-kit/") || normalized.includes("dist/") || normalized.includes(".synapse/")) {
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2561
|
+
if (debounceTimer)
|
|
2562
|
+
clearTimeout(debounceTimer);
|
|
2563
|
+
debounceTimer = setTimeout(async () => {
|
|
2564
|
+
if (isChecking)
|
|
2565
|
+
return;
|
|
2566
|
+
isChecking = true;
|
|
2567
|
+
const timeStr = new Date().toLocaleTimeString("ko-KR", { hour12: false });
|
|
2568
|
+
process.stdout.write(`
|
|
2569
|
+
${CYAN2}${t("interactiveDetected", timeStr, normalized)}${RESET2}
|
|
2570
|
+
`);
|
|
2571
|
+
const retryStart = performance.now();
|
|
2572
|
+
const retryResults = await Promise.all(failedPlugins.map((p) => p.check({ rootDir, options })));
|
|
2573
|
+
const retryDuration = ((performance.now() - retryStart) / 1000).toFixed(2);
|
|
2574
|
+
const stillFailed = retryResults.some((r) => r.status === "error");
|
|
2575
|
+
if (!stillFailed) {
|
|
2576
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("interactivePassed", retryDuration)}${RESET2}
|
|
2577
|
+
`);
|
|
2578
|
+
process.stdout.write(`${BOLD2}${CYAN2}${t("interactiveResumed")}${RESET2}
|
|
2579
|
+
|
|
2580
|
+
`);
|
|
2581
|
+
watcher.close();
|
|
2582
|
+
const cache = loadBuildCache(rootDir);
|
|
2583
|
+
const { head } = await getGitState(rootDir);
|
|
2584
|
+
if (head && head !== "unknown") {
|
|
2585
|
+
cache.lastVerifiedHead = head;
|
|
2586
|
+
saveBuildCache(rootDir, cache);
|
|
2587
|
+
}
|
|
2588
|
+
resolve(0);
|
|
2589
|
+
} else {
|
|
2590
|
+
process.stdout.write(`${BOLD2}${RED2}${t("interactiveFailed")}${RESET2}
|
|
2591
|
+
`);
|
|
2592
|
+
for (const res of retryResults) {
|
|
2593
|
+
if (res.status === "error" && res.details) {
|
|
2594
|
+
process.stdout.write(` \u2514\u2500 ${GRAY2}${res.details}${RESET2}
|
|
2595
|
+
`);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
isChecking = false;
|
|
2599
|
+
}
|
|
2600
|
+
}, 60);
|
|
2601
|
+
});
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
async function executeBuild(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
2605
|
+
const rootDir = config.rootDir || process.cwd();
|
|
2606
|
+
const tracks = config.buildTracks || [];
|
|
2607
|
+
if (tracks.length === 0) {
|
|
2608
|
+
process.stderr.write(`${RED2}${t("noBuildTracks")}${RESET2}
|
|
2609
|
+
`);
|
|
2610
|
+
return 1;
|
|
2611
|
+
}
|
|
2612
|
+
const startTime = performance.now();
|
|
2613
|
+
const line = "\u2501".repeat(68);
|
|
2614
|
+
process.stdout.write(`
|
|
2615
|
+
${BOLD2}${CYAN2}${t("buildHeader")} (${tracks.length})${RESET2}
|
|
2616
|
+
`);
|
|
2617
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2618
|
+
`);
|
|
2619
|
+
const cache = loadBuildCache(rootDir);
|
|
2620
|
+
const { head: currentHead, modifiedFiles, repoRoot } = await getGitState(rootDir);
|
|
2621
|
+
const isForce = options.force || options.mode === "all";
|
|
2622
|
+
const taskPromises = tracks.map(async (track) => {
|
|
2623
|
+
const { skip, reason } = shouldSkipBuildTrack(track, rootDir, repoRoot, cache, modifiedFiles, isForce);
|
|
2624
|
+
if (skip) {
|
|
2625
|
+
return {
|
|
2626
|
+
name: track.name,
|
|
2627
|
+
durationMs: 0,
|
|
2628
|
+
exitCode: 0,
|
|
2629
|
+
skipped: true,
|
|
2630
|
+
reason
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
const trackStart = performance.now();
|
|
2634
|
+
const proc = spawn2([...track.command], {
|
|
2635
|
+
cwd: track.cwd || rootDir,
|
|
2636
|
+
stdout: "inherit",
|
|
2637
|
+
stderr: "inherit"
|
|
2638
|
+
});
|
|
2639
|
+
const exitCode = await proc.exited;
|
|
2640
|
+
const durationMs = performance.now() - trackStart;
|
|
2641
|
+
return {
|
|
2642
|
+
name: track.name,
|
|
2643
|
+
durationMs,
|
|
2644
|
+
exitCode,
|
|
2645
|
+
skipped: false,
|
|
2646
|
+
reason
|
|
2647
|
+
};
|
|
2648
|
+
});
|
|
2649
|
+
const taskResults = await Promise.all(taskPromises);
|
|
2650
|
+
const totalDuration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
2651
|
+
const hasFailed = taskResults.some((t) => t.exitCode !== 0);
|
|
2652
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2653
|
+
`);
|
|
2654
|
+
for (const res of taskResults) {
|
|
2655
|
+
if (res.skipped) {
|
|
2656
|
+
process.stdout.write(` \u2022 ${BOLD2}${res.name.padEnd(38, " ")}${RESET2} : ${YELLOW2}\u26A1 ${t("trackSkipped")}${RESET2} ${GRAY2}(0.00s)${RESET2}
|
|
2657
|
+
`);
|
|
2658
|
+
} else {
|
|
2659
|
+
const sec = (res.durationMs / 1000).toFixed(2);
|
|
2660
|
+
const badge = res.exitCode === 0 ? `${GREEN2}\u2705 ${t("trackComplete")} (${sec}s)${RESET2}` : `${RED2}\u274C ${t("trackFailed")} (${sec}s)${RESET2}`;
|
|
2661
|
+
process.stdout.write(` \u2022 ${BOLD2}${res.name.padEnd(38, " ")}${RESET2} : ${badge}
|
|
2662
|
+
`);
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2666
|
+
`);
|
|
2667
|
+
if (!hasFailed) {
|
|
2668
|
+
const now = new Date().toISOString();
|
|
2669
|
+
for (const res of taskResults) {
|
|
2670
|
+
if (!res.skipped && res.exitCode === 0) {
|
|
2671
|
+
cache.tracks[res.name] = {
|
|
2672
|
+
lastBuildTime: now,
|
|
2673
|
+
gitCommit: currentHead,
|
|
2674
|
+
artifactExists: true
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
saveBuildCache(rootDir, cache);
|
|
2679
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("buildSuccessSummary", tracks.length, totalDuration)}${RESET2}
|
|
2680
|
+
|
|
2681
|
+
`);
|
|
2682
|
+
return 0;
|
|
2683
|
+
} else {
|
|
2684
|
+
process.stdout.write(`${BOLD2}${RED2}${t("buildFailureSummary")}${RESET2}
|
|
2685
|
+
|
|
2686
|
+
`);
|
|
2687
|
+
return 1;
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
async function executePackage(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
2691
|
+
const rootDir = config.rootDir || process.cwd();
|
|
2692
|
+
const startTime = performance.now();
|
|
2693
|
+
const line = "\u2501".repeat(68);
|
|
2694
|
+
process.stdout.write(`
|
|
2695
|
+
${BOLD2}${CYAN2}${t("packageHeader")}${RESET2}
|
|
2696
|
+
`);
|
|
2697
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2698
|
+
`);
|
|
2699
|
+
if (config.buildTracks && config.buildTracks.length > 0) {
|
|
2700
|
+
process.stdout.write(`${CYAN2}${t("packagingPreBuild")}${RESET2}
|
|
2701
|
+
`);
|
|
2702
|
+
const buildExit = await executeBuild(config, options);
|
|
2703
|
+
if (buildExit !== 0)
|
|
2704
|
+
return buildExit;
|
|
2705
|
+
}
|
|
2706
|
+
const tauriConfCandidates = [
|
|
2707
|
+
resolve3(rootDir, "src-tauri/tauri.conf.json"),
|
|
2708
|
+
resolve3(rootDir, "tauri.conf.json")
|
|
2709
|
+
];
|
|
2710
|
+
const tauriConfPath = tauriConfCandidates.find((p) => existsSync3(p));
|
|
2711
|
+
if (tauriConfPath) {
|
|
2712
|
+
try {
|
|
2713
|
+
const content = await Bun.file(tauriConfPath).json();
|
|
2714
|
+
const targets = content?.bundle?.targets;
|
|
2715
|
+
if (targets === "all") {
|
|
2716
|
+
process.stdout.write(`${YELLOW2}${t("packagingGuide")}${RESET2}
|
|
2717
|
+
`);
|
|
2718
|
+
}
|
|
2719
|
+
} catch {}
|
|
2720
|
+
}
|
|
2721
|
+
process.stdout.write(`${BOLD2}${t("packagingStart")}${RESET2}
|
|
2722
|
+
`);
|
|
2723
|
+
const pkgProc = spawn2(["bun", "x", "tauri", "build", "--bundles", "nsis"], {
|
|
2724
|
+
cwd: rootDir,
|
|
2725
|
+
stdout: "inherit",
|
|
2726
|
+
stderr: "inherit"
|
|
2727
|
+
});
|
|
2728
|
+
const exitCode = await pkgProc.exited;
|
|
2729
|
+
const duration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
2730
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2731
|
+
`);
|
|
2732
|
+
if (exitCode === 0) {
|
|
2733
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("packageSuccess", duration)}${RESET2}
|
|
2734
|
+
|
|
2735
|
+
`);
|
|
2736
|
+
return 0;
|
|
2737
|
+
} else {
|
|
2738
|
+
process.stdout.write(`${BOLD2}${RED2}${t("packageFailed", duration)}${RESET2}
|
|
2739
|
+
|
|
2740
|
+
`);
|
|
2741
|
+
return exitCode;
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
async function executeSign(config, options = { mode: "smart", agentMode: false, compactMode: false, watch: false }) {
|
|
2745
|
+
const rootDir = config.rootDir || process.cwd();
|
|
2746
|
+
const startTime = performance.now();
|
|
2747
|
+
const line = "\u2501".repeat(68);
|
|
2748
|
+
process.stdout.write(`
|
|
2749
|
+
${BOLD2}${CYAN2}${t("signHeader")}${RESET2}
|
|
2750
|
+
`);
|
|
2751
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2752
|
+
`);
|
|
2753
|
+
const signConfig = config.sign;
|
|
2754
|
+
if (!signConfig || !signConfig.privateKeyPath) {
|
|
2755
|
+
process.stderr.write(`${RED2}${t("signNoConfig")}${RESET2}
|
|
2756
|
+
`);
|
|
2757
|
+
return 1;
|
|
2758
|
+
}
|
|
2759
|
+
const keyPath = resolve3(rootDir, signConfig.privateKeyPath);
|
|
2760
|
+
if (!existsSync3(keyPath)) {
|
|
2761
|
+
process.stderr.write(`${RED2}${t("signNoKey", keyPath)}${RESET2}
|
|
2762
|
+
`);
|
|
2763
|
+
return 1;
|
|
2764
|
+
}
|
|
2765
|
+
let installerPath = signConfig.targetInstaller ? resolve3(rootDir, signConfig.targetInstaller) : "";
|
|
2766
|
+
if (!installerPath || !existsSync3(installerPath)) {
|
|
2767
|
+
const candidates = [
|
|
2768
|
+
resolve3(rootDir, "target/release/bundle/nsis"),
|
|
2769
|
+
resolve3(rootDir, "src-tauri/target/release/bundle/nsis"),
|
|
2770
|
+
resolve3(rootDir, "../target/release/bundle/nsis")
|
|
2771
|
+
];
|
|
2772
|
+
for (const dir of candidates) {
|
|
2773
|
+
if (existsSync3(dir)) {
|
|
2774
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".exe") && !f.endsWith(".sig"));
|
|
2775
|
+
if (files.length > 0) {
|
|
2776
|
+
installerPath = resolve3(dir, files[0]);
|
|
2777
|
+
break;
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
if (!installerPath || !existsSync3(installerPath)) {
|
|
2783
|
+
process.stderr.write(`${RED2}${t("signNoInstaller")}${RESET2}
|
|
2784
|
+
`);
|
|
2785
|
+
return 1;
|
|
2786
|
+
}
|
|
2787
|
+
const signaturePath = `${installerPath}.sig`;
|
|
2788
|
+
const cache = loadBuildCache(rootDir);
|
|
2789
|
+
const isForce = options.force || options.mode === "all";
|
|
2790
|
+
const { skip, reason, currentHash } = shouldSkipSign(installerPath, signaturePath, cache, isForce);
|
|
2791
|
+
if (skip) {
|
|
2792
|
+
process.stdout.write(` \u2022 ${t("signTarget")} : ${BOLD2}${installerPath}${RESET2}
|
|
2793
|
+
` + ` \u2022 ${t("signStatus")} : ${YELLOW2}\u26A1 ${t("signCacheHit")}${RESET2} ${GRAY2}(0.00s)${RESET2}
|
|
2794
|
+
` + ` \u2022 ${t("signFile")} : ${GREEN2}\u2705 ${t("signExistingKeep", signaturePath)}${RESET2}
|
|
2795
|
+
`);
|
|
2796
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2797
|
+
`);
|
|
2798
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("signIntegrityPass")}${RESET2}
|
|
2799
|
+
|
|
2800
|
+
`);
|
|
2801
|
+
return 0;
|
|
2802
|
+
}
|
|
2803
|
+
process.stdout.write(` \u2022 ${t("signTarget")} : ${BOLD2}${installerPath}${RESET2}
|
|
2804
|
+
`);
|
|
2805
|
+
process.stdout.write(` \u2022 ${t("signReasonLabel")} : ${CYAN2}${reason}${RESET2}
|
|
2806
|
+
`);
|
|
2807
|
+
process.stdout.write(` \u2022 ${t("signEngineLabel")} : ${BOLD2}Bun Native Tauri Signer (Ed25519)${RESET2}
|
|
2808
|
+
`);
|
|
2809
|
+
const passwordEnvName = signConfig.passwordEnv || "TAURI_KEY_PASSWORD";
|
|
2810
|
+
const passwordVal = process.env[passwordEnvName] || process.env.TAURI_PRIVATE_KEY_PASSWORD || process.env.TAURI_KEY_PASSWORD || "";
|
|
2811
|
+
const signArgs = [
|
|
2812
|
+
"bun",
|
|
2813
|
+
"x",
|
|
2814
|
+
"tauri",
|
|
2815
|
+
"signer",
|
|
2816
|
+
"sign",
|
|
2817
|
+
"--private-key-path",
|
|
2818
|
+
keyPath
|
|
2819
|
+
];
|
|
2820
|
+
if (passwordVal) {
|
|
2821
|
+
signArgs.push("--password", passwordVal);
|
|
2822
|
+
}
|
|
2823
|
+
signArgs.push(installerPath);
|
|
2824
|
+
const proc = spawn2(signArgs, {
|
|
2825
|
+
cwd: rootDir,
|
|
2826
|
+
env: {
|
|
2827
|
+
...process.env,
|
|
2828
|
+
TAURI_PRIVATE_KEY_PASSWORD: passwordVal,
|
|
2829
|
+
TAURI_KEY_PASSWORD: passwordVal
|
|
2830
|
+
},
|
|
2831
|
+
stdout: "inherit",
|
|
2832
|
+
stderr: "inherit"
|
|
2833
|
+
});
|
|
2834
|
+
const exitCode = await proc.exited;
|
|
2835
|
+
const duration = ((performance.now() - startTime) / 1000).toFixed(2);
|
|
2836
|
+
process.stdout.write(`${GRAY2}${line}${RESET2}
|
|
2837
|
+
`);
|
|
2838
|
+
if (exitCode === 0) {
|
|
2839
|
+
cache.sign = {
|
|
2840
|
+
lastSignTime: new Date().toISOString(),
|
|
2841
|
+
installerHash: currentHash || computeFileHash(installerPath),
|
|
2842
|
+
signaturePath
|
|
2843
|
+
};
|
|
2844
|
+
saveBuildCache(rootDir, cache);
|
|
2845
|
+
process.stdout.write(`${BOLD2}${GREEN2}${t("signSuccess", duration)}${RESET2}
|
|
2846
|
+
` + ` \u2022 ${t("signFile")}: ${BOLD2}${signaturePath}${RESET2}
|
|
2847
|
+
|
|
2848
|
+
`);
|
|
2849
|
+
return 0;
|
|
2850
|
+
} else {
|
|
2851
|
+
process.stdout.write(`${BOLD2}${RED2}${t("signFailed", duration)}${RESET2}
|
|
2852
|
+
|
|
2853
|
+
`);
|
|
2854
|
+
return exitCode;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
// src/cli-memory.ts
|
|
2859
|
+
init_causal_config();
|
|
2860
|
+
init_causal_store();
|
|
2861
|
+
init_causal_query();
|
|
2862
|
+
init_causal_server();
|
|
2863
|
+
|
|
2864
|
+
// src/memory/causal-migrator.ts
|
|
2865
|
+
init_causal_config();
|
|
2866
|
+
init_causal_store();
|
|
2867
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
2868
|
+
import { dirname as dirname2 } from "path";
|
|
2869
|
+
function migrateLegacyMemoryGraph(sourceBackupPath = CAUSAL_MEMORY_CONFIG.LEGACY_BACKUP_PATH, targetGlobalPath = CAUSAL_MEMORY_CONFIG.GLOBAL_DB_PATH, targetLocalPath = CAUSAL_MEMORY_CONFIG.LOCAL_DB_PATH) {
|
|
2870
|
+
if (!existsSync5(sourceBackupPath)) {
|
|
2871
|
+
throw new Error(`\uAD6C\uD615 \uBA54\uBAA8\uB9AC \uBC31\uC5C5 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${sourceBackupPath}`);
|
|
2872
|
+
}
|
|
2873
|
+
const raw = readFileSync3(sourceBackupPath, "utf-8");
|
|
2874
|
+
const legacy = JSON.parse(raw);
|
|
2875
|
+
const entities = legacy.entities || [];
|
|
2876
|
+
const legacyRelations = legacy.relations || [];
|
|
2877
|
+
const today = new Date().toISOString().split("T")[0];
|
|
2878
|
+
const seenIds = new Map;
|
|
2879
|
+
const rules = [];
|
|
2880
|
+
for (const ent of entities) {
|
|
2881
|
+
const inferred = CausalMemoryStore.inferRuleFromEntity(ent, today);
|
|
2882
|
+
const baseId = inferred.id;
|
|
2883
|
+
const count = seenIds.get(baseId) || 0;
|
|
2884
|
+
seenIds.set(baseId, count + 1);
|
|
2885
|
+
const uniqueId = count === 0 ? baseId : `${baseId}-${count + 1}`;
|
|
2886
|
+
rules.push({
|
|
2887
|
+
...inferred,
|
|
2888
|
+
id: uniqueId
|
|
2889
|
+
});
|
|
2890
|
+
}
|
|
2891
|
+
const hasVesperCore = rules.some((r) => r.id === "rule-project_vesper_dsp-vesper-dsp-master-invariants");
|
|
2892
|
+
if (!hasVesperCore) {
|
|
2893
|
+
rules.push({
|
|
2894
|
+
id: "rule-project_vesper_dsp-vesper-dsp-master-invariants",
|
|
2895
|
+
domain: "Project_Vesper_DSP",
|
|
2896
|
+
title: "Vesper_DSP_Master_Invariants",
|
|
2897
|
+
entityType: "Architecture_Invariant",
|
|
2898
|
+
triggers: {
|
|
2899
|
+
files: ["D:/Vesper", "crates/vesper-", "vesper-apo", "dsp-settings.json"],
|
|
2900
|
+
keywords: ["vesper", "dsp", "mmcss", "virtuallock", "\uC624\uB514\uC624", "\uC0AC\uC6B4\uB4DC", "\uB04A\uAE40", "apo"],
|
|
2901
|
+
commands: ["check", "build", "package", "sign"]
|
|
2902
|
+
},
|
|
2903
|
+
invariants: [
|
|
2904
|
+
"\uC624\uB514\uC624 \uBC84\uD37C\uB294 \uBC18\uB4DC\uC2DC Win32 VirtualLock\uC73C\uB85C \uBB3C\uB9AC RAM\uC5D0 \uACE0\uC815\uD558\uC5EC \uB514\uC2A4\uD06C \uC2A4\uC651 \uC544\uC6C3(\uD558\uB4DC \uD398\uC774\uC9C0 \uD3F4\uD2B8)\uC744 \uC6D0\uCC9C \uCC28\uB2E8\uD560 \uAC83",
|
|
2905
|
+
"\uC624\uB514\uC624 \uCC98\uB9AC \uC2A4\uB808\uB4DC\uB294 Windows MMCSS(Pro Audio) \uC2E4\uC2DC\uAC04 \uC2A4\uCF00\uC904\uB7EC\uC5D0 \uD544\uC218 \uB4F1\uB85D\uD560 \uAC83",
|
|
2906
|
+
"\uC124\uC815 \uC800\uC7A5\uC740 \uBE0C\uB77C\uC6B0\uC800 localStorage \uB2E8\uB3C5 \uC758\uC874\uC744 \uAE08\uC9C0\uD558\uACE0 Crash-Safe \uC6D0\uC790\uC801(Atomic) \uD30C\uC77C \uC800\uC7A5(dsp-settings.json)\uC744 \uC0AC\uC6A9\uD560 \uAC83",
|
|
2907
|
+
"Windows \uC167\uB2E4\uC6B4 \uC2DC WM_QUERYENDSESSION / SM_SHUTTINGDOWN \uAC10\uC9C0 \uD6C4 \uC815\uC0C1 \uC885\uB8CC\uB97C \uBCF4\uC7A5\uD560 \uAC83"
|
|
2908
|
+
],
|
|
2909
|
+
actions: [
|
|
2910
|
+
"1. Cargo Workspace 5\uB300 \uB9C8\uC774\uD06C\uB85C \uD06C\uB808\uC774\uD2B8(vesper-config, vesper-ipc, vesper-audio-core, vesper-system, vesper-tauri) \uACBD\uACC4 \uC900\uC218",
|
|
2911
|
+
"2. \uC218\uC815\uB41C \uD06C\uB808\uC774\uD2B8 \uD2B8\uB799\uB9CC \uC778\uACFC\uC728 \uC99D\uBD84 \uBE4C\uB4DC \uC218\uD589"
|
|
2912
|
+
],
|
|
2913
|
+
context: [
|
|
2914
|
+
"\uC2E4\uC99D \uD0C0\uAE43 \uACBD\uB85C: D:\\Vesper\\dsp-boot-fix\\dsp",
|
|
2915
|
+
"APO DLL \uBC0F Taskbar \uB124\uC774\uD2F0\uBE0C \uBC14\uC774\uB108\uB9AC \uC544\uD0A4\uD14D\uCC98 \uBB34\uACB0\uC131(x64 PE) \uAC80\uC99D \uD544\uC218"
|
|
2916
|
+
],
|
|
2917
|
+
lastVerified: today
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
const hasSynapseCore = rules.some((r) => r.id === "rule-project_synapse_kit-synapse-kit-core-invariants");
|
|
2921
|
+
if (!hasSynapseCore) {
|
|
2922
|
+
rules.push({
|
|
2923
|
+
id: "rule-project_synapse_kit-synapse-kit-core-invariants",
|
|
2924
|
+
domain: "Project_Synapse_Kit",
|
|
2925
|
+
title: "Synapse_Kit_Core_Invariants",
|
|
2926
|
+
entityType: "Framework_Invariant",
|
|
2927
|
+
triggers: {
|
|
2928
|
+
files: ["D:/synapse", "D:/synapse-site", "synapse.config.ts"],
|
|
2929
|
+
keywords: ["synapse", "synapse-kit", "\uC2DC\uB0C5\uC2A4", "\uC778\uACFC\uC728", "causal", "\uCEF4\uD30C\uC77C\uB7EC", "\uCCB4\uCEE4"],
|
|
2930
|
+
commands: ["check", "build", "package", "sign", "init", "memory"]
|
|
2931
|
+
},
|
|
2932
|
+
invariants: [
|
|
2933
|
+
"Git \uC0C1\uD0DC \uC2A4\uCE94 \uC2DC \uBC18\uB4DC\uC2DC git status --porcelain -uall \uD50C\uB798\uADF8\uB97C \uC0AC\uC6A9\uD558\uC5EC \uBBF8\uCD94\uC801 \uD558\uC704 \uB514\uB809\uD130\uB9AC \uD30C\uC77C \uB204\uB77D\uC744 \uBC29\uC9C0\uD560 \uAC83",
|
|
2934
|
+
"AI \uC5D0\uC774\uC804\uD2B8 \uC5F0\uB3D9 \uC2DC --compact \uBAA8\uB4DC\uB97C \uD1B5\uD574 \uC131\uACF5 \uC2DC 11\uD1A0\uD070 \uB2E8\uC77C \uB77C\uC778 JSON\uC744 \uBC18\uD658\uD558\uC5EC \uD1A0\uD070\uC744 99.8% \uC808\uAC10\uD560 \uAC83",
|
|
2935
|
+
"\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uBC0F \uB7F0\uD0C0\uC784\uC740 npm/npx\uB97C \uC808\uB300 \uC0AC\uC6A9\uD558\uC9C0 \uC54A\uACE0 \uBC18\uB4DC\uC2DC bun\uC744 \uC0AC\uC6A9\uD560 \uAC83"
|
|
2936
|
+
],
|
|
2937
|
+
actions: [
|
|
2938
|
+
"1. \uCF54\uB4DC \uBCC0\uACBD \uD6C4 bun D:/synapse/dist/cli.js check --compact\uB85C \uBB34\uACB0\uC131 \uAC80\uC99D",
|
|
2939
|
+
"2. \uBA54\uBAA8\uB9AC \uC870\uD68C \uC2DC synapse memory query\uB85C \uACF5\uBA85 \uADDC\uCE59\uB9CC \uCD5C\uC18C \uD1A0\uD070 \uC8FC\uC785"
|
|
2940
|
+
],
|
|
2941
|
+
context: [
|
|
2942
|
+
"\uC5D4\uC9C4 \uCF54\uC5B4 \uACBD\uB85C: D:\\synapse",
|
|
2943
|
+
"\uACF5\uC2DD \uBB38\uC11C \uBC0F \uC704\uD0A4 \uACBD\uB85C: D:\\synapse-site (KO/EN \uB2E4\uAD6D\uC5B4 \uB85C\uCF00\uC77C \uC790\uB3D9 \uBD84\uAE30)"
|
|
2944
|
+
],
|
|
2945
|
+
lastVerified: today
|
|
2946
|
+
});
|
|
2947
|
+
}
|
|
2948
|
+
const relations = [...legacyRelations];
|
|
2949
|
+
const coreRelations = [
|
|
2950
|
+
{
|
|
2951
|
+
from: "POE2_AutoFilter_Project",
|
|
2952
|
+
to: "POE2_AutoFilter_ReleaseProcess",
|
|
2953
|
+
relationType: "governed_by_workflow"
|
|
2954
|
+
},
|
|
2955
|
+
{
|
|
2956
|
+
from: "POE2_AutoFilter_ReleaseProcess",
|
|
2957
|
+
to: "POE2_AutoFilter_Updater",
|
|
2958
|
+
relationType: "triggers_update_of"
|
|
2959
|
+
},
|
|
2960
|
+
{
|
|
2961
|
+
from: "POE2_AutoFilter_ReleaseProcess",
|
|
2962
|
+
to: "POE2_AutoFilter_KnownBugs",
|
|
2963
|
+
relationType: "verifies_and_notifies"
|
|
2964
|
+
},
|
|
2965
|
+
{
|
|
2966
|
+
from: "Synapse_Kit_Core_Invariants",
|
|
2967
|
+
to: "Vesper_DSP_Master_Invariants",
|
|
2968
|
+
relationType: "verifies_and_builds"
|
|
2969
|
+
}
|
|
2970
|
+
];
|
|
2971
|
+
for (const cr of coreRelations) {
|
|
2972
|
+
const exists = relations.some((r) => r.from === cr.from && r.to === cr.to && r.relationType === cr.relationType);
|
|
2973
|
+
if (!exists) {
|
|
2974
|
+
relations.push(cr);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
const db = {
|
|
2978
|
+
version: CAUSAL_MEMORY_CONFIG.SCHEMA_VERSION,
|
|
2979
|
+
updatedAt: new Date().toISOString(),
|
|
2980
|
+
totalRules: rules.length,
|
|
2981
|
+
totalRelations: relations.length,
|
|
2982
|
+
rules,
|
|
2983
|
+
relations
|
|
2984
|
+
};
|
|
2985
|
+
const serialized = JSON.stringify(db, null, 2);
|
|
2986
|
+
for (const outPath of [targetGlobalPath, targetLocalPath]) {
|
|
2987
|
+
const dir = dirname2(outPath);
|
|
2988
|
+
if (!existsSync5(dir)) {
|
|
2989
|
+
mkdirSync3(dir, { recursive: true });
|
|
2990
|
+
}
|
|
2991
|
+
writeFileSync3(outPath, serialized, "utf-8");
|
|
2992
|
+
}
|
|
2993
|
+
const alwaysActiveCount = rules.filter((r) => r.triggers.alwaysActive).length;
|
|
2994
|
+
const domains = Array.from(new Set(rules.map((r) => r.domain)));
|
|
2995
|
+
return {
|
|
2996
|
+
ok: true,
|
|
2997
|
+
totalRules: rules.length,
|
|
2998
|
+
totalRelations: relations.length,
|
|
2999
|
+
alwaysActiveCount,
|
|
3000
|
+
domains
|
|
3001
|
+
};
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
// src/cli-memory.ts
|
|
3005
|
+
var RESET4 = "\x1B[0m";
|
|
3006
|
+
var BOLD4 = "\x1B[1m";
|
|
3007
|
+
var CYAN4 = "\x1B[36m";
|
|
3008
|
+
var GREEN4 = "\x1B[32m";
|
|
3009
|
+
var RED4 = "\x1B[31m";
|
|
3010
|
+
var GRAY4 = "\x1B[90m";
|
|
3011
|
+
var YELLOW4 = "\x1B[33m";
|
|
3012
|
+
function printMemoryHelp() {
|
|
3013
|
+
process.stdout.write(`
|
|
3014
|
+
${BOLD4}${CYAN4}\uD83E\uDDE0 Synapse Kit - Causal Memory Engine (\uC778\uACFC\uC728 \uC9C0\uB2A5\uD615 \uBA54\uBAA8\uB9AC CLI)${RESET4}
|
|
3015
|
+
|
|
3016
|
+
${BOLD4}\uC0AC\uC6A9\uBC95:${RESET4}
|
|
3017
|
+
synapse memory <subcommand> [options]
|
|
3018
|
+
|
|
3019
|
+
${BOLD4}\uC11C\uBE0C \uBA85\uB839\uC5B4:${RESET4}
|
|
3020
|
+
query \uC791\uC5C5 \uD30C\uC77C/\uD0A4\uC6CC\uB4DC\uC5D0 \uB9E4\uCE6D\uB418\uB294 \uC778\uACFC \uADDC\uCE59 \uBC0F \uAC04\uC120(Relations) \uCD08\uACBD\uB7C9 \uACF5\uBA85 \uC870\uD68C (\uAE30\uBCF8\uAC12)
|
|
3021
|
+
list \uB4F1\uB85D\uB41C \uB3C4\uBA54\uC778, \uC778\uACFC \uADDC\uCE59 \uBC0F \uC778\uACFC \uAC04\uC120(Relations) \uD1B5\uACC4 \uD655\uC778
|
|
3022
|
+
audit \uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uBB34\uACB0\uC131 \uBC0F \uD1A0\uD070 \uC808\uAC10 \uC0C1\uD0DC \uAC10\uC0AC
|
|
3023
|
+
assert \uC2E0\uADDC \uC778\uACFC\uC728 \uADDC\uCE59 \uB4F1\uB85D \uB610\uB294 \uAC31\uC2E0 (--json '<json>')
|
|
3024
|
+
migrate \uAD6C\uD615 \uC9C0\uC2DD \uADF8\uB798\uD504 \uBC31\uC5C5\uBCF8\uC744 \uC778\uACFC\uC728 \uBA54\uBAA8\uB9AC \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB85C \uBB34\uC190\uC2E4 \uBCC0\uD658
|
|
3025
|
+
benchmark 4\uB300 \uCC28\uC6D0 \uACFC\uBD80\uD558 \uC2A4\uD2B8\uB808\uC2A4 \uBCA4\uCE58\uB9C8\uD06C \uC2E4\uD589 (--scale 10000 --concurrency 50)
|
|
3026
|
+
serve \uB3C5\uB9BD \uB85C\uCEEC \uBC31\uADF8\uB77C\uC6B4\uB4DC \uC11C\uBC84/\uB370\uBAAC \uAD6C\uB3D9 (0ms \uC778\uBA54\uBAA8\uB9AC HTTP & MCP API)
|
|
3027
|
+
mcp-stdio MCP \uD45C\uC900 \uC785\uCD9C\uB825(stdio) JSON-RPC 2.0 \uC11C\uBC84 \uAD6C\uB3D9 (mcp_config.json \uC5F0\uB3D9\uC6A9)
|
|
3028
|
+
|
|
3029
|
+
${BOLD4}query \uC635\uC158:${RESET4}
|
|
3030
|
+
--files <paths...> \uD2B8\uB9AC\uAC70 \uB300\uC0C1 \uD30C\uC77C \uACBD\uB85C (\uBBF8\uC9C0\uC815 \uC2DC Git \uBCC0\uACBD \uC790\uB3D9 \uC2A4\uCE94)
|
|
3031
|
+
--keywords <words...> \uD2B8\uB9AC\uAC70 \uAC80\uC0C9 \uD0A4\uC6CC\uB4DC
|
|
3032
|
+
--command <cmd> \uD2B8\uB9AC\uAC70 \uC5F0\uB3D9 \uBA85\uB839\uC5B4 (\uC608: release, build, sign)
|
|
3033
|
+
--domain <domain> \uD2B9\uC815 \uB3C4\uBA54\uC778\uC73C\uB85C \uAC80\uC0C9 \uC81C\uD55C
|
|
3034
|
+
--format <json|md|compact> \uCD9C\uB825 \uD3EC\uB9F7 \uC9C0\uC815
|
|
3035
|
+
|
|
3036
|
+
${BOLD4}serve \uC635\uC158:${RESET4}
|
|
3037
|
+
--port <number> \uC11C\uBC84 \uD3EC\uD2B8 \uBC88\uD638 (\uAE30\uBCF8: ${CAUSAL_MEMORY_CONFIG.DEFAULT_PORT})
|
|
3038
|
+
--host <string> \uBC14\uC778\uB529 \uD638\uC2A4\uD2B8 (\uAE30\uBCF8: ${CAUSAL_MEMORY_CONFIG.DEFAULT_HOST})
|
|
3039
|
+
|
|
3040
|
+
${BOLD4}\uACF5\uD1B5 \uD50C\uB798\uADF8:${RESET4}
|
|
3041
|
+
--agent, --compact AI \uC5D0\uC774\uC804\uD2B8 \uC804\uC6A9 \uCD08\uACBD\uB7C9 JSON \uBAA8\uB4DC
|
|
3042
|
+
|
|
3043
|
+
`);
|
|
3044
|
+
}
|
|
3045
|
+
async function handleMemoryCommand(args, options) {
|
|
3046
|
+
const subArgs = args.filter((a) => a !== "memory");
|
|
3047
|
+
const subCommand = subArgs.find((a) => !a.startsWith("-")) || "query";
|
|
3048
|
+
if (subArgs.includes("--help") || subArgs.includes("-h") || subCommand === "help") {
|
|
3049
|
+
printMemoryHelp();
|
|
3050
|
+
return 0;
|
|
3051
|
+
}
|
|
3052
|
+
if (subCommand === "mcp-stdio") {
|
|
3053
|
+
await startCausalMcpStdioServer();
|
|
3054
|
+
return 0;
|
|
3055
|
+
}
|
|
3056
|
+
if (subCommand === "benchmark") {
|
|
3057
|
+
let ruleScale = 1e4;
|
|
3058
|
+
let concurrency = 50;
|
|
3059
|
+
let totalRequests = 5000;
|
|
3060
|
+
for (let i = 0;i < subArgs.length; i++) {
|
|
3061
|
+
if (subArgs[i] === "--scale" && subArgs[i + 1]) {
|
|
3062
|
+
ruleScale = parseInt(subArgs[i + 1], 10);
|
|
3063
|
+
} else if (subArgs[i] === "--concurrency" && subArgs[i + 1]) {
|
|
3064
|
+
concurrency = parseInt(subArgs[i + 1], 10);
|
|
3065
|
+
} else if (subArgs[i] === "--requests" && subArgs[i + 1]) {
|
|
3066
|
+
totalRequests = parseInt(subArgs[i + 1], 10);
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
await Promise.resolve().then(() => init_causal_benchmark());
|
|
3070
|
+
const report = await executeOverloadBenchmark({
|
|
3071
|
+
ruleScale,
|
|
3072
|
+
relationScale: ruleScale * 2,
|
|
3073
|
+
concurrency,
|
|
3074
|
+
totalRequests,
|
|
3075
|
+
fileInputScale: ruleScale,
|
|
3076
|
+
crudIterations: totalRequests
|
|
3077
|
+
}, options.agentMode);
|
|
3078
|
+
if (options.agentMode) {
|
|
3079
|
+
process.stdout.write(JSON.stringify(report, null, 2) + `
|
|
3080
|
+
`);
|
|
3081
|
+
}
|
|
3082
|
+
return report.allPassed ? 0 : 1;
|
|
3083
|
+
}
|
|
3084
|
+
if (subCommand === "migrate") {
|
|
3085
|
+
const result = migrateLegacyMemoryGraph();
|
|
3086
|
+
if (options.agentMode) {
|
|
3087
|
+
process.stdout.write(JSON.stringify(result) + `
|
|
3088
|
+
`);
|
|
3089
|
+
} else {
|
|
3090
|
+
process.stdout.write(`
|
|
3091
|
+
${BOLD4}${GREEN4}\u2728 [Causal Memory \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC644\uB8CC]${RESET4}
|
|
3092
|
+
` + ` \u2022 \uBCC0\uD658\uB41C \uC778\uACFC \uADDC\uCE59(Rules) : ${BOLD4}${result.totalRules}\uAC1C${RESET4}
|
|
3093
|
+
` + ` \u2022 \uBCF4\uC874\uB41C \uC778\uACFC \uAC04\uC120(Relations) : ${BOLD4}${result.totalRelations}\uAC1C${RESET4}
|
|
3094
|
+
` + ` \u2022 \uC0C1\uC2DC \uD65C\uC131 \uADDC\uCE59(AlwaysActive): ${BOLD4}${result.alwaysActiveCount}\uAC1C${RESET4}
|
|
3095
|
+
` + ` \u2022 \uBD84\uB958 \uB3C4\uBA54\uC778 : ${result.domains.join(", ")}
|
|
3096
|
+
|
|
3097
|
+
`);
|
|
3098
|
+
}
|
|
3099
|
+
return 0;
|
|
3100
|
+
}
|
|
3101
|
+
if (subCommand === "assert") {
|
|
3102
|
+
const jsonIdx = subArgs.indexOf("--json");
|
|
3103
|
+
if (jsonIdx < 0 || !subArgs[jsonIdx + 1]) {
|
|
3104
|
+
process.stderr.write(`${RED4}\u274C --json '<\uADDC\uCE59 JSON>' \uC778\uC790\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.${RESET4}
|
|
3105
|
+
`);
|
|
3106
|
+
return 1;
|
|
3107
|
+
}
|
|
3108
|
+
const rule = JSON.parse(subArgs[jsonIdx + 1]);
|
|
3109
|
+
const store = new CausalMemoryStore;
|
|
3110
|
+
store.assertRule(rule);
|
|
3111
|
+
if (options.agentMode) {
|
|
3112
|
+
process.stdout.write(JSON.stringify({ ok: true, id: rule.id }) + `
|
|
3113
|
+
`);
|
|
3114
|
+
} else {
|
|
3115
|
+
process.stdout.write(`${BOLD4}${GREEN4}\u2705 \uC778\uACFC \uADDC\uCE59 \uB4F1\uB85D \uC644\uB8CC: ${rule.id}${RESET4}
|
|
3116
|
+
`);
|
|
3117
|
+
}
|
|
3118
|
+
return 0;
|
|
3119
|
+
}
|
|
3120
|
+
if (subCommand === "query") {
|
|
3121
|
+
const files = [];
|
|
3122
|
+
const keywords = [];
|
|
3123
|
+
let command;
|
|
3124
|
+
let domain;
|
|
3125
|
+
let format = options.compactMode ? "compact" : options.agentMode ? "json" : "text";
|
|
3126
|
+
for (let i = 0;i < subArgs.length; i++) {
|
|
3127
|
+
const arg = subArgs[i];
|
|
3128
|
+
if (arg === "--files" || arg === "-f") {
|
|
3129
|
+
let j = i + 1;
|
|
3130
|
+
while (j < subArgs.length && !subArgs[j].startsWith("-")) {
|
|
3131
|
+
files.push(subArgs[j]);
|
|
3132
|
+
j++;
|
|
3133
|
+
}
|
|
3134
|
+
i = j - 1;
|
|
3135
|
+
} else if (arg === "--keywords" || arg === "-k") {
|
|
3136
|
+
let j = i + 1;
|
|
3137
|
+
while (j < subArgs.length && !subArgs[j].startsWith("-")) {
|
|
3138
|
+
keywords.push(subArgs[j]);
|
|
3139
|
+
j++;
|
|
3140
|
+
}
|
|
3141
|
+
i = j - 1;
|
|
3142
|
+
} else if (arg === "--command" || arg === "-c") {
|
|
3143
|
+
command = subArgs[++i];
|
|
3144
|
+
} else if (arg === "--domain" || arg === "-d") {
|
|
3145
|
+
domain = subArgs[++i];
|
|
3146
|
+
} else if (arg === "--format") {
|
|
3147
|
+
format = subArgs[++i];
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
const result = await runCausalQuery({
|
|
3151
|
+
files,
|
|
3152
|
+
keywords,
|
|
3153
|
+
command,
|
|
3154
|
+
domain,
|
|
3155
|
+
autoGit: files.length === 0
|
|
3156
|
+
});
|
|
3157
|
+
if (options.compactMode || format === "compact") {
|
|
3158
|
+
process.stdout.write(formatResonanceForAgent(result, true) + `
|
|
3159
|
+
`);
|
|
3160
|
+
} else if (options.agentMode || format === "json") {
|
|
3161
|
+
process.stdout.write(JSON.stringify(result, null, 2) + `
|
|
3162
|
+
`);
|
|
3163
|
+
} else if (format === "md" || format === "markdown") {
|
|
3164
|
+
process.stdout.write(formatResonanceForAgent(result, false) + `
|
|
3165
|
+
`);
|
|
3166
|
+
} else {
|
|
3167
|
+
process.stdout.write(`
|
|
3168
|
+
${BOLD4}${CYAN4}\uD83E\uDDE0 [Causal Memory] \uACF5\uBA85 \uCFFC\uB9AC \uC644\uACB0 (${result.matchedCount}/${result.totalDatabaseRules}\uAC1C \uADDC\uCE59 \uD65C\uC131\uD654, \uAC04\uC120 ${result.activeRelations.length}\uAC1C, \uC808\uAC10\uB960: ${result.tokenDietSavingsRatio}, ${result.queryDurationMs}ms)${RESET4}
|
|
3169
|
+
`);
|
|
3170
|
+
for (const rule of result.resonanceRules) {
|
|
3171
|
+
process.stdout.write(`
|
|
3172
|
+
${BOLD4}${GREEN4}\u2714 [${rule.domain}]${RESET4} ${BOLD4}${rule.title}${RESET4} ${GRAY4}(${rule.id})${RESET4}
|
|
3173
|
+
`);
|
|
3174
|
+
if (rule.invariants.length > 0) {
|
|
3175
|
+
process.stdout.write(` ${YELLOW4}\uD83D\uDEE1\uFE0F \uBD88\uBCC0 \uADDC\uCE59:${RESET4}
|
|
3176
|
+
`);
|
|
3177
|
+
for (const inv of rule.invariants) {
|
|
3178
|
+
process.stdout.write(` \u2022 ${inv}
|
|
3179
|
+
`);
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
if (rule.actions.length > 0) {
|
|
3183
|
+
process.stdout.write(` ${CYAN4}\u26A1 \uC2E4\uD589 \uC9C0\uCE68:${RESET4}
|
|
3184
|
+
`);
|
|
3185
|
+
for (const act of rule.actions) {
|
|
3186
|
+
process.stdout.write(` \u2022 ${act}
|
|
3187
|
+
`);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
if (result.activeRelations.length > 0) {
|
|
3192
|
+
process.stdout.write(`
|
|
3193
|
+
${BOLD4}${CYAN4}\uD83D\uDD17 \uD65C\uC131 \uC778\uACFC \uAC04\uC120 (Relations):${RESET4}
|
|
3194
|
+
`);
|
|
3195
|
+
for (const rel of result.activeRelations) {
|
|
3196
|
+
process.stdout.write(` \u2022 ${rel.from} \u2500\u2500[${rel.relationType}]\u2500\u2500\u25B6 ${rel.to}
|
|
3197
|
+
`);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
process.stdout.write(`
|
|
3201
|
+
`);
|
|
3202
|
+
}
|
|
3203
|
+
return 0;
|
|
3204
|
+
}
|
|
3205
|
+
if (subCommand === "list") {
|
|
3206
|
+
const store = new CausalMemoryStore;
|
|
3207
|
+
const status = store.getStatus();
|
|
3208
|
+
const rules = store.getAllRules();
|
|
3209
|
+
if (options.agentMode) {
|
|
3210
|
+
process.stdout.write(JSON.stringify({ ok: true, status, rulesCount: rules.length, relationsCount: status.totalRelations }) + `
|
|
3211
|
+
`);
|
|
3212
|
+
return 0;
|
|
3213
|
+
}
|
|
3214
|
+
process.stdout.write(`
|
|
3215
|
+
${BOLD4}${CYAN4}\uD83E\uDDE0 [Causal Memory] \uC778\uACFC\uC728 \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC0C1\uD0DC${RESET4}
|
|
3216
|
+
`);
|
|
3217
|
+
process.stdout.write(` \u2022 \uC800\uC7A5\uC18C \uACBD\uB85C : ${GRAY4}${status.dbPath}${RESET4}
|
|
3218
|
+
`);
|
|
3219
|
+
process.stdout.write(` \u2022 \uC5D4\uC9C4 \uBC84\uC804 : ${GREEN4}v${status.version}${RESET4}
|
|
3220
|
+
`);
|
|
3221
|
+
process.stdout.write(` \u2022 \uCD1D \uADDC\uCE59 \uC218 : ${BOLD4}${status.totalRules}\uAC1C${RESET4}
|
|
3222
|
+
`);
|
|
3223
|
+
process.stdout.write(` \u2022 \uCD1D \uC778\uACFC \uAC04\uC120: ${BOLD4}${status.totalRelations}\uAC1C${RESET4}
|
|
3224
|
+
`);
|
|
3225
|
+
process.stdout.write(` \u2022 \uAD00\uB9AC \uB3C4\uBA54\uC778 : ${status.domains.join(", ")}
|
|
3226
|
+
|
|
3227
|
+
`);
|
|
3228
|
+
for (const domain of status.domains) {
|
|
3229
|
+
const domainRules = rules.filter((r) => r.domain === domain);
|
|
3230
|
+
process.stdout.write(` ${BOLD4}${YELLOW4}[${domain}]${RESET4} (${domainRules.length}\uAC1C \uADDC\uCE59)
|
|
3231
|
+
`);
|
|
3232
|
+
for (const r of domainRules) {
|
|
3233
|
+
process.stdout.write(` \u2022 ${r.title} ${GRAY4}(${r.id})${RESET4}
|
|
3234
|
+
`);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
process.stdout.write(`
|
|
3238
|
+
`);
|
|
3239
|
+
return 0;
|
|
3240
|
+
}
|
|
3241
|
+
if (subCommand === "audit") {
|
|
3242
|
+
const store = new CausalMemoryStore;
|
|
3243
|
+
const audit = store.audit();
|
|
3244
|
+
if (options.agentMode) {
|
|
3245
|
+
process.stdout.write(JSON.stringify(audit) + `
|
|
3246
|
+
`);
|
|
3247
|
+
return audit.ok ? 0 : 1;
|
|
3248
|
+
}
|
|
3249
|
+
if (audit.ok) {
|
|
3250
|
+
process.stdout.write(`
|
|
3251
|
+
${BOLD4}${GREEN4}\u2728 [Causal Memory Audit \uD1B5\uACFC] \uCD1D ${audit.totalRules}\uAC1C \uADDC\uCE59, ${audit.totalRelations}\uAC1C \uC778\uACFC \uAC04\uC120 (\uC0C1\uC2DC \uD65C\uC131: ${audit.alwaysActiveCount}\uAC1C) \uBB34\uACB0\uC131 100% \uC815\uC0C1${RESET4}
|
|
3252
|
+
|
|
3253
|
+
`);
|
|
3254
|
+
return 0;
|
|
3255
|
+
} else {
|
|
3256
|
+
process.stderr.write(`
|
|
3257
|
+
${BOLD4}${RED4}\uD83D\uDEA8 [Causal Memory Audit \uACB0\uD568 \uBC1C\uACAC] \uCD1D ${audit.issues.length}\uAC1C \uD56D\uBAA9 \uC774\uC0C1 \uBC1C\uC0DD:${RESET4}
|
|
3258
|
+
`);
|
|
3259
|
+
for (const issue of audit.issues) {
|
|
3260
|
+
process.stderr.write(` \u2022 ${issue}
|
|
3261
|
+
`);
|
|
3262
|
+
}
|
|
3263
|
+
process.stderr.write(`
|
|
3264
|
+
`);
|
|
3265
|
+
return 1;
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
if (subCommand === "serve") {
|
|
3269
|
+
let port = CAUSAL_MEMORY_CONFIG.DEFAULT_PORT;
|
|
3270
|
+
let host = CAUSAL_MEMORY_CONFIG.DEFAULT_HOST;
|
|
3271
|
+
for (let i = 0;i < subArgs.length; i++) {
|
|
3272
|
+
if (subArgs[i] === "--port" && subArgs[i + 1]) {
|
|
3273
|
+
port = parseInt(subArgs[i + 1], 10);
|
|
3274
|
+
} else if (subArgs[i] === "--host" && subArgs[i + 1]) {
|
|
3275
|
+
host = subArgs[i + 1];
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
const server = startCausalServer({ port, host });
|
|
3279
|
+
if (options.agentMode) {
|
|
3280
|
+
process.stdout.write(JSON.stringify({ ok: true, port: server.port, host, url: `http://${host}:${server.port}` }) + `
|
|
3281
|
+
`);
|
|
3282
|
+
} else {
|
|
3283
|
+
process.stdout.write(`
|
|
3284
|
+
${BOLD4}${GREEN4}\uD83D\uDE80 [Causal Memory Daemon \uAC00\uB3D9 \uC644\uB8CC]${RESET4}
|
|
3285
|
+
\u2022 \uC8FC\uC18C: ${CYAN4}http://${host}:${server.port}${RESET4}
|
|
3286
|
+
\u2022 MCP API: ${GRAY4}http://${host}:${server.port}/mcp${RESET4}
|
|
3287
|
+
\u2022 0ms \uC778\uBA54\uBAA8\uB9AC \uACF5\uBA85 \uB300\uAE30 \uC911... (\uC885\uB8CC: Ctrl+C)
|
|
3288
|
+
|
|
3289
|
+
`);
|
|
3290
|
+
}
|
|
3291
|
+
await new Promise(() => {});
|
|
3292
|
+
return 0;
|
|
3293
|
+
}
|
|
3294
|
+
process.stderr.write(`${RED4}\u274C \uC54C \uC218 \uC5C6\uB294 memory \uC11C\uBE0C \uBA85\uB839\uC5B4: '${subCommand}'${RESET4}
|
|
3295
|
+
`);
|
|
3296
|
+
printMemoryHelp();
|
|
3297
|
+
return 1;
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
// src/cli.ts
|
|
3301
|
+
var RESET5 = "\x1B[0m";
|
|
3302
|
+
var BOLD5 = "\x1B[1m";
|
|
3303
|
+
var CYAN5 = "\x1B[36m";
|
|
3304
|
+
var GREEN5 = "\x1B[32m";
|
|
3305
|
+
var RED5 = "\x1B[31m";
|
|
3306
|
+
async function handleInit(targetDir = process.cwd()) {
|
|
3307
|
+
const configPath = resolve5(targetDir, "synapse.config.ts");
|
|
3308
|
+
if (existsSync6(configPath)) {
|
|
3309
|
+
process.stderr.write(`${RED5}\u274C ${t("configExists")} ${configPath}${RESET5}
|
|
3310
|
+
`);
|
|
3311
|
+
return 1;
|
|
3312
|
+
}
|
|
3313
|
+
const template = `import { defineConfig, rustChecker, svelteChecker, schemaChecker, nativeChecker, nsisChecker } from 'synapse-kit';
|
|
3314
|
+
|
|
3315
|
+
export default defineConfig({
|
|
3316
|
+
aiMemory: {
|
|
3317
|
+
enabled: true,
|
|
3318
|
+
smartSkipping: true,
|
|
3319
|
+
},
|
|
3320
|
+
plugins: [
|
|
3321
|
+
rustChecker({ workspaceDir: './src-tauri' }),
|
|
3322
|
+
svelteChecker({ tsconfig: './tsconfig.json' }),
|
|
3323
|
+
schemaChecker({
|
|
3324
|
+
targets: [
|
|
3325
|
+
{ path: './src-tauri/tauri.conf.json' },
|
|
3326
|
+
],
|
|
3327
|
+
}),
|
|
3328
|
+
nativeChecker({
|
|
3329
|
+
targets: [
|
|
3330
|
+
{ path: './src-tauri/resources/vesper_apo.dll', expectedArchitecture: 'x64' },
|
|
3331
|
+
],
|
|
3332
|
+
}),
|
|
3333
|
+
nsisChecker({
|
|
3334
|
+
templatePath: './installer-template.nsi',
|
|
3335
|
+
}),
|
|
3336
|
+
],
|
|
3337
|
+
buildTracks: [
|
|
3338
|
+
{
|
|
3339
|
+
name: 'APO DLL \uBE4C\uB4DC',
|
|
3340
|
+
command: ['bun', 'tooling/build-apo.mjs'],
|
|
3341
|
+
sources: ['vesper-apo/'],
|
|
3342
|
+
artifacts: ['src-tauri/resources/vesper_apo.dll'],
|
|
3343
|
+
},
|
|
3344
|
+
{
|
|
3345
|
+
name: 'Taskbar \uC704\uC82F \uBE4C\uB4DC',
|
|
3346
|
+
command: ['bun', 'tooling/build-taskbar.mjs'],
|
|
3347
|
+
sources: ['windhawk/', 'standalone/'],
|
|
3348
|
+
artifacts: ['src-tauri/resources/taskbar/VesperTaskbar.dll'],
|
|
3349
|
+
},
|
|
3350
|
+
{
|
|
3351
|
+
name: 'Svelte UI \uBE4C\uB4DC',
|
|
3352
|
+
command: ['bun', 'run', 'build'],
|
|
3353
|
+
sources: ['src/', 'static/'],
|
|
3354
|
+
artifacts: ['build/index.html'],
|
|
3355
|
+
},
|
|
3356
|
+
],
|
|
3357
|
+
package: {
|
|
3358
|
+
framework: 'tauri',
|
|
3359
|
+
targets: ['nsis'],
|
|
3360
|
+
compression: 'zlib',
|
|
3361
|
+
},
|
|
3362
|
+
sign: {
|
|
3363
|
+
privateKeyPath: 'src-tauri/keys/updater',
|
|
3364
|
+
passwordEnv: 'TAURI_KEY_PASSWORD',
|
|
3365
|
+
},
|
|
3366
|
+
});
|
|
3367
|
+
`;
|
|
3368
|
+
await writeFile(configPath, template, "utf8");
|
|
3369
|
+
process.stdout.write(`${BOLD5}${GREEN5}\u2705 ${t("configCreated")}${RESET5}
|
|
3370
|
+
`);
|
|
3371
|
+
return 0;
|
|
3372
|
+
}
|
|
3373
|
+
function printHelp() {
|
|
3374
|
+
process.stdout.write(`
|
|
3375
|
+
${BOLD5}${CYAN5}${t("cliTitle")}${RESET5}
|
|
3376
|
+
|
|
3377
|
+
${BOLD5}${t("cliUsage")}${RESET5}
|
|
3378
|
+
synapse <command> [options]
|
|
3379
|
+
|
|
3380
|
+
${BOLD5}${t("cliCommands")}${RESET5}
|
|
3381
|
+
check ${t("cmdCheck")}
|
|
3382
|
+
build ${t("cmdBuild")}
|
|
3383
|
+
package ${t("cmdPackage")}
|
|
3384
|
+
sign ${t("cmdSign")}
|
|
3385
|
+
init ${t("cmdInit")}
|
|
3386
|
+
memory ${t("cmdMemory")}
|
|
3387
|
+
|
|
3388
|
+
${BOLD5}${t("cliOptions")}${RESET5}
|
|
3389
|
+
--all ${t("optAll")}
|
|
3390
|
+
-f, --force ${t("optForce")}
|
|
3391
|
+
--agent ${t("optAgent")}
|
|
3392
|
+
--compact ${t("optCompact")}
|
|
3393
|
+
-i, --interactive ${t("optInteractive")}
|
|
3394
|
+
--watch ${t("optWatch")}
|
|
3395
|
+
--lang <ko|en> ${t("optLang")}
|
|
3396
|
+
--help, -h ${t("optHelp")}
|
|
3397
|
+
--version, -v ${t("optVersion")}
|
|
3398
|
+
|
|
3399
|
+
`);
|
|
3400
|
+
}
|
|
3401
|
+
async function main() {
|
|
3402
|
+
const args = process.argv.slice(2);
|
|
3403
|
+
let explicitLang;
|
|
3404
|
+
for (let i = 0;i < args.length; i++) {
|
|
3405
|
+
if (args[i].startsWith("--lang=")) {
|
|
3406
|
+
explicitLang = args[i].split("=")[1];
|
|
3407
|
+
} else if (args[i] === "--lang" && args[i + 1]) {
|
|
3408
|
+
explicitLang = args[i + 1];
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
detectLocale(explicitLang);
|
|
3412
|
+
if (args.includes("--help") || args.includes("-h") || args[0] === "help") {
|
|
3413
|
+
printHelp();
|
|
3414
|
+
process.exit(0);
|
|
3415
|
+
}
|
|
3416
|
+
if (args.includes("--version") || args.includes("-v") || args[0] === "version") {
|
|
3417
|
+
process.stdout.write(`synapse-kit v${package_default.version}
|
|
3418
|
+
`);
|
|
3419
|
+
process.exit(0);
|
|
3420
|
+
}
|
|
3421
|
+
const command = args.find((a) => !a.startsWith("-")) || "check";
|
|
3422
|
+
if (command === "init") {
|
|
3423
|
+
const code = await handleInit();
|
|
3424
|
+
process.exit(code);
|
|
3425
|
+
}
|
|
3426
|
+
const isInteractive = args.includes("--interactive") || args.includes("-i");
|
|
3427
|
+
const isForce = args.includes("--force") || args.includes("-f");
|
|
3428
|
+
const options = {
|
|
3429
|
+
mode: args.includes("--all") ? "all" : "smart",
|
|
3430
|
+
agentMode: args.includes("--agent") || args.includes("--compact"),
|
|
3431
|
+
compactMode: args.includes("--compact"),
|
|
3432
|
+
watch: args.includes("--watch"),
|
|
3433
|
+
interactive: isInteractive,
|
|
3434
|
+
force: isForce
|
|
3435
|
+
};
|
|
3436
|
+
if (command === "memory") {
|
|
3437
|
+
const code = await handleMemoryCommand(args, options);
|
|
3438
|
+
process.exit(code);
|
|
3439
|
+
}
|
|
3440
|
+
try {
|
|
3441
|
+
const { config } = await loadSynapseConfig();
|
|
3442
|
+
if (command === "check") {
|
|
3443
|
+
const code = await executeChecks(config, options);
|
|
3444
|
+
process.exit(code);
|
|
3445
|
+
} else if (command === "build") {
|
|
3446
|
+
const code = await executeBuild(config, options);
|
|
3447
|
+
process.exit(code);
|
|
3448
|
+
} else if (command === "package") {
|
|
3449
|
+
const code = await executePackage(config, options);
|
|
3450
|
+
process.exit(code);
|
|
3451
|
+
} else if (command === "sign") {
|
|
3452
|
+
const code = await executeSign(config, options);
|
|
3453
|
+
process.exit(code);
|
|
3454
|
+
} else {
|
|
3455
|
+
process.stderr.write(`${RED5}\u274C ${t("unknownCmd")} '${command}'${RESET5}
|
|
3456
|
+
`);
|
|
3457
|
+
printHelp();
|
|
3458
|
+
process.exit(1);
|
|
3459
|
+
}
|
|
3460
|
+
} catch (error) {
|
|
3461
|
+
if (options.agentMode) {
|
|
3462
|
+
process.stdout.write(JSON.stringify({
|
|
3463
|
+
success: false,
|
|
3464
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3465
|
+
}) + `
|
|
3466
|
+
`);
|
|
3467
|
+
} else {
|
|
3468
|
+
process.stderr.write(`${RED5}${t("errPrefix")}${RESET5} ${error instanceof Error ? error.message : String(error)}
|
|
3469
|
+
`);
|
|
3470
|
+
}
|
|
3471
|
+
process.exit(1);
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
main();
|