@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 +1855 -1602
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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
|
|
722
|
-
import * as
|
|
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,
|
|
826
|
-
const parts =
|
|
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,
|
|
840
|
-
const parts =
|
|
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/
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
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
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
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
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
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
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
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
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
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
|
-
|
|
1157
|
-
|
|
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
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
]
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
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/
|
|
1223
|
+
// src/services/scanner/scanner.ts
|
|
1217
1224
|
init_esm_shims();
|
|
1218
|
-
import
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
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
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
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
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
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
|
-
|
|
1272
|
-
|
|
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
|
|
1282
|
-
if (
|
|
1283
|
-
|
|
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
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
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
|
|
1296
|
-
|
|
1297
|
-
|
|
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
|
-
|
|
1302
|
+
return "1.0.0";
|
|
1305
1303
|
}
|
|
1306
|
-
function
|
|
1307
|
-
|
|
1308
|
-
|
|
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
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
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
|
|
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/
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
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
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
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
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
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
|
-
|
|
1507
|
-
logger.log(` ${pc6.bold(totalCognitives.toString().padStart(5))} total`);
|
|
1416
|
+
return null;
|
|
1508
1417
|
}
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
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
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
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
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
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
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
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
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
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
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
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
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
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
|
-
*
|
|
1566
|
+
* Generate an empty managed section (used by init).
|
|
1805
1567
|
*/
|
|
1806
|
-
|
|
1807
|
-
const
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
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
|
-
*
|
|
1588
|
+
* Remove the AGENTS.md file entirely (used by purge).
|
|
1823
1589
|
*/
|
|
1824
|
-
|
|
1825
|
-
const
|
|
1826
|
-
|
|
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
|
-
*
|
|
1599
|
+
* Build enriched entries from manifest cognitives.
|
|
1600
|
+
* Scans filesystem for descriptions from frontmatter.
|
|
1833
1601
|
*/
|
|
1834
|
-
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
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
|
-
|
|
1858
|
-
|
|
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
|
-
*
|
|
1640
|
+
* Render the full managed section (between markers).
|
|
1870
1641
|
*/
|
|
1871
|
-
|
|
1872
|
-
const
|
|
1873
|
-
|
|
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
|
-
*
|
|
1671
|
+
* Render the empty managed section.
|
|
1877
1672
|
*/
|
|
1878
|
-
|
|
1879
|
-
const
|
|
1880
|
-
|
|
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
|
-
*
|
|
1686
|
+
* Render a markdown table for a group of entries.
|
|
1887
1687
|
*/
|
|
1888
|
-
|
|
1889
|
-
const
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
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
|
|
1701
|
+
return lines;
|
|
1898
1702
|
}
|
|
1899
1703
|
/**
|
|
1900
|
-
*
|
|
1704
|
+
* Write content within markers, preserving user content outside.
|
|
1901
1705
|
*/
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
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
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
if (
|
|
1919
|
-
|
|
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
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
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
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
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
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
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
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
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
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
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
|
-
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
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
|
-
|
|
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
|
|
2038
|
-
logger.error(
|
|
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
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
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
|
|
2078
|
-
|
|
2079
|
-
|
|
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
|
-
|
|
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
|
|
2103
|
-
const
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
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
|
|
2121
|
-
const
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
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
|
|
1903
|
+
return hints[provider];
|
|
2129
1904
|
}
|
|
2130
|
-
function
|
|
2131
|
-
|
|
2132
|
-
|
|
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
|
|
2135
|
-
program.command("
|
|
2136
|
-
await
|
|
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/
|
|
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
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
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
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
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
|
|
2170
|
-
const
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
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
|
-
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
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
|
-
|
|
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
|
|
2222
|
-
if (
|
|
2223
|
-
|
|
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
|
|
2226
|
-
|
|
2227
|
-
|
|
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
|
|
2232
|
-
if (
|
|
2233
|
-
|
|
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
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
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
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
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
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
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
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
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
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
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
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
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
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
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
|
-
|
|
2181
|
+
statuses.push({
|
|
2182
|
+
name: provider,
|
|
2183
|
+
enabled,
|
|
2184
|
+
connected: false,
|
|
2185
|
+
// TODO: Check actual connection status
|
|
2186
|
+
cognitivesCount
|
|
2187
|
+
});
|
|
2381
2188
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
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
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
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
|
-
*
|
|
2527
|
+
* Fetch the registry index
|
|
2404
2528
|
*/
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
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
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
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
|
-
|
|
2539
|
+
const index = await response.json();
|
|
2540
|
+
this.indexCache = index;
|
|
2541
|
+
this.indexCacheTime = now;
|
|
2542
|
+
return index;
|
|
2423
2543
|
}
|
|
2424
2544
|
/**
|
|
2425
|
-
* Get
|
|
2545
|
+
* Get total count of cognitives in registry
|
|
2426
2546
|
*/
|
|
2427
|
-
|
|
2428
|
-
const
|
|
2429
|
-
|
|
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
|
-
*
|
|
2555
|
+
* Search for cognitives in the registry
|
|
2466
2556
|
*/
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
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
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
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
|
-
*
|
|
2592
|
+
* Find a cognitive by name
|
|
2486
2593
|
*/
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
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
|
-
*
|
|
2599
|
+
* List all cognitives
|
|
2494
2600
|
*/
|
|
2495
|
-
|
|
2496
|
-
|
|
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
|
|
2609
|
+
* Get the manifest for a cognitive
|
|
2500
2610
|
*/
|
|
2501
|
-
|
|
2502
|
-
|
|
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
|
|
2623
|
+
* Get the content file for a cognitive
|
|
2506
2624
|
*/
|
|
2507
|
-
|
|
2508
|
-
|
|
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
|
-
*
|
|
2637
|
+
* Download a cognitive (manifest + content)
|
|
2512
2638
|
*/
|
|
2513
|
-
|
|
2514
|
-
|
|
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
|
-
*
|
|
2653
|
+
* Download additional assets for a cognitive
|
|
2518
2654
|
*/
|
|
2519
|
-
|
|
2520
|
-
this.
|
|
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
|
-
*
|
|
2670
|
+
* Check if registry is reachable
|
|
2524
2671
|
*/
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
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
|
-
*
|
|
2682
|
+
* Clear the cache
|
|
2533
2683
|
*/
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
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
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
};
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
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
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
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
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
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
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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
|
-
|
|
2581
|
-
|
|
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
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
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
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
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
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
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
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
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
|
|
2641
|
-
import * as
|
|
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 =
|
|
2660
|
-
const testTarget =
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
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:
|
|
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:
|
|
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 =
|
|
2795
|
-
if (!
|
|
2796
|
-
const entries =
|
|
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 =
|
|
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 =
|
|
3050
|
+
const stats = fs8.lstatSync(linkPath);
|
|
2816
3051
|
const isSymlink = stats.isSymbolicLink();
|
|
2817
|
-
const baseName =
|
|
3052
|
+
const baseName = path9.basename(linkPath);
|
|
2818
3053
|
let isDirectory = stats.isDirectory();
|
|
2819
3054
|
if (isSymlink) {
|
|
2820
3055
|
try {
|
|
2821
|
-
const realStats =
|
|
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 =
|
|
2832
|
-
const resolvedTarget =
|
|
2833
|
-
isValid =
|
|
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 =
|
|
2862
|
-
if (!
|
|
2863
|
-
|
|
3096
|
+
const targetDir = path9.dirname(mapping.targetPath);
|
|
3097
|
+
if (!fs8.existsSync(targetDir)) {
|
|
3098
|
+
fs8.mkdirSync(targetDir, { recursive: true });
|
|
2864
3099
|
}
|
|
2865
|
-
if (
|
|
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 =
|
|
2880
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
3166
|
+
const stats = fs8.lstatSync(linkPath);
|
|
2932
3167
|
if (stats.isSymbolicLink() || stats.isFile()) {
|
|
2933
|
-
|
|
3168
|
+
fs8.unlinkSync(linkPath);
|
|
2934
3169
|
} else if (stats.isDirectory()) {
|
|
2935
|
-
|
|
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
|
-
|
|
2943
|
-
const entries =
|
|
3177
|
+
fs8.mkdirSync(target, { recursive: true });
|
|
3178
|
+
const entries = fs8.readdirSync(source, { withFileTypes: true });
|
|
2944
3179
|
for (const entry of entries) {
|
|
2945
|
-
const sourcePath =
|
|
2946
|
-
const targetPath =
|
|
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
|
-
|
|
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 =
|
|
2980
|
-
if (!resolvedTarget.includes(
|
|
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 ??
|
|
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:
|
|
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 (
|
|
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:")} ${
|
|
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 =
|
|
3453
|
-
if (!
|
|
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 =
|
|
3465
|
-
if (!
|
|
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 =
|
|
3704
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
3469
3705
|
const metadata = parseMetadata(content);
|
|
3470
|
-
const name = metadata["name"] ??
|
|
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 (
|
|
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 =
|
|
3496
|
-
if (
|
|
3497
|
-
const assetFiles =
|
|
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 =
|
|
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:")} ${
|
|
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 (
|
|
3752
|
+
if (fs9.existsSync(path11.join(dirPath, fileName))) {
|
|
3517
3753
|
return { type, fileName };
|
|
3518
3754
|
}
|
|
3519
3755
|
}
|
|
3520
|
-
if (!
|
|
3521
|
-
const files =
|
|
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 =
|
|
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
|
|
3809
|
+
return path11.join(synapSyncDir, `${type}s`, category, name);
|
|
3574
3810
|
}
|
|
3575
3811
|
function saveCognitive(targetDir, manifest, content, assets) {
|
|
3576
|
-
|
|
3577
|
-
const mainFilePath =
|
|
3578
|
-
|
|
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 =
|
|
3581
|
-
const assetDir =
|
|
3582
|
-
|
|
3583
|
-
|
|
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 =
|
|
3824
|
+
const manifestPath = path11.join(synapSyncDir, "manifest.json");
|
|
3589
3825
|
let projectManifest;
|
|
3590
|
-
if (
|
|
3591
|
-
const content =
|
|
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
|
-
|
|
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
|
|
3626
|
-
import * as
|
|
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 =
|
|
3747
|
-
if (!
|
|
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 =
|
|
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
|
|
3866
|
-
import * as
|
|
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 (
|
|
3897
|
-
|
|
3898
|
-
logger.log(` ${pc11.dim("Removed files from")} ${
|
|
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 =
|
|
3920
|
-
if (!
|
|
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 =
|
|
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 =
|
|
3943
|
-
|
|
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
|
|
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
|
|
4232
|
-
import * as
|
|
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 =
|
|
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 =
|
|
4419
|
-
if (!
|
|
4420
|
-
|
|
4660
|
+
const filePath = path14.join(targetDir, fileName);
|
|
4661
|
+
if (!fs12.existsSync(targetDir)) {
|
|
4662
|
+
fs12.mkdirSync(targetDir, { recursive: true });
|
|
4421
4663
|
}
|
|
4422
|
-
|
|
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
|
|
4486
|
-
import * as
|
|
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 (
|
|
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 =
|
|
4602
|
-
if (
|
|
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 =
|
|
4633
|
-
if (!
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
4864
|
-
|
|
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 =
|
|
4868
|
-
if (!
|
|
4869
|
-
|
|
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
|
|
5046
|
-
import * as
|
|
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 =
|
|
5107
|
-
if (!
|
|
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
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
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 (
|
|
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 =
|
|
5206
|
-
const ext =
|
|
5207
|
-
if (
|
|
5448
|
+
const dir = path16.dirname(pattern);
|
|
5449
|
+
const ext = path16.extname(pattern);
|
|
5450
|
+
if (fs14.existsSync(dir)) {
|
|
5208
5451
|
try {
|
|
5209
|
-
const entries =
|
|
5452
|
+
const entries = fs14.readdirSync(dir);
|
|
5210
5453
|
for (const entry of entries) {
|
|
5211
5454
|
if (entry.endsWith(ext.slice(1))) {
|
|
5212
|
-
const fullPath =
|
|
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 =
|
|
5491
|
+
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
5249
5492
|
for (const entry of entries) {
|
|
5250
|
-
const fullPath =
|
|
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 =
|
|
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 =
|
|
5512
|
+
const entries = fs14.readdirSync(itemPath, { withFileTypes: true });
|
|
5270
5513
|
for (const entry of entries) {
|
|
5271
|
-
size += this.getSize(
|
|
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 =
|
|
5527
|
+
const stats = fs14.lstatSync(itemPath);
|
|
5285
5528
|
if (stats.isSymbolicLink() || stats.isFile()) {
|
|
5286
|
-
|
|
5529
|
+
fs14.unlinkSync(itemPath);
|
|
5287
5530
|
} else if (stats.isDirectory()) {
|
|
5288
|
-
|
|
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
|
|
5422
|
-
import * as
|
|
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 (
|
|
5449
|
-
|
|
5450
|
-
logger.log(` ${pc16.red("\u2717")} Removed ${
|
|
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 =
|
|
5454
|
-
if (
|
|
5455
|
-
|
|
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(`${
|
|
5732
|
+
items.push(`${path17.relative(projectRoot, link)} (symlink)`);
|
|
5484
5733
|
}
|
|
5485
|
-
if (
|
|
5486
|
-
items.push(
|
|
5734
|
+
if (fs15.existsSync(synapSyncDir)) {
|
|
5735
|
+
items.push(path17.relative(projectRoot, synapSyncDir) + "/");
|
|
5487
5736
|
}
|
|
5488
|
-
const configPath =
|
|
5489
|
-
if (
|
|
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
|
|
5493
|
-
if (
|
|
5494
|
-
|
|
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 =
|
|
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 =
|
|
5508
|
-
if (!
|
|
5760
|
+
const typePath = path17.join(projectRoot, providerPaths[type]);
|
|
5761
|
+
if (!fs15.existsSync(typePath)) continue;
|
|
5509
5762
|
try {
|
|
5510
|
-
const entries =
|
|
5763
|
+
const entries = fs15.readdirSync(typePath, { withFileTypes: true });
|
|
5511
5764
|
for (const entry of entries) {
|
|
5512
|
-
const fullPath =
|
|
5765
|
+
const fullPath = path17.join(typePath, entry.name);
|
|
5513
5766
|
if (entry.isSymbolicLink()) {
|
|
5514
|
-
const target =
|
|
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
|
-
|
|
5530
|
-
logger.log(` ${pc16.red("\u2717")} Removed symlink ${
|
|
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 =
|
|
5536
|
-
if (!
|
|
5537
|
-
const content =
|
|
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
|
-
|
|
5794
|
+
fs15.unlinkSync(gitignorePath);
|
|
5542
5795
|
} else {
|
|
5543
|
-
|
|
5796
|
+
fs15.writeFileSync(gitignorePath, cleaned, "utf-8");
|
|
5544
5797
|
}
|
|
5545
5798
|
return true;
|
|
5546
5799
|
}
|