@synapsync/cli 0.1.5 → 0.1.6

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/index.js CHANGED
@@ -28,7 +28,7 @@ var init_version = __esm({
28
28
  "src/version.ts"() {
29
29
  "use strict";
30
30
  init_esm_shims();
31
- version = "0.1.5";
31
+ version = "0.1.6";
32
32
  }
33
33
  });
34
34
 
@@ -70,6 +70,7 @@ var COGNITIVE_FILE_NAMES = {
70
70
  };
71
71
  var DEFAULT_SYNAPSYNC_DIR = process.env["SYNAPSYNC_DIR"] ?? ".synapsync";
72
72
  var CONFIG_FILE_NAME = "synapsync.config.yaml";
73
+ var AGENTS_MD_FILE_NAME = "AGENTS.md";
73
74
  var DEFAULT_AGENTS_DIR = process.env["SYNAPSYNC_AGENTS_DIR"] ?? ".agents";
74
75
  var DEFAULT_SKILLS_SUBDIR = process.env["SYNAPSYNC_SKILLS_SUBDIR"] ?? "skills";
75
76
  var CATEGORIES = [
@@ -718,8 +719,8 @@ function registerInfoCommand(program) {
718
719
 
719
720
  // src/commands/init.ts
720
721
  init_esm_shims();
721
- import * as fs2 from "fs";
722
- import * as path3 from "path";
722
+ import * as fs5 from "fs";
723
+ import * as path6 from "path";
723
724
  import * as p from "@clack/prompts";
724
725
  import pc4 from "picocolors";
725
726
 
@@ -822,8 +823,8 @@ function validateConfig(config) {
822
823
  }
823
824
  return errors;
824
825
  }
825
- function getNestedValue(obj, path17) {
826
- const parts = path17.split(".");
826
+ function getNestedValue(obj, path18) {
827
+ const parts = path18.split(".");
827
828
  let current = obj;
828
829
  for (const part of parts) {
829
830
  if (current === null || current === void 0) {
@@ -836,8 +837,8 @@ function getNestedValue(obj, path17) {
836
837
  }
837
838
  return current;
838
839
  }
839
- function setNestedValue(obj, path17, value) {
840
- const parts = path17.split(".");
840
+ function setNestedValue(obj, path18, value) {
841
+ const parts = path18.split(".");
841
842
  let current = obj;
842
843
  for (let i = 0; i < parts.length - 1; i++) {
843
844
  const part = parts[i];
@@ -1018,1627 +1019,1861 @@ ${messages}`);
1018
1019
  }
1019
1020
  };
1020
1021
 
1021
- // src/commands/init.ts
1022
- async function executeInitCommand(options = {}) {
1023
- const projectRoot = process.cwd();
1024
- const configPath = path3.join(projectRoot, CONFIG_FILE_NAME);
1025
- const storagePath = path3.join(projectRoot, DEFAULT_SYNAPSYNC_DIR);
1026
- if (ConfigManager.isProjectInitialized(projectRoot)) {
1027
- logger.line();
1028
- logger.warning("Project already initialized.");
1029
- logger.log(` ${pc4.dim("Config:")} ${configPath}`);
1030
- logger.log(` ${pc4.dim("Storage:")} ${storagePath}`);
1031
- logger.line();
1032
- logger.hint("Use /config to view or modify settings.");
1033
- return null;
1022
+ // src/services/agents-md/generator.ts
1023
+ init_esm_shims();
1024
+ import * as fs4 from "fs";
1025
+ import * as path5 from "path";
1026
+
1027
+ // src/services/manifest/manager.ts
1028
+ init_esm_shims();
1029
+ import * as fs2 from "fs";
1030
+ import * as path3 from "path";
1031
+
1032
+ // src/services/manifest/types.ts
1033
+ init_esm_shims();
1034
+ var DEFAULT_MANIFEST = {
1035
+ version: "1.0.0",
1036
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
1037
+ cognitives: {},
1038
+ syncs: {}
1039
+ };
1040
+
1041
+ // src/services/manifest/manager.ts
1042
+ var ManifestManager = class {
1043
+ manifestPath;
1044
+ manifest;
1045
+ constructor(synapSyncDir) {
1046
+ this.manifestPath = path3.join(synapSyncDir, "manifest.json");
1047
+ this.manifest = this.load();
1034
1048
  }
1035
- if (options.yes === true) {
1036
- return initializeProject({
1037
- name: options.name ?? path3.basename(projectRoot),
1038
- ...options.description !== void 0 && { description: options.description },
1039
- providers: options.providers ?? ["claude"]
1040
- });
1049
+ /**
1050
+ * Load manifest from disk
1051
+ */
1052
+ load() {
1053
+ if (!fs2.existsSync(this.manifestPath)) {
1054
+ return { ...DEFAULT_MANIFEST };
1055
+ }
1056
+ try {
1057
+ const content = fs2.readFileSync(this.manifestPath, "utf-8");
1058
+ const parsed = JSON.parse(content);
1059
+ return {
1060
+ version: parsed.version ?? DEFAULT_MANIFEST.version,
1061
+ lastUpdated: parsed.lastUpdated ?? DEFAULT_MANIFEST.lastUpdated,
1062
+ cognitives: parsed.cognitives ?? {},
1063
+ syncs: parsed.syncs ?? {}
1064
+ };
1065
+ } catch {
1066
+ return { ...DEFAULT_MANIFEST };
1067
+ }
1041
1068
  }
1042
- logger.line();
1043
- p.intro(pc4.bgCyan(pc4.black(" Initialize SynapSync Project ")));
1044
- const result = await p.group(
1045
- {
1046
- name: () => {
1047
- const defaultName = path3.basename(projectRoot);
1048
- return p.text({
1049
- message: "Project name",
1050
- placeholder: defaultName,
1051
- defaultValue: defaultName,
1052
- validate: (value) => {
1053
- const finalValue = value.trim() === "" ? defaultName : value;
1054
- if (!/^[a-z0-9-_]+$/i.test(finalValue)) {
1055
- return "Project name can only contain letters, numbers, hyphens, and underscores";
1056
- }
1057
- return void 0;
1058
- }
1059
- });
1060
- },
1061
- description: () => p.text({
1062
- message: "Description (optional)",
1063
- placeholder: "A brief description of your project"
1064
- }),
1065
- providers: () => p.multiselect({
1066
- message: "Select AI providers to enable",
1067
- options: SUPPORTED_PROVIDERS.map((provider) => ({
1068
- value: provider,
1069
- label: getProviderLabel(provider),
1070
- hint: getProviderHint(provider)
1071
- })),
1072
- initialValues: ["claude"],
1073
- required: false
1074
- })
1075
- },
1076
- {
1077
- onCancel: () => {
1078
- p.cancel("Project initialization cancelled.");
1079
- return process.exit(0);
1080
- }
1069
+ /**
1070
+ * Save manifest to disk
1071
+ */
1072
+ save() {
1073
+ this.manifest.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
1074
+ const content = JSON.stringify(this.manifest, null, 2);
1075
+ fs2.writeFileSync(this.manifestPath, content, "utf-8");
1076
+ }
1077
+ /**
1078
+ * Get the current manifest
1079
+ */
1080
+ getManifest() {
1081
+ return this.manifest;
1082
+ }
1083
+ /**
1084
+ * Get all cognitives from manifest
1085
+ */
1086
+ getCognitives() {
1087
+ return Object.values(this.manifest.cognitives);
1088
+ }
1089
+ /**
1090
+ * Get a specific cognitive by name
1091
+ */
1092
+ getCognitive(name) {
1093
+ return this.manifest.cognitives[name];
1094
+ }
1095
+ /**
1096
+ * Check if a cognitive exists in manifest
1097
+ */
1098
+ hasCognitive(name) {
1099
+ return this.manifest.cognitives[name] !== void 0;
1100
+ }
1101
+ /**
1102
+ * Add a cognitive to manifest
1103
+ */
1104
+ addCognitive(cognitive) {
1105
+ this.manifest.cognitives[cognitive.name] = cognitive;
1106
+ }
1107
+ /**
1108
+ * Update a cognitive in manifest
1109
+ */
1110
+ updateCognitive(name, updates) {
1111
+ const existing = this.manifest.cognitives[name];
1112
+ if (existing !== void 0) {
1113
+ this.manifest.cognitives[name] = { ...existing, ...updates };
1081
1114
  }
1082
- );
1083
- if (p.isCancel(result)) {
1084
- return null;
1085
1115
  }
1086
- return initializeProject({
1087
- name: result.name,
1088
- description: result.description,
1089
- providers: result.providers
1090
- });
1091
- }
1092
- function initializeProject(setup) {
1093
- const projectRoot = process.cwd();
1094
- const configPath = path3.join(projectRoot, CONFIG_FILE_NAME);
1095
- const storagePath = path3.join(projectRoot, DEFAULT_SYNAPSYNC_DIR);
1096
- const s = p.spinner();
1097
- s.start("Creating project structure...");
1098
- try {
1099
- createStorageStructure(storagePath);
1100
- const configManager = new ConfigManager(projectRoot);
1101
- configManager.create(setup.name, setup.description);
1102
- for (const provider of setup.providers) {
1103
- configManager.set(`sync.providers.${provider}.enabled`, true);
1116
+ /**
1117
+ * Remove a cognitive from manifest
1118
+ */
1119
+ removeCognitive(name) {
1120
+ if (this.manifest.cognitives[name] !== void 0) {
1121
+ delete this.manifest.cognitives[name];
1122
+ return true;
1104
1123
  }
1105
- configManager.save();
1106
- createManifest(storagePath);
1107
- updateGitignore(projectRoot);
1108
- s.stop("Project structure created!");
1109
- showSuccessMessage(setup, configPath, storagePath);
1110
- return {
1111
- success: true,
1112
- projectPath: projectRoot,
1113
- configPath,
1114
- storagePath
1124
+ return false;
1125
+ }
1126
+ /**
1127
+ * Reconcile manifest with scanned cognitives
1128
+ * Returns what was added, removed, and updated
1129
+ */
1130
+ reconcile(scannedCognitives) {
1131
+ const result = {
1132
+ added: [],
1133
+ removed: [],
1134
+ updated: [],
1135
+ unchanged: 0
1115
1136
  };
1116
- } catch (error) {
1117
- s.stop("Failed to create project.");
1118
- logger.line();
1119
- if (error instanceof Error) {
1120
- logger.error(error.message);
1137
+ const scannedMap = /* @__PURE__ */ new Map();
1138
+ for (const cognitive of scannedCognitives) {
1139
+ scannedMap.set(cognitive.name, cognitive);
1121
1140
  }
1122
- throw error;
1123
- }
1124
- }
1125
- function createStorageStructure(storagePath) {
1126
- fs2.mkdirSync(storagePath, { recursive: true });
1127
- for (const cognitiveType of COGNITIVE_TYPES) {
1128
- const typePath = path3.join(storagePath, `${cognitiveType}s`);
1129
- fs2.mkdirSync(typePath, { recursive: true });
1130
- const gitkeepPath = path3.join(typePath, ".gitkeep");
1131
- fs2.writeFileSync(gitkeepPath, "");
1132
- }
1133
- }
1134
- function createManifest(storagePath) {
1135
- const manifestPath = path3.join(storagePath, "manifest.json");
1136
- const manifest = {
1137
- version: "1.0.0",
1138
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
1139
- cognitives: {},
1140
- syncs: {}
1141
- };
1142
- fs2.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
1143
- }
1144
- function updateGitignore(projectRoot) {
1145
- const gitignorePath = path3.join(projectRoot, ".gitignore");
1146
- const synapsyncEntries = `
1147
- # SynapSync
1148
- .synapsync/manifest.json
1149
- *.local.yaml
1150
- `;
1151
- if (fs2.existsSync(gitignorePath)) {
1152
- const content = fs2.readFileSync(gitignorePath, "utf-8");
1153
- if (!content.includes("# SynapSync")) {
1154
- fs2.appendFileSync(gitignorePath, synapsyncEntries);
1141
+ for (const name of Object.keys(this.manifest.cognitives)) {
1142
+ if (!scannedMap.has(name)) {
1143
+ result.removed.push(name);
1144
+ }
1155
1145
  }
1156
- } else {
1157
- fs2.writeFileSync(gitignorePath, synapsyncEntries.trim() + "\n");
1146
+ for (const scanned of scannedCognitives) {
1147
+ const existing = this.manifest.cognitives[scanned.name];
1148
+ if (existing === void 0) {
1149
+ result.added.push(scanned);
1150
+ } else if (scanned.hash !== void 0 && existing.hash !== scanned.hash) {
1151
+ result.updated.push(scanned);
1152
+ } else {
1153
+ result.unchanged++;
1154
+ }
1155
+ }
1156
+ return result;
1158
1157
  }
1159
- }
1160
- function getProviderLabel(provider) {
1161
- const labels = {
1162
- claude: "Claude (Anthropic)",
1163
- openai: "OpenAI (GPT)",
1164
- gemini: "Gemini (Google)",
1165
- cursor: "Cursor IDE",
1166
- windsurf: "Windsurf IDE",
1167
- copilot: "GitHub Copilot"
1168
- };
1169
- return labels[provider];
1170
- }
1171
- function getProviderHint(provider) {
1172
- const hints = {
1173
- claude: "Claude Code, Claude Desktop",
1174
- openai: "ChatGPT, API",
1175
- gemini: "Google AI Studio",
1176
- cursor: "AI-first code editor",
1177
- windsurf: "AI-powered IDE",
1178
- copilot: "VS Code integration"
1179
- };
1180
- return hints[provider];
1181
- }
1182
- function showSuccessMessage(setup, configPath, storagePath) {
1183
- logger.line();
1184
- p.note(
1185
- [
1186
- `${pc4.dim("Config:")} ${pc4.cyan(configPath)}`,
1187
- `${pc4.dim("Storage:")} ${pc4.cyan(storagePath)}`,
1188
- "",
1189
- `${pc4.dim("Providers:")} ${setup.providers.map((p2) => pc4.green(p2)).join(", ") || pc4.dim("none")}`
1190
- ].join("\n"),
1191
- `Project "${setup.name}" initialized!`
1192
- );
1193
- logger.line();
1194
- logger.bold(" Next Steps:");
1195
- logger.line();
1196
- logger.log(` ${pc4.cyan("1.")} Browse available cognitives:`);
1197
- logger.log(` ${pc4.dim("$")} synapsync list --remote`);
1198
- logger.line();
1199
- logger.log(` ${pc4.cyan("2.")} Add cognitives:`);
1200
- logger.log(` ${pc4.dim("$")} synapsync add code-reviewer`);
1201
- logger.log(` ${pc4.dim("$")} synapsync add github:user/my-skill`);
1202
- logger.line();
1203
- p.outro(pc4.green("Happy syncing!"));
1204
- }
1205
- function registerInitCommand(program) {
1206
- program.command("init").description("Initialize a new SynapSync project").option("-n, --name <name>", "Project name").option("-d, --description <desc>", "Project description").option("-p, --provider <providers...>", "Enable providers (claude, openai, etc.)").option("-y, --yes", "Skip prompts and use defaults").action(async (options) => {
1207
- await executeInitCommand({
1208
- ...options.name !== void 0 && { name: options.name },
1209
- ...options.description !== void 0 && { description: options.description },
1210
- ...options.provider !== void 0 && { providers: options.provider },
1211
- ...options.yes !== void 0 && { yes: options.yes }
1212
- });
1213
- });
1214
- }
1158
+ /**
1159
+ * Apply reconciliation result to manifest
1160
+ */
1161
+ applyReconciliation(result) {
1162
+ for (const name of result.removed) {
1163
+ delete this.manifest.cognitives[name];
1164
+ }
1165
+ for (const cognitive of result.added) {
1166
+ this.manifest.cognitives[cognitive.name] = cognitive;
1167
+ }
1168
+ for (const cognitive of result.updated) {
1169
+ const existing = this.manifest.cognitives[cognitive.name];
1170
+ if (existing !== void 0) {
1171
+ const updated = {
1172
+ ...existing,
1173
+ ...cognitive,
1174
+ // Keep original installation info
1175
+ installedAt: existing.installedAt,
1176
+ source: existing.source
1177
+ };
1178
+ if (existing.sourceUrl !== void 0) {
1179
+ updated.sourceUrl = existing.sourceUrl;
1180
+ }
1181
+ this.manifest.cognitives[cognitive.name] = updated;
1182
+ }
1183
+ }
1184
+ }
1185
+ /**
1186
+ * Get provider sync state
1187
+ */
1188
+ getProviderSync(provider) {
1189
+ return this.manifest.syncs[provider];
1190
+ }
1191
+ /**
1192
+ * Update provider sync state
1193
+ */
1194
+ setProviderSync(provider, state) {
1195
+ this.manifest.syncs[provider] = state;
1196
+ }
1197
+ /**
1198
+ * Get all synced cognitives for a provider
1199
+ */
1200
+ getSyncedCognitives(provider) {
1201
+ return this.manifest.syncs[provider]?.cognitives ?? [];
1202
+ }
1203
+ /**
1204
+ * Get cognitive count
1205
+ */
1206
+ getCognitiveCount() {
1207
+ return Object.keys(this.manifest.cognitives).length;
1208
+ }
1209
+ /**
1210
+ * Get cognitives by type
1211
+ */
1212
+ getCognitivesByType(type) {
1213
+ return Object.values(this.manifest.cognitives).filter((c) => c.type === type);
1214
+ }
1215
+ /**
1216
+ * Get cognitives by source
1217
+ */
1218
+ getCognitivesBySource(source) {
1219
+ return Object.values(this.manifest.cognitives).filter((c) => c.source === source);
1220
+ }
1221
+ };
1215
1222
 
1216
- // src/commands/config.ts
1223
+ // src/services/scanner/scanner.ts
1217
1224
  init_esm_shims();
1218
- import pc5 from "picocolors";
1219
- function executeConfigCommand(args) {
1220
- const options = parseConfigArgs(args);
1221
- const configManager = ConfigManager.findConfig();
1222
- if (configManager === null) {
1223
- logger.line();
1224
- logger.error("No SynapSync project found.");
1225
- logger.hint("Run /init to initialize a project.");
1226
- return;
1225
+ import * as fs3 from "fs";
1226
+ import * as path4 from "path";
1227
+ import * as crypto from "crypto";
1228
+
1229
+ // src/services/scanner/parser.ts
1230
+ init_esm_shims();
1231
+ function parseFrontmatter(content) {
1232
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
1233
+ if (match?.[1] === void 0) {
1234
+ return {};
1227
1235
  }
1228
- switch (options.action) {
1229
- case "list":
1230
- showConfigList(configManager);
1231
- break;
1232
- case "get":
1233
- showConfigValue(configManager, options.key ?? "");
1234
- break;
1235
- case "set":
1236
- setConfigValue(configManager, options.key ?? "", options.value ?? "");
1237
- break;
1236
+ try {
1237
+ return parseYaml(match[1]);
1238
+ } catch {
1239
+ return {};
1238
1240
  }
1239
1241
  }
1240
- function showConfigList(configManager) {
1241
- const flatConfig = configManager.flatten();
1242
- logger.line();
1243
- logger.bold(" Configuration");
1244
- logger.line();
1245
- const groups = {};
1246
- for (const [key, value] of Object.entries(flatConfig)) {
1247
- const parts = key.split(".");
1248
- const group2 = parts[0] ?? "other";
1249
- groups[group2] ??= {};
1250
- groups[group2][key] = value;
1251
- }
1252
- for (const [group2, values] of Object.entries(groups)) {
1253
- logger.log(` ${pc5.cyan(group2)}:`);
1254
- for (const [key, value] of Object.entries(values)) {
1255
- const displayKey = key.replace(`${group2}.`, "");
1256
- const displayValue = formatValue(value);
1257
- logger.log(` ${pc5.dim(displayKey.padEnd(30))} ${displayValue}`);
1242
+ function parseYaml(yaml2) {
1243
+ const result = {};
1244
+ const lines = yaml2.split("\n");
1245
+ let currentKey = null;
1246
+ let currentArray = null;
1247
+ for (const line of lines) {
1248
+ if (line.trim() === "" || line.trim().startsWith("#")) {
1249
+ continue;
1250
+ }
1251
+ if (line.match(/^\s+-\s+/)) {
1252
+ const value = line.replace(/^\s+-\s+/, "").trim();
1253
+ if (currentArray !== null) {
1254
+ currentArray.push(cleanValue(value));
1255
+ }
1256
+ continue;
1257
+ }
1258
+ const colonIndex = line.indexOf(":");
1259
+ if (colonIndex > 0) {
1260
+ const key = line.slice(0, colonIndex).trim();
1261
+ const rawValue = line.slice(colonIndex + 1).trim();
1262
+ if (currentKey !== null && currentArray !== null) {
1263
+ setNestedValue2(result, currentKey, currentArray);
1264
+ currentArray = null;
1265
+ }
1266
+ currentKey = key;
1267
+ if (rawValue === "" || rawValue === "|" || rawValue === ">") {
1268
+ currentArray = [];
1269
+ } else if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
1270
+ const arrayContent = rawValue.slice(1, -1);
1271
+ const items = arrayContent.split(",").map((item) => cleanValue(item.trim()));
1272
+ setNestedValue2(result, key, items);
1273
+ currentKey = null;
1274
+ } else {
1275
+ setNestedValue2(result, key, cleanValue(rawValue));
1276
+ currentKey = null;
1277
+ }
1258
1278
  }
1259
- logger.line();
1260
- }
1261
- logger.hint(`Config file: ${configManager.getProjectRoot()}/synapsync.config.yaml`);
1262
- }
1263
- function showConfigValue(configManager, key) {
1264
- if (key === "") {
1265
- logger.line();
1266
- logger.error("Key is required.");
1267
- logger.hint("Usage: /config get <key>");
1268
- logger.hint("Example: /config get cli.theme");
1269
- return;
1270
1279
  }
1271
- const value = configManager.get(key);
1272
- logger.line();
1273
- if (value === void 0) {
1274
- logger.warning(`Key not found: ${pc5.cyan(key)}`);
1275
- logger.line();
1276
- logger.hint("Use /config list to see all available keys.");
1277
- } else {
1278
- logger.log(` ${pc5.cyan(key)} = ${formatValue(value)}`);
1280
+ if (currentKey !== null && currentArray !== null) {
1281
+ setNestedValue2(result, currentKey, currentArray);
1279
1282
  }
1283
+ return result;
1280
1284
  }
1281
- function setConfigValue(configManager, key, value) {
1282
- if (key === "") {
1283
- logger.line();
1284
- logger.error("Key is required.");
1285
- logger.hint("Usage: /config set <key> <value>");
1286
- logger.hint("Example: /config set cli.theme dark");
1287
- return;
1285
+ function cleanValue(value) {
1286
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1287
+ return value.slice(1, -1);
1288
1288
  }
1289
- if (value === "") {
1290
- logger.line();
1291
- logger.error("Value is required.");
1292
- logger.hint("Usage: /config set <key> <value>");
1293
- return;
1289
+ return value;
1290
+ }
1291
+ function setNestedValue2(obj, key, value) {
1292
+ obj[key] = value;
1293
+ }
1294
+ function extractVersion(metadata, content) {
1295
+ if (metadata.version !== void 0) {
1296
+ return metadata.version;
1294
1297
  }
1295
- const existingValue = configManager.get(key);
1296
- const isNewKey = existingValue === void 0;
1297
- const parsedValue = parseValue(value);
1298
- configManager.set(key, parsedValue);
1299
- configManager.save();
1300
- logger.line();
1301
- if (isNewKey) {
1302
- logger.warning(`Created new key: ${pc5.cyan(key)}`);
1298
+ const versionMatch = content.match(/version:\s*['"]?([0-9]+\.[0-9]+\.[0-9]+)['"]?/i);
1299
+ if (versionMatch?.[1] !== void 0) {
1300
+ return versionMatch[1];
1303
1301
  }
1304
- logger.success(`${pc5.cyan(key)} = ${formatValue(parsedValue)}`);
1302
+ return "1.0.0";
1305
1303
  }
1306
- function parseConfigArgs(args) {
1307
- const parts = args.trim().split(/\s+/);
1308
- const action = (parts[0] ?? "list").toLowerCase();
1309
- if (action === "" || action === "list") {
1310
- return { action: "list" };
1304
+ function extractName(metadata, dirName, content) {
1305
+ if (metadata.name !== void 0) {
1306
+ return metadata.name;
1311
1307
  }
1312
- if (action === "get") {
1313
- return {
1314
- action: "get",
1315
- key: parts[1] ?? ""
1316
- };
1317
- }
1318
- if (action === "set") {
1319
- return {
1320
- action: "set",
1321
- key: parts[1] ?? "",
1322
- value: parts.slice(2).join(" ")
1323
- };
1324
- }
1325
- return {
1326
- action: "get",
1327
- key: action
1328
- };
1329
- }
1330
- function formatValue(value) {
1331
- if (value === null || value === void 0) {
1332
- return pc5.dim("(not set)");
1333
- }
1334
- if (typeof value === "boolean") {
1335
- return value ? pc5.green("true") : pc5.red("false");
1336
- }
1337
- if (typeof value === "number") {
1338
- return pc5.yellow(String(value));
1339
- }
1340
- if (typeof value === "string") {
1341
- return pc5.white(`"${value}"`);
1342
- }
1343
- if (Array.isArray(value)) {
1344
- return pc5.dim(`[${value.join(", ")}]`);
1308
+ const titleMatch = content.match(/^#\s+(.+)$/m);
1309
+ if (titleMatch?.[1] !== void 0) {
1310
+ return titleMatch[1].toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
1345
1311
  }
1346
- return pc5.dim(JSON.stringify(value));
1347
- }
1348
- function parseValue(value) {
1349
- if (value.toLowerCase() === "true") return true;
1350
- if (value.toLowerCase() === "false") return false;
1351
- const num = Number(value);
1352
- if (!isNaN(num) && value.trim() !== "") return num;
1353
- return value;
1354
- }
1355
- function registerConfigCommand(program) {
1356
- const configCmd = program.command("config").description("Manage project configuration");
1357
- configCmd.command("list").description("Show all configuration values").action(() => {
1358
- executeConfigCommand("list");
1359
- });
1360
- configCmd.command("get <key>").description("Get a configuration value").action((key) => {
1361
- executeConfigCommand(`get ${key}`);
1362
- });
1363
- configCmd.command("set <key> <value>").description("Set a configuration value").action((key, value) => {
1364
- executeConfigCommand(`set ${key} ${value}`);
1365
- });
1366
- configCmd.action(() => {
1367
- executeConfigCommand("list");
1368
- });
1312
+ return dirName;
1369
1313
  }
1370
1314
 
1371
- // src/commands/status.ts
1372
- init_esm_shims();
1373
- import * as fs3 from "fs";
1374
- import * as path4 from "path";
1375
- import pc6 from "picocolors";
1376
- function executeStatusCommand(_args = "") {
1377
- const status = getProjectStatus();
1378
- logger.line();
1379
- if (!status.initialized) {
1380
- showNotInitialized();
1381
- return;
1382
- }
1383
- showProjectStatus(status);
1384
- }
1385
- function getProjectStatus() {
1386
- const configManager = ConfigManager.findConfig();
1387
- if (configManager === null) {
1388
- return {
1389
- initialized: false,
1390
- cognitives: createEmptyCognitiveCount(),
1391
- providers: []
1392
- };
1393
- }
1394
- const config = configManager.getConfig();
1395
- const projectRoot = configManager.getProjectRoot();
1396
- const storagePath = configManager.getSynapSyncDir();
1397
- const cognitives = countCognitives(storagePath);
1398
- const providers = getProviderStatuses(config, projectRoot);
1399
- const lastSync = getLastSyncTime(storagePath);
1400
- const status = {
1401
- initialized: true,
1402
- projectName: config.name,
1403
- projectRoot,
1404
- configPath: path4.join(projectRoot, "synapsync.config.yaml"),
1405
- storagePath,
1406
- cognitives,
1407
- providers
1408
- };
1409
- if (lastSync !== void 0) {
1410
- status.lastSync = lastSync;
1411
- }
1412
- return status;
1413
- }
1414
- function createEmptyCognitiveCount() {
1415
- const counts = {};
1416
- for (const type of COGNITIVE_TYPES) {
1417
- counts[type] = 0;
1315
+ // src/services/scanner/scanner.ts
1316
+ var CognitiveScanner = class {
1317
+ synapSyncDir;
1318
+ constructor(synapSyncDir) {
1319
+ this.synapSyncDir = synapSyncDir;
1418
1320
  }
1419
- return counts;
1420
- }
1421
- function countCognitives(storagePath) {
1422
- const counts = createEmptyCognitiveCount();
1423
- for (const type of COGNITIVE_TYPES) {
1424
- const typePath = path4.join(storagePath, `${type}s`);
1425
- if (fs3.existsSync(typePath)) {
1426
- try {
1427
- const entries = fs3.readdirSync(typePath, { withFileTypes: true });
1428
- counts[type] = entries.filter(
1429
- (e) => e.isDirectory() || e.isSymbolicLink() && !e.name.startsWith(".")
1430
- ).length;
1431
- } catch {
1432
- counts[type] = 0;
1321
+ /**
1322
+ * Scan the filesystem for cognitives
1323
+ */
1324
+ scan(options = {}) {
1325
+ const cognitives = [];
1326
+ const errors = [];
1327
+ const typesToScan = options.types ?? COGNITIVE_TYPES;
1328
+ for (const type of typesToScan) {
1329
+ const typeDir = path4.join(this.synapSyncDir, `${type}s`);
1330
+ if (!fs3.existsSync(typeDir)) {
1331
+ continue;
1433
1332
  }
1434
- }
1435
- }
1436
- return counts;
1437
- }
1438
- function getProviderStatuses(config, projectRoot) {
1439
- const statuses = [];
1440
- for (const provider of SUPPORTED_PROVIDERS) {
1441
- const providerConfig = config.sync?.providers?.[provider];
1442
- const enabled = providerConfig?.enabled ?? false;
1443
- const providerPath = path4.join(projectRoot, `.${provider}`);
1444
- let cognitivesCount = 0;
1445
- if (fs3.existsSync(providerPath)) {
1446
- try {
1447
- const subdirs = ["skills", "agents", "prompts", "workflows", "tools"];
1448
- for (const subdir of subdirs) {
1449
- const subdirPath = path4.join(providerPath, subdir);
1450
- if (fs3.existsSync(subdirPath)) {
1451
- const entries = fs3.readdirSync(subdirPath);
1452
- cognitivesCount += entries.filter((e) => !e.startsWith(".")).length;
1333
+ const categories = this.listDirectories(typeDir);
1334
+ for (const category of categories) {
1335
+ if (options.categories !== void 0 && !options.categories.includes(category)) {
1336
+ continue;
1337
+ }
1338
+ const categoryDir = path4.join(typeDir, category);
1339
+ const cognitiveDirs = this.listDirectories(categoryDir);
1340
+ for (const cognitiveDir of cognitiveDirs) {
1341
+ try {
1342
+ const cognitive = this.scanCognitive(
1343
+ path4.join(categoryDir, cognitiveDir),
1344
+ type,
1345
+ category
1346
+ );
1347
+ if (cognitive !== null) {
1348
+ cognitives.push(cognitive);
1349
+ }
1350
+ } catch (error) {
1351
+ errors.push({
1352
+ path: path4.join(categoryDir, cognitiveDir),
1353
+ error: error instanceof Error ? error.message : "Unknown error"
1354
+ });
1453
1355
  }
1454
1356
  }
1455
- } catch {
1456
1357
  }
1457
1358
  }
1458
- statuses.push({
1459
- name: provider,
1460
- enabled,
1461
- connected: false,
1462
- // TODO: Check actual connection status
1463
- cognitivesCount
1464
- });
1465
- }
1466
- return statuses;
1467
- }
1468
- function getLastSyncTime(storagePath) {
1469
- const manifestPath = path4.join(storagePath, "manifest.json");
1470
- if (!fs3.existsSync(manifestPath)) {
1471
- return void 0;
1359
+ return cognitives;
1472
1360
  }
1473
- try {
1474
- const content = fs3.readFileSync(manifestPath, "utf-8");
1475
- const manifest = JSON.parse(content);
1476
- return manifest.lastUpdated;
1477
- } catch {
1478
- return void 0;
1361
+ /**
1362
+ * Scan a single cognitive directory
1363
+ */
1364
+ scanCognitive(cognitiveDir, type, category) {
1365
+ const filePath = this.findCognitiveFile(cognitiveDir, type);
1366
+ if (filePath === null) {
1367
+ return null;
1368
+ }
1369
+ const content = fs3.readFileSync(filePath, "utf-8");
1370
+ const metadata = parseFrontmatter(content);
1371
+ const dirName = path4.basename(cognitiveDir);
1372
+ const fileName = path4.basename(filePath);
1373
+ const name = extractName(metadata, dirName, content);
1374
+ const version2 = extractVersion(metadata, content);
1375
+ const hash = this.computeHash(content);
1376
+ return {
1377
+ name,
1378
+ type,
1379
+ category: metadata.category ?? category,
1380
+ path: cognitiveDir,
1381
+ filePath,
1382
+ fileName,
1383
+ // Add original filename
1384
+ hash,
1385
+ metadata: {
1386
+ ...metadata,
1387
+ name,
1388
+ version: version2
1389
+ }
1390
+ };
1479
1391
  }
1480
- }
1481
- function showNotInitialized() {
1482
- logger.bold(" Project Status");
1483
- logger.line();
1484
- logger.log(` ${pc6.red("\u25CF")} ${pc6.dim("Not initialized")}`);
1485
- logger.line();
1486
- logger.hint("Run /init to initialize a SynapSync project.");
1487
- }
1488
- function showProjectStatus(status) {
1489
- logger.bold(` ${status.projectName ?? "SynapSync Project"}`);
1490
- logger.line();
1491
- logger.log(` ${pc6.green("\u25CF")} ${pc6.dim("Initialized")}`);
1492
- logger.log(` ${pc6.dim("Root:")} ${status.projectRoot}`);
1493
- logger.line();
1494
- logger.bold(" Cognitives");
1495
- const totalCognitives = Object.values(status.cognitives).reduce((a, b) => a + b, 0);
1496
- if (totalCognitives === 0) {
1497
- logger.log(` ${pc6.dim("No cognitives installed")}`);
1498
- } else {
1499
- for (const type of COGNITIVE_TYPES) {
1500
- const count = status.cognitives[type];
1501
- if (count > 0) {
1502
- const icon = getCognitiveIcon(type);
1503
- logger.log(` ${icon} ${pc6.white(count.toString().padStart(3))} ${type}s`);
1392
+ /**
1393
+ * Find the cognitive file in a directory
1394
+ * Checks for legacy fixed filename first, then any file with matching extension
1395
+ */
1396
+ findCognitiveFile(cognitiveDir, type) {
1397
+ const legacyFileName = COGNITIVE_FILE_NAMES[type];
1398
+ const legacyPath = path4.join(cognitiveDir, legacyFileName);
1399
+ if (fs3.existsSync(legacyPath)) {
1400
+ return legacyPath;
1401
+ }
1402
+ const extension = COGNITIVE_FILE_EXTENSIONS[type];
1403
+ if (!fs3.existsSync(cognitiveDir)) {
1404
+ return null;
1405
+ }
1406
+ const files = fs3.readdirSync(cognitiveDir);
1407
+ for (const file of files) {
1408
+ if (file.endsWith(extension) && !file.startsWith(".")) {
1409
+ const fullPath = path4.join(cognitiveDir, file);
1410
+ const stat = fs3.statSync(fullPath);
1411
+ if (stat.isFile()) {
1412
+ return fullPath;
1413
+ }
1504
1414
  }
1505
1415
  }
1506
- logger.log(` ${pc6.dim("\u2500\u2500\u2500")}`);
1507
- logger.log(` ${pc6.bold(totalCognitives.toString().padStart(5))} total`);
1416
+ return null;
1508
1417
  }
1509
- logger.line();
1510
- logger.bold(" Providers");
1511
- const enabledProviders = status.providers.filter((p2) => p2.enabled);
1512
- if (enabledProviders.length === 0) {
1513
- logger.log(` ${pc6.dim("No providers enabled")}`);
1514
- } else {
1515
- for (const provider of enabledProviders) {
1516
- const icon = provider.cognitivesCount > 0 ? pc6.green("\u25CF") : pc6.yellow("\u25CB");
1517
- const syncStatus = provider.cognitivesCount > 0 ? pc6.dim(`(${provider.cognitivesCount} synced)`) : pc6.dim("(not synced)");
1518
- logger.log(` ${icon} ${pc6.white(provider.name)} ${syncStatus}`);
1418
+ /**
1419
+ * Compare scanned cognitives with manifest and return differences
1420
+ */
1421
+ compare(scanned, manifestCognitives) {
1422
+ const result = {
1423
+ found: scanned,
1424
+ new: [],
1425
+ removed: [],
1426
+ modified: [],
1427
+ unchanged: 0,
1428
+ errors: []
1429
+ };
1430
+ const manifestMap = /* @__PURE__ */ new Map();
1431
+ for (const cognitive of manifestCognitives) {
1432
+ manifestMap.set(cognitive.name, cognitive);
1519
1433
  }
1520
- }
1521
- logger.line();
1522
- if (status.lastSync !== void 0) {
1523
- const syncDate = new Date(status.lastSync);
1524
- const relativeTime = getRelativeTime(syncDate);
1525
- logger.log(` ${pc6.dim("Last updated:")} ${relativeTime}`);
1526
- logger.line();
1527
- }
1528
- logger.hint("Run /help for available commands.");
1529
- }
1530
- function getCognitiveIcon(type) {
1531
- const icons = {
1532
- skill: pc6.blue("\u25C6"),
1533
- agent: pc6.magenta("\u25C6"),
1534
- prompt: pc6.yellow("\u25C6"),
1535
- workflow: pc6.cyan("\u25C6"),
1536
- tool: pc6.green("\u25C6")
1537
- };
1538
- return icons[type];
1539
- }
1540
- function getRelativeTime(date) {
1541
- const now = /* @__PURE__ */ new Date();
1542
- const diffMs = now.getTime() - date.getTime();
1543
- const diffMins = Math.floor(diffMs / 6e4);
1544
- const diffHours = Math.floor(diffMins / 60);
1545
- const diffDays = Math.floor(diffHours / 24);
1546
- if (diffMins < 1) return "just now";
1547
- if (diffMins < 60) return `${diffMins} minute${diffMins === 1 ? "" : "s"} ago`;
1548
- if (diffHours < 24) return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
1549
- if (diffDays < 7) return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
1550
- return date.toLocaleDateString();
1551
- }
1552
- function registerStatusCommand(program) {
1553
- program.command("status").description("Show project status").action(() => {
1554
- executeStatusCommand();
1555
- });
1556
- }
1557
-
1558
- // src/commands/providers.ts
1559
- init_esm_shims();
1560
- import * as fs4 from "fs";
1561
- import * as path5 from "path";
1562
- import pc7 from "picocolors";
1563
- function executeProvidersCommand(args) {
1564
- const parts = args.trim().split(/\s+/);
1565
- const subcommand = parts[0]?.toLowerCase() ?? "";
1566
- const configManager = ConfigManager.findConfig();
1567
- if (configManager === null) {
1568
- logger.line();
1569
- logger.error("No SynapSync project found.");
1570
- logger.hint("Run /init to initialize a project.");
1571
- return;
1572
- }
1573
- switch (subcommand) {
1574
- case "":
1575
- case "list":
1576
- listProviders(configManager);
1577
- break;
1578
- case "enable":
1579
- enableProvider(configManager, parts[1]);
1580
- break;
1581
- case "disable":
1582
- disableProvider(configManager, parts[1]);
1583
- break;
1584
- case "path":
1585
- setProviderPath(configManager, parts[1], parts[2]);
1586
- break;
1587
- default:
1588
- if (SUPPORTED_PROVIDERS.includes(subcommand)) {
1589
- showProviderInfo(configManager, subcommand);
1434
+ const scannedMap = /* @__PURE__ */ new Map();
1435
+ for (const cognitive of scanned) {
1436
+ scannedMap.set(cognitive.name, cognitive);
1437
+ }
1438
+ for (const scannedCognitive of scanned) {
1439
+ const manifestCognitive = manifestMap.get(scannedCognitive.name);
1440
+ if (manifestCognitive === void 0) {
1441
+ result.new.push(scannedCognitive);
1442
+ } else if (manifestCognitive.hash !== void 0 && manifestCognitive.hash !== scannedCognitive.hash) {
1443
+ result.modified.push(scannedCognitive);
1590
1444
  } else {
1591
- logger.line();
1592
- logger.error(`Unknown subcommand: ${subcommand}`);
1593
- logger.hint("Usage: /providers [list|enable|disable|path]");
1445
+ result.unchanged++;
1594
1446
  }
1447
+ }
1448
+ for (const manifestCognitive of manifestCognitives) {
1449
+ if (!scannedMap.has(manifestCognitive.name)) {
1450
+ result.removed.push(manifestCognitive.name);
1451
+ }
1452
+ }
1453
+ return result;
1595
1454
  }
1596
- }
1597
- function listProviders(configManager) {
1598
- const providers = getProvidersInfo(configManager);
1599
- logger.line();
1600
- logger.bold(" Providers");
1601
- logger.line();
1602
- logger.log(
1603
- ` ${pc7.dim("Provider".padEnd(12))} ${pc7.dim("Status".padEnd(10))} ${pc7.dim("Path".padEnd(20))} ${pc7.dim("Directory")}`
1604
- );
1605
- logger.log(` ${pc7.dim("\u2500".repeat(60))}`);
1606
- for (const provider of providers) {
1607
- const statusIcon = provider.enabled ? pc7.green("\u25CF") : pc7.dim("\u25CB");
1608
- const statusText = provider.enabled ? pc7.green("enabled") : pc7.dim("disabled");
1609
- const pathText = pc7.cyan(provider.path);
1610
- const existsText = provider.exists ? pc7.green("\u2713 exists") : pc7.dim("\u2717 missing");
1611
- logger.log(
1612
- ` ${statusIcon} ${pc7.white(provider.name.padEnd(10))} ${statusText.padEnd(19)} ${pathText.padEnd(29)} ${existsText}`
1613
- );
1614
- }
1615
- logger.line();
1616
- const enabledCount = providers.filter((p2) => p2.enabled).length;
1617
- logger.log(` ${pc7.dim("Enabled:")} ${enabledCount} of ${providers.length} providers`);
1618
- logger.line();
1619
- logger.hint("Use /providers enable <name> or /providers disable <name>");
1620
- }
1621
- function enableProvider(configManager, providerName) {
1622
- if (providerName === void 0 || providerName === "") {
1623
- logger.line();
1624
- logger.error("Provider name is required.");
1625
- logger.hint("Usage: /providers enable <provider>");
1626
- logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
1627
- return;
1455
+ /**
1456
+ * Convert a scanned cognitive to a manifest cognitive
1457
+ */
1458
+ toManifestCognitive(scanned) {
1459
+ return {
1460
+ name: scanned.name,
1461
+ type: scanned.type,
1462
+ category: scanned.category,
1463
+ version: scanned.metadata.version ?? "1.0.0",
1464
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
1465
+ source: "local",
1466
+ hash: scanned.hash
1467
+ };
1628
1468
  }
1629
- const provider = providerName.toLowerCase();
1630
- if (!SUPPORTED_PROVIDERS.includes(provider)) {
1631
- logger.line();
1632
- logger.error(`Unknown provider: ${provider}`);
1633
- logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
1634
- return;
1469
+ /**
1470
+ * Compute content hash for change detection
1471
+ */
1472
+ computeHash(content) {
1473
+ return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
1635
1474
  }
1636
- const currentValue = configManager.get(`sync.providers.${provider}.enabled`);
1637
- if (currentValue === true) {
1638
- logger.line();
1639
- logger.info(`Provider '${provider}' is already enabled.`);
1640
- return;
1475
+ /**
1476
+ * List directories in a path
1477
+ */
1478
+ listDirectories(dirPath) {
1479
+ if (!fs3.existsSync(dirPath)) {
1480
+ return [];
1481
+ }
1482
+ return fs3.readdirSync(dirPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => !dirent.name.startsWith(".")).map((dirent) => dirent.name);
1641
1483
  }
1642
- configManager.set(`sync.providers.${provider}.enabled`, true);
1643
- const defaultPaths = PROVIDER_PATHS[provider];
1644
- const currentPaths = configManager.get(`sync.providers.${provider}.paths`);
1645
- if (currentPaths === void 0) {
1646
- configManager.set(`sync.providers.${provider}.paths`, defaultPaths);
1484
+ /**
1485
+ * Detect cognitive type from directory contents
1486
+ */
1487
+ detectType(cognitiveDir) {
1488
+ for (const type of COGNITIVE_TYPES) {
1489
+ const fileName = COGNITIVE_FILE_NAMES[type];
1490
+ const filePath = path4.join(cognitiveDir, fileName);
1491
+ if (fs3.existsSync(filePath)) {
1492
+ return type;
1493
+ }
1494
+ }
1495
+ return null;
1647
1496
  }
1648
- configManager.save();
1649
- logger.line();
1650
- logger.success(`Provider '${pc7.cyan(provider)}' enabled`);
1651
- logger.log(` ${pc7.dim("Path:")} ${defaultPaths.skill.split("/")[0]}/`);
1652
- logger.line();
1653
- logger.hint("Run /sync to synchronize cognitives to this provider.");
1654
- }
1655
- function disableProvider(configManager, providerName) {
1656
- if (providerName === void 0 || providerName === "") {
1657
- logger.line();
1658
- logger.error("Provider name is required.");
1659
- logger.hint("Usage: /providers disable <provider>");
1660
- return;
1497
+ /**
1498
+ * Get cognitive count by type
1499
+ */
1500
+ countByType(cognitives) {
1501
+ const counts = {
1502
+ skill: 0,
1503
+ agent: 0,
1504
+ prompt: 0,
1505
+ workflow: 0,
1506
+ tool: 0
1507
+ };
1508
+ for (const cognitive of cognitives) {
1509
+ counts[cognitive.type]++;
1510
+ }
1511
+ return counts;
1661
1512
  }
1662
- const provider = providerName.toLowerCase();
1663
- if (!SUPPORTED_PROVIDERS.includes(provider)) {
1664
- logger.line();
1665
- logger.error(`Unknown provider: ${provider}`);
1666
- logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
1667
- return;
1513
+ };
1514
+
1515
+ // src/services/agents-md/generator.ts
1516
+ var START_MARKER = "<!-- synapsync:start -->";
1517
+ var END_MARKER = "<!-- synapsync:end -->";
1518
+ var TYPE_ICONS = {
1519
+ skill: "\u{1F527}",
1520
+ agent: "\u{1F916}",
1521
+ prompt: "\u{1F4AC}",
1522
+ workflow: "\u{1F504}",
1523
+ tool: "\u{1F9F0}"
1524
+ };
1525
+ var TYPE_LABELS = {
1526
+ skill: "Skills",
1527
+ agent: "Agents",
1528
+ prompt: "Prompts",
1529
+ workflow: "Workflows",
1530
+ tool: "Tools"
1531
+ };
1532
+ var MAX_DESCRIPTION_LENGTH = 80;
1533
+ var AgentsMdGenerator = class {
1534
+ projectRoot;
1535
+ synapSyncDir;
1536
+ scanner;
1537
+ constructor(projectRoot, synapSyncDir) {
1538
+ this.projectRoot = projectRoot;
1539
+ this.synapSyncDir = synapSyncDir;
1540
+ this.scanner = new CognitiveScanner(this.synapSyncDir);
1668
1541
  }
1669
- const currentValue = configManager.get(`sync.providers.${provider}.enabled`);
1670
- if (currentValue !== true) {
1671
- logger.line();
1672
- logger.info(`Provider '${provider}' is already disabled.`);
1673
- return;
1542
+ /**
1543
+ * Generate and write the AGENTS.md file from manifest cognitives.
1544
+ */
1545
+ generate(cognitives) {
1546
+ const outputPath = path5.join(this.projectRoot, AGENTS_MD_FILE_NAME);
1547
+ try {
1548
+ const entries = this.buildEntries(cognitives);
1549
+ const managedContent = this.renderManagedSection(entries);
1550
+ this.writeWithMarkers(outputPath, managedContent);
1551
+ return {
1552
+ success: true,
1553
+ filePath: outputPath,
1554
+ cognitiveCount: entries.length
1555
+ };
1556
+ } catch (error) {
1557
+ return {
1558
+ success: false,
1559
+ filePath: outputPath,
1560
+ cognitiveCount: 0,
1561
+ error: error instanceof Error ? error.message : "Unknown error"
1562
+ };
1563
+ }
1674
1564
  }
1675
- configManager.set(`sync.providers.${provider}.enabled`, false);
1676
- configManager.save();
1677
- logger.line();
1678
- logger.success(`Provider '${pc7.cyan(provider)}' disabled`);
1679
- }
1680
- function setProviderPath(configManager, providerName, newPath) {
1681
- if (providerName === void 0 || providerName === "") {
1682
- logger.line();
1683
- logger.error("Provider name is required.");
1684
- logger.hint("Usage: /providers path <provider> <path>");
1685
- return;
1686
- }
1687
- if (newPath === void 0 || newPath === "") {
1688
- logger.line();
1689
- logger.error("Path is required.");
1690
- logger.hint("Usage: /providers path <provider> <path>");
1691
- logger.hint("Example: /providers path claude .claude-code/");
1692
- return;
1693
- }
1694
- const provider = providerName.toLowerCase();
1695
- if (!SUPPORTED_PROVIDERS.includes(provider)) {
1696
- logger.line();
1697
- logger.error(`Unknown provider: ${provider}`);
1698
- logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
1699
- return;
1700
- }
1701
- const normalizedPath = newPath.endsWith("/") ? newPath : `${newPath}/`;
1702
- const cognitiveTypes = ["skill", "agent", "prompt", "workflow", "tool"];
1703
- for (const type of cognitiveTypes) {
1704
- configManager.set(`sync.providers.${provider}.paths.${type}`, `${normalizedPath}${type}s`);
1705
- }
1706
- configManager.save();
1707
- logger.line();
1708
- logger.success(`Updated paths for '${pc7.cyan(provider)}'`);
1709
- logger.log(` ${pc7.dim("Base path:")} ${pc7.cyan(normalizedPath)}`);
1710
- logger.line();
1711
- }
1712
- function showProviderInfo(configManager, provider) {
1713
- const config = configManager.getConfig();
1714
- const projectRoot = configManager.getProjectRoot();
1715
- const providerConfig = config.sync?.providers?.[provider];
1716
- const enabled = providerConfig?.enabled ?? false;
1717
- const paths = providerConfig?.paths ?? PROVIDER_PATHS[provider];
1718
- logger.line();
1719
- logger.bold(` ${getProviderDisplayName(provider)}`);
1720
- logger.line();
1721
- const statusIcon = enabled ? pc7.green("\u25CF") : pc7.dim("\u25CB");
1722
- const statusText = enabled ? pc7.green("Enabled") : pc7.dim("Disabled");
1723
- logger.log(` ${pc7.dim("Status:")} ${statusIcon} ${statusText}`);
1724
- logger.line();
1725
- logger.log(` ${pc7.dim("Paths:")}`);
1726
- const cognitiveTypes = ["skill", "agent", "prompt", "workflow", "tool"];
1727
- for (const type of cognitiveTypes) {
1728
- const typePath = paths[type] ?? "";
1729
- const fullPath = path5.join(projectRoot, typePath);
1730
- const exists = fs4.existsSync(fullPath);
1731
- const existsIcon = exists ? pc7.green("\u2713") : pc7.dim("\u2717");
1732
- logger.log(` ${pc7.dim(type.padEnd(10))} ${pc7.cyan(typePath)} ${existsIcon}`);
1733
- }
1734
- logger.line();
1735
- }
1736
- function getProvidersInfo(configManager) {
1737
- const config = configManager.getConfig();
1738
- const projectRoot = configManager.getProjectRoot();
1739
- const providers = [];
1740
- for (const provider of SUPPORTED_PROVIDERS) {
1741
- const providerConfig = config.sync?.providers?.[provider];
1742
- const enabled = providerConfig?.enabled ?? false;
1743
- const basePath = providerConfig?.paths?.skill?.split("/")[0] ?? `.${provider}`;
1744
- const fullPath = path5.join(projectRoot, basePath);
1745
- const exists = fs4.existsSync(fullPath);
1746
- providers.push({
1747
- name: provider,
1748
- enabled,
1749
- path: `${basePath}/`,
1750
- exists
1751
- });
1752
- }
1753
- return providers;
1754
- }
1755
- function getProviderDisplayName(provider) {
1756
- const names = {
1757
- claude: "Claude (Anthropic)",
1758
- openai: "OpenAI (GPT)",
1759
- gemini: "Gemini (Google)",
1760
- cursor: "Cursor IDE",
1761
- windsurf: "Windsurf IDE",
1762
- copilot: "GitHub Copilot"
1763
- };
1764
- return names[provider];
1765
- }
1766
- function registerProvidersCommand(program) {
1767
- const providersCmd = program.command("providers").description("Manage provider configuration");
1768
- providersCmd.command("list", { isDefault: true }).description("List all providers and their status").action(() => {
1769
- executeProvidersCommand("list");
1770
- });
1771
- providersCmd.command("enable <provider>").description("Enable a provider").action((provider) => {
1772
- executeProvidersCommand(`enable ${provider}`);
1773
- });
1774
- providersCmd.command("disable <provider>").description("Disable a provider").action((provider) => {
1775
- executeProvidersCommand(`disable ${provider}`);
1776
- });
1777
- providersCmd.command("path <provider> <path>").description("Set custom sync path for a provider").action((provider, newPath) => {
1778
- executeProvidersCommand(`path ${provider} ${newPath}`);
1779
- });
1780
- providersCmd.action(() => {
1781
- executeProvidersCommand("list");
1782
- });
1783
- }
1784
-
1785
- // src/commands/search.ts
1786
- init_esm_shims();
1787
- import pc8 from "picocolors";
1788
-
1789
- // src/services/registry/client.ts
1790
- init_esm_shims();
1791
- var RegistryClient = class {
1792
- baseUrl;
1793
- indexCache = null;
1794
- indexCacheTime = 0;
1795
- cacheTtl;
1796
- constructor(options = {}) {
1797
- this.baseUrl = options.baseUrl ?? REGISTRY_BASE_URL;
1798
- this.cacheTtl = options.cacheTtl ?? 5 * 60 * 1e3;
1799
- }
1800
- // ============================================
1801
- // Index Operations
1802
- // ============================================
1803
1565
  /**
1804
- * Fetch the registry index
1566
+ * Generate an empty managed section (used by init).
1805
1567
  */
1806
- async getIndex(forceRefresh = false) {
1807
- const now = Date.now();
1808
- if (!forceRefresh && this.indexCache !== null && now - this.indexCacheTime < this.cacheTtl) {
1809
- return this.indexCache;
1810
- }
1811
- const url = `${this.baseUrl}/${REGISTRY_INDEX_FILE}`;
1812
- const response = await this.fetch(url);
1813
- if (!response.ok) {
1814
- throw new RegistryError(`Failed to fetch registry index: ${response.status} ${response.statusText}`, url);
1568
+ generateEmpty() {
1569
+ const outputPath = path5.join(this.projectRoot, AGENTS_MD_FILE_NAME);
1570
+ try {
1571
+ const managedContent = this.renderEmptySection();
1572
+ this.writeWithMarkers(outputPath, managedContent);
1573
+ return {
1574
+ success: true,
1575
+ filePath: outputPath,
1576
+ cognitiveCount: 0
1577
+ };
1578
+ } catch (error) {
1579
+ return {
1580
+ success: false,
1581
+ filePath: outputPath,
1582
+ cognitiveCount: 0,
1583
+ error: error instanceof Error ? error.message : "Unknown error"
1584
+ };
1815
1585
  }
1816
- const index = await response.json();
1817
- this.indexCache = index;
1818
- this.indexCacheTime = now;
1819
- return index;
1820
1586
  }
1821
1587
  /**
1822
- * Get total count of cognitives in registry
1588
+ * Remove the AGENTS.md file entirely (used by purge).
1823
1589
  */
1824
- async getCount() {
1825
- const index = await this.getIndex();
1826
- return index.totalCognitives;
1590
+ remove() {
1591
+ const outputPath = path5.join(this.projectRoot, AGENTS_MD_FILE_NAME);
1592
+ if (fs4.existsSync(outputPath)) {
1593
+ fs4.unlinkSync(outputPath);
1594
+ return true;
1595
+ }
1596
+ return false;
1827
1597
  }
1828
- // ============================================
1829
- // Search Operations
1830
- // ============================================
1831
1598
  /**
1832
- * Search for cognitives in the registry
1599
+ * Build enriched entries from manifest cognitives.
1600
+ * Scans filesystem for descriptions from frontmatter.
1833
1601
  */
1834
- async search(query, options = {}) {
1835
- const index = await this.getIndex();
1836
- let results = [...index.cognitives];
1837
- if (query !== void 0 && query.trim() !== "") {
1838
- const q = query.toLowerCase();
1839
- results = results.filter(
1840
- (c) => c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q) || c.tags.some((t) => t.toLowerCase().includes(q))
1841
- );
1842
- }
1843
- if (options.type !== void 0) {
1844
- results = results.filter((c) => c.type === options.type);
1845
- }
1846
- if (options.category !== void 0) {
1847
- results = results.filter((c) => c.category === options.category);
1848
- }
1849
- if (options.tag !== void 0) {
1850
- const tag = options.tag.toLowerCase();
1851
- results = results.filter((c) => c.tags.some((t) => t.toLowerCase() === tag));
1852
- }
1853
- const total = results.length;
1854
- if (options.limit !== void 0 && options.limit > 0) {
1855
- results = results.slice(0, options.limit);
1602
+ buildEntries(cognitives) {
1603
+ const scanned = this.scanner.scan();
1604
+ const scannedMap = new Map(scanned.map((s) => [s.name, s]));
1605
+ const entries = [];
1606
+ for (const cognitive of cognitives) {
1607
+ const scannedCognitive = scannedMap.get(cognitive.name);
1608
+ let description = "No description available";
1609
+ let relativePath = "";
1610
+ let fileName = "";
1611
+ if (scannedCognitive !== void 0) {
1612
+ const rawDesc = scannedCognitive.metadata.description;
1613
+ if (typeof rawDesc === "string" && rawDesc.length > 0) {
1614
+ description = rawDesc;
1615
+ } else if (Array.isArray(rawDesc) && rawDesc.length > 0) {
1616
+ description = rawDesc.join(" ");
1617
+ }
1618
+ relativePath = path5.relative(this.projectRoot, scannedCognitive.filePath);
1619
+ fileName = scannedCognitive.fileName ?? path5.basename(scannedCognitive.filePath);
1620
+ } else {
1621
+ const typeDir = `${cognitive.type}s`;
1622
+ const expectedDir = path5.join(this.synapSyncDir, typeDir, cognitive.category, cognitive.name);
1623
+ relativePath = path5.relative(this.projectRoot, expectedDir);
1624
+ fileName = cognitive.name;
1625
+ }
1626
+ entries.push({
1627
+ name: cognitive.name,
1628
+ type: cognitive.type,
1629
+ category: cognitive.category,
1630
+ description: truncateDescription(description),
1631
+ version: cognitive.version,
1632
+ relativePath,
1633
+ fileName
1634
+ });
1856
1635
  }
1857
- const filters = {};
1858
- if (options.type !== void 0) filters.type = options.type;
1859
- if (options.category !== void 0) filters.category = options.category;
1860
- if (options.tag !== void 0) filters.tag = options.tag;
1861
- return {
1862
- cognitives: results,
1863
- total,
1864
- ...query !== void 0 ? { query } : {},
1865
- filters
1866
- };
1636
+ entries.sort((a, b) => a.name.localeCompare(b.name));
1637
+ return entries;
1867
1638
  }
1868
1639
  /**
1869
- * Find a cognitive by name
1640
+ * Render the full managed section (between markers).
1870
1641
  */
1871
- async findByName(name) {
1872
- const index = await this.getIndex();
1873
- return index.cognitives.find((c) => c.name === name) ?? null;
1642
+ renderManagedSection(entries) {
1643
+ const lines = [
1644
+ START_MARKER,
1645
+ "# SynapSync Project Cognitives",
1646
+ "",
1647
+ "> Auto-generated by [SynapSync](https://synapsync.github.io/synapsync-cli/). Do not edit this section manually.",
1648
+ ""
1649
+ ];
1650
+ if (entries.length === 0) {
1651
+ lines.push("*No cognitives installed yet. Run `synapsync add <name>` to get started.*");
1652
+ } else {
1653
+ lines.push("## Available Cognitives");
1654
+ lines.push("");
1655
+ for (const type of COGNITIVE_TYPES) {
1656
+ const typeEntries = entries.filter((e) => e.type === type);
1657
+ if (typeEntries.length === 0) continue;
1658
+ lines.push(`### ${TYPE_ICONS[type]} ${TYPE_LABELS[type]}`);
1659
+ lines.push("");
1660
+ lines.push(...this.renderTypeTable(typeEntries));
1661
+ lines.push("");
1662
+ }
1663
+ lines.push("---");
1664
+ lines.push("");
1665
+ lines.push(`*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()} \xB7 ${entries.length} cognitive${entries.length !== 1 ? "s" : ""} installed*`);
1666
+ }
1667
+ lines.push(END_MARKER);
1668
+ return lines.join("\n");
1874
1669
  }
1875
1670
  /**
1876
- * List all cognitives
1671
+ * Render the empty managed section.
1877
1672
  */
1878
- async list(options = {}) {
1879
- const result = await this.search(void 0, options);
1880
- return result.cognitives;
1673
+ renderEmptySection() {
1674
+ const lines = [
1675
+ START_MARKER,
1676
+ "# SynapSync Project Cognitives",
1677
+ "",
1678
+ "> Auto-generated by [SynapSync](https://synapsync.github.io/synapsync-cli/). Do not edit this section manually.",
1679
+ "",
1680
+ "*No cognitives installed yet. Run `synapsync add <name>` to get started.*",
1681
+ END_MARKER
1682
+ ];
1683
+ return lines.join("\n");
1881
1684
  }
1882
- // ============================================
1883
- // Download Operations
1884
- // ============================================
1885
1685
  /**
1886
- * Get the manifest for a cognitive
1686
+ * Render a markdown table for a group of entries.
1887
1687
  */
1888
- async getManifest(cognitiveEntry) {
1889
- const url = `${this.baseUrl}/${cognitiveEntry.path}/${REGISTRY_MANIFEST_FILE}`;
1890
- const response = await this.fetch(url);
1891
- if (!response.ok) {
1892
- throw new RegistryError(
1893
- `Failed to fetch manifest for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
1894
- url
1895
- );
1688
+ renderTypeTable(entries) {
1689
+ const lines = [
1690
+ "| Name | Category | Description | Version | Path |",
1691
+ "|------|----------|-------------|---------|------|"
1692
+ ];
1693
+ for (const entry of entries) {
1694
+ const name = `\`${escapeTableCell(entry.name)}\``;
1695
+ const category = escapeTableCell(entry.category);
1696
+ const description = escapeTableCell(entry.description);
1697
+ const version2 = escapeTableCell(entry.version);
1698
+ const pathLink = `[${escapeTableCell(entry.fileName)}](${entry.relativePath})`;
1699
+ lines.push(`| ${name} | ${category} | ${description} | ${version2} | ${pathLink} |`);
1896
1700
  }
1897
- return await response.json();
1701
+ return lines;
1898
1702
  }
1899
1703
  /**
1900
- * Get the content file for a cognitive
1704
+ * Write content within markers, preserving user content outside.
1901
1705
  */
1902
- async getContent(cognitiveEntry, manifest) {
1903
- const url = `${this.baseUrl}/${cognitiveEntry.path}/${manifest.file}`;
1904
- const response = await this.fetch(url);
1905
- if (!response.ok) {
1906
- throw new RegistryError(
1907
- `Failed to fetch content for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
1908
- url
1909
- );
1706
+ writeWithMarkers(filePath, managedContent) {
1707
+ if (!fs4.existsSync(filePath)) {
1708
+ fs4.writeFileSync(filePath, managedContent + "\n", "utf-8");
1709
+ return;
1910
1710
  }
1911
- return response.text();
1912
- }
1913
- /**
1914
- * Download a cognitive (manifest + content)
1915
- */
1916
- async download(name) {
1917
- const entry = await this.findByName(name);
1918
- if (entry === null) {
1919
- throw new CognitiveNotFoundError(name);
1711
+ const existing = fs4.readFileSync(filePath, "utf-8");
1712
+ const startIdx = existing.indexOf(START_MARKER);
1713
+ const endIdx = existing.indexOf(END_MARKER);
1714
+ if (startIdx !== -1 && endIdx !== -1) {
1715
+ const before = existing.slice(0, startIdx);
1716
+ const after = existing.slice(endIdx + END_MARKER.length);
1717
+ fs4.writeFileSync(filePath, before + managedContent + after, "utf-8");
1718
+ } else if (startIdx !== -1 && endIdx === -1) {
1719
+ const before = existing.slice(0, startIdx);
1720
+ fs4.writeFileSync(filePath, before + managedContent + "\n", "utf-8");
1721
+ } else {
1722
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
1723
+ fs4.writeFileSync(filePath, existing + separator + managedContent + "\n", "utf-8");
1920
1724
  }
1921
- const manifest = await this.getManifest(entry);
1922
- const content = await this.getContent(entry, manifest);
1923
- return {
1924
- manifest,
1925
- content,
1926
- path: entry.path
1927
- };
1928
- }
1929
- /**
1930
- * Download additional assets for a cognitive
1931
- */
1932
- async downloadAsset(cognitiveEntry, assetPath) {
1933
- const url = `${this.baseUrl}/${cognitiveEntry.path}/${assetPath}`;
1934
- const response = await this.fetch(url);
1935
- if (!response.ok) {
1936
- throw new RegistryError(
1937
- `Failed to fetch asset ${assetPath} for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
1938
- url
1939
- );
1940
- }
1941
- return response.text();
1942
1725
  }
1943
- // ============================================
1944
- // Utility Methods
1945
- // ============================================
1946
- /**
1947
- * Check if registry is reachable
1948
- */
1949
- async ping() {
1950
- try {
1951
- const url = `${this.baseUrl}/${REGISTRY_INDEX_FILE}`;
1952
- const response = await this.fetch(url, { method: "HEAD" });
1953
- return response.ok;
1954
- } catch {
1955
- return false;
1956
- }
1726
+ };
1727
+ function truncateDescription(description) {
1728
+ const text2 = String(description ?? "");
1729
+ if (text2.length <= MAX_DESCRIPTION_LENGTH) {
1730
+ return text2;
1957
1731
  }
1958
- /**
1959
- * Clear the cache
1960
- */
1961
- clearCache() {
1962
- this.indexCache = null;
1963
- this.indexCacheTime = 0;
1732
+ return text2.slice(0, MAX_DESCRIPTION_LENGTH - 3) + "...";
1733
+ }
1734
+ function escapeTableCell(value) {
1735
+ return String(value ?? "").replace(/\|/g, "\\|");
1736
+ }
1737
+ function regenerateAgentsMd(projectRoot, synapSyncDir) {
1738
+ const manifest = new ManifestManager(synapSyncDir);
1739
+ const generator = new AgentsMdGenerator(projectRoot, synapSyncDir);
1740
+ return generator.generate(manifest.getCognitives());
1741
+ }
1742
+
1743
+ // src/commands/init.ts
1744
+ async function executeInitCommand(options = {}) {
1745
+ const projectRoot = process.cwd();
1746
+ const configPath = path6.join(projectRoot, CONFIG_FILE_NAME);
1747
+ const storagePath = path6.join(projectRoot, DEFAULT_SYNAPSYNC_DIR);
1748
+ if (ConfigManager.isProjectInitialized(projectRoot)) {
1749
+ logger.line();
1750
+ logger.warning("Project already initialized.");
1751
+ logger.log(` ${pc4.dim("Config:")} ${configPath}`);
1752
+ logger.log(` ${pc4.dim("Storage:")} ${storagePath}`);
1753
+ logger.line();
1754
+ logger.hint("Use /config to view or modify settings.");
1755
+ return null;
1964
1756
  }
1965
- /**
1966
- * Get the base URL
1967
- */
1968
- getBaseUrl() {
1969
- return this.baseUrl;
1757
+ if (options.yes === true) {
1758
+ return initializeProject({
1759
+ name: options.name ?? path6.basename(projectRoot),
1760
+ ...options.description !== void 0 && { description: options.description },
1761
+ providers: options.providers ?? ["claude"]
1762
+ });
1970
1763
  }
1971
- // ============================================
1972
- // Private Methods
1973
- // ============================================
1974
- async fetch(url, options) {
1975
- try {
1976
- return await fetch(url, {
1977
- ...options,
1978
- headers: {
1979
- "User-Agent": "SynapSync-CLI",
1980
- ...options?.headers
1981
- }
1982
- });
1983
- } catch (error) {
1984
- if (error instanceof Error) {
1985
- throw new RegistryError(`Network error: ${error.message}`, url);
1764
+ logger.line();
1765
+ p.intro(pc4.bgCyan(pc4.black(" Initialize SynapSync Project ")));
1766
+ const result = await p.group(
1767
+ {
1768
+ name: () => {
1769
+ const defaultName = path6.basename(projectRoot);
1770
+ return p.text({
1771
+ message: "Project name",
1772
+ placeholder: defaultName,
1773
+ defaultValue: defaultName,
1774
+ validate: (value) => {
1775
+ const finalValue = value.trim() === "" ? defaultName : value;
1776
+ if (!/^[a-z0-9-_]+$/i.test(finalValue)) {
1777
+ return "Project name can only contain letters, numbers, hyphens, and underscores";
1778
+ }
1779
+ return void 0;
1780
+ }
1781
+ });
1782
+ },
1783
+ description: () => p.text({
1784
+ message: "Description (optional)",
1785
+ placeholder: "A brief description of your project"
1786
+ }),
1787
+ providers: () => p.multiselect({
1788
+ message: "Select AI providers to enable",
1789
+ options: SUPPORTED_PROVIDERS.map((provider) => ({
1790
+ value: provider,
1791
+ label: getProviderLabel(provider),
1792
+ hint: getProviderHint(provider)
1793
+ })),
1794
+ initialValues: ["claude"],
1795
+ required: false
1796
+ })
1797
+ },
1798
+ {
1799
+ onCancel: () => {
1800
+ p.cancel("Project initialization cancelled.");
1801
+ return process.exit(0);
1986
1802
  }
1987
- throw new RegistryError("Network error", url);
1988
1803
  }
1804
+ );
1805
+ if (p.isCancel(result)) {
1806
+ return null;
1989
1807
  }
1990
- };
1991
- var RegistryError = class extends Error {
1992
- constructor(message, url) {
1993
- super(message);
1994
- this.url = url;
1995
- this.name = "RegistryError";
1996
- }
1997
- };
1998
- var CognitiveNotFoundError = class extends Error {
1999
- constructor(cognitiveName) {
2000
- super(`Cognitive '${cognitiveName}' not found in registry`);
2001
- this.cognitiveName = cognitiveName;
2002
- this.name = "CognitiveNotFoundError";
2003
- }
2004
- };
2005
-
2006
- // src/commands/search.ts
2007
- async function executeSearchCommand(query, options) {
2008
- logger.line();
2009
- const validatedOptions = validateOptions(options);
2010
- if (validatedOptions === null) {
2011
- return;
2012
- }
2013
- const searchingText = query !== void 0 && query.trim() !== "" ? `Searching for "${query}"...` : "Fetching cognitives from registry...";
2014
- logger.log(` ${pc8.dim(searchingText)}`);
1808
+ return initializeProject({
1809
+ name: result.name,
1810
+ description: result.description,
1811
+ providers: result.providers
1812
+ });
1813
+ }
1814
+ function initializeProject(setup) {
1815
+ const projectRoot = process.cwd();
1816
+ const configPath = path6.join(projectRoot, CONFIG_FILE_NAME);
1817
+ const storagePath = path6.join(projectRoot, DEFAULT_SYNAPSYNC_DIR);
1818
+ const s = p.spinner();
1819
+ s.start("Creating project structure...");
2015
1820
  try {
2016
- const client = new RegistryClient();
2017
- const isReachable = await client.ping();
2018
- if (!isReachable) {
2019
- logger.line();
2020
- logger.error("Unable to reach the registry. Check your internet connection.");
2021
- return;
2022
- }
2023
- const searchOpts = {};
2024
- if (validatedOptions.type !== void 0) searchOpts.type = validatedOptions.type;
2025
- if (validatedOptions.category !== void 0) searchOpts.category = validatedOptions.category;
2026
- if (validatedOptions.tag !== void 0) searchOpts.tag = validatedOptions.tag;
2027
- if (validatedOptions.limit !== void 0) searchOpts.limit = validatedOptions.limit;
2028
- const result = await client.search(query, searchOpts);
2029
- process.stdout.write("\x1B[1A\x1B[2K");
2030
- if (options.json === true) {
2031
- console.log(JSON.stringify(result, null, 2));
2032
- return;
1821
+ createStorageStructure(storagePath);
1822
+ const configManager = new ConfigManager(projectRoot);
1823
+ configManager.create(setup.name, setup.description);
1824
+ for (const provider of setup.providers) {
1825
+ configManager.set(`sync.providers.${provider}.enabled`, true);
2033
1826
  }
2034
- displaySearchResults(result.cognitives, query, result.total);
1827
+ configManager.save();
1828
+ createManifest(storagePath);
1829
+ new AgentsMdGenerator(projectRoot, storagePath).generateEmpty();
1830
+ updateGitignore(projectRoot);
1831
+ s.stop("Project structure created!");
1832
+ showSuccessMessage(setup, configPath, storagePath);
1833
+ return {
1834
+ success: true,
1835
+ projectPath: projectRoot,
1836
+ configPath,
1837
+ storagePath
1838
+ };
2035
1839
  } catch (error) {
1840
+ s.stop("Failed to create project.");
2036
1841
  logger.line();
2037
- if (error instanceof RegistryError) {
2038
- logger.error(`Registry error: ${error.message}`);
2039
- } else if (error instanceof Error) {
2040
- logger.error(`Search failed: ${error.message}`);
2041
- } else {
2042
- logger.error("Search failed with unknown error");
1842
+ if (error instanceof Error) {
1843
+ logger.error(error.message);
2043
1844
  }
1845
+ throw error;
2044
1846
  }
2045
1847
  }
2046
- function validateOptions(options) {
2047
- const validated = {};
2048
- if (options.type !== void 0) {
2049
- if (!COGNITIVE_TYPES.includes(options.type)) {
2050
- logger.error(`Invalid type: ${options.type}`);
2051
- logger.hint(`Valid types: ${COGNITIVE_TYPES.join(", ")}`);
2052
- return null;
2053
- }
2054
- validated.type = options.type;
2055
- }
2056
- if (options.category !== void 0) {
2057
- if (!CATEGORIES.includes(options.category)) {
2058
- logger.error(`Invalid category: ${options.category}`);
2059
- logger.hint(`Valid categories: ${CATEGORIES.join(", ")}`);
2060
- return null;
2061
- }
2062
- validated.category = options.category;
2063
- }
2064
- if (options.tag !== void 0) {
2065
- validated.tag = options.tag;
2066
- }
2067
- if (options.limit !== void 0) {
2068
- const limit = parseInt(options.limit, 10);
2069
- if (isNaN(limit) || limit < 1) {
2070
- logger.error("Limit must be a positive number");
2071
- return null;
2072
- }
2073
- validated.limit = limit;
1848
+ function createStorageStructure(storagePath) {
1849
+ fs5.mkdirSync(storagePath, { recursive: true });
1850
+ for (const cognitiveType of COGNITIVE_TYPES) {
1851
+ const typePath = path6.join(storagePath, `${cognitiveType}s`);
1852
+ fs5.mkdirSync(typePath, { recursive: true });
1853
+ const gitkeepPath = path6.join(typePath, ".gitkeep");
1854
+ fs5.writeFileSync(gitkeepPath, "");
2074
1855
  }
2075
- return validated;
2076
1856
  }
2077
- function displaySearchResults(cognitives, query, total) {
2078
- if (query !== void 0 && query.trim() !== "") {
2079
- logger.bold(` Search Results for "${query}"`);
1857
+ function createManifest(storagePath) {
1858
+ const manifestPath = path6.join(storagePath, "manifest.json");
1859
+ const manifest = {
1860
+ version: "1.0.0",
1861
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
1862
+ cognitives: {},
1863
+ syncs: {}
1864
+ };
1865
+ fs5.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
1866
+ }
1867
+ function updateGitignore(projectRoot) {
1868
+ const gitignorePath = path6.join(projectRoot, ".gitignore");
1869
+ const synapsyncEntries = `
1870
+ # SynapSync
1871
+ .synapsync/manifest.json
1872
+ *.local.yaml
1873
+ `;
1874
+ if (fs5.existsSync(gitignorePath)) {
1875
+ const content = fs5.readFileSync(gitignorePath, "utf-8");
1876
+ if (!content.includes("# SynapSync")) {
1877
+ fs5.appendFileSync(gitignorePath, synapsyncEntries);
1878
+ }
2080
1879
  } else {
2081
- logger.bold(" Registry Cognitives");
1880
+ fs5.writeFileSync(gitignorePath, synapsyncEntries.trim() + "\n");
2082
1881
  }
2083
- logger.line();
2084
- if (cognitives.length === 0) {
2085
- logger.log(` ${pc8.dim("No cognitives found")}`);
2086
- logger.line();
2087
- logger.hint("Try a different search query or remove filters.");
2088
- return;
2089
- }
2090
- if (cognitives.length < total) {
2091
- logger.log(` ${pc8.dim(`Showing ${cognitives.length} of ${total} results`)}`);
2092
- } else {
2093
- logger.log(` ${pc8.dim(`Found ${total} cognitive${total === 1 ? "" : "s"}`)}`);
2094
- }
2095
- logger.line();
2096
- for (const cognitive of cognitives) {
2097
- displayCognitive(cognitive);
2098
- }
2099
- logger.line();
2100
- logger.hint("Run synapsync add <name> to add a cognitive.");
2101
1882
  }
2102
- function displayCognitive(cognitive) {
2103
- const typeIcon = getCognitiveIcon2(cognitive.type);
2104
- const typeLabel = pc8.dim(`[${cognitive.type}]`);
2105
- logger.log(` ${typeIcon} ${pc8.bold(pc8.white(cognitive.name))} ${typeLabel}`);
2106
- logger.log(` ${pc8.dim(truncate(cognitive.description, 60))}`);
2107
- const meta = [];
2108
- meta.push(pc8.dim(`v${cognitive.version}`));
2109
- meta.push(pc8.dim(cognitive.category));
2110
- if (cognitive.downloads > 0) {
2111
- meta.push(pc8.dim(`${cognitive.downloads} downloads`));
2112
- }
2113
- logger.log(` ${meta.join(" \xB7 ")}`);
2114
- if (cognitive.tags.length > 0) {
2115
- const tags = cognitive.tags.slice(0, 5).map((t) => pc8.cyan(t)).join(" ");
2116
- logger.log(` ${tags}`);
2117
- }
2118
- logger.line();
1883
+ function getProviderLabel(provider) {
1884
+ const labels = {
1885
+ claude: "Claude (Anthropic)",
1886
+ openai: "OpenAI (GPT)",
1887
+ gemini: "Gemini (Google)",
1888
+ cursor: "Cursor IDE",
1889
+ windsurf: "Windsurf IDE",
1890
+ copilot: "GitHub Copilot"
1891
+ };
1892
+ return labels[provider];
2119
1893
  }
2120
- function getCognitiveIcon2(type) {
2121
- const icons = {
2122
- skill: pc8.blue("\u25C6"),
2123
- agent: pc8.magenta("\u25C6"),
2124
- prompt: pc8.yellow("\u25C6"),
2125
- workflow: pc8.cyan("\u25C6"),
2126
- tool: pc8.green("\u25C6")
1894
+ function getProviderHint(provider) {
1895
+ const hints = {
1896
+ claude: "Claude Code, Claude Desktop",
1897
+ openai: "ChatGPT, API",
1898
+ gemini: "Google AI Studio",
1899
+ cursor: "AI-first code editor",
1900
+ windsurf: "AI-powered IDE",
1901
+ copilot: "VS Code integration"
2127
1902
  };
2128
- return icons[type];
1903
+ return hints[provider];
2129
1904
  }
2130
- function truncate(text2, maxLength) {
2131
- if (text2.length <= maxLength) return text2;
2132
- return text2.slice(0, maxLength - 3) + "...";
1905
+ function showSuccessMessage(setup, configPath, storagePath) {
1906
+ logger.line();
1907
+ p.note(
1908
+ [
1909
+ `${pc4.dim("Config:")} ${pc4.cyan(configPath)}`,
1910
+ `${pc4.dim("Storage:")} ${pc4.cyan(storagePath)}`,
1911
+ "",
1912
+ `${pc4.dim("Providers:")} ${setup.providers.map((p2) => pc4.green(p2)).join(", ") || pc4.dim("none")}`
1913
+ ].join("\n"),
1914
+ `Project "${setup.name}" initialized!`
1915
+ );
1916
+ logger.line();
1917
+ logger.bold(" Next Steps:");
1918
+ logger.line();
1919
+ logger.log(` ${pc4.cyan("1.")} Browse available cognitives:`);
1920
+ logger.log(` ${pc4.dim("$")} synapsync list --remote`);
1921
+ logger.line();
1922
+ logger.log(` ${pc4.cyan("2.")} Add cognitives:`);
1923
+ logger.log(` ${pc4.dim("$")} synapsync add code-reviewer`);
1924
+ logger.log(` ${pc4.dim("$")} synapsync add github:user/my-skill`);
1925
+ logger.line();
1926
+ p.outro(pc4.green("Happy syncing!"));
2133
1927
  }
2134
- function registerSearchCommand(program) {
2135
- program.command("search [query]").description("Search for cognitives in the registry").option("-t, --type <type>", "Filter by type (skill, agent, prompt, workflow, tool)").option("-c, --category <category>", "Filter by category").option("--tag <tag>", "Filter by tag").option("-l, --limit <number>", "Limit results", "20").option("--json", "Output as JSON").action(async (query, options) => {
2136
- await executeSearchCommand(query, options);
1928
+ function registerInitCommand(program) {
1929
+ program.command("init").description("Initialize a new SynapSync project").option("-n, --name <name>", "Project name").option("-d, --description <desc>", "Project description").option("-p, --provider <providers...>", "Enable providers (claude, openai, etc.)").option("-y, --yes", "Skip prompts and use defaults").action(async (options) => {
1930
+ await executeInitCommand({
1931
+ ...options.name !== void 0 && { name: options.name },
1932
+ ...options.description !== void 0 && { description: options.description },
1933
+ ...options.provider !== void 0 && { providers: options.provider },
1934
+ ...options.yes !== void 0 && { yes: options.yes }
1935
+ });
2137
1936
  });
2138
1937
  }
2139
1938
 
2140
- // src/commands/add.ts
2141
- init_esm_shims();
2142
- import * as fs8 from "fs";
2143
- import * as path10 from "path";
2144
- import pc9 from "picocolors";
2145
-
2146
- // src/services/sync/engine.ts
2147
- init_esm_shims();
2148
- import * as path9 from "path";
2149
-
2150
- // src/services/scanner/scanner.ts
2151
- init_esm_shims();
2152
- import * as fs5 from "fs";
2153
- import * as path6 from "path";
2154
- import * as crypto from "crypto";
2155
-
2156
- // src/services/scanner/parser.ts
1939
+ // src/commands/config.ts
2157
1940
  init_esm_shims();
2158
- function parseFrontmatter(content) {
2159
- const match = content.match(/^---\n([\s\S]*?)\n---/);
2160
- if (match?.[1] === void 0) {
2161
- return {};
1941
+ import pc5 from "picocolors";
1942
+ function executeConfigCommand(args) {
1943
+ const options = parseConfigArgs(args);
1944
+ const configManager = ConfigManager.findConfig();
1945
+ if (configManager === null) {
1946
+ logger.line();
1947
+ logger.error("No SynapSync project found.");
1948
+ logger.hint("Run /init to initialize a project.");
1949
+ return;
2162
1950
  }
2163
- try {
2164
- return parseYaml(match[1]);
2165
- } catch {
2166
- return {};
1951
+ switch (options.action) {
1952
+ case "list":
1953
+ showConfigList(configManager);
1954
+ break;
1955
+ case "get":
1956
+ showConfigValue(configManager, options.key ?? "");
1957
+ break;
1958
+ case "set":
1959
+ setConfigValue(configManager, options.key ?? "", options.value ?? "");
1960
+ break;
2167
1961
  }
2168
1962
  }
2169
- function parseYaml(yaml2) {
2170
- const result = {};
2171
- const lines = yaml2.split("\n");
2172
- let currentKey = null;
2173
- let currentArray = null;
2174
- for (const line of lines) {
2175
- if (line.trim() === "" || line.trim().startsWith("#")) {
2176
- continue;
2177
- }
2178
- if (line.match(/^\s+-\s+/)) {
2179
- const value = line.replace(/^\s+-\s+/, "").trim();
2180
- if (currentArray !== null) {
2181
- currentArray.push(cleanValue(value));
2182
- }
2183
- continue;
2184
- }
2185
- const colonIndex = line.indexOf(":");
2186
- if (colonIndex > 0) {
2187
- const key = line.slice(0, colonIndex).trim();
2188
- const rawValue = line.slice(colonIndex + 1).trim();
2189
- if (currentKey !== null && currentArray !== null) {
2190
- setNestedValue2(result, currentKey, currentArray);
2191
- currentArray = null;
2192
- }
2193
- currentKey = key;
2194
- if (rawValue === "" || rawValue === "|" || rawValue === ">") {
2195
- currentArray = [];
2196
- } else if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
2197
- const arrayContent = rawValue.slice(1, -1);
2198
- const items = arrayContent.split(",").map((item) => cleanValue(item.trim()));
2199
- setNestedValue2(result, key, items);
2200
- currentKey = null;
2201
- } else {
2202
- setNestedValue2(result, key, cleanValue(rawValue));
2203
- currentKey = null;
2204
- }
2205
- }
2206
- }
2207
- if (currentKey !== null && currentArray !== null) {
2208
- setNestedValue2(result, currentKey, currentArray);
1963
+ function showConfigList(configManager) {
1964
+ const flatConfig = configManager.flatten();
1965
+ logger.line();
1966
+ logger.bold(" Configuration");
1967
+ logger.line();
1968
+ const groups = {};
1969
+ for (const [key, value] of Object.entries(flatConfig)) {
1970
+ const parts = key.split(".");
1971
+ const group2 = parts[0] ?? "other";
1972
+ groups[group2] ??= {};
1973
+ groups[group2][key] = value;
2209
1974
  }
2210
- return result;
2211
- }
2212
- function cleanValue(value) {
2213
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2214
- return value.slice(1, -1);
1975
+ for (const [group2, values] of Object.entries(groups)) {
1976
+ logger.log(` ${pc5.cyan(group2)}:`);
1977
+ for (const [key, value] of Object.entries(values)) {
1978
+ const displayKey = key.replace(`${group2}.`, "");
1979
+ const displayValue = formatValue(value);
1980
+ logger.log(` ${pc5.dim(displayKey.padEnd(30))} ${displayValue}`);
1981
+ }
1982
+ logger.line();
2215
1983
  }
2216
- return value;
2217
- }
2218
- function setNestedValue2(obj, key, value) {
2219
- obj[key] = value;
1984
+ logger.hint(`Config file: ${configManager.getProjectRoot()}/synapsync.config.yaml`);
2220
1985
  }
2221
- function extractVersion(metadata, content) {
2222
- if (metadata.version !== void 0) {
2223
- return metadata.version;
1986
+ function showConfigValue(configManager, key) {
1987
+ if (key === "") {
1988
+ logger.line();
1989
+ logger.error("Key is required.");
1990
+ logger.hint("Usage: /config get <key>");
1991
+ logger.hint("Example: /config get cli.theme");
1992
+ return;
2224
1993
  }
2225
- const versionMatch = content.match(/version:\s*['"]?([0-9]+\.[0-9]+\.[0-9]+)['"]?/i);
2226
- if (versionMatch?.[1] !== void 0) {
2227
- return versionMatch[1];
1994
+ const value = configManager.get(key);
1995
+ logger.line();
1996
+ if (value === void 0) {
1997
+ logger.warning(`Key not found: ${pc5.cyan(key)}`);
1998
+ logger.line();
1999
+ logger.hint("Use /config list to see all available keys.");
2000
+ } else {
2001
+ logger.log(` ${pc5.cyan(key)} = ${formatValue(value)}`);
2228
2002
  }
2229
- return "1.0.0";
2230
2003
  }
2231
- function extractName(metadata, dirName, content) {
2232
- if (metadata.name !== void 0) {
2233
- return metadata.name;
2004
+ function setConfigValue(configManager, key, value) {
2005
+ if (key === "") {
2006
+ logger.line();
2007
+ logger.error("Key is required.");
2008
+ logger.hint("Usage: /config set <key> <value>");
2009
+ logger.hint("Example: /config set cli.theme dark");
2010
+ return;
2234
2011
  }
2235
- const titleMatch = content.match(/^#\s+(.+)$/m);
2236
- if (titleMatch?.[1] !== void 0) {
2237
- return titleMatch[1].toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2012
+ if (value === "") {
2013
+ logger.line();
2014
+ logger.error("Value is required.");
2015
+ logger.hint("Usage: /config set <key> <value>");
2016
+ return;
2238
2017
  }
2239
- return dirName;
2018
+ const existingValue = configManager.get(key);
2019
+ const isNewKey = existingValue === void 0;
2020
+ const parsedValue = parseValue(value);
2021
+ configManager.set(key, parsedValue);
2022
+ configManager.save();
2023
+ logger.line();
2024
+ if (isNewKey) {
2025
+ logger.warning(`Created new key: ${pc5.cyan(key)}`);
2026
+ }
2027
+ logger.success(`${pc5.cyan(key)} = ${formatValue(parsedValue)}`);
2240
2028
  }
2241
-
2242
- // src/services/scanner/scanner.ts
2243
- var CognitiveScanner = class {
2244
- synapSyncDir;
2245
- constructor(synapSyncDir) {
2246
- this.synapSyncDir = synapSyncDir;
2029
+ function parseConfigArgs(args) {
2030
+ const parts = args.trim().split(/\s+/);
2031
+ const action = (parts[0] ?? "list").toLowerCase();
2032
+ if (action === "" || action === "list") {
2033
+ return { action: "list" };
2247
2034
  }
2248
- /**
2249
- * Scan the filesystem for cognitives
2250
- */
2251
- scan(options = {}) {
2252
- const cognitives = [];
2253
- const errors = [];
2254
- const typesToScan = options.types ?? COGNITIVE_TYPES;
2255
- for (const type of typesToScan) {
2256
- const typeDir = path6.join(this.synapSyncDir, `${type}s`);
2257
- if (!fs5.existsSync(typeDir)) {
2258
- continue;
2259
- }
2260
- const categories = this.listDirectories(typeDir);
2261
- for (const category of categories) {
2262
- if (options.categories !== void 0 && !options.categories.includes(category)) {
2263
- continue;
2264
- }
2265
- const categoryDir = path6.join(typeDir, category);
2266
- const cognitiveDirs = this.listDirectories(categoryDir);
2267
- for (const cognitiveDir of cognitiveDirs) {
2268
- try {
2269
- const cognitive = this.scanCognitive(
2270
- path6.join(categoryDir, cognitiveDir),
2271
- type,
2272
- category
2273
- );
2274
- if (cognitive !== null) {
2275
- cognitives.push(cognitive);
2276
- }
2277
- } catch (error) {
2278
- errors.push({
2279
- path: path6.join(categoryDir, cognitiveDir),
2280
- error: error instanceof Error ? error.message : "Unknown error"
2281
- });
2282
- }
2283
- }
2284
- }
2285
- }
2286
- return cognitives;
2035
+ if (action === "get") {
2036
+ return {
2037
+ action: "get",
2038
+ key: parts[1] ?? ""
2039
+ };
2287
2040
  }
2288
- /**
2289
- * Scan a single cognitive directory
2290
- */
2291
- scanCognitive(cognitiveDir, type, category) {
2292
- const filePath = this.findCognitiveFile(cognitiveDir, type);
2293
- if (filePath === null) {
2294
- return null;
2295
- }
2296
- const content = fs5.readFileSync(filePath, "utf-8");
2297
- const metadata = parseFrontmatter(content);
2298
- const dirName = path6.basename(cognitiveDir);
2299
- const fileName = path6.basename(filePath);
2300
- const name = extractName(metadata, dirName, content);
2301
- const version2 = extractVersion(metadata, content);
2302
- const hash = this.computeHash(content);
2041
+ if (action === "set") {
2303
2042
  return {
2304
- name,
2305
- type,
2306
- category: metadata.category ?? category,
2307
- path: cognitiveDir,
2308
- filePath,
2309
- fileName,
2310
- // Add original filename
2311
- hash,
2312
- metadata: {
2313
- ...metadata,
2314
- name,
2315
- version: version2
2316
- }
2043
+ action: "set",
2044
+ key: parts[1] ?? "",
2045
+ value: parts.slice(2).join(" ")
2317
2046
  };
2318
2047
  }
2319
- /**
2320
- * Find the cognitive file in a directory
2321
- * Checks for legacy fixed filename first, then any file with matching extension
2322
- */
2323
- findCognitiveFile(cognitiveDir, type) {
2324
- const legacyFileName = COGNITIVE_FILE_NAMES[type];
2325
- const legacyPath = path6.join(cognitiveDir, legacyFileName);
2326
- if (fs5.existsSync(legacyPath)) {
2327
- return legacyPath;
2328
- }
2329
- const extension = COGNITIVE_FILE_EXTENSIONS[type];
2330
- if (!fs5.existsSync(cognitiveDir)) {
2331
- return null;
2332
- }
2333
- const files = fs5.readdirSync(cognitiveDir);
2334
- for (const file of files) {
2335
- if (file.endsWith(extension) && !file.startsWith(".")) {
2336
- const fullPath = path6.join(cognitiveDir, file);
2337
- const stat = fs5.statSync(fullPath);
2338
- if (stat.isFile()) {
2339
- return fullPath;
2340
- }
2341
- }
2342
- }
2343
- return null;
2048
+ return {
2049
+ action: "get",
2050
+ key: action
2051
+ };
2052
+ }
2053
+ function formatValue(value) {
2054
+ if (value === null || value === void 0) {
2055
+ return pc5.dim("(not set)");
2344
2056
  }
2345
- /**
2346
- * Compare scanned cognitives with manifest and return differences
2347
- */
2348
- compare(scanned, manifestCognitives) {
2349
- const result = {
2350
- found: scanned,
2351
- new: [],
2352
- removed: [],
2353
- modified: [],
2354
- unchanged: 0,
2355
- errors: []
2057
+ if (typeof value === "boolean") {
2058
+ return value ? pc5.green("true") : pc5.red("false");
2059
+ }
2060
+ if (typeof value === "number") {
2061
+ return pc5.yellow(String(value));
2062
+ }
2063
+ if (typeof value === "string") {
2064
+ return pc5.white(`"${value}"`);
2065
+ }
2066
+ if (Array.isArray(value)) {
2067
+ return pc5.dim(`[${value.join(", ")}]`);
2068
+ }
2069
+ return pc5.dim(JSON.stringify(value));
2070
+ }
2071
+ function parseValue(value) {
2072
+ if (value.toLowerCase() === "true") return true;
2073
+ if (value.toLowerCase() === "false") return false;
2074
+ const num = Number(value);
2075
+ if (!isNaN(num) && value.trim() !== "") return num;
2076
+ return value;
2077
+ }
2078
+ function registerConfigCommand(program) {
2079
+ const configCmd = program.command("config").description("Manage project configuration");
2080
+ configCmd.command("list").description("Show all configuration values").action(() => {
2081
+ executeConfigCommand("list");
2082
+ });
2083
+ configCmd.command("get <key>").description("Get a configuration value").action((key) => {
2084
+ executeConfigCommand(`get ${key}`);
2085
+ });
2086
+ configCmd.command("set <key> <value>").description("Set a configuration value").action((key, value) => {
2087
+ executeConfigCommand(`set ${key} ${value}`);
2088
+ });
2089
+ configCmd.action(() => {
2090
+ executeConfigCommand("list");
2091
+ });
2092
+ }
2093
+
2094
+ // src/commands/status.ts
2095
+ init_esm_shims();
2096
+ import * as fs6 from "fs";
2097
+ import * as path7 from "path";
2098
+ import pc6 from "picocolors";
2099
+ function executeStatusCommand(_args = "") {
2100
+ const status = getProjectStatus();
2101
+ logger.line();
2102
+ if (!status.initialized) {
2103
+ showNotInitialized();
2104
+ return;
2105
+ }
2106
+ showProjectStatus(status);
2107
+ }
2108
+ function getProjectStatus() {
2109
+ const configManager = ConfigManager.findConfig();
2110
+ if (configManager === null) {
2111
+ return {
2112
+ initialized: false,
2113
+ cognitives: createEmptyCognitiveCount(),
2114
+ providers: []
2356
2115
  };
2357
- const manifestMap = /* @__PURE__ */ new Map();
2358
- for (const cognitive of manifestCognitives) {
2359
- manifestMap.set(cognitive.name, cognitive);
2360
- }
2361
- const scannedMap = /* @__PURE__ */ new Map();
2362
- for (const cognitive of scanned) {
2363
- scannedMap.set(cognitive.name, cognitive);
2364
- }
2365
- for (const scannedCognitive of scanned) {
2366
- const manifestCognitive = manifestMap.get(scannedCognitive.name);
2367
- if (manifestCognitive === void 0) {
2368
- result.new.push(scannedCognitive);
2369
- } else if (manifestCognitive.hash !== void 0 && manifestCognitive.hash !== scannedCognitive.hash) {
2370
- result.modified.push(scannedCognitive);
2371
- } else {
2372
- result.unchanged++;
2116
+ }
2117
+ const config = configManager.getConfig();
2118
+ const projectRoot = configManager.getProjectRoot();
2119
+ const storagePath = configManager.getSynapSyncDir();
2120
+ const cognitives = countCognitives(storagePath);
2121
+ const providers = getProviderStatuses(config, projectRoot);
2122
+ const lastSync = getLastSyncTime(storagePath);
2123
+ const status = {
2124
+ initialized: true,
2125
+ projectName: config.name,
2126
+ projectRoot,
2127
+ configPath: path7.join(projectRoot, "synapsync.config.yaml"),
2128
+ storagePath,
2129
+ cognitives,
2130
+ providers
2131
+ };
2132
+ if (lastSync !== void 0) {
2133
+ status.lastSync = lastSync;
2134
+ }
2135
+ return status;
2136
+ }
2137
+ function createEmptyCognitiveCount() {
2138
+ const counts = {};
2139
+ for (const type of COGNITIVE_TYPES) {
2140
+ counts[type] = 0;
2141
+ }
2142
+ return counts;
2143
+ }
2144
+ function countCognitives(storagePath) {
2145
+ const counts = createEmptyCognitiveCount();
2146
+ for (const type of COGNITIVE_TYPES) {
2147
+ const typePath = path7.join(storagePath, `${type}s`);
2148
+ if (fs6.existsSync(typePath)) {
2149
+ try {
2150
+ const entries = fs6.readdirSync(typePath, { withFileTypes: true });
2151
+ counts[type] = entries.filter(
2152
+ (e) => e.isDirectory() || e.isSymbolicLink() && !e.name.startsWith(".")
2153
+ ).length;
2154
+ } catch {
2155
+ counts[type] = 0;
2373
2156
  }
2374
2157
  }
2375
- for (const manifestCognitive of manifestCognitives) {
2376
- if (!scannedMap.has(manifestCognitive.name)) {
2377
- result.removed.push(manifestCognitive.name);
2158
+ }
2159
+ return counts;
2160
+ }
2161
+ function getProviderStatuses(config, projectRoot) {
2162
+ const statuses = [];
2163
+ for (const provider of SUPPORTED_PROVIDERS) {
2164
+ const providerConfig = config.sync?.providers?.[provider];
2165
+ const enabled = providerConfig?.enabled ?? false;
2166
+ const providerPath = path7.join(projectRoot, `.${provider}`);
2167
+ let cognitivesCount = 0;
2168
+ if (fs6.existsSync(providerPath)) {
2169
+ try {
2170
+ const subdirs = ["skills", "agents", "prompts", "workflows", "tools"];
2171
+ for (const subdir of subdirs) {
2172
+ const subdirPath = path7.join(providerPath, subdir);
2173
+ if (fs6.existsSync(subdirPath)) {
2174
+ const entries = fs6.readdirSync(subdirPath);
2175
+ cognitivesCount += entries.filter((e) => !e.startsWith(".")).length;
2176
+ }
2177
+ }
2178
+ } catch {
2378
2179
  }
2379
2180
  }
2380
- return result;
2181
+ statuses.push({
2182
+ name: provider,
2183
+ enabled,
2184
+ connected: false,
2185
+ // TODO: Check actual connection status
2186
+ cognitivesCount
2187
+ });
2381
2188
  }
2382
- /**
2383
- * Convert a scanned cognitive to a manifest cognitive
2384
- */
2385
- toManifestCognitive(scanned) {
2386
- return {
2387
- name: scanned.name,
2388
- type: scanned.type,
2389
- category: scanned.category,
2390
- version: scanned.metadata.version ?? "1.0.0",
2391
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
2392
- source: "local",
2393
- hash: scanned.hash
2394
- };
2189
+ return statuses;
2190
+ }
2191
+ function getLastSyncTime(storagePath) {
2192
+ const manifestPath = path7.join(storagePath, "manifest.json");
2193
+ if (!fs6.existsSync(manifestPath)) {
2194
+ return void 0;
2395
2195
  }
2396
- /**
2397
- * Compute content hash for change detection
2398
- */
2399
- computeHash(content) {
2400
- return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
2196
+ try {
2197
+ const content = fs6.readFileSync(manifestPath, "utf-8");
2198
+ const manifest = JSON.parse(content);
2199
+ return manifest.lastUpdated;
2200
+ } catch {
2201
+ return void 0;
2202
+ }
2203
+ }
2204
+ function showNotInitialized() {
2205
+ logger.bold(" Project Status");
2206
+ logger.line();
2207
+ logger.log(` ${pc6.red("\u25CF")} ${pc6.dim("Not initialized")}`);
2208
+ logger.line();
2209
+ logger.hint("Run /init to initialize a SynapSync project.");
2210
+ }
2211
+ function showProjectStatus(status) {
2212
+ logger.bold(` ${status.projectName ?? "SynapSync Project"}`);
2213
+ logger.line();
2214
+ logger.log(` ${pc6.green("\u25CF")} ${pc6.dim("Initialized")}`);
2215
+ logger.log(` ${pc6.dim("Root:")} ${status.projectRoot}`);
2216
+ logger.line();
2217
+ logger.bold(" Cognitives");
2218
+ const totalCognitives = Object.values(status.cognitives).reduce((a, b) => a + b, 0);
2219
+ if (totalCognitives === 0) {
2220
+ logger.log(` ${pc6.dim("No cognitives installed")}`);
2221
+ } else {
2222
+ for (const type of COGNITIVE_TYPES) {
2223
+ const count = status.cognitives[type];
2224
+ if (count > 0) {
2225
+ const icon = getCognitiveIcon(type);
2226
+ logger.log(` ${icon} ${pc6.white(count.toString().padStart(3))} ${type}s`);
2227
+ }
2228
+ }
2229
+ logger.log(` ${pc6.dim("\u2500\u2500\u2500")}`);
2230
+ logger.log(` ${pc6.bold(totalCognitives.toString().padStart(5))} total`);
2231
+ }
2232
+ logger.line();
2233
+ logger.bold(" Providers");
2234
+ const enabledProviders = status.providers.filter((p2) => p2.enabled);
2235
+ if (enabledProviders.length === 0) {
2236
+ logger.log(` ${pc6.dim("No providers enabled")}`);
2237
+ } else {
2238
+ for (const provider of enabledProviders) {
2239
+ const icon = provider.cognitivesCount > 0 ? pc6.green("\u25CF") : pc6.yellow("\u25CB");
2240
+ const syncStatus = provider.cognitivesCount > 0 ? pc6.dim(`(${provider.cognitivesCount} synced)`) : pc6.dim("(not synced)");
2241
+ logger.log(` ${icon} ${pc6.white(provider.name)} ${syncStatus}`);
2242
+ }
2243
+ }
2244
+ logger.line();
2245
+ if (status.lastSync !== void 0) {
2246
+ const syncDate = new Date(status.lastSync);
2247
+ const relativeTime = getRelativeTime(syncDate);
2248
+ logger.log(` ${pc6.dim("Last updated:")} ${relativeTime}`);
2249
+ logger.line();
2250
+ }
2251
+ logger.hint("Run /help for available commands.");
2252
+ }
2253
+ function getCognitiveIcon(type) {
2254
+ const icons = {
2255
+ skill: pc6.blue("\u25C6"),
2256
+ agent: pc6.magenta("\u25C6"),
2257
+ prompt: pc6.yellow("\u25C6"),
2258
+ workflow: pc6.cyan("\u25C6"),
2259
+ tool: pc6.green("\u25C6")
2260
+ };
2261
+ return icons[type];
2262
+ }
2263
+ function getRelativeTime(date) {
2264
+ const now = /* @__PURE__ */ new Date();
2265
+ const diffMs = now.getTime() - date.getTime();
2266
+ const diffMins = Math.floor(diffMs / 6e4);
2267
+ const diffHours = Math.floor(diffMins / 60);
2268
+ const diffDays = Math.floor(diffHours / 24);
2269
+ if (diffMins < 1) return "just now";
2270
+ if (diffMins < 60) return `${diffMins} minute${diffMins === 1 ? "" : "s"} ago`;
2271
+ if (diffHours < 24) return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
2272
+ if (diffDays < 7) return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
2273
+ return date.toLocaleDateString();
2274
+ }
2275
+ function registerStatusCommand(program) {
2276
+ program.command("status").description("Show project status").action(() => {
2277
+ executeStatusCommand();
2278
+ });
2279
+ }
2280
+
2281
+ // src/commands/providers.ts
2282
+ init_esm_shims();
2283
+ import * as fs7 from "fs";
2284
+ import * as path8 from "path";
2285
+ import pc7 from "picocolors";
2286
+ function executeProvidersCommand(args) {
2287
+ const parts = args.trim().split(/\s+/);
2288
+ const subcommand = parts[0]?.toLowerCase() ?? "";
2289
+ const configManager = ConfigManager.findConfig();
2290
+ if (configManager === null) {
2291
+ logger.line();
2292
+ logger.error("No SynapSync project found.");
2293
+ logger.hint("Run /init to initialize a project.");
2294
+ return;
2295
+ }
2296
+ switch (subcommand) {
2297
+ case "":
2298
+ case "list":
2299
+ listProviders(configManager);
2300
+ break;
2301
+ case "enable":
2302
+ enableProvider(configManager, parts[1]);
2303
+ break;
2304
+ case "disable":
2305
+ disableProvider(configManager, parts[1]);
2306
+ break;
2307
+ case "path":
2308
+ setProviderPath(configManager, parts[1], parts[2]);
2309
+ break;
2310
+ default:
2311
+ if (SUPPORTED_PROVIDERS.includes(subcommand)) {
2312
+ showProviderInfo(configManager, subcommand);
2313
+ } else {
2314
+ logger.line();
2315
+ logger.error(`Unknown subcommand: ${subcommand}`);
2316
+ logger.hint("Usage: /providers [list|enable|disable|path]");
2317
+ }
2318
+ }
2319
+ }
2320
+ function listProviders(configManager) {
2321
+ const providers = getProvidersInfo(configManager);
2322
+ logger.line();
2323
+ logger.bold(" Providers");
2324
+ logger.line();
2325
+ logger.log(
2326
+ ` ${pc7.dim("Provider".padEnd(12))} ${pc7.dim("Status".padEnd(10))} ${pc7.dim("Path".padEnd(20))} ${pc7.dim("Directory")}`
2327
+ );
2328
+ logger.log(` ${pc7.dim("\u2500".repeat(60))}`);
2329
+ for (const provider of providers) {
2330
+ const statusIcon = provider.enabled ? pc7.green("\u25CF") : pc7.dim("\u25CB");
2331
+ const statusText = provider.enabled ? pc7.green("enabled") : pc7.dim("disabled");
2332
+ const pathText = pc7.cyan(provider.path);
2333
+ const existsText = provider.exists ? pc7.green("\u2713 exists") : pc7.dim("\u2717 missing");
2334
+ logger.log(
2335
+ ` ${statusIcon} ${pc7.white(provider.name.padEnd(10))} ${statusText.padEnd(19)} ${pathText.padEnd(29)} ${existsText}`
2336
+ );
2337
+ }
2338
+ logger.line();
2339
+ const enabledCount = providers.filter((p2) => p2.enabled).length;
2340
+ logger.log(` ${pc7.dim("Enabled:")} ${enabledCount} of ${providers.length} providers`);
2341
+ logger.line();
2342
+ logger.hint("Use /providers enable <name> or /providers disable <name>");
2343
+ }
2344
+ function enableProvider(configManager, providerName) {
2345
+ if (providerName === void 0 || providerName === "") {
2346
+ logger.line();
2347
+ logger.error("Provider name is required.");
2348
+ logger.hint("Usage: /providers enable <provider>");
2349
+ logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
2350
+ return;
2351
+ }
2352
+ const provider = providerName.toLowerCase();
2353
+ if (!SUPPORTED_PROVIDERS.includes(provider)) {
2354
+ logger.line();
2355
+ logger.error(`Unknown provider: ${provider}`);
2356
+ logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
2357
+ return;
2358
+ }
2359
+ const currentValue = configManager.get(`sync.providers.${provider}.enabled`);
2360
+ if (currentValue === true) {
2361
+ logger.line();
2362
+ logger.info(`Provider '${provider}' is already enabled.`);
2363
+ return;
2364
+ }
2365
+ configManager.set(`sync.providers.${provider}.enabled`, true);
2366
+ const defaultPaths = PROVIDER_PATHS[provider];
2367
+ const currentPaths = configManager.get(`sync.providers.${provider}.paths`);
2368
+ if (currentPaths === void 0) {
2369
+ configManager.set(`sync.providers.${provider}.paths`, defaultPaths);
2370
+ }
2371
+ configManager.save();
2372
+ logger.line();
2373
+ logger.success(`Provider '${pc7.cyan(provider)}' enabled`);
2374
+ logger.log(` ${pc7.dim("Path:")} ${defaultPaths.skill.split("/")[0]}/`);
2375
+ logger.line();
2376
+ logger.hint("Run /sync to synchronize cognitives to this provider.");
2377
+ }
2378
+ function disableProvider(configManager, providerName) {
2379
+ if (providerName === void 0 || providerName === "") {
2380
+ logger.line();
2381
+ logger.error("Provider name is required.");
2382
+ logger.hint("Usage: /providers disable <provider>");
2383
+ return;
2384
+ }
2385
+ const provider = providerName.toLowerCase();
2386
+ if (!SUPPORTED_PROVIDERS.includes(provider)) {
2387
+ logger.line();
2388
+ logger.error(`Unknown provider: ${provider}`);
2389
+ logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
2390
+ return;
2391
+ }
2392
+ const currentValue = configManager.get(`sync.providers.${provider}.enabled`);
2393
+ if (currentValue !== true) {
2394
+ logger.line();
2395
+ logger.info(`Provider '${provider}' is already disabled.`);
2396
+ return;
2397
+ }
2398
+ configManager.set(`sync.providers.${provider}.enabled`, false);
2399
+ configManager.save();
2400
+ logger.line();
2401
+ logger.success(`Provider '${pc7.cyan(provider)}' disabled`);
2402
+ }
2403
+ function setProviderPath(configManager, providerName, newPath) {
2404
+ if (providerName === void 0 || providerName === "") {
2405
+ logger.line();
2406
+ logger.error("Provider name is required.");
2407
+ logger.hint("Usage: /providers path <provider> <path>");
2408
+ return;
2409
+ }
2410
+ if (newPath === void 0 || newPath === "") {
2411
+ logger.line();
2412
+ logger.error("Path is required.");
2413
+ logger.hint("Usage: /providers path <provider> <path>");
2414
+ logger.hint("Example: /providers path claude .claude-code/");
2415
+ return;
2416
+ }
2417
+ const provider = providerName.toLowerCase();
2418
+ if (!SUPPORTED_PROVIDERS.includes(provider)) {
2419
+ logger.line();
2420
+ logger.error(`Unknown provider: ${provider}`);
2421
+ logger.hint(`Available: ${SUPPORTED_PROVIDERS.join(", ")}`);
2422
+ return;
2423
+ }
2424
+ const normalizedPath = newPath.endsWith("/") ? newPath : `${newPath}/`;
2425
+ const cognitiveTypes = ["skill", "agent", "prompt", "workflow", "tool"];
2426
+ for (const type of cognitiveTypes) {
2427
+ configManager.set(`sync.providers.${provider}.paths.${type}`, `${normalizedPath}${type}s`);
2428
+ }
2429
+ configManager.save();
2430
+ logger.line();
2431
+ logger.success(`Updated paths for '${pc7.cyan(provider)}'`);
2432
+ logger.log(` ${pc7.dim("Base path:")} ${pc7.cyan(normalizedPath)}`);
2433
+ logger.line();
2434
+ }
2435
+ function showProviderInfo(configManager, provider) {
2436
+ const config = configManager.getConfig();
2437
+ const projectRoot = configManager.getProjectRoot();
2438
+ const providerConfig = config.sync?.providers?.[provider];
2439
+ const enabled = providerConfig?.enabled ?? false;
2440
+ const paths = providerConfig?.paths ?? PROVIDER_PATHS[provider];
2441
+ logger.line();
2442
+ logger.bold(` ${getProviderDisplayName(provider)}`);
2443
+ logger.line();
2444
+ const statusIcon = enabled ? pc7.green("\u25CF") : pc7.dim("\u25CB");
2445
+ const statusText = enabled ? pc7.green("Enabled") : pc7.dim("Disabled");
2446
+ logger.log(` ${pc7.dim("Status:")} ${statusIcon} ${statusText}`);
2447
+ logger.line();
2448
+ logger.log(` ${pc7.dim("Paths:")}`);
2449
+ const cognitiveTypes = ["skill", "agent", "prompt", "workflow", "tool"];
2450
+ for (const type of cognitiveTypes) {
2451
+ const typePath = paths[type] ?? "";
2452
+ const fullPath = path8.join(projectRoot, typePath);
2453
+ const exists = fs7.existsSync(fullPath);
2454
+ const existsIcon = exists ? pc7.green("\u2713") : pc7.dim("\u2717");
2455
+ logger.log(` ${pc7.dim(type.padEnd(10))} ${pc7.cyan(typePath)} ${existsIcon}`);
2456
+ }
2457
+ logger.line();
2458
+ }
2459
+ function getProvidersInfo(configManager) {
2460
+ const config = configManager.getConfig();
2461
+ const projectRoot = configManager.getProjectRoot();
2462
+ const providers = [];
2463
+ for (const provider of SUPPORTED_PROVIDERS) {
2464
+ const providerConfig = config.sync?.providers?.[provider];
2465
+ const enabled = providerConfig?.enabled ?? false;
2466
+ const basePath = providerConfig?.paths?.skill?.split("/")[0] ?? `.${provider}`;
2467
+ const fullPath = path8.join(projectRoot, basePath);
2468
+ const exists = fs7.existsSync(fullPath);
2469
+ providers.push({
2470
+ name: provider,
2471
+ enabled,
2472
+ path: `${basePath}/`,
2473
+ exists
2474
+ });
2475
+ }
2476
+ return providers;
2477
+ }
2478
+ function getProviderDisplayName(provider) {
2479
+ const names = {
2480
+ claude: "Claude (Anthropic)",
2481
+ openai: "OpenAI (GPT)",
2482
+ gemini: "Gemini (Google)",
2483
+ cursor: "Cursor IDE",
2484
+ windsurf: "Windsurf IDE",
2485
+ copilot: "GitHub Copilot"
2486
+ };
2487
+ return names[provider];
2488
+ }
2489
+ function registerProvidersCommand(program) {
2490
+ const providersCmd = program.command("providers").description("Manage provider configuration");
2491
+ providersCmd.command("list", { isDefault: true }).description("List all providers and their status").action(() => {
2492
+ executeProvidersCommand("list");
2493
+ });
2494
+ providersCmd.command("enable <provider>").description("Enable a provider").action((provider) => {
2495
+ executeProvidersCommand(`enable ${provider}`);
2496
+ });
2497
+ providersCmd.command("disable <provider>").description("Disable a provider").action((provider) => {
2498
+ executeProvidersCommand(`disable ${provider}`);
2499
+ });
2500
+ providersCmd.command("path <provider> <path>").description("Set custom sync path for a provider").action((provider, newPath) => {
2501
+ executeProvidersCommand(`path ${provider} ${newPath}`);
2502
+ });
2503
+ providersCmd.action(() => {
2504
+ executeProvidersCommand("list");
2505
+ });
2506
+ }
2507
+
2508
+ // src/commands/search.ts
2509
+ init_esm_shims();
2510
+ import pc8 from "picocolors";
2511
+
2512
+ // src/services/registry/client.ts
2513
+ init_esm_shims();
2514
+ var RegistryClient = class {
2515
+ baseUrl;
2516
+ indexCache = null;
2517
+ indexCacheTime = 0;
2518
+ cacheTtl;
2519
+ constructor(options = {}) {
2520
+ this.baseUrl = options.baseUrl ?? REGISTRY_BASE_URL;
2521
+ this.cacheTtl = options.cacheTtl ?? 5 * 60 * 1e3;
2401
2522
  }
2523
+ // ============================================
2524
+ // Index Operations
2525
+ // ============================================
2402
2526
  /**
2403
- * List directories in a path
2527
+ * Fetch the registry index
2404
2528
  */
2405
- listDirectories(dirPath) {
2406
- if (!fs5.existsSync(dirPath)) {
2407
- return [];
2529
+ async getIndex(forceRefresh = false) {
2530
+ const now = Date.now();
2531
+ if (!forceRefresh && this.indexCache !== null && now - this.indexCacheTime < this.cacheTtl) {
2532
+ return this.indexCache;
2408
2533
  }
2409
- return fs5.readdirSync(dirPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => !dirent.name.startsWith(".")).map((dirent) => dirent.name);
2410
- }
2411
- /**
2412
- * Detect cognitive type from directory contents
2413
- */
2414
- detectType(cognitiveDir) {
2415
- for (const type of COGNITIVE_TYPES) {
2416
- const fileName = COGNITIVE_FILE_NAMES[type];
2417
- const filePath = path6.join(cognitiveDir, fileName);
2418
- if (fs5.existsSync(filePath)) {
2419
- return type;
2420
- }
2534
+ const url = `${this.baseUrl}/${REGISTRY_INDEX_FILE}`;
2535
+ const response = await this.fetch(url);
2536
+ if (!response.ok) {
2537
+ throw new RegistryError(`Failed to fetch registry index: ${response.status} ${response.statusText}`, url);
2421
2538
  }
2422
- return null;
2539
+ const index = await response.json();
2540
+ this.indexCache = index;
2541
+ this.indexCacheTime = now;
2542
+ return index;
2423
2543
  }
2424
2544
  /**
2425
- * Get cognitive count by type
2545
+ * Get total count of cognitives in registry
2426
2546
  */
2427
- countByType(cognitives) {
2428
- const counts = {
2429
- skill: 0,
2430
- agent: 0,
2431
- prompt: 0,
2432
- workflow: 0,
2433
- tool: 0
2434
- };
2435
- for (const cognitive of cognitives) {
2436
- counts[cognitive.type]++;
2437
- }
2438
- return counts;
2439
- }
2440
- };
2441
-
2442
- // src/services/manifest/manager.ts
2443
- init_esm_shims();
2444
- import * as fs6 from "fs";
2445
- import * as path7 from "path";
2446
-
2447
- // src/services/manifest/types.ts
2448
- init_esm_shims();
2449
- var DEFAULT_MANIFEST = {
2450
- version: "1.0.0",
2451
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
2452
- cognitives: {},
2453
- syncs: {}
2454
- };
2455
-
2456
- // src/services/manifest/manager.ts
2457
- var ManifestManager = class {
2458
- manifestPath;
2459
- manifest;
2460
- constructor(synapSyncDir) {
2461
- this.manifestPath = path7.join(synapSyncDir, "manifest.json");
2462
- this.manifest = this.load();
2547
+ async getCount() {
2548
+ const index = await this.getIndex();
2549
+ return index.totalCognitives;
2463
2550
  }
2551
+ // ============================================
2552
+ // Search Operations
2553
+ // ============================================
2464
2554
  /**
2465
- * Load manifest from disk
2555
+ * Search for cognitives in the registry
2466
2556
  */
2467
- load() {
2468
- if (!fs6.existsSync(this.manifestPath)) {
2469
- return { ...DEFAULT_MANIFEST };
2557
+ async search(query, options = {}) {
2558
+ const index = await this.getIndex();
2559
+ let results = [...index.cognitives];
2560
+ if (query !== void 0 && query.trim() !== "") {
2561
+ const q = query.toLowerCase();
2562
+ results = results.filter(
2563
+ (c) => c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q) || c.tags.some((t) => t.toLowerCase().includes(q))
2564
+ );
2470
2565
  }
2471
- try {
2472
- const content = fs6.readFileSync(this.manifestPath, "utf-8");
2473
- const parsed = JSON.parse(content);
2474
- return {
2475
- version: parsed.version ?? DEFAULT_MANIFEST.version,
2476
- lastUpdated: parsed.lastUpdated ?? DEFAULT_MANIFEST.lastUpdated,
2477
- cognitives: parsed.cognitives ?? {},
2478
- syncs: parsed.syncs ?? {}
2479
- };
2480
- } catch {
2481
- return { ...DEFAULT_MANIFEST };
2566
+ if (options.type !== void 0) {
2567
+ results = results.filter((c) => c.type === options.type);
2568
+ }
2569
+ if (options.category !== void 0) {
2570
+ results = results.filter((c) => c.category === options.category);
2571
+ }
2572
+ if (options.tag !== void 0) {
2573
+ const tag = options.tag.toLowerCase();
2574
+ results = results.filter((c) => c.tags.some((t) => t.toLowerCase() === tag));
2482
2575
  }
2576
+ const total = results.length;
2577
+ if (options.limit !== void 0 && options.limit > 0) {
2578
+ results = results.slice(0, options.limit);
2579
+ }
2580
+ const filters = {};
2581
+ if (options.type !== void 0) filters.type = options.type;
2582
+ if (options.category !== void 0) filters.category = options.category;
2583
+ if (options.tag !== void 0) filters.tag = options.tag;
2584
+ return {
2585
+ cognitives: results,
2586
+ total,
2587
+ ...query !== void 0 ? { query } : {},
2588
+ filters
2589
+ };
2483
2590
  }
2484
2591
  /**
2485
- * Save manifest to disk
2592
+ * Find a cognitive by name
2486
2593
  */
2487
- save() {
2488
- this.manifest.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
2489
- const content = JSON.stringify(this.manifest, null, 2);
2490
- fs6.writeFileSync(this.manifestPath, content, "utf-8");
2594
+ async findByName(name) {
2595
+ const index = await this.getIndex();
2596
+ return index.cognitives.find((c) => c.name === name) ?? null;
2491
2597
  }
2492
2598
  /**
2493
- * Get the current manifest
2599
+ * List all cognitives
2494
2600
  */
2495
- getManifest() {
2496
- return this.manifest;
2601
+ async list(options = {}) {
2602
+ const result = await this.search(void 0, options);
2603
+ return result.cognitives;
2497
2604
  }
2605
+ // ============================================
2606
+ // Download Operations
2607
+ // ============================================
2498
2608
  /**
2499
- * Get all cognitives from manifest
2609
+ * Get the manifest for a cognitive
2500
2610
  */
2501
- getCognitives() {
2502
- return Object.values(this.manifest.cognitives);
2611
+ async getManifest(cognitiveEntry) {
2612
+ const url = `${this.baseUrl}/${cognitiveEntry.path}/${REGISTRY_MANIFEST_FILE}`;
2613
+ const response = await this.fetch(url);
2614
+ if (!response.ok) {
2615
+ throw new RegistryError(
2616
+ `Failed to fetch manifest for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
2617
+ url
2618
+ );
2619
+ }
2620
+ return await response.json();
2503
2621
  }
2504
2622
  /**
2505
- * Get a specific cognitive by name
2623
+ * Get the content file for a cognitive
2506
2624
  */
2507
- getCognitive(name) {
2508
- return this.manifest.cognitives[name];
2625
+ async getContent(cognitiveEntry, manifest) {
2626
+ const url = `${this.baseUrl}/${cognitiveEntry.path}/${manifest.file}`;
2627
+ const response = await this.fetch(url);
2628
+ if (!response.ok) {
2629
+ throw new RegistryError(
2630
+ `Failed to fetch content for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
2631
+ url
2632
+ );
2633
+ }
2634
+ return response.text();
2509
2635
  }
2510
2636
  /**
2511
- * Check if a cognitive exists in manifest
2637
+ * Download a cognitive (manifest + content)
2512
2638
  */
2513
- hasCognitive(name) {
2514
- return this.manifest.cognitives[name] !== void 0;
2639
+ async download(name) {
2640
+ const entry = await this.findByName(name);
2641
+ if (entry === null) {
2642
+ throw new CognitiveNotFoundError(name);
2643
+ }
2644
+ const manifest = await this.getManifest(entry);
2645
+ const content = await this.getContent(entry, manifest);
2646
+ return {
2647
+ manifest,
2648
+ content,
2649
+ path: entry.path
2650
+ };
2515
2651
  }
2516
2652
  /**
2517
- * Add a cognitive to manifest
2653
+ * Download additional assets for a cognitive
2518
2654
  */
2519
- addCognitive(cognitive) {
2520
- this.manifest.cognitives[cognitive.name] = cognitive;
2655
+ async downloadAsset(cognitiveEntry, assetPath) {
2656
+ const url = `${this.baseUrl}/${cognitiveEntry.path}/${assetPath}`;
2657
+ const response = await this.fetch(url);
2658
+ if (!response.ok) {
2659
+ throw new RegistryError(
2660
+ `Failed to fetch asset ${assetPath} for ${cognitiveEntry.name}: ${response.status} ${response.statusText}`,
2661
+ url
2662
+ );
2663
+ }
2664
+ return response.text();
2521
2665
  }
2666
+ // ============================================
2667
+ // Utility Methods
2668
+ // ============================================
2522
2669
  /**
2523
- * Update a cognitive in manifest
2670
+ * Check if registry is reachable
2524
2671
  */
2525
- updateCognitive(name, updates) {
2526
- const existing = this.manifest.cognitives[name];
2527
- if (existing !== void 0) {
2528
- this.manifest.cognitives[name] = { ...existing, ...updates };
2672
+ async ping() {
2673
+ try {
2674
+ const url = `${this.baseUrl}/${REGISTRY_INDEX_FILE}`;
2675
+ const response = await this.fetch(url, { method: "HEAD" });
2676
+ return response.ok;
2677
+ } catch {
2678
+ return false;
2529
2679
  }
2530
2680
  }
2531
2681
  /**
2532
- * Remove a cognitive from manifest
2682
+ * Clear the cache
2533
2683
  */
2534
- removeCognitive(name) {
2535
- if (this.manifest.cognitives[name] !== void 0) {
2536
- delete this.manifest.cognitives[name];
2537
- return true;
2684
+ clearCache() {
2685
+ this.indexCache = null;
2686
+ this.indexCacheTime = 0;
2687
+ }
2688
+ /**
2689
+ * Get the base URL
2690
+ */
2691
+ getBaseUrl() {
2692
+ return this.baseUrl;
2693
+ }
2694
+ // ============================================
2695
+ // Private Methods
2696
+ // ============================================
2697
+ async fetch(url, options) {
2698
+ try {
2699
+ return await fetch(url, {
2700
+ ...options,
2701
+ headers: {
2702
+ "User-Agent": "SynapSync-CLI",
2703
+ ...options?.headers
2704
+ }
2705
+ });
2706
+ } catch (error) {
2707
+ if (error instanceof Error) {
2708
+ throw new RegistryError(`Network error: ${error.message}`, url);
2709
+ }
2710
+ throw new RegistryError("Network error", url);
2538
2711
  }
2539
- return false;
2540
2712
  }
2541
- /**
2542
- * Reconcile manifest with scanned cognitives
2543
- * Returns what was added, removed, and updated
2544
- */
2545
- reconcile(scannedCognitives) {
2546
- const result = {
2547
- added: [],
2548
- removed: [],
2549
- updated: [],
2550
- unchanged: 0
2551
- };
2552
- const scannedMap = /* @__PURE__ */ new Map();
2553
- for (const cognitive of scannedCognitives) {
2554
- scannedMap.set(cognitive.name, cognitive);
2713
+ };
2714
+ var RegistryError = class extends Error {
2715
+ constructor(message, url) {
2716
+ super(message);
2717
+ this.url = url;
2718
+ this.name = "RegistryError";
2719
+ }
2720
+ };
2721
+ var CognitiveNotFoundError = class extends Error {
2722
+ constructor(cognitiveName) {
2723
+ super(`Cognitive '${cognitiveName}' not found in registry`);
2724
+ this.cognitiveName = cognitiveName;
2725
+ this.name = "CognitiveNotFoundError";
2726
+ }
2727
+ };
2728
+
2729
+ // src/commands/search.ts
2730
+ async function executeSearchCommand(query, options) {
2731
+ logger.line();
2732
+ const validatedOptions = validateOptions(options);
2733
+ if (validatedOptions === null) {
2734
+ return;
2735
+ }
2736
+ const searchingText = query !== void 0 && query.trim() !== "" ? `Searching for "${query}"...` : "Fetching cognitives from registry...";
2737
+ logger.log(` ${pc8.dim(searchingText)}`);
2738
+ try {
2739
+ const client = new RegistryClient();
2740
+ const isReachable = await client.ping();
2741
+ if (!isReachable) {
2742
+ logger.line();
2743
+ logger.error("Unable to reach the registry. Check your internet connection.");
2744
+ return;
2555
2745
  }
2556
- for (const name of Object.keys(this.manifest.cognitives)) {
2557
- if (!scannedMap.has(name)) {
2558
- result.removed.push(name);
2559
- }
2746
+ const searchOpts = {};
2747
+ if (validatedOptions.type !== void 0) searchOpts.type = validatedOptions.type;
2748
+ if (validatedOptions.category !== void 0) searchOpts.category = validatedOptions.category;
2749
+ if (validatedOptions.tag !== void 0) searchOpts.tag = validatedOptions.tag;
2750
+ if (validatedOptions.limit !== void 0) searchOpts.limit = validatedOptions.limit;
2751
+ const result = await client.search(query, searchOpts);
2752
+ process.stdout.write("\x1B[1A\x1B[2K");
2753
+ if (options.json === true) {
2754
+ console.log(JSON.stringify(result, null, 2));
2755
+ return;
2560
2756
  }
2561
- for (const scanned of scannedCognitives) {
2562
- const existing = this.manifest.cognitives[scanned.name];
2563
- if (existing === void 0) {
2564
- result.added.push(scanned);
2565
- } else if (scanned.hash !== void 0 && existing.hash !== scanned.hash) {
2566
- result.updated.push(scanned);
2567
- } else {
2568
- result.unchanged++;
2569
- }
2757
+ displaySearchResults(result.cognitives, query, result.total);
2758
+ } catch (error) {
2759
+ logger.line();
2760
+ if (error instanceof RegistryError) {
2761
+ logger.error(`Registry error: ${error.message}`);
2762
+ } else if (error instanceof Error) {
2763
+ logger.error(`Search failed: ${error.message}`);
2764
+ } else {
2765
+ logger.error("Search failed with unknown error");
2570
2766
  }
2571
- return result;
2572
2767
  }
2573
- /**
2574
- * Apply reconciliation result to manifest
2575
- */
2576
- applyReconciliation(result) {
2577
- for (const name of result.removed) {
2578
- delete this.manifest.cognitives[name];
2768
+ }
2769
+ function validateOptions(options) {
2770
+ const validated = {};
2771
+ if (options.type !== void 0) {
2772
+ if (!COGNITIVE_TYPES.includes(options.type)) {
2773
+ logger.error(`Invalid type: ${options.type}`);
2774
+ logger.hint(`Valid types: ${COGNITIVE_TYPES.join(", ")}`);
2775
+ return null;
2579
2776
  }
2580
- for (const cognitive of result.added) {
2581
- this.manifest.cognitives[cognitive.name] = cognitive;
2777
+ validated.type = options.type;
2778
+ }
2779
+ if (options.category !== void 0) {
2780
+ if (!CATEGORIES.includes(options.category)) {
2781
+ logger.error(`Invalid category: ${options.category}`);
2782
+ logger.hint(`Valid categories: ${CATEGORIES.join(", ")}`);
2783
+ return null;
2582
2784
  }
2583
- for (const cognitive of result.updated) {
2584
- const existing = this.manifest.cognitives[cognitive.name];
2585
- if (existing !== void 0) {
2586
- const updated = {
2587
- ...existing,
2588
- ...cognitive,
2589
- // Keep original installation info
2590
- installedAt: existing.installedAt,
2591
- source: existing.source
2592
- };
2593
- if (existing.sourceUrl !== void 0) {
2594
- updated.sourceUrl = existing.sourceUrl;
2595
- }
2596
- this.manifest.cognitives[cognitive.name] = updated;
2597
- }
2785
+ validated.category = options.category;
2786
+ }
2787
+ if (options.tag !== void 0) {
2788
+ validated.tag = options.tag;
2789
+ }
2790
+ if (options.limit !== void 0) {
2791
+ const limit = parseInt(options.limit, 10);
2792
+ if (isNaN(limit) || limit < 1) {
2793
+ logger.error("Limit must be a positive number");
2794
+ return null;
2598
2795
  }
2796
+ validated.limit = limit;
2599
2797
  }
2600
- /**
2601
- * Get provider sync state
2602
- */
2603
- getProviderSync(provider) {
2604
- return this.manifest.syncs[provider];
2798
+ return validated;
2799
+ }
2800
+ function displaySearchResults(cognitives, query, total) {
2801
+ if (query !== void 0 && query.trim() !== "") {
2802
+ logger.bold(` Search Results for "${query}"`);
2803
+ } else {
2804
+ logger.bold(" Registry Cognitives");
2605
2805
  }
2606
- /**
2607
- * Update provider sync state
2608
- */
2609
- setProviderSync(provider, state) {
2610
- this.manifest.syncs[provider] = state;
2806
+ logger.line();
2807
+ if (cognitives.length === 0) {
2808
+ logger.log(` ${pc8.dim("No cognitives found")}`);
2809
+ logger.line();
2810
+ logger.hint("Try a different search query or remove filters.");
2811
+ return;
2611
2812
  }
2612
- /**
2613
- * Get all synced cognitives for a provider
2614
- */
2615
- getSyncedCognitives(provider) {
2616
- return this.manifest.syncs[provider]?.cognitives ?? [];
2813
+ if (cognitives.length < total) {
2814
+ logger.log(` ${pc8.dim(`Showing ${cognitives.length} of ${total} results`)}`);
2815
+ } else {
2816
+ logger.log(` ${pc8.dim(`Found ${total} cognitive${total === 1 ? "" : "s"}`)}`);
2617
2817
  }
2618
- /**
2619
- * Get cognitive count
2620
- */
2621
- getCognitiveCount() {
2622
- return Object.keys(this.manifest.cognitives).length;
2818
+ logger.line();
2819
+ for (const cognitive of cognitives) {
2820
+ displayCognitive(cognitive);
2623
2821
  }
2624
- /**
2625
- * Get cognitives by type
2626
- */
2627
- getCognitivesByType(type) {
2628
- return Object.values(this.manifest.cognitives).filter((c) => c.type === type);
2822
+ logger.line();
2823
+ logger.hint("Run synapsync add <name> to add a cognitive.");
2824
+ }
2825
+ function displayCognitive(cognitive) {
2826
+ const typeIcon = getCognitiveIcon2(cognitive.type);
2827
+ const typeLabel = pc8.dim(`[${cognitive.type}]`);
2828
+ logger.log(` ${typeIcon} ${pc8.bold(pc8.white(cognitive.name))} ${typeLabel}`);
2829
+ logger.log(` ${pc8.dim(truncate(cognitive.description, 60))}`);
2830
+ const meta = [];
2831
+ meta.push(pc8.dim(`v${cognitive.version}`));
2832
+ meta.push(pc8.dim(cognitive.category));
2833
+ if (cognitive.downloads > 0) {
2834
+ meta.push(pc8.dim(`${cognitive.downloads} downloads`));
2629
2835
  }
2630
- /**
2631
- * Get cognitives by source
2632
- */
2633
- getCognitivesBySource(source) {
2634
- return Object.values(this.manifest.cognitives).filter((c) => c.source === source);
2836
+ logger.log(` ${meta.join(" \xB7 ")}`);
2837
+ if (cognitive.tags.length > 0) {
2838
+ const tags = cognitive.tags.slice(0, 5).map((t) => pc8.cyan(t)).join(" ");
2839
+ logger.log(` ${tags}`);
2635
2840
  }
2636
- };
2841
+ logger.line();
2842
+ }
2843
+ function getCognitiveIcon2(type) {
2844
+ const icons = {
2845
+ skill: pc8.blue("\u25C6"),
2846
+ agent: pc8.magenta("\u25C6"),
2847
+ prompt: pc8.yellow("\u25C6"),
2848
+ workflow: pc8.cyan("\u25C6"),
2849
+ tool: pc8.green("\u25C6")
2850
+ };
2851
+ return icons[type];
2852
+ }
2853
+ function truncate(text2, maxLength) {
2854
+ if (text2.length <= maxLength) return text2;
2855
+ return text2.slice(0, maxLength - 3) + "...";
2856
+ }
2857
+ function registerSearchCommand(program) {
2858
+ program.command("search [query]").description("Search for cognitives in the registry").option("-t, --type <type>", "Filter by type (skill, agent, prompt, workflow, tool)").option("-c, --category <category>", "Filter by category").option("--tag <tag>", "Filter by tag").option("-l, --limit <number>", "Limit results", "20").option("--json", "Output as JSON").action(async (query, options) => {
2859
+ await executeSearchCommand(query, options);
2860
+ });
2861
+ }
2862
+
2863
+ // src/commands/add.ts
2864
+ init_esm_shims();
2865
+ import * as fs9 from "fs";
2866
+ import * as path11 from "path";
2867
+ import pc9 from "picocolors";
2868
+
2869
+ // src/services/sync/engine.ts
2870
+ init_esm_shims();
2871
+ import * as path10 from "path";
2637
2872
 
2638
2873
  // src/services/symlink/manager.ts
2639
2874
  init_esm_shims();
2640
- import * as fs7 from "fs";
2641
- import * as path8 from "path";
2875
+ import * as fs8 from "fs";
2876
+ import * as path9 from "path";
2642
2877
  var SymlinkManager = class {
2643
2878
  projectRoot;
2644
2879
  synapSyncDir;
@@ -2656,12 +2891,12 @@ var SymlinkManager = class {
2656
2891
  }
2657
2892
  if (process.platform === "win32") {
2658
2893
  try {
2659
- const testSource = path8.join(this.synapSyncDir, ".symlink-test");
2660
- const testTarget = path8.join(this.synapSyncDir, ".symlink-test-target");
2661
- fs7.writeFileSync(testTarget, "test", "utf-8");
2662
- fs7.symlinkSync(testTarget, testSource);
2663
- fs7.unlinkSync(testSource);
2664
- fs7.unlinkSync(testTarget);
2894
+ const testSource = path9.join(this.synapSyncDir, ".symlink-test");
2895
+ const testTarget = path9.join(this.synapSyncDir, ".symlink-test-target");
2896
+ fs8.writeFileSync(testTarget, "test", "utf-8");
2897
+ fs8.symlinkSync(testTarget, testSource);
2898
+ fs8.unlinkSync(testSource);
2899
+ fs8.unlinkSync(testTarget);
2665
2900
  this.supportsSymlinks = true;
2666
2901
  } catch {
2667
2902
  this.supportsSymlinks = false;
@@ -2764,7 +2999,7 @@ var SymlinkManager = class {
2764
2999
  cognitiveType: cognitive.type,
2765
3000
  sourcePath: cognitive.path,
2766
3001
  // Directory path
2767
- targetPath: path8.join(this.projectRoot, typeDir, cognitive.name),
3002
+ targetPath: path9.join(this.projectRoot, typeDir, cognitive.name),
2768
3003
  isFile: false
2769
3004
  });
2770
3005
  } else {
@@ -2774,7 +3009,7 @@ var SymlinkManager = class {
2774
3009
  cognitiveType: cognitive.type,
2775
3010
  sourcePath: cognitive.filePath,
2776
3011
  // File path
2777
- targetPath: path8.join(this.projectRoot, typeDir, fileName),
3012
+ targetPath: path9.join(this.projectRoot, typeDir, fileName),
2778
3013
  isFile: true
2779
3014
  });
2780
3015
  }
@@ -2791,12 +3026,12 @@ var SymlinkManager = class {
2791
3026
  for (const cognitiveType of COGNITIVE_TYPES) {
2792
3027
  const typeDir = providerPaths[cognitiveType];
2793
3028
  if (typeDir === void 0) continue;
2794
- const fullPath = path8.join(this.projectRoot, typeDir);
2795
- if (!fs7.existsSync(fullPath)) continue;
2796
- const entries = fs7.readdirSync(fullPath, { withFileTypes: true });
3029
+ const fullPath = path9.join(this.projectRoot, typeDir);
3030
+ if (!fs8.existsSync(fullPath)) continue;
3031
+ const entries = fs8.readdirSync(fullPath, { withFileTypes: true });
2797
3032
  for (const entry of entries) {
2798
3033
  if (entry.name.startsWith(".")) continue;
2799
- const entryPath = path8.join(fullPath, entry.name);
3034
+ const entryPath = path9.join(fullPath, entry.name);
2800
3035
  if (entry.isFile() || entry.isDirectory() || entry.isSymbolicLink()) {
2801
3036
  const info = this.getLinkInfo(entryPath, cognitiveType);
2802
3037
  if (info !== null) {
@@ -2812,13 +3047,13 @@ var SymlinkManager = class {
2812
3047
  */
2813
3048
  getLinkInfo(linkPath, cognitiveType) {
2814
3049
  try {
2815
- const stats = fs7.lstatSync(linkPath);
3050
+ const stats = fs8.lstatSync(linkPath);
2816
3051
  const isSymlink = stats.isSymbolicLink();
2817
- const baseName = path8.basename(linkPath);
3052
+ const baseName = path9.basename(linkPath);
2818
3053
  let isDirectory = stats.isDirectory();
2819
3054
  if (isSymlink) {
2820
3055
  try {
2821
- const realStats = fs7.statSync(linkPath);
3056
+ const realStats = fs8.statSync(linkPath);
2822
3057
  isDirectory = realStats.isDirectory();
2823
3058
  } catch {
2824
3059
  isDirectory = !baseName.match(/\.(md|yaml)$/i);
@@ -2828,9 +3063,9 @@ var SymlinkManager = class {
2828
3063
  let target = "";
2829
3064
  let isValid = false;
2830
3065
  if (isSymlink) {
2831
- target = fs7.readlinkSync(linkPath);
2832
- const resolvedTarget = path8.resolve(path8.dirname(linkPath), target);
2833
- isValid = fs7.existsSync(resolvedTarget);
3066
+ target = fs8.readlinkSync(linkPath);
3067
+ const resolvedTarget = path9.resolve(path9.dirname(linkPath), target);
3068
+ isValid = fs8.existsSync(resolvedTarget);
2834
3069
  } else if (stats.isDirectory()) {
2835
3070
  target = linkPath;
2836
3071
  isValid = true;
@@ -2858,11 +3093,11 @@ var SymlinkManager = class {
2858
3093
  const method = this.getMethod(options);
2859
3094
  const isFile = mapping.isFile ?? false;
2860
3095
  try {
2861
- const targetDir = path8.dirname(mapping.targetPath);
2862
- if (!fs7.existsSync(targetDir)) {
2863
- fs7.mkdirSync(targetDir, { recursive: true });
3096
+ const targetDir = path9.dirname(mapping.targetPath);
3097
+ if (!fs8.existsSync(targetDir)) {
3098
+ fs8.mkdirSync(targetDir, { recursive: true });
2864
3099
  }
2865
- if (fs7.existsSync(mapping.targetPath)) {
3100
+ if (fs8.existsSync(mapping.targetPath)) {
2866
3101
  if (options.force === true) {
2867
3102
  this.removeLink(mapping.targetPath);
2868
3103
  } else {
@@ -2876,11 +3111,11 @@ var SymlinkManager = class {
2876
3111
  }
2877
3112
  }
2878
3113
  if (method === "symlink") {
2879
- const relativePath = path8.relative(targetDir, mapping.sourcePath);
2880
- fs7.symlinkSync(relativePath, mapping.targetPath, isFile ? "file" : "dir");
3114
+ const relativePath = path9.relative(targetDir, mapping.sourcePath);
3115
+ fs8.symlinkSync(relativePath, mapping.targetPath, isFile ? "file" : "dir");
2881
3116
  } else {
2882
3117
  if (isFile) {
2883
- fs7.copyFileSync(mapping.sourcePath, mapping.targetPath);
3118
+ fs8.copyFileSync(mapping.sourcePath, mapping.targetPath);
2884
3119
  } else {
2885
3120
  this.copyDirectory(mapping.sourcePath, mapping.targetPath);
2886
3121
  }
@@ -2895,7 +3130,7 @@ var SymlinkManager = class {
2895
3130
  if (method === "symlink" && options.copy !== true) {
2896
3131
  try {
2897
3132
  if (isFile) {
2898
- fs7.copyFileSync(mapping.sourcePath, mapping.targetPath);
3133
+ fs8.copyFileSync(mapping.sourcePath, mapping.targetPath);
2899
3134
  } else {
2900
3135
  this.copyDirectory(mapping.sourcePath, mapping.targetPath);
2901
3136
  }
@@ -2928,26 +3163,26 @@ var SymlinkManager = class {
2928
3163
  * Remove a symlink, file, or directory
2929
3164
  */
2930
3165
  removeLink(linkPath) {
2931
- const stats = fs7.lstatSync(linkPath);
3166
+ const stats = fs8.lstatSync(linkPath);
2932
3167
  if (stats.isSymbolicLink() || stats.isFile()) {
2933
- fs7.unlinkSync(linkPath);
3168
+ fs8.unlinkSync(linkPath);
2934
3169
  } else if (stats.isDirectory()) {
2935
- fs7.rmSync(linkPath, { recursive: true });
3170
+ fs8.rmSync(linkPath, { recursive: true });
2936
3171
  }
2937
3172
  }
2938
3173
  /**
2939
3174
  * Copy a directory recursively
2940
3175
  */
2941
3176
  copyDirectory(source, target) {
2942
- fs7.mkdirSync(target, { recursive: true });
2943
- const entries = fs7.readdirSync(source, { withFileTypes: true });
3177
+ fs8.mkdirSync(target, { recursive: true });
3178
+ const entries = fs8.readdirSync(source, { withFileTypes: true });
2944
3179
  for (const entry of entries) {
2945
- const sourcePath = path8.join(source, entry.name);
2946
- const targetPath = path8.join(target, entry.name);
3180
+ const sourcePath = path9.join(source, entry.name);
3181
+ const targetPath = path9.join(target, entry.name);
2947
3182
  if (entry.isDirectory()) {
2948
3183
  this.copyDirectory(sourcePath, targetPath);
2949
3184
  } else {
2950
- fs7.copyFileSync(sourcePath, targetPath);
3185
+ fs8.copyFileSync(sourcePath, targetPath);
2951
3186
  }
2952
3187
  }
2953
3188
  }
@@ -2976,8 +3211,8 @@ var SymlinkManager = class {
2976
3211
  broken.push(link);
2977
3212
  } else {
2978
3213
  if (link.isSymlink) {
2979
- const resolvedTarget = path8.resolve(path8.dirname(link.path), link.target);
2980
- if (!resolvedTarget.includes(path8.basename(this.synapSyncDir))) {
3214
+ const resolvedTarget = path9.resolve(path9.dirname(link.path), link.target);
3215
+ if (!resolvedTarget.includes(path9.basename(this.synapSyncDir))) {
2981
3216
  orphaned.push(link);
2982
3217
  } else {
2983
3218
  valid.push(link);
@@ -3018,7 +3253,7 @@ var SyncEngine = class {
3018
3253
  projectRoot;
3019
3254
  config;
3020
3255
  constructor(synapSyncDir, projectRoot, config) {
3021
- this.projectRoot = projectRoot ?? path9.dirname(synapSyncDir);
3256
+ this.projectRoot = projectRoot ?? path10.dirname(synapSyncDir);
3022
3257
  this.config = config ?? null;
3023
3258
  this.scanner = new CognitiveScanner(synapSyncDir);
3024
3259
  this.manifest = new ManifestManager(synapSyncDir);
@@ -3358,6 +3593,7 @@ async function executeAddCommand(source, options) {
3358
3593
  }
3359
3594
  }
3360
3595
  }
3596
+ regenerateAgentsMd(projectRoot, synapSyncDir);
3361
3597
  logger.line();
3362
3598
  }
3363
3599
  } catch (error) {
@@ -3378,7 +3614,7 @@ function parseSource(source) {
3378
3614
  if (source.startsWith("./") || source.startsWith("/") || source.startsWith("../")) {
3379
3615
  return {
3380
3616
  type: "local",
3381
- name: path10.basename(source),
3617
+ name: path11.basename(source),
3382
3618
  path: source
3383
3619
  };
3384
3620
  }
@@ -3415,7 +3651,7 @@ async function installFromRegistry(name, options, configManager) {
3415
3651
  const manifest = downloaded.manifest;
3416
3652
  const category = options.category ?? manifest.category;
3417
3653
  const targetDir = getTargetDir(configManager, manifest.type, category, manifest.name);
3418
- if (fs8.existsSync(targetDir) && options.force !== true) {
3654
+ if (fs9.existsSync(targetDir) && options.force !== true) {
3419
3655
  logger.line();
3420
3656
  logger.error(`Cognitive '${manifest.name}' is already installed.`);
3421
3657
  logger.hint("Use --force to overwrite.");
@@ -3428,7 +3664,7 @@ async function installFromRegistry(name, options, configManager) {
3428
3664
  logger.log(` ${pc9.green("\u2713")} Installed ${pc9.bold(manifest.name)} ${pc9.dim(`v${manifest.version}`)}`);
3429
3665
  logger.log(` ${pc9.dim("Type:")} ${manifest.type}`);
3430
3666
  logger.log(` ${pc9.dim("Category:")} ${category}`);
3431
- logger.log(` ${pc9.dim("Location:")} ${path10.relative(process.cwd(), targetDir)}`);
3667
+ logger.log(` ${pc9.dim("Location:")} ${path11.relative(process.cwd(), targetDir)}`);
3432
3668
  return true;
3433
3669
  }
3434
3670
  async function downloadAssets(client, name, _manifest) {
@@ -3449,8 +3685,8 @@ async function downloadAssets(client, name, _manifest) {
3449
3685
  return assets;
3450
3686
  }
3451
3687
  function installFromLocal(sourcePath, options, configManager) {
3452
- const absolutePath = path10.resolve(process.cwd(), sourcePath);
3453
- if (!fs8.existsSync(absolutePath)) {
3688
+ const absolutePath = path11.resolve(process.cwd(), sourcePath);
3689
+ if (!fs9.existsSync(absolutePath)) {
3454
3690
  throw new Error(`Path not found: ${absolutePath}`);
3455
3691
  }
3456
3692
  const detected = detectCognitiveType(absolutePath);
@@ -3461,13 +3697,13 @@ function installFromLocal(sourcePath, options, configManager) {
3461
3697
  }
3462
3698
  const cognitiveType = options.type ?? detected?.type ?? "skill";
3463
3699
  const fileName = detected?.fileName ?? COGNITIVE_FILE_NAMES[cognitiveType];
3464
- const filePath = path10.join(absolutePath, fileName);
3465
- if (!fs8.existsSync(filePath)) {
3700
+ const filePath = path11.join(absolutePath, fileName);
3701
+ if (!fs9.existsSync(filePath)) {
3466
3702
  throw new Error(`Cognitive file not found: ${filePath}`);
3467
3703
  }
3468
- const content = fs8.readFileSync(filePath, "utf-8");
3704
+ const content = fs9.readFileSync(filePath, "utf-8");
3469
3705
  const metadata = parseMetadata(content);
3470
- const name = metadata["name"] ?? path10.basename(absolutePath);
3706
+ const name = metadata["name"] ?? path11.basename(absolutePath);
3471
3707
  const category = options.category ?? metadata["category"] ?? "general";
3472
3708
  const manifest = {
3473
3709
  name,
@@ -3485,18 +3721,18 @@ function installFromLocal(sourcePath, options, configManager) {
3485
3721
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3486
3722
  };
3487
3723
  const targetDir = getTargetDir(configManager, cognitiveType, category, name);
3488
- if (fs8.existsSync(targetDir) && options.force !== true) {
3724
+ if (fs9.existsSync(targetDir) && options.force !== true) {
3489
3725
  logger.line();
3490
3726
  logger.error(`Cognitive '${name}' is already installed.`);
3491
3727
  logger.hint("Use --force to overwrite.");
3492
3728
  return false;
3493
3729
  }
3494
3730
  const assets = /* @__PURE__ */ new Map();
3495
- const assetsDir = path10.join(absolutePath, "assets");
3496
- if (fs8.existsSync(assetsDir)) {
3497
- const assetFiles = fs8.readdirSync(assetsDir);
3731
+ const assetsDir = path11.join(absolutePath, "assets");
3732
+ if (fs9.existsSync(assetsDir)) {
3733
+ const assetFiles = fs9.readdirSync(assetsDir);
3498
3734
  for (const file of assetFiles) {
3499
- const assetContent = fs8.readFileSync(path10.join(assetsDir, file), "utf-8");
3735
+ const assetContent = fs9.readFileSync(path11.join(assetsDir, file), "utf-8");
3500
3736
  assets.set(`assets/${file}`, assetContent);
3501
3737
  }
3502
3738
  }
@@ -3507,18 +3743,18 @@ function installFromLocal(sourcePath, options, configManager) {
3507
3743
  logger.log(` ${pc9.dim("Type:")} ${cognitiveType}`);
3508
3744
  logger.log(` ${pc9.dim("Category:")} ${category}`);
3509
3745
  logger.log(` ${pc9.dim("Source:")} local`);
3510
- logger.log(` ${pc9.dim("Location:")} ${path10.relative(process.cwd(), targetDir)}`);
3746
+ logger.log(` ${pc9.dim("Location:")} ${path11.relative(process.cwd(), targetDir)}`);
3511
3747
  return true;
3512
3748
  }
3513
3749
  function detectCognitiveType(dirPath) {
3514
3750
  for (const type of COGNITIVE_TYPES) {
3515
3751
  const fileName = COGNITIVE_FILE_NAMES[type];
3516
- if (fs8.existsSync(path10.join(dirPath, fileName))) {
3752
+ if (fs9.existsSync(path11.join(dirPath, fileName))) {
3517
3753
  return { type, fileName };
3518
3754
  }
3519
3755
  }
3520
- if (!fs8.existsSync(dirPath)) return null;
3521
- const files = fs8.readdirSync(dirPath);
3756
+ if (!fs9.existsSync(dirPath)) return null;
3757
+ const files = fs9.readdirSync(dirPath);
3522
3758
  for (const file of files) {
3523
3759
  if (file.endsWith(".yaml") && !file.startsWith(".")) {
3524
3760
  return { type: "workflow", fileName: file };
@@ -3526,7 +3762,7 @@ function detectCognitiveType(dirPath) {
3526
3762
  }
3527
3763
  for (const file of files) {
3528
3764
  if (file.endsWith(".md") && !file.startsWith(".")) {
3529
- const content = fs8.readFileSync(path10.join(dirPath, file), "utf-8");
3765
+ const content = fs9.readFileSync(path11.join(dirPath, file), "utf-8");
3530
3766
  const metadata = parseMetadata(content);
3531
3767
  const detectedType = metadata["type"] ?? "skill";
3532
3768
  if (COGNITIVE_TYPES.includes(detectedType)) {
@@ -3570,25 +3806,25 @@ function installFromGitHub(_source, _options, _configManager) {
3570
3806
  }
3571
3807
  function getTargetDir(configManager, type, category, name) {
3572
3808
  const synapSyncDir = configManager.getSynapSyncDir();
3573
- return path10.join(synapSyncDir, `${type}s`, category, name);
3809
+ return path11.join(synapSyncDir, `${type}s`, category, name);
3574
3810
  }
3575
3811
  function saveCognitive(targetDir, manifest, content, assets) {
3576
- fs8.mkdirSync(targetDir, { recursive: true });
3577
- const mainFilePath = path10.join(targetDir, manifest.file);
3578
- fs8.writeFileSync(mainFilePath, content, "utf-8");
3812
+ fs9.mkdirSync(targetDir, { recursive: true });
3813
+ const mainFilePath = path11.join(targetDir, manifest.file);
3814
+ fs9.writeFileSync(mainFilePath, content, "utf-8");
3579
3815
  for (const [assetPath, assetContent] of assets) {
3580
- const fullPath = path10.join(targetDir, assetPath);
3581
- const assetDir = path10.dirname(fullPath);
3582
- fs8.mkdirSync(assetDir, { recursive: true });
3583
- fs8.writeFileSync(fullPath, assetContent, "utf-8");
3816
+ const fullPath = path11.join(targetDir, assetPath);
3817
+ const assetDir = path11.dirname(fullPath);
3818
+ fs9.mkdirSync(assetDir, { recursive: true });
3819
+ fs9.writeFileSync(fullPath, assetContent, "utf-8");
3584
3820
  }
3585
3821
  }
3586
3822
  function updateProjectManifest(configManager, manifest, source) {
3587
3823
  const synapSyncDir = configManager.getSynapSyncDir();
3588
- const manifestPath = path10.join(synapSyncDir, "manifest.json");
3824
+ const manifestPath = path11.join(synapSyncDir, "manifest.json");
3589
3825
  let projectManifest;
3590
- if (fs8.existsSync(manifestPath)) {
3591
- const content = fs8.readFileSync(manifestPath, "utf-8");
3826
+ if (fs9.existsSync(manifestPath)) {
3827
+ const content = fs9.readFileSync(manifestPath, "utf-8");
3592
3828
  projectManifest = JSON.parse(content);
3593
3829
  } else {
3594
3830
  projectManifest = {
@@ -3612,7 +3848,7 @@ function updateProjectManifest(configManager, manifest, source) {
3612
3848
  }
3613
3849
  projectManifest.cognitives[manifest.name] = entry;
3614
3850
  projectManifest.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
3615
- fs8.writeFileSync(manifestPath, JSON.stringify(projectManifest, null, 2), "utf-8");
3851
+ fs9.writeFileSync(manifestPath, JSON.stringify(projectManifest, null, 2), "utf-8");
3616
3852
  }
3617
3853
  function registerAddCommand(program) {
3618
3854
  program.command("add <source>").description("Add a cognitive from registry, local path, or GitHub").option("-t, --type <type>", "Cognitive type (skill, agent, prompt, workflow, tool)").option("-c, --category <category>", "Category (overrides default)").option("-f, --force", "Overwrite if already installed").action(async (source, options) => {
@@ -3622,8 +3858,8 @@ function registerAddCommand(program) {
3622
3858
 
3623
3859
  // src/commands/list.ts
3624
3860
  init_esm_shims();
3625
- import * as fs9 from "fs";
3626
- import * as path11 from "path";
3861
+ import * as fs10 from "fs";
3862
+ import * as path12 from "path";
3627
3863
  import pc10 from "picocolors";
3628
3864
  async function executeListCommand(options) {
3629
3865
  logger.line();
@@ -3743,8 +3979,8 @@ function validateOptions2(options) {
3743
3979
  }
3744
3980
  function readManifest(configManager) {
3745
3981
  const synapSyncDir = configManager.getSynapSyncDir();
3746
- const manifestPath = path11.join(synapSyncDir, "manifest.json");
3747
- if (!fs9.existsSync(manifestPath)) {
3982
+ const manifestPath = path12.join(synapSyncDir, "manifest.json");
3983
+ if (!fs10.existsSync(manifestPath)) {
3748
3984
  return {
3749
3985
  version: "1.0.0",
3750
3986
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3753,7 +3989,7 @@ function readManifest(configManager) {
3753
3989
  };
3754
3990
  }
3755
3991
  try {
3756
- const content = fs9.readFileSync(manifestPath, "utf-8");
3992
+ const content = fs10.readFileSync(manifestPath, "utf-8");
3757
3993
  return JSON.parse(content);
3758
3994
  } catch {
3759
3995
  return {
@@ -3862,8 +4098,8 @@ function registerListCommand(program) {
3862
4098
 
3863
4099
  // src/commands/uninstall.ts
3864
4100
  init_esm_shims();
3865
- import * as fs10 from "fs";
3866
- import * as path12 from "path";
4101
+ import * as fs11 from "fs";
4102
+ import * as path13 from "path";
3867
4103
  import pc11 from "picocolors";
3868
4104
  function executeUninstallCommand(name, options) {
3869
4105
  logger.line();
@@ -3893,14 +4129,15 @@ function executeUninstallCommand(name, options) {
3893
4129
  try {
3894
4130
  if (options.keepFiles !== true) {
3895
4131
  const cognitiveDir = getCognitiveDir(configManager, cognitive);
3896
- if (fs10.existsSync(cognitiveDir)) {
3897
- fs10.rmSync(cognitiveDir, { recursive: true, force: true });
3898
- logger.log(` ${pc11.dim("Removed files from")} ${path12.relative(process.cwd(), cognitiveDir)}`);
4132
+ if (fs11.existsSync(cognitiveDir)) {
4133
+ fs11.rmSync(cognitiveDir, { recursive: true, force: true });
4134
+ logger.log(` ${pc11.dim("Removed files from")} ${path13.relative(process.cwd(), cognitiveDir)}`);
3899
4135
  }
3900
4136
  }
3901
4137
  delete manifest.cognitives[name];
3902
4138
  manifest.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
3903
4139
  saveManifest(configManager, manifest);
4140
+ regenerateAgentsMd(configManager.getProjectRoot(), configManager.getSynapSyncDir());
3904
4141
  logger.line();
3905
4142
  logger.log(` ${pc11.green("\u2713")} Uninstalled ${pc11.bold(name)}`);
3906
4143
  logger.line();
@@ -3916,8 +4153,8 @@ function executeUninstallCommand(name, options) {
3916
4153
  }
3917
4154
  function readManifest2(configManager) {
3918
4155
  const synapSyncDir = configManager.getSynapSyncDir();
3919
- const manifestPath = path12.join(synapSyncDir, "manifest.json");
3920
- if (!fs10.existsSync(manifestPath)) {
4156
+ const manifestPath = path13.join(synapSyncDir, "manifest.json");
4157
+ if (!fs11.existsSync(manifestPath)) {
3921
4158
  return {
3922
4159
  version: "1.0.0",
3923
4160
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3926,7 +4163,7 @@ function readManifest2(configManager) {
3926
4163
  };
3927
4164
  }
3928
4165
  try {
3929
- const content = fs10.readFileSync(manifestPath, "utf-8");
4166
+ const content = fs11.readFileSync(manifestPath, "utf-8");
3930
4167
  return JSON.parse(content);
3931
4168
  } catch {
3932
4169
  return {
@@ -3939,12 +4176,12 @@ function readManifest2(configManager) {
3939
4176
  }
3940
4177
  function saveManifest(configManager, manifest) {
3941
4178
  const synapSyncDir = configManager.getSynapSyncDir();
3942
- const manifestPath = path12.join(synapSyncDir, "manifest.json");
3943
- fs10.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
4179
+ const manifestPath = path13.join(synapSyncDir, "manifest.json");
4180
+ fs11.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
3944
4181
  }
3945
4182
  function getCognitiveDir(configManager, cognitive) {
3946
4183
  const synapSyncDir = configManager.getSynapSyncDir();
3947
- return path12.join(synapSyncDir, `${cognitive.type}s`, cognitive.category, cognitive.name);
4184
+ return path13.join(synapSyncDir, `${cognitive.type}s`, cognitive.category, cognitive.name);
3948
4185
  }
3949
4186
  function registerUninstallCommand(program) {
3950
4187
  program.command("uninstall <name>").alias("rm").description("Uninstall a cognitive").option("-f, --force", "Skip confirmation").option("--keep-files", "Remove from manifest but keep files").action((name, options) => {
@@ -3995,6 +4232,11 @@ function executeSyncCommand(options) {
3995
4232
  }
3996
4233
  } : void 0
3997
4234
  );
4235
+ if (options.dryRun !== true) {
4236
+ const synapSyncDir2 = configManager.getSynapSyncDir();
4237
+ const projectRoot2 = configManager.getProjectRoot();
4238
+ regenerateAgentsMd(projectRoot2, synapSyncDir2);
4239
+ }
3998
4240
  if (options.json === true) {
3999
4241
  console.log(JSON.stringify(result, null, 2));
4000
4242
  return;
@@ -4228,8 +4470,8 @@ function registerSyncCommand(program) {
4228
4470
 
4229
4471
  // src/commands/update.ts
4230
4472
  init_esm_shims();
4231
- import * as fs11 from "fs";
4232
- import * as path13 from "path";
4473
+ import * as fs12 from "fs";
4474
+ import * as path14 from "path";
4233
4475
  import pc13 from "picocolors";
4234
4476
 
4235
4477
  // src/services/maintenance/update-checker.ts
@@ -4408,18 +4650,18 @@ async function executeUpdateCommand(cognitiveName, options = {}) {
4408
4650
  const downloaded = await registry.download(update.name);
4409
4651
  const manifestEntry = installed.find((c) => c.name === update.name);
4410
4652
  if (manifestEntry === void 0) continue;
4411
- const targetDir = path13.join(
4653
+ const targetDir = path14.join(
4412
4654
  synapSyncDir,
4413
4655
  `${update.type}s`,
4414
4656
  update.category,
4415
4657
  update.name
4416
4658
  );
4417
4659
  const fileName = COGNITIVE_FILE_NAMES[update.type];
4418
- const filePath = path13.join(targetDir, fileName);
4419
- if (!fs11.existsSync(targetDir)) {
4420
- fs11.mkdirSync(targetDir, { recursive: true });
4660
+ const filePath = path14.join(targetDir, fileName);
4661
+ if (!fs12.existsSync(targetDir)) {
4662
+ fs12.mkdirSync(targetDir, { recursive: true });
4421
4663
  }
4422
- fs11.writeFileSync(filePath, downloaded.content, "utf-8");
4664
+ fs12.writeFileSync(filePath, downloaded.content, "utf-8");
4423
4665
  manifest.updateCognitive(update.name, {
4424
4666
  version: update.latestVersion
4425
4667
  });
@@ -4439,6 +4681,7 @@ async function executeUpdateCommand(cognitiveName, options = {}) {
4439
4681
  const config = configManager.getConfig();
4440
4682
  const syncEngine = new SyncEngine(synapSyncDir, projectRoot, config);
4441
4683
  syncEngine.sync();
4684
+ regenerateAgentsMd(projectRoot, synapSyncDir);
4442
4685
  logger.line();
4443
4686
  if (updated.length > 0) {
4444
4687
  logger.log(` ${pc13.green("\u2713")} Updated ${updated.length} cognitive(s)`);
@@ -4482,8 +4725,8 @@ import pc14 from "picocolors";
4482
4725
 
4483
4726
  // src/services/maintenance/doctor.ts
4484
4727
  init_esm_shims();
4485
- import * as fs12 from "fs";
4486
- import * as path14 from "path";
4728
+ import * as fs13 from "fs";
4729
+ import * as path15 from "path";
4487
4730
  var DoctorService = class {
4488
4731
  projectRoot;
4489
4732
  synapSyncDir;
@@ -4578,7 +4821,7 @@ var DoctorService = class {
4578
4821
  };
4579
4822
  }
4580
4823
  checkSynapSyncDir() {
4581
- if (fs12.existsSync(this.synapSyncDir)) {
4824
+ if (fs13.existsSync(this.synapSyncDir)) {
4582
4825
  return {
4583
4826
  id: "synapsync-dir",
4584
4827
  name: ".synapsync Directory",
@@ -4598,8 +4841,8 @@ var DoctorService = class {
4598
4841
  };
4599
4842
  }
4600
4843
  checkConfig() {
4601
- const configPath = path14.join(this.projectRoot, "synapsync.config.yaml");
4602
- if (fs12.existsSync(configPath)) {
4844
+ const configPath = path15.join(this.projectRoot, "synapsync.config.yaml");
4845
+ if (fs13.existsSync(configPath)) {
4603
4846
  if (this.config !== null) {
4604
4847
  return {
4605
4848
  id: "config-valid",
@@ -4629,8 +4872,8 @@ var DoctorService = class {
4629
4872
  };
4630
4873
  }
4631
4874
  checkManifest() {
4632
- const manifestPath = path14.join(this.synapSyncDir, "manifest.json");
4633
- if (!fs12.existsSync(manifestPath)) {
4875
+ const manifestPath = path15.join(this.synapSyncDir, "manifest.json");
4876
+ if (!fs13.existsSync(manifestPath)) {
4634
4877
  return {
4635
4878
  id: "manifest-exists",
4636
4879
  name: "Manifest File",
@@ -4641,7 +4884,7 @@ var DoctorService = class {
4641
4884
  };
4642
4885
  }
4643
4886
  try {
4644
- const content = fs12.readFileSync(manifestPath, "utf-8");
4887
+ const content = fs13.readFileSync(manifestPath, "utf-8");
4645
4888
  JSON.parse(content);
4646
4889
  return {
4647
4890
  id: "manifest-exists",
@@ -4663,7 +4906,7 @@ var DoctorService = class {
4663
4906
  }
4664
4907
  }
4665
4908
  checkManifestConsistency() {
4666
- if (!fs12.existsSync(this.synapSyncDir)) {
4909
+ if (!fs13.existsSync(this.synapSyncDir)) {
4667
4910
  return {
4668
4911
  id: "manifest-consistency",
4669
4912
  name: "Manifest Consistency",
@@ -4860,13 +5103,13 @@ var DoctorService = class {
4860
5103
  }
4861
5104
  }
4862
5105
  fixSynapSyncDir() {
4863
- if (!fs12.existsSync(this.synapSyncDir)) {
4864
- fs12.mkdirSync(this.synapSyncDir, { recursive: true });
5106
+ if (!fs13.existsSync(this.synapSyncDir)) {
5107
+ fs13.mkdirSync(this.synapSyncDir, { recursive: true });
4865
5108
  }
4866
5109
  for (const type of COGNITIVE_TYPES) {
4867
- const typeDir = path14.join(this.synapSyncDir, `${type}s`);
4868
- if (!fs12.existsSync(typeDir)) {
4869
- fs12.mkdirSync(typeDir, { recursive: true });
5110
+ const typeDir = path15.join(this.synapSyncDir, `${type}s`);
5111
+ if (!fs13.existsSync(typeDir)) {
5112
+ fs13.mkdirSync(typeDir, { recursive: true });
4870
5113
  }
4871
5114
  }
4872
5115
  }
@@ -5042,8 +5285,8 @@ import pc15 from "picocolors";
5042
5285
 
5043
5286
  // src/services/maintenance/cleaner.ts
5044
5287
  init_esm_shims();
5045
- import * as fs13 from "fs";
5046
- import * as path15 from "path";
5288
+ import * as fs14 from "fs";
5289
+ import * as path16 from "path";
5047
5290
  var CleanerService = class {
5048
5291
  projectRoot;
5049
5292
  synapSyncDir;
@@ -5103,8 +5346,8 @@ var CleanerService = class {
5103
5346
  const cleaned = [];
5104
5347
  const errors = [];
5105
5348
  let bytes = 0;
5106
- const cacheDir = path15.join(this.synapSyncDir, "cache");
5107
- if (!fs13.existsSync(cacheDir)) {
5349
+ const cacheDir = path16.join(this.synapSyncDir, "cache");
5350
+ if (!fs14.existsSync(cacheDir)) {
5108
5351
  return { cleaned, bytes, errors };
5109
5352
  }
5110
5353
  try {
@@ -5175,14 +5418,14 @@ var CleanerService = class {
5175
5418
  const errors = [];
5176
5419
  let bytes = 0;
5177
5420
  const tempPatterns = [
5178
- path15.join(this.synapSyncDir, ".tmp"),
5179
- path15.join(this.synapSyncDir, "temp"),
5180
- path15.join(this.synapSyncDir, "*.tmp"),
5181
- path15.join(this.synapSyncDir, "*.temp")
5421
+ path16.join(this.synapSyncDir, ".tmp"),
5422
+ path16.join(this.synapSyncDir, "temp"),
5423
+ path16.join(this.synapSyncDir, "*.tmp"),
5424
+ path16.join(this.synapSyncDir, "*.temp")
5182
5425
  ];
5183
5426
  for (const pattern of tempPatterns) {
5184
5427
  if (!pattern.includes("*")) {
5185
- if (fs13.existsSync(pattern)) {
5428
+ if (fs14.existsSync(pattern)) {
5186
5429
  const size = this.getSize(pattern);
5187
5430
  cleaned.push({
5188
5431
  type: "temp",
@@ -5202,14 +5445,14 @@ var CleanerService = class {
5202
5445
  }
5203
5446
  }
5204
5447
  } else {
5205
- const dir = path15.dirname(pattern);
5206
- const ext = path15.extname(pattern);
5207
- if (fs13.existsSync(dir)) {
5448
+ const dir = path16.dirname(pattern);
5449
+ const ext = path16.extname(pattern);
5450
+ if (fs14.existsSync(dir)) {
5208
5451
  try {
5209
- const entries = fs13.readdirSync(dir);
5452
+ const entries = fs14.readdirSync(dir);
5210
5453
  for (const entry of entries) {
5211
5454
  if (entry.endsWith(ext.slice(1))) {
5212
- const fullPath = path15.join(dir, entry);
5455
+ const fullPath = path16.join(dir, entry);
5213
5456
  const size = this.getSize(fullPath);
5214
5457
  cleaned.push({
5215
5458
  type: "temp",
@@ -5245,9 +5488,9 @@ var CleanerService = class {
5245
5488
  */
5246
5489
  listDirectory(dir) {
5247
5490
  const items = [];
5248
- const entries = fs13.readdirSync(dir, { withFileTypes: true });
5491
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
5249
5492
  for (const entry of entries) {
5250
- const fullPath = path15.join(dir, entry.name);
5493
+ const fullPath = path16.join(dir, entry.name);
5251
5494
  items.push(fullPath);
5252
5495
  if (entry.isDirectory()) {
5253
5496
  items.push(...this.listDirectory(fullPath));
@@ -5260,15 +5503,15 @@ var CleanerService = class {
5260
5503
  */
5261
5504
  getSize(itemPath) {
5262
5505
  try {
5263
- const stats = fs13.statSync(itemPath);
5506
+ const stats = fs14.statSync(itemPath);
5264
5507
  if (stats.isFile()) {
5265
5508
  return stats.size;
5266
5509
  }
5267
5510
  if (stats.isDirectory()) {
5268
5511
  let size = 0;
5269
- const entries = fs13.readdirSync(itemPath, { withFileTypes: true });
5512
+ const entries = fs14.readdirSync(itemPath, { withFileTypes: true });
5270
5513
  for (const entry of entries) {
5271
- size += this.getSize(path15.join(itemPath, entry.name));
5514
+ size += this.getSize(path16.join(itemPath, entry.name));
5272
5515
  }
5273
5516
  return size;
5274
5517
  }
@@ -5281,11 +5524,11 @@ var CleanerService = class {
5281
5524
  * Remove a file or directory
5282
5525
  */
5283
5526
  removeItem(itemPath) {
5284
- const stats = fs13.lstatSync(itemPath);
5527
+ const stats = fs14.lstatSync(itemPath);
5285
5528
  if (stats.isSymbolicLink() || stats.isFile()) {
5286
- fs13.unlinkSync(itemPath);
5529
+ fs14.unlinkSync(itemPath);
5287
5530
  } else if (stats.isDirectory()) {
5288
- fs13.rmSync(itemPath, { recursive: true });
5531
+ fs14.rmSync(itemPath, { recursive: true });
5289
5532
  }
5290
5533
  }
5291
5534
  /**
@@ -5418,8 +5661,8 @@ function registerCleanCommand(program) {
5418
5661
 
5419
5662
  // src/commands/purge.ts
5420
5663
  init_esm_shims();
5421
- import * as fs14 from "fs";
5422
- import * as path16 from "path";
5664
+ import * as fs15 from "fs";
5665
+ import * as path17 from "path";
5423
5666
  import pc16 from "picocolors";
5424
5667
  function executePurgeCommand(options) {
5425
5668
  logger.line();
@@ -5445,17 +5688,23 @@ function executePurgeCommand(options) {
5445
5688
  let removedCount = 0;
5446
5689
  try {
5447
5690
  removedCount += removeProviderSymlinks(projectRoot, synapSyncDir);
5448
- if (fs14.existsSync(synapSyncDir)) {
5449
- fs14.rmSync(synapSyncDir, { recursive: true, force: true });
5450
- logger.log(` ${pc16.red("\u2717")} Removed ${path16.relative(projectRoot, synapSyncDir)}/`);
5691
+ if (fs15.existsSync(synapSyncDir)) {
5692
+ fs15.rmSync(synapSyncDir, { recursive: true, force: true });
5693
+ logger.log(` ${pc16.red("\u2717")} Removed ${path17.relative(projectRoot, synapSyncDir)}/`);
5451
5694
  removedCount++;
5452
5695
  }
5453
- const configPath = path16.join(projectRoot, "synapsync.config.yaml");
5454
- if (fs14.existsSync(configPath)) {
5455
- fs14.unlinkSync(configPath);
5696
+ const configPath = path17.join(projectRoot, "synapsync.config.yaml");
5697
+ if (fs15.existsSync(configPath)) {
5698
+ fs15.unlinkSync(configPath);
5456
5699
  logger.log(` ${pc16.red("\u2717")} Removed synapsync.config.yaml`);
5457
5700
  removedCount++;
5458
5701
  }
5702
+ const agentsMdPath = path17.join(projectRoot, AGENTS_MD_FILE_NAME);
5703
+ if (fs15.existsSync(agentsMdPath)) {
5704
+ fs15.unlinkSync(agentsMdPath);
5705
+ logger.log(` ${pc16.red("\u2717")} Removed ${AGENTS_MD_FILE_NAME}`);
5706
+ removedCount++;
5707
+ }
5459
5708
  if (cleanGitignore(projectRoot)) {
5460
5709
  logger.log(` ${pc16.red("\u2717")} Cleaned SynapSync entries from .gitignore`);
5461
5710
  removedCount++;
@@ -5480,18 +5729,22 @@ function collectItemsToRemove(projectRoot, synapSyncDir) {
5480
5729
  const items = [];
5481
5730
  const symlinks = findSynapSyncSymlinks(projectRoot, synapSyncDir);
5482
5731
  for (const link of symlinks) {
5483
- items.push(`${path16.relative(projectRoot, link)} (symlink)`);
5732
+ items.push(`${path17.relative(projectRoot, link)} (symlink)`);
5484
5733
  }
5485
- if (fs14.existsSync(synapSyncDir)) {
5486
- items.push(path16.relative(projectRoot, synapSyncDir) + "/");
5734
+ if (fs15.existsSync(synapSyncDir)) {
5735
+ items.push(path17.relative(projectRoot, synapSyncDir) + "/");
5487
5736
  }
5488
- const configPath = path16.join(projectRoot, "synapsync.config.yaml");
5489
- if (fs14.existsSync(configPath)) {
5737
+ const configPath = path17.join(projectRoot, "synapsync.config.yaml");
5738
+ if (fs15.existsSync(configPath)) {
5490
5739
  items.push("synapsync.config.yaml");
5491
5740
  }
5492
- const gitignorePath = path16.join(projectRoot, ".gitignore");
5493
- if (fs14.existsSync(gitignorePath)) {
5494
- const content = fs14.readFileSync(gitignorePath, "utf-8");
5741
+ const agentsMdPath = path17.join(projectRoot, AGENTS_MD_FILE_NAME);
5742
+ if (fs15.existsSync(agentsMdPath)) {
5743
+ items.push(AGENTS_MD_FILE_NAME);
5744
+ }
5745
+ const gitignorePath = path17.join(projectRoot, ".gitignore");
5746
+ if (fs15.existsSync(gitignorePath)) {
5747
+ const content = fs15.readFileSync(gitignorePath, "utf-8");
5495
5748
  if (content.includes("# SynapSync")) {
5496
5749
  items.push(".gitignore (SynapSync entries)");
5497
5750
  }
@@ -5500,18 +5753,18 @@ function collectItemsToRemove(projectRoot, synapSyncDir) {
5500
5753
  }
5501
5754
  function findSynapSyncSymlinks(projectRoot, synapSyncDir) {
5502
5755
  const symlinks = [];
5503
- const resolvedSynapSync = path16.resolve(synapSyncDir);
5756
+ const resolvedSynapSync = path17.resolve(synapSyncDir);
5504
5757
  for (const provider of SUPPORTED_PROVIDERS) {
5505
5758
  const providerPaths = PROVIDER_PATHS[provider];
5506
5759
  for (const type of COGNITIVE_TYPES) {
5507
- const typePath = path16.join(projectRoot, providerPaths[type]);
5508
- if (!fs14.existsSync(typePath)) continue;
5760
+ const typePath = path17.join(projectRoot, providerPaths[type]);
5761
+ if (!fs15.existsSync(typePath)) continue;
5509
5762
  try {
5510
- const entries = fs14.readdirSync(typePath, { withFileTypes: true });
5763
+ const entries = fs15.readdirSync(typePath, { withFileTypes: true });
5511
5764
  for (const entry of entries) {
5512
- const fullPath = path16.join(typePath, entry.name);
5765
+ const fullPath = path17.join(typePath, entry.name);
5513
5766
  if (entry.isSymbolicLink()) {
5514
- const target = path16.resolve(typePath, fs14.readlinkSync(fullPath));
5767
+ const target = path17.resolve(typePath, fs15.readlinkSync(fullPath));
5515
5768
  if (target.startsWith(resolvedSynapSync)) {
5516
5769
  symlinks.push(fullPath);
5517
5770
  }
@@ -5526,21 +5779,21 @@ function findSynapSyncSymlinks(projectRoot, synapSyncDir) {
5526
5779
  function removeProviderSymlinks(projectRoot, synapSyncDir) {
5527
5780
  const symlinks = findSynapSyncSymlinks(projectRoot, synapSyncDir);
5528
5781
  for (const link of symlinks) {
5529
- fs14.unlinkSync(link);
5530
- logger.log(` ${pc16.red("\u2717")} Removed symlink ${path16.relative(projectRoot, link)}`);
5782
+ fs15.unlinkSync(link);
5783
+ logger.log(` ${pc16.red("\u2717")} Removed symlink ${path17.relative(projectRoot, link)}`);
5531
5784
  }
5532
5785
  return symlinks.length;
5533
5786
  }
5534
5787
  function cleanGitignore(projectRoot) {
5535
- const gitignorePath = path16.join(projectRoot, ".gitignore");
5536
- if (!fs14.existsSync(gitignorePath)) return false;
5537
- const content = fs14.readFileSync(gitignorePath, "utf-8");
5788
+ const gitignorePath = path17.join(projectRoot, ".gitignore");
5789
+ if (!fs15.existsSync(gitignorePath)) return false;
5790
+ const content = fs15.readFileSync(gitignorePath, "utf-8");
5538
5791
  if (!content.includes("# SynapSync")) return false;
5539
5792
  const cleaned = content.replace(/\n?# SynapSync\n\.synapsync\/manifest\.json\n\*\.local\.yaml\n?/g, "").replace(/^\s*\n$/gm, "\n");
5540
5793
  if (cleaned.trim() === "") {
5541
- fs14.unlinkSync(gitignorePath);
5794
+ fs15.unlinkSync(gitignorePath);
5542
5795
  } else {
5543
- fs14.writeFileSync(gitignorePath, cleaned, "utf-8");
5796
+ fs15.writeFileSync(gitignorePath, cleaned, "utf-8");
5544
5797
  }
5545
5798
  return true;
5546
5799
  }