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.
@@ -42,6 +42,15 @@ const i18n = {
42
42
  noObsTitle: 'No Observations',
43
43
  noObsDesc: 'Use memorix_store to create observations',
44
44
  untitled: 'Untitled',
45
+ exportData: 'Export',
46
+ deleteObs: 'Delete',
47
+ deleteConfirm: 'Delete observation #%id%?',
48
+ deleted: 'Deleted',
49
+ narrative: 'Narrative',
50
+ facts: 'Facts',
51
+ concepts: 'Concepts',
52
+ files: 'Files Modified',
53
+ clickToExpand: 'Click to expand',
45
54
 
46
55
  // Retention
47
56
  memoryRetention: 'Memory Retention',
@@ -102,6 +111,15 @@ const i18n = {
102
111
  noObsTitle: '暂无观察记录',
103
112
  noObsDesc: '使用 memorix_store 创建观察记录',
104
113
  untitled: '无标题',
114
+ exportData: '导出',
115
+ deleteObs: '删除',
116
+ deleteConfirm: '确认删除观察 #%id%?',
117
+ deleted: '已删除',
118
+ narrative: '叙述',
119
+ facts: '事实',
120
+ concepts: '概念',
121
+ files: '相关文件',
122
+ clickToExpand: '点击展开',
105
123
 
106
124
  // Retention
107
125
  memoryRetention: '记忆衰减',
@@ -760,9 +778,15 @@ async function loadObservations() {
760
778
  const types = [...new Set(allObservations.map(o => o.type).filter(Boolean))];
761
779
 
762
780
  container.innerHTML = `
763
- <div class="page-header">
764
- <h1 class="page-title">${t('observations')}</h1>
765
- <p class="page-subtitle">${allObservations.length} ${t('observationsStored')}</p>
781
+ <div class="page-header" style="display:flex;align-items:center;justify-content:space-between;">
782
+ <div>
783
+ <h1 class="page-title">${t('observations')}</h1>
784
+ <p class="page-subtitle">${allObservations.length} ${t('observationsStored')}</p>
785
+ </div>
786
+ <button class="export-btn" id="btn-export" title="${t('exportData')}">
787
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 2v8M4 7l4 4 4-4M2 12v2h12v-2"/></svg>
788
+ ${t('exportData')}
789
+ </button>
766
790
  </div>
767
791
 
768
792
  <div class="search-bar">
@@ -774,6 +798,12 @@ async function loadObservations() {
774
798
  <div class="obs-grid" id="obs-list"></div>
775
799
  `;
776
800
 
801
+ // Export handler
802
+ document.getElementById('btn-export').addEventListener('click', () => {
803
+ const sep = selectedProject ? `?project=${encodeURIComponent(selectedProject)}` : '';
804
+ window.open(`/api/export${sep}`, '_blank');
805
+ });
806
+
777
807
  document.getElementById('obs-search').addEventListener('input', (e) => {
778
808
  obsFilter = e.target.value.toLowerCase();
779
809
  renderObsList();
@@ -822,25 +852,32 @@ function renderObsList() {
822
852
  }
823
853
 
824
854
  list.innerHTML = filtered.map(obs => `
825
- <div class="obs-card">
826
- <div class="obs-card-header">
855
+ <div class="obs-card" data-obs-id="${obs.id}">
856
+ <div class="obs-card-header" onclick="toggleObsDetail(${obs.id})">
827
857
  <span class="obs-card-id">#${obs.id}</span>
828
858
  <span class="type-badge" data-type="${obs.type || 'unknown'}">
829
859
  ${typeIcons[obs.type] || '❓'} ${obs.type || 'unknown'}
830
860
  </span>
831
861
  <span class="obs-card-title">${escapeHtml(obs.title || t('untitled'))}</span>
862
+ <span class="obs-expand-icon">▼</span>
832
863
  </div>
833
864
  <div class="obs-card-meta">
834
865
  <span>📁 ${escapeHtml(obs.entityName || 'unknown')}</span>
835
866
  ${obs.createdAt ? `<span>🕐 ${formatTime(obs.createdAt)}</span>` : ''}
836
867
  ${obs.accessCount ? `<span>👁 ${obs.accessCount}</span>` : ''}
837
868
  </div>
838
- ${obs.narrative ? `<div class="obs-card-narrative">${escapeHtml(obs.narrative)}</div>` : ''}
839
- ${obs.facts && obs.facts.length > 0 ? `
840
- <div class="obs-card-facts">
841
- ${obs.facts.map(f => `<span class="fact-tag">${escapeHtml(f)}</span>`).join('')}
869
+ <div class="obs-detail" id="obs-detail-${obs.id}" style="display:none;">
870
+ ${obs.narrative ? `<div class="obs-detail-section"><label>${t('narrative')}</label><div class="obs-card-narrative">${escapeHtml(obs.narrative)}</div></div>` : ''}
871
+ ${obs.facts && obs.facts.length > 0 ? `<div class="obs-detail-section"><label>${t('facts')}</label><div class="obs-card-facts">${obs.facts.map(f => `<span class="fact-tag">${escapeHtml(f)}</span>`).join('')}</div></div>` : ''}
872
+ ${obs.concepts && obs.concepts.length > 0 ? `<div class="obs-detail-section"><label>${t('concepts')}</label><div class="obs-card-facts">${obs.concepts.map(c => `<span class="fact-tag concept-tag">${escapeHtml(c)}</span>`).join('')}</div></div>` : ''}
873
+ ${obs.filesModified && obs.filesModified.length > 0 ? `<div class="obs-detail-section"><label>${t('files')}</label><div class="obs-card-facts">${obs.filesModified.map(f => `<span class="fact-tag file-tag">${escapeHtml(f)}</span>`).join('')}</div></div>` : ''}
874
+ <div class="obs-detail-actions">
875
+ <button class="delete-btn" onclick="deleteObs(${obs.id}, event)">
876
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1M6 7v5M10 7v5M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>
877
+ ${t('deleteObs')}
878
+ </button>
842
879
  </div>
843
- ` : ''}
880
+ </div>
844
881
  </div>
845
882
  `).join('');
846
883
  }
@@ -931,6 +968,52 @@ async function loadRetention() {
931
968
  `;
932
969
  }
933
970
 
971
+ // ============================================================
972
+ // Observation Interactions
973
+ // ============================================================
974
+
975
+ function toggleObsDetail(id) {
976
+ const detail = document.getElementById(`obs-detail-${id}`);
977
+ const card = detail?.closest('.obs-card');
978
+ if (!detail || !card) return;
979
+
980
+ const isOpen = detail.style.display !== 'none';
981
+ detail.style.display = isOpen ? 'none' : 'block';
982
+ card.classList.toggle('expanded', !isOpen);
983
+
984
+ // Rotate expand icon
985
+ const icon = card.querySelector('.obs-expand-icon');
986
+ if (icon) icon.style.transform = isOpen ? '' : 'rotate(180deg)';
987
+ }
988
+
989
+ async function deleteObs(id, event) {
990
+ event?.stopPropagation();
991
+ const msg = t('deleteConfirm').replace('%id%', id);
992
+ if (!confirm(msg)) return;
993
+
994
+ try {
995
+ const sep = selectedProject ? `?project=${encodeURIComponent(selectedProject)}` : '';
996
+ const res = await fetch(`/api/observations/${id}${sep}`, { method: 'DELETE' });
997
+ const data = await res.json();
998
+ if (data.ok) {
999
+ // Remove from local array and re-render
1000
+ allObservations = allObservations.filter(o => o.id !== id);
1001
+ renderObsList();
1002
+ // Update counter in header
1003
+ const subtitle = document.querySelector('#page-observations .page-subtitle');
1004
+ if (subtitle) subtitle.textContent = `${allObservations.length} ${t('observationsStored')}`;
1005
+ } else {
1006
+ alert(data.error || 'Delete failed');
1007
+ }
1008
+ } catch (err) {
1009
+ alert('Delete failed: ' + err.message);
1010
+ }
1011
+ }
1012
+
1013
+ // Make functions globally accessible for onclick handlers
1014
+ window.toggleObsDetail = toggleObsDetail;
1015
+ window.deleteObs = deleteObs;
1016
+
934
1017
  // ============================================================
935
1018
  // Utilities
936
1019
  // ============================================================
@@ -1092,4 +1092,154 @@ body {
1092
1092
  color: var(--text-primary);
1093
1093
  font-size: 12px;
1094
1094
  padding: 4px 8px;
1095
+ }
1096
+
1097
+ /* ============================================================
1098
+ * Export Button
1099
+ * ============================================================ */
1100
+
1101
+ .export-btn {
1102
+ display: flex;
1103
+ align-items: center;
1104
+ gap: 6px;
1105
+ padding: 8px 16px;
1106
+ background: var(--bg-card);
1107
+ border: 1px solid var(--border-subtle);
1108
+ border-radius: 8px;
1109
+ color: var(--text-secondary);
1110
+ font-size: 13px;
1111
+ font-family: var(--font-sans);
1112
+ cursor: pointer;
1113
+ transition: all 0.2s;
1114
+ }
1115
+
1116
+ .export-btn:hover {
1117
+ background: var(--bg-card-hover);
1118
+ border-color: var(--accent-cyan);
1119
+ color: var(--accent-cyan);
1120
+ box-shadow: var(--glow-cyan);
1121
+ }
1122
+
1123
+ /* ============================================================
1124
+ * Observation Card Enhancements
1125
+ * ============================================================ */
1126
+
1127
+ .obs-card {
1128
+ cursor: pointer;
1129
+ transition: all 0.25s ease;
1130
+ }
1131
+
1132
+ .obs-card:hover {
1133
+ border-color: var(--border-medium);
1134
+ transform: translateY(-1px);
1135
+ }
1136
+
1137
+ .obs-card.expanded {
1138
+ border-color: var(--accent-cyan);
1139
+ box-shadow: var(--glow-cyan);
1140
+ }
1141
+
1142
+ .obs-card-header {
1143
+ display: flex;
1144
+ align-items: center;
1145
+ gap: 8px;
1146
+ position: relative;
1147
+ }
1148
+
1149
+ .obs-expand-icon {
1150
+ margin-left: auto;
1151
+ font-size: 10px;
1152
+ color: var(--text-muted);
1153
+ transition: transform 0.25s ease;
1154
+ flex-shrink: 0;
1155
+ }
1156
+
1157
+ .obs-card:hover .obs-expand-icon {
1158
+ color: var(--text-secondary);
1159
+ }
1160
+
1161
+ /* Observation Detail Section */
1162
+ .obs-detail {
1163
+ margin-top: 12px;
1164
+ padding-top: 12px;
1165
+ border-top: 1px solid var(--border-subtle);
1166
+ animation: slideDown 0.2s ease;
1167
+ }
1168
+
1169
+ @keyframes slideDown {
1170
+ from {
1171
+ opacity: 0;
1172
+ transform: translateY(-8px);
1173
+ }
1174
+
1175
+ to {
1176
+ opacity: 1;
1177
+ transform: translateY(0);
1178
+ }
1179
+ }
1180
+
1181
+ .obs-detail-section {
1182
+ margin-bottom: 12px;
1183
+ }
1184
+
1185
+ .obs-detail-section label {
1186
+ display: block;
1187
+ font-size: 11px;
1188
+ font-weight: 600;
1189
+ color: var(--text-muted);
1190
+ text-transform: uppercase;
1191
+ letter-spacing: 0.5px;
1192
+ margin-bottom: 6px;
1193
+ }
1194
+
1195
+ .obs-detail-section .obs-card-narrative {
1196
+ -webkit-line-clamp: unset;
1197
+ white-space: pre-wrap;
1198
+ max-height: none;
1199
+ }
1200
+
1201
+ /* Tag variants */
1202
+ .concept-tag {
1203
+ background: rgba(168, 85, 247, 0.1) !important;
1204
+ border-color: rgba(168, 85, 247, 0.2) !important;
1205
+ color: var(--accent-purple) !important;
1206
+ }
1207
+
1208
+ .file-tag {
1209
+ background: rgba(59, 130, 246, 0.1) !important;
1210
+ border-color: rgba(59, 130, 246, 0.2) !important;
1211
+ color: var(--accent-blue) !important;
1212
+ font-family: var(--font-mono);
1213
+ font-size: 11px !important;
1214
+ }
1215
+
1216
+ /* Delete Button */
1217
+ .obs-detail-actions {
1218
+ display: flex;
1219
+ justify-content: flex-end;
1220
+ margin-top: 12px;
1221
+ padding-top: 8px;
1222
+ border-top: 1px solid var(--border-subtle);
1223
+ }
1224
+
1225
+ .delete-btn {
1226
+ display: flex;
1227
+ align-items: center;
1228
+ gap: 5px;
1229
+ padding: 6px 12px;
1230
+ background: transparent;
1231
+ border: 1px solid rgba(239, 68, 68, 0.2);
1232
+ border-radius: 6px;
1233
+ color: var(--accent-red);
1234
+ font-size: 12px;
1235
+ font-family: var(--font-sans);
1236
+ cursor: pointer;
1237
+ transition: all 0.2s;
1238
+ opacity: 0.7;
1239
+ }
1240
+
1241
+ .delete-btn:hover {
1242
+ background: rgba(239, 68, 68, 0.1);
1243
+ border-color: var(--accent-red);
1244
+ opacity: 1;
1095
1245
  }
package/dist/index.js CHANGED
@@ -1261,8 +1261,42 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir) {
1261
1261
  });
1262
1262
  break;
1263
1263
  }
1264
- default:
1264
+ default: {
1265
+ const deleteMatch = apiPath.match(/^\/observations\/(\d+)$/);
1266
+ if (deleteMatch && req.method === "DELETE") {
1267
+ const obsId = parseInt(deleteMatch[1], 10);
1268
+ const allObs = await loadObservationsJson(effectiveDataDir);
1269
+ const idx = allObs.findIndex((o) => o.id === obsId);
1270
+ if (idx === -1) {
1271
+ sendError(res, "Observation not found", 404);
1272
+ } else {
1273
+ allObs.splice(idx, 1);
1274
+ await saveObservationsJson(effectiveDataDir, allObs);
1275
+ sendJson(res, { ok: true, deleted: obsId });
1276
+ }
1277
+ break;
1278
+ }
1279
+ if (apiPath === "/export") {
1280
+ const graph = await loadGraphJsonl(effectiveDataDir);
1281
+ const allObs = await loadObservationsJson(effectiveDataDir);
1282
+ const observations2 = filterByProject(allObs, effectiveProjectId);
1283
+ const nextId2 = await loadIdCounter(effectiveDataDir);
1284
+ const exportData = {
1285
+ project: { id: effectiveProjectId, name: effectiveProjectName },
1286
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1287
+ graph,
1288
+ observations: observations2,
1289
+ nextId: nextId2
1290
+ };
1291
+ res.writeHead(200, {
1292
+ "Content-Type": "application/json",
1293
+ "Content-Disposition": `attachment; filename="memorix-${effectiveProjectId.replace(/\//g, "-")}-export.json"`
1294
+ });
1295
+ res.end(JSON.stringify(exportData, null, 2));
1296
+ break;
1297
+ }
1265
1298
  sendError(res, "Not found", 404);
1299
+ }
1266
1300
  }
1267
1301
  } catch (err) {
1268
1302
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -2464,6 +2498,82 @@ var CopilotAdapter = class {
2464
2498
  }
2465
2499
  };
2466
2500
 
2501
+ // src/rules/adapters/kiro.ts
2502
+ init_esm_shims();
2503
+ import matter7 from "gray-matter";
2504
+ var KiroAdapter = class {
2505
+ source = "kiro";
2506
+ filePatterns = [
2507
+ ".kiro/steering/*.md",
2508
+ "AGENTS.md"
2509
+ ];
2510
+ parse(filePath, content) {
2511
+ if (filePath.includes(".kiro/steering/")) {
2512
+ return this.parseSteeringRule(filePath, content);
2513
+ }
2514
+ if (filePath.endsWith("AGENTS.md")) {
2515
+ return this.parseAgentsMd(filePath, content);
2516
+ }
2517
+ return [];
2518
+ }
2519
+ generate(rules) {
2520
+ return rules.map((rule, i) => {
2521
+ const fm = {};
2522
+ if (rule.description) fm.description = rule.description;
2523
+ if (rule.paths && rule.paths.length > 0) {
2524
+ fm.inclusion = "fileMatch";
2525
+ fm.fileMatchPattern = rule.paths.length === 1 ? rule.paths[0] : rule.paths;
2526
+ } else if (rule.alwaysApply) {
2527
+ fm.inclusion = "always";
2528
+ }
2529
+ const fileName = rule.id.replace(/^kiro:/, "").replace(/[^a-zA-Z0-9-_]/g, "-") || `rule-${i}`;
2530
+ const body = Object.keys(fm).length > 0 ? matter7.stringify(rule.content, fm) : rule.content;
2531
+ return {
2532
+ filePath: `.kiro/steering/${fileName}.md`,
2533
+ content: body
2534
+ };
2535
+ });
2536
+ }
2537
+ parseSteeringRule(filePath, content) {
2538
+ const { data, content: body } = matter7(content);
2539
+ const trimmed = body.trim();
2540
+ if (!trimmed) return [];
2541
+ const inclusion = data.inclusion ?? "always";
2542
+ const alwaysApply = inclusion === "always" || inclusion === "auto";
2543
+ let paths;
2544
+ if (inclusion === "fileMatch" && data.fileMatchPattern) {
2545
+ paths = Array.isArray(data.fileMatchPattern) ? data.fileMatchPattern : [data.fileMatchPattern];
2546
+ }
2547
+ let scope = "project";
2548
+ if (alwaysApply) scope = "global";
2549
+ else if (paths && paths.length > 0) scope = "path-specific";
2550
+ return [{
2551
+ id: generateRuleId("kiro", filePath),
2552
+ content: trimmed,
2553
+ description: data.description,
2554
+ source: "kiro",
2555
+ scope,
2556
+ paths,
2557
+ alwaysApply,
2558
+ priority: alwaysApply ? 10 : 5,
2559
+ hash: hashContent(trimmed)
2560
+ }];
2561
+ }
2562
+ parseAgentsMd(filePath, content) {
2563
+ const trimmed = content.trim();
2564
+ if (!trimmed) return [];
2565
+ return [{
2566
+ id: generateRuleId("kiro", filePath),
2567
+ content: trimmed,
2568
+ source: "kiro",
2569
+ scope: "project",
2570
+ alwaysApply: true,
2571
+ priority: 10,
2572
+ hash: hashContent(trimmed)
2573
+ }];
2574
+ }
2575
+ };
2576
+
2467
2577
  // src/rules/syncer.ts
2468
2578
  var RulesSyncer = class {
2469
2579
  projectRoot;
@@ -2477,7 +2587,8 @@ var RulesSyncer = class {
2477
2587
  new CodexAdapter(),
2478
2588
  new WindsurfAdapter(),
2479
2589
  new AntigravityAdapter(),
2480
- new CopilotAdapter()
2590
+ new CopilotAdapter(),
2591
+ new KiroAdapter()
2481
2592
  ];
2482
2593
  for (const a of all) {
2483
2594
  this.adapters.set(a.source, a);
@@ -2619,8 +2730,8 @@ var RulesSyncer = class {
2619
2730
  // src/workspace/engine.ts
2620
2731
  init_esm_shims();
2621
2732
  import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync4, cpSync, mkdirSync as mkdirSync2 } from "fs";
2622
- import { join as join8 } from "path";
2623
- import { homedir as homedir7 } from "os";
2733
+ import { join as join9 } from "path";
2734
+ import { homedir as homedir8 } from "os";
2624
2735
 
2625
2736
  // src/workspace/mcp-adapters/windsurf.ts
2626
2737
  init_esm_shims();
@@ -3054,9 +3165,55 @@ var AntigravityMCPAdapter = class {
3054
3165
  }
3055
3166
  };
3056
3167
 
3168
+ // src/workspace/mcp-adapters/kiro.ts
3169
+ init_esm_shims();
3170
+ import { homedir as homedir7 } from "os";
3171
+ import { join as join7 } from "path";
3172
+ var KiroMCPAdapter = class {
3173
+ source = "kiro";
3174
+ parse(content) {
3175
+ try {
3176
+ const config = JSON.parse(content);
3177
+ const servers = config.mcpServers ?? {};
3178
+ return Object.entries(servers).map(([name, entry]) => ({
3179
+ name,
3180
+ command: entry.command ?? "",
3181
+ args: entry.args ?? [],
3182
+ ...entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {},
3183
+ ...entry.url ? { url: entry.url } : {}
3184
+ }));
3185
+ } catch {
3186
+ return [];
3187
+ }
3188
+ }
3189
+ generate(servers) {
3190
+ const mcpServers = {};
3191
+ for (const s of servers) {
3192
+ const entry = {};
3193
+ if (s.url) {
3194
+ entry.url = s.url;
3195
+ } else {
3196
+ entry.command = s.command;
3197
+ entry.args = s.args;
3198
+ }
3199
+ if (s.env && Object.keys(s.env).length > 0) {
3200
+ entry.env = s.env;
3201
+ }
3202
+ mcpServers[s.name] = entry;
3203
+ }
3204
+ return JSON.stringify({ mcpServers }, null, 2);
3205
+ }
3206
+ getConfigPath(projectRoot) {
3207
+ if (projectRoot) {
3208
+ return join7(projectRoot, ".kiro", "settings", "mcp.json");
3209
+ }
3210
+ return join7(homedir7(), ".kiro", "settings", "mcp.json");
3211
+ }
3212
+ };
3213
+
3057
3214
  // src/workspace/workflow-sync.ts
3058
3215
  init_esm_shims();
3059
- import matter7 from "gray-matter";
3216
+ import matter8 from "gray-matter";
3060
3217
  var WorkflowSyncer = class {
3061
3218
  /**
3062
3219
  * Parse a Windsurf workflow markdown file into a WorkflowEntry.
@@ -3066,7 +3223,7 @@ var WorkflowSyncer = class {
3066
3223
  let description = "";
3067
3224
  let content = raw;
3068
3225
  try {
3069
- const parsed = matter7(raw);
3226
+ const parsed = matter8(raw);
3070
3227
  description = parsed.data?.description ?? "";
3071
3228
  content = parsed.content.trim();
3072
3229
  } catch {
@@ -3088,7 +3245,7 @@ var WorkflowSyncer = class {
3088
3245
  if (wf.description) {
3089
3246
  fm.description = wf.description;
3090
3247
  }
3091
- const content = matter7.stringify(wf.content, fm);
3248
+ const content = matter8.stringify(wf.content, fm);
3092
3249
  return {
3093
3250
  filePath: `.agents/skills/${safeName}/SKILL.md`,
3094
3251
  content
@@ -3105,7 +3262,7 @@ var WorkflowSyncer = class {
3105
3262
  }
3106
3263
  fm.globs = "";
3107
3264
  fm.alwaysApply = "false";
3108
- const content = matter7.stringify(wf.content, fm);
3265
+ const content = matter8.stringify(wf.content, fm);
3109
3266
  return {
3110
3267
  filePath: `.cursor/rules/${safeName}.mdc`,
3111
3268
  content
@@ -3287,7 +3444,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3287
3444
  ["codex", new CodexMCPAdapter()],
3288
3445
  ["claude-code", new ClaudeCodeMCPAdapter()],
3289
3446
  ["copilot", new CopilotMCPAdapter()],
3290
- ["antigravity", new AntigravityMCPAdapter()]
3447
+ ["antigravity", new AntigravityMCPAdapter()],
3448
+ ["kiro", new KiroMCPAdapter()]
3291
3449
  ]);
3292
3450
  this.workflowSyncer = new WorkflowSyncer();
3293
3451
  this.rulesSyncer = new RulesSyncer(projectRoot);
@@ -3305,7 +3463,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3305
3463
  codex: [],
3306
3464
  "claude-code": [],
3307
3465
  copilot: [],
3308
- antigravity: []
3466
+ antigravity: [],
3467
+ kiro: []
3309
3468
  };
3310
3469
  for (const [target, adapter] of this.adapters) {
3311
3470
  const configPath = adapter.getConfigPath(this.projectRoot);
@@ -3397,13 +3556,14 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3397
3556
  windsurf: [".windsurf/skills"],
3398
3557
  "claude-code": [".claude/skills"],
3399
3558
  copilot: [".github/skills", ".copilot/skills"],
3400
- antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"]
3559
+ antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"],
3560
+ kiro: [".kiro/skills"]
3401
3561
  };
3402
3562
  /** Get the target skills directory for an agent (null if agent has no skills support) */
3403
3563
  getTargetSkillsDir(target) {
3404
3564
  const dirs = _WorkspaceSyncEngine.SKILLS_DIRS[target];
3405
3565
  if (!dirs || dirs.length === 0) return null;
3406
- return join8(this.projectRoot, dirs[0]);
3566
+ return join9(this.projectRoot, dirs[0]);
3407
3567
  }
3408
3568
  /**
3409
3569
  * Scan all agent skills directories and collect unique skills.
@@ -3412,12 +3572,12 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3412
3572
  const skills = [];
3413
3573
  const conflicts = [];
3414
3574
  const seen = /* @__PURE__ */ new Map();
3415
- const home = homedir7();
3575
+ const home = homedir8();
3416
3576
  for (const [agent, dirs] of Object.entries(_WorkspaceSyncEngine.SKILLS_DIRS)) {
3417
3577
  for (const dir of dirs) {
3418
3578
  const paths = [
3419
- join8(this.projectRoot, dir),
3420
- join8(home, dir)
3579
+ join9(this.projectRoot, dir),
3580
+ join9(home, dir)
3421
3581
  ];
3422
3582
  for (const skillsRoot of paths) {
3423
3583
  if (!existsSync4(skillsRoot)) continue;
@@ -3425,7 +3585,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3425
3585
  const entries = readdirSync(skillsRoot, { withFileTypes: true });
3426
3586
  for (const entry of entries) {
3427
3587
  if (!entry.isDirectory()) continue;
3428
- const skillMd = join8(skillsRoot, entry.name, "SKILL.md");
3588
+ const skillMd = join9(skillsRoot, entry.name, "SKILL.md");
3429
3589
  if (!existsSync4(skillMd)) continue;
3430
3590
  let description = "";
3431
3591
  try {
@@ -3437,7 +3597,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3437
3597
  const newEntry = {
3438
3598
  name: entry.name,
3439
3599
  description,
3440
- sourcePath: join8(skillsRoot, entry.name),
3600
+ sourcePath: join9(skillsRoot, entry.name),
3441
3601
  sourceAgent: agent
3442
3602
  };
3443
3603
  const existing = seen.get(entry.name);
@@ -3474,7 +3634,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3474
3634
  }
3475
3635
  for (const skill of skills) {
3476
3636
  if (skill.sourceAgent === target) continue;
3477
- const dest = join8(targetDir, skill.name);
3637
+ const dest = join9(targetDir, skill.name);
3478
3638
  if (existsSync4(dest)) {
3479
3639
  skipped.push(`${skill.name} (already exists in ${target})`);
3480
3640
  continue;
@@ -3490,13 +3650,13 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3490
3650
  }
3491
3651
  scanWorkflows() {
3492
3652
  const workflows = [];
3493
- const wfDir = join8(this.projectRoot, ".windsurf", "workflows");
3653
+ const wfDir = join9(this.projectRoot, ".windsurf", "workflows");
3494
3654
  if (!existsSync4(wfDir)) return workflows;
3495
3655
  try {
3496
3656
  const files = readdirSync(wfDir).filter((f) => f.endsWith(".md"));
3497
3657
  for (const file of files) {
3498
3658
  try {
3499
- const content = readFileSync2(join8(wfDir, file), "utf-8");
3659
+ const content = readFileSync2(join9(wfDir, file), "utf-8");
3500
3660
  workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));
3501
3661
  } catch {
3502
3662
  }
@@ -3584,7 +3744,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
3584
3744
  codex: "codex",
3585
3745
  windsurf: "windsurf",
3586
3746
  copilot: "copilot",
3587
- antigravity: "antigravity"
3747
+ antigravity: "antigravity",
3748
+ kiro: "kiro"
3588
3749
  };
3589
3750
  return map[target] ?? null;
3590
3751
  }