memorix 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +197 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +93 -10
- package/dist/dashboard/static/style.css +150 -0
- package/dist/index.js +182 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -1799,6 +1799,89 @@ var init_copilot = __esm({
|
|
|
1799
1799
|
}
|
|
1800
1800
|
});
|
|
1801
1801
|
|
|
1802
|
+
// src/rules/adapters/kiro.ts
|
|
1803
|
+
import matter7 from "gray-matter";
|
|
1804
|
+
var KiroAdapter;
|
|
1805
|
+
var init_kiro = __esm({
|
|
1806
|
+
"src/rules/adapters/kiro.ts"() {
|
|
1807
|
+
"use strict";
|
|
1808
|
+
init_esm_shims();
|
|
1809
|
+
init_utils();
|
|
1810
|
+
KiroAdapter = class {
|
|
1811
|
+
source = "kiro";
|
|
1812
|
+
filePatterns = [
|
|
1813
|
+
".kiro/steering/*.md",
|
|
1814
|
+
"AGENTS.md"
|
|
1815
|
+
];
|
|
1816
|
+
parse(filePath, content) {
|
|
1817
|
+
if (filePath.includes(".kiro/steering/")) {
|
|
1818
|
+
return this.parseSteeringRule(filePath, content);
|
|
1819
|
+
}
|
|
1820
|
+
if (filePath.endsWith("AGENTS.md")) {
|
|
1821
|
+
return this.parseAgentsMd(filePath, content);
|
|
1822
|
+
}
|
|
1823
|
+
return [];
|
|
1824
|
+
}
|
|
1825
|
+
generate(rules) {
|
|
1826
|
+
return rules.map((rule, i) => {
|
|
1827
|
+
const fm = {};
|
|
1828
|
+
if (rule.description) fm.description = rule.description;
|
|
1829
|
+
if (rule.paths && rule.paths.length > 0) {
|
|
1830
|
+
fm.inclusion = "fileMatch";
|
|
1831
|
+
fm.fileMatchPattern = rule.paths.length === 1 ? rule.paths[0] : rule.paths;
|
|
1832
|
+
} else if (rule.alwaysApply) {
|
|
1833
|
+
fm.inclusion = "always";
|
|
1834
|
+
}
|
|
1835
|
+
const fileName = rule.id.replace(/^kiro:/, "").replace(/[^a-zA-Z0-9-_]/g, "-") || `rule-${i}`;
|
|
1836
|
+
const body = Object.keys(fm).length > 0 ? matter7.stringify(rule.content, fm) : rule.content;
|
|
1837
|
+
return {
|
|
1838
|
+
filePath: `.kiro/steering/${fileName}.md`,
|
|
1839
|
+
content: body
|
|
1840
|
+
};
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
parseSteeringRule(filePath, content) {
|
|
1844
|
+
const { data, content: body } = matter7(content);
|
|
1845
|
+
const trimmed = body.trim();
|
|
1846
|
+
if (!trimmed) return [];
|
|
1847
|
+
const inclusion = data.inclusion ?? "always";
|
|
1848
|
+
const alwaysApply = inclusion === "always" || inclusion === "auto";
|
|
1849
|
+
let paths;
|
|
1850
|
+
if (inclusion === "fileMatch" && data.fileMatchPattern) {
|
|
1851
|
+
paths = Array.isArray(data.fileMatchPattern) ? data.fileMatchPattern : [data.fileMatchPattern];
|
|
1852
|
+
}
|
|
1853
|
+
let scope = "project";
|
|
1854
|
+
if (alwaysApply) scope = "global";
|
|
1855
|
+
else if (paths && paths.length > 0) scope = "path-specific";
|
|
1856
|
+
return [{
|
|
1857
|
+
id: generateRuleId("kiro", filePath),
|
|
1858
|
+
content: trimmed,
|
|
1859
|
+
description: data.description,
|
|
1860
|
+
source: "kiro",
|
|
1861
|
+
scope,
|
|
1862
|
+
paths,
|
|
1863
|
+
alwaysApply,
|
|
1864
|
+
priority: alwaysApply ? 10 : 5,
|
|
1865
|
+
hash: hashContent(trimmed)
|
|
1866
|
+
}];
|
|
1867
|
+
}
|
|
1868
|
+
parseAgentsMd(filePath, content) {
|
|
1869
|
+
const trimmed = content.trim();
|
|
1870
|
+
if (!trimmed) return [];
|
|
1871
|
+
return [{
|
|
1872
|
+
id: generateRuleId("kiro", filePath),
|
|
1873
|
+
content: trimmed,
|
|
1874
|
+
source: "kiro",
|
|
1875
|
+
scope: "project",
|
|
1876
|
+
alwaysApply: true,
|
|
1877
|
+
priority: 10,
|
|
1878
|
+
hash: hashContent(trimmed)
|
|
1879
|
+
}];
|
|
1880
|
+
}
|
|
1881
|
+
};
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1802
1885
|
// src/rules/syncer.ts
|
|
1803
1886
|
var syncer_exports = {};
|
|
1804
1887
|
__export(syncer_exports, {
|
|
@@ -1817,6 +1900,7 @@ var init_syncer = __esm({
|
|
|
1817
1900
|
init_windsurf();
|
|
1818
1901
|
init_antigravity();
|
|
1819
1902
|
init_copilot();
|
|
1903
|
+
init_kiro();
|
|
1820
1904
|
RulesSyncer = class {
|
|
1821
1905
|
projectRoot;
|
|
1822
1906
|
adapters;
|
|
@@ -1829,7 +1913,8 @@ var init_syncer = __esm({
|
|
|
1829
1913
|
new CodexAdapter(),
|
|
1830
1914
|
new WindsurfAdapter(),
|
|
1831
1915
|
new AntigravityAdapter(),
|
|
1832
|
-
new CopilotAdapter()
|
|
1916
|
+
new CopilotAdapter(),
|
|
1917
|
+
new KiroAdapter()
|
|
1833
1918
|
];
|
|
1834
1919
|
for (const a of all) {
|
|
1835
1920
|
this.adapters.set(a.source, a);
|
|
@@ -2438,8 +2523,60 @@ var init_antigravity2 = __esm({
|
|
|
2438
2523
|
}
|
|
2439
2524
|
});
|
|
2440
2525
|
|
|
2526
|
+
// src/workspace/mcp-adapters/kiro.ts
|
|
2527
|
+
import { homedir as homedir7 } from "os";
|
|
2528
|
+
import { join as join7 } from "path";
|
|
2529
|
+
var KiroMCPAdapter;
|
|
2530
|
+
var init_kiro2 = __esm({
|
|
2531
|
+
"src/workspace/mcp-adapters/kiro.ts"() {
|
|
2532
|
+
"use strict";
|
|
2533
|
+
init_esm_shims();
|
|
2534
|
+
KiroMCPAdapter = class {
|
|
2535
|
+
source = "kiro";
|
|
2536
|
+
parse(content) {
|
|
2537
|
+
try {
|
|
2538
|
+
const config = JSON.parse(content);
|
|
2539
|
+
const servers = config.mcpServers ?? {};
|
|
2540
|
+
return Object.entries(servers).map(([name, entry]) => ({
|
|
2541
|
+
name,
|
|
2542
|
+
command: entry.command ?? "",
|
|
2543
|
+
args: entry.args ?? [],
|
|
2544
|
+
...entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {},
|
|
2545
|
+
...entry.url ? { url: entry.url } : {}
|
|
2546
|
+
}));
|
|
2547
|
+
} catch {
|
|
2548
|
+
return [];
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
generate(servers) {
|
|
2552
|
+
const mcpServers = {};
|
|
2553
|
+
for (const s of servers) {
|
|
2554
|
+
const entry = {};
|
|
2555
|
+
if (s.url) {
|
|
2556
|
+
entry.url = s.url;
|
|
2557
|
+
} else {
|
|
2558
|
+
entry.command = s.command;
|
|
2559
|
+
entry.args = s.args;
|
|
2560
|
+
}
|
|
2561
|
+
if (s.env && Object.keys(s.env).length > 0) {
|
|
2562
|
+
entry.env = s.env;
|
|
2563
|
+
}
|
|
2564
|
+
mcpServers[s.name] = entry;
|
|
2565
|
+
}
|
|
2566
|
+
return JSON.stringify({ mcpServers }, null, 2);
|
|
2567
|
+
}
|
|
2568
|
+
getConfigPath(projectRoot) {
|
|
2569
|
+
if (projectRoot) {
|
|
2570
|
+
return join7(projectRoot, ".kiro", "settings", "mcp.json");
|
|
2571
|
+
}
|
|
2572
|
+
return join7(homedir7(), ".kiro", "settings", "mcp.json");
|
|
2573
|
+
}
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
});
|
|
2577
|
+
|
|
2441
2578
|
// src/workspace/workflow-sync.ts
|
|
2442
|
-
import
|
|
2579
|
+
import matter8 from "gray-matter";
|
|
2443
2580
|
var WorkflowSyncer;
|
|
2444
2581
|
var init_workflow_sync = __esm({
|
|
2445
2582
|
"src/workspace/workflow-sync.ts"() {
|
|
@@ -2454,7 +2591,7 @@ var init_workflow_sync = __esm({
|
|
|
2454
2591
|
let description = "";
|
|
2455
2592
|
let content = raw;
|
|
2456
2593
|
try {
|
|
2457
|
-
const parsed =
|
|
2594
|
+
const parsed = matter8(raw);
|
|
2458
2595
|
description = parsed.data?.description ?? "";
|
|
2459
2596
|
content = parsed.content.trim();
|
|
2460
2597
|
} catch {
|
|
@@ -2476,7 +2613,7 @@ var init_workflow_sync = __esm({
|
|
|
2476
2613
|
if (wf.description) {
|
|
2477
2614
|
fm.description = wf.description;
|
|
2478
2615
|
}
|
|
2479
|
-
const content =
|
|
2616
|
+
const content = matter8.stringify(wf.content, fm);
|
|
2480
2617
|
return {
|
|
2481
2618
|
filePath: `.agents/skills/${safeName}/SKILL.md`,
|
|
2482
2619
|
content
|
|
@@ -2493,7 +2630,7 @@ var init_workflow_sync = __esm({
|
|
|
2493
2630
|
}
|
|
2494
2631
|
fm.globs = "";
|
|
2495
2632
|
fm.alwaysApply = "false";
|
|
2496
|
-
const content =
|
|
2633
|
+
const content = matter8.stringify(wf.content, fm);
|
|
2497
2634
|
return {
|
|
2498
2635
|
filePath: `.cursor/rules/${safeName}.mdc`,
|
|
2499
2636
|
content
|
|
@@ -2681,8 +2818,8 @@ var init_applier = __esm({
|
|
|
2681
2818
|
|
|
2682
2819
|
// src/workspace/engine.ts
|
|
2683
2820
|
import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync4, cpSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2684
|
-
import { join as
|
|
2685
|
-
import { homedir as
|
|
2821
|
+
import { join as join9 } from "path";
|
|
2822
|
+
import { homedir as homedir8 } from "os";
|
|
2686
2823
|
var WorkspaceSyncEngine;
|
|
2687
2824
|
var init_engine2 = __esm({
|
|
2688
2825
|
"src/workspace/engine.ts"() {
|
|
@@ -2694,6 +2831,7 @@ var init_engine2 = __esm({
|
|
|
2694
2831
|
init_claude_code2();
|
|
2695
2832
|
init_copilot2();
|
|
2696
2833
|
init_antigravity2();
|
|
2834
|
+
init_kiro2();
|
|
2697
2835
|
init_workflow_sync();
|
|
2698
2836
|
init_syncer();
|
|
2699
2837
|
init_sanitizer();
|
|
@@ -2707,7 +2845,8 @@ var init_engine2 = __esm({
|
|
|
2707
2845
|
["codex", new CodexMCPAdapter()],
|
|
2708
2846
|
["claude-code", new ClaudeCodeMCPAdapter()],
|
|
2709
2847
|
["copilot", new CopilotMCPAdapter()],
|
|
2710
|
-
["antigravity", new AntigravityMCPAdapter()]
|
|
2848
|
+
["antigravity", new AntigravityMCPAdapter()],
|
|
2849
|
+
["kiro", new KiroMCPAdapter()]
|
|
2711
2850
|
]);
|
|
2712
2851
|
this.workflowSyncer = new WorkflowSyncer();
|
|
2713
2852
|
this.rulesSyncer = new RulesSyncer(projectRoot);
|
|
@@ -2725,7 +2864,8 @@ var init_engine2 = __esm({
|
|
|
2725
2864
|
codex: [],
|
|
2726
2865
|
"claude-code": [],
|
|
2727
2866
|
copilot: [],
|
|
2728
|
-
antigravity: []
|
|
2867
|
+
antigravity: [],
|
|
2868
|
+
kiro: []
|
|
2729
2869
|
};
|
|
2730
2870
|
for (const [target, adapter] of this.adapters) {
|
|
2731
2871
|
const configPath = adapter.getConfigPath(this.projectRoot);
|
|
@@ -2817,13 +2957,14 @@ var init_engine2 = __esm({
|
|
|
2817
2957
|
windsurf: [".windsurf/skills"],
|
|
2818
2958
|
"claude-code": [".claude/skills"],
|
|
2819
2959
|
copilot: [".github/skills", ".copilot/skills"],
|
|
2820
|
-
antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"]
|
|
2960
|
+
antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"],
|
|
2961
|
+
kiro: [".kiro/skills"]
|
|
2821
2962
|
};
|
|
2822
2963
|
/** Get the target skills directory for an agent (null if agent has no skills support) */
|
|
2823
2964
|
getTargetSkillsDir(target) {
|
|
2824
2965
|
const dirs = _WorkspaceSyncEngine.SKILLS_DIRS[target];
|
|
2825
2966
|
if (!dirs || dirs.length === 0) return null;
|
|
2826
|
-
return
|
|
2967
|
+
return join9(this.projectRoot, dirs[0]);
|
|
2827
2968
|
}
|
|
2828
2969
|
/**
|
|
2829
2970
|
* Scan all agent skills directories and collect unique skills.
|
|
@@ -2832,12 +2973,12 @@ var init_engine2 = __esm({
|
|
|
2832
2973
|
const skills = [];
|
|
2833
2974
|
const conflicts = [];
|
|
2834
2975
|
const seen = /* @__PURE__ */ new Map();
|
|
2835
|
-
const home =
|
|
2976
|
+
const home = homedir8();
|
|
2836
2977
|
for (const [agent, dirs] of Object.entries(_WorkspaceSyncEngine.SKILLS_DIRS)) {
|
|
2837
2978
|
for (const dir of dirs) {
|
|
2838
2979
|
const paths = [
|
|
2839
|
-
|
|
2840
|
-
|
|
2980
|
+
join9(this.projectRoot, dir),
|
|
2981
|
+
join9(home, dir)
|
|
2841
2982
|
];
|
|
2842
2983
|
for (const skillsRoot of paths) {
|
|
2843
2984
|
if (!existsSync4(skillsRoot)) continue;
|
|
@@ -2845,7 +2986,7 @@ var init_engine2 = __esm({
|
|
|
2845
2986
|
const entries = readdirSync(skillsRoot, { withFileTypes: true });
|
|
2846
2987
|
for (const entry of entries) {
|
|
2847
2988
|
if (!entry.isDirectory()) continue;
|
|
2848
|
-
const skillMd =
|
|
2989
|
+
const skillMd = join9(skillsRoot, entry.name, "SKILL.md");
|
|
2849
2990
|
if (!existsSync4(skillMd)) continue;
|
|
2850
2991
|
let description = "";
|
|
2851
2992
|
try {
|
|
@@ -2857,7 +2998,7 @@ var init_engine2 = __esm({
|
|
|
2857
2998
|
const newEntry = {
|
|
2858
2999
|
name: entry.name,
|
|
2859
3000
|
description,
|
|
2860
|
-
sourcePath:
|
|
3001
|
+
sourcePath: join9(skillsRoot, entry.name),
|
|
2861
3002
|
sourceAgent: agent
|
|
2862
3003
|
};
|
|
2863
3004
|
const existing = seen.get(entry.name);
|
|
@@ -2894,7 +3035,7 @@ var init_engine2 = __esm({
|
|
|
2894
3035
|
}
|
|
2895
3036
|
for (const skill of skills) {
|
|
2896
3037
|
if (skill.sourceAgent === target) continue;
|
|
2897
|
-
const dest =
|
|
3038
|
+
const dest = join9(targetDir, skill.name);
|
|
2898
3039
|
if (existsSync4(dest)) {
|
|
2899
3040
|
skipped.push(`${skill.name} (already exists in ${target})`);
|
|
2900
3041
|
continue;
|
|
@@ -2910,13 +3051,13 @@ var init_engine2 = __esm({
|
|
|
2910
3051
|
}
|
|
2911
3052
|
scanWorkflows() {
|
|
2912
3053
|
const workflows = [];
|
|
2913
|
-
const wfDir =
|
|
3054
|
+
const wfDir = join9(this.projectRoot, ".windsurf", "workflows");
|
|
2914
3055
|
if (!existsSync4(wfDir)) return workflows;
|
|
2915
3056
|
try {
|
|
2916
3057
|
const files = readdirSync(wfDir).filter((f) => f.endsWith(".md"));
|
|
2917
3058
|
for (const file of files) {
|
|
2918
3059
|
try {
|
|
2919
|
-
const content = readFileSync2(
|
|
3060
|
+
const content = readFileSync2(join9(wfDir, file), "utf-8");
|
|
2920
3061
|
workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));
|
|
2921
3062
|
} catch {
|
|
2922
3063
|
}
|
|
@@ -3004,7 +3145,8 @@ var init_engine2 = __esm({
|
|
|
3004
3145
|
codex: "codex",
|
|
3005
3146
|
windsurf: "windsurf",
|
|
3006
3147
|
copilot: "copilot",
|
|
3007
|
-
antigravity: "antigravity"
|
|
3148
|
+
antigravity: "antigravity",
|
|
3149
|
+
kiro: "kiro"
|
|
3008
3150
|
};
|
|
3009
3151
|
return map[target] ?? null;
|
|
3010
3152
|
}
|
|
@@ -3670,8 +3812,42 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir) {
|
|
|
3670
3812
|
});
|
|
3671
3813
|
break;
|
|
3672
3814
|
}
|
|
3673
|
-
default:
|
|
3815
|
+
default: {
|
|
3816
|
+
const deleteMatch = apiPath.match(/^\/observations\/(\d+)$/);
|
|
3817
|
+
if (deleteMatch && req.method === "DELETE") {
|
|
3818
|
+
const obsId = parseInt(deleteMatch[1], 10);
|
|
3819
|
+
const allObs = await loadObservationsJson(effectiveDataDir);
|
|
3820
|
+
const idx = allObs.findIndex((o) => o.id === obsId);
|
|
3821
|
+
if (idx === -1) {
|
|
3822
|
+
sendError(res, "Observation not found", 404);
|
|
3823
|
+
} else {
|
|
3824
|
+
allObs.splice(idx, 1);
|
|
3825
|
+
await saveObservationsJson(effectiveDataDir, allObs);
|
|
3826
|
+
sendJson(res, { ok: true, deleted: obsId });
|
|
3827
|
+
}
|
|
3828
|
+
break;
|
|
3829
|
+
}
|
|
3830
|
+
if (apiPath === "/export") {
|
|
3831
|
+
const graph = await loadGraphJsonl(effectiveDataDir);
|
|
3832
|
+
const allObs = await loadObservationsJson(effectiveDataDir);
|
|
3833
|
+
const observations2 = filterByProject(allObs, effectiveProjectId);
|
|
3834
|
+
const nextId2 = await loadIdCounter(effectiveDataDir);
|
|
3835
|
+
const exportData = {
|
|
3836
|
+
project: { id: effectiveProjectId, name: effectiveProjectName },
|
|
3837
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3838
|
+
graph,
|
|
3839
|
+
observations: observations2,
|
|
3840
|
+
nextId: nextId2
|
|
3841
|
+
};
|
|
3842
|
+
res.writeHead(200, {
|
|
3843
|
+
"Content-Type": "application/json",
|
|
3844
|
+
"Content-Disposition": `attachment; filename="memorix-${effectiveProjectId.replace(/\//g, "-")}-export.json"`
|
|
3845
|
+
});
|
|
3846
|
+
res.end(JSON.stringify(exportData, null, 2));
|
|
3847
|
+
break;
|
|
3848
|
+
}
|
|
3674
3849
|
sendError(res, "Not found", 404);
|
|
3850
|
+
}
|
|
3675
3851
|
}
|
|
3676
3852
|
} catch (err) {
|
|
3677
3853
|
const message = err instanceof Error ? err.message : "Unknown error";
|