@shahmilsaari/memory-core 0.1.8 → 0.2.3
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/README.md +2 -2
- package/dist/cli.js +125 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ cd my-api
|
|
|
156
156
|
# 2. Initialize — answers a few questions, generates all config files
|
|
157
157
|
npx @shahmilsaari/memory-core init
|
|
158
158
|
|
|
159
|
-
# 3. Load
|
|
159
|
+
# 3. Load 281 predefined best-practice rules
|
|
160
160
|
npx @shahmilsaari/memory-core seed
|
|
161
161
|
|
|
162
162
|
# 4. Install the pre-commit hook (optional but recommended)
|
|
@@ -237,7 +237,7 @@ Uses AI search — finds related rules even if you don't use the exact words.
|
|
|
237
237
|
|
|
238
238
|
### `seed` — Load predefined rules
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
281 best-practice rules across all supported architectures, each with a plain-English reason explaining why the rule exists.
|
|
241
241
|
|
|
242
242
|
```bash
|
|
243
243
|
npx @shahmilsaari/memory-core seed # all architectures
|
package/dist/cli.js
CHANGED
|
@@ -530,9 +530,18 @@ import { join as join2 } from "path";
|
|
|
530
530
|
var localEnv = join2(process.cwd(), ".memory-core.env");
|
|
531
531
|
config({ path: existsSync2(localEnv) ? localEnv : join2(process.cwd(), ".env") });
|
|
532
532
|
var Config = {
|
|
533
|
-
databaseUrl
|
|
534
|
-
|
|
535
|
-
|
|
533
|
+
get databaseUrl() {
|
|
534
|
+
return process.env.DATABASE_URL ?? "";
|
|
535
|
+
},
|
|
536
|
+
get ollamaUrl() {
|
|
537
|
+
return process.env.OLLAMA_URL ?? "http://localhost:11434";
|
|
538
|
+
},
|
|
539
|
+
get ollamaModel() {
|
|
540
|
+
return process.env.OLLAMA_MODEL ?? "nomic-embed-text";
|
|
541
|
+
},
|
|
542
|
+
get chatModel() {
|
|
543
|
+
return process.env.OLLAMA_CHAT_MODEL ?? "llama3.2";
|
|
544
|
+
}
|
|
536
545
|
};
|
|
537
546
|
|
|
538
547
|
// src/embedding.ts
|
|
@@ -1157,7 +1166,9 @@ function startWatch(options = {}) {
|
|
|
1157
1166
|
}
|
|
1158
1167
|
|
|
1159
1168
|
// src/cli.ts
|
|
1160
|
-
function printBanner(projectName, agentCount) {
|
|
1169
|
+
function printBanner(projectName, agentCount, status) {
|
|
1170
|
+
const pg2 = status ? status.postgresOk ? chalk3.green(" \u2713 PostgreSQL ") + chalk3.bold("connected") : chalk3.red(" \u2717 PostgreSQL ") + chalk3.bold("not connected \u2014 check DATABASE_URL") : chalk3.green(" \u2713 Memory ") + chalk3.bold("PostgreSQL + pgvector ready");
|
|
1171
|
+
const ol = status ? status.ollamaOk ? chalk3.green(" \u2713 Ollama ") + chalk3.bold(`connected (model: ${status.chatModel})`) : chalk3.red(" \u2717 Ollama ") + chalk3.bold("not running \u2014 start with: ollama serve") : null;
|
|
1161
1172
|
const lines = [
|
|
1162
1173
|
"",
|
|
1163
1174
|
chalk3.cyan(" \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 "),
|
|
@@ -1171,9 +1182,11 @@ function printBanner(projectName, agentCount) {
|
|
|
1171
1182
|
"",
|
|
1172
1183
|
chalk3.green(` \u2713 Project `) + chalk3.bold(projectName),
|
|
1173
1184
|
chalk3.green(` \u2713 Agents `) + chalk3.bold(`${agentCount} AI agents configured`),
|
|
1174
|
-
|
|
1185
|
+
pg2,
|
|
1186
|
+
...ol ? [ol] : [],
|
|
1175
1187
|
"",
|
|
1176
1188
|
chalk3.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1189
|
+
chalk3.dim(" Built by ") + chalk3.bold.white("Shahmil Saari"),
|
|
1177
1190
|
"",
|
|
1178
1191
|
chalk3.bold(" Every AI agent in this project now follows your rules."),
|
|
1179
1192
|
"",
|
|
@@ -1185,6 +1198,35 @@ function printBanner(projectName, agentCount) {
|
|
|
1185
1198
|
];
|
|
1186
1199
|
lines.forEach((l) => console.log(l));
|
|
1187
1200
|
}
|
|
1201
|
+
async function checkConnections(dbUrl, ollamaUrl, chatModel) {
|
|
1202
|
+
const spinner = ora("Checking connections\u2026").start();
|
|
1203
|
+
let postgresOk = false;
|
|
1204
|
+
let ollamaOk = false;
|
|
1205
|
+
try {
|
|
1206
|
+
const { Pool: Pool2 } = (await import("pg")).default;
|
|
1207
|
+
const testPool = new Pool2({ connectionString: dbUrl, connectionTimeoutMillis: 5e3 });
|
|
1208
|
+
await testPool.query("SELECT 1");
|
|
1209
|
+
await testPool.end();
|
|
1210
|
+
postgresOk = true;
|
|
1211
|
+
} catch {
|
|
1212
|
+
postgresOk = false;
|
|
1213
|
+
}
|
|
1214
|
+
try {
|
|
1215
|
+
const res = await fetch(`${ollamaUrl}/api/tags`, { signal: AbortSignal.timeout(5e3) });
|
|
1216
|
+
ollamaOk = res.ok;
|
|
1217
|
+
} catch {
|
|
1218
|
+
ollamaOk = false;
|
|
1219
|
+
}
|
|
1220
|
+
spinner.stop();
|
|
1221
|
+
console.log(
|
|
1222
|
+
postgresOk ? chalk3.green(" \u2713 PostgreSQL") + chalk3.dim(" \u2014 connected") : chalk3.red(" \u2717 PostgreSQL") + chalk3.dim(" \u2014 cannot connect. Check DATABASE_URL and that PostgreSQL is running.")
|
|
1223
|
+
);
|
|
1224
|
+
console.log(
|
|
1225
|
+
ollamaOk ? chalk3.green(" \u2713 Ollama ") + chalk3.dim(` \u2014 connected (${chatModel})`) : chalk3.red(" \u2717 Ollama ") + chalk3.dim(" \u2014 not reachable. Run: ollama serve")
|
|
1226
|
+
);
|
|
1227
|
+
console.log();
|
|
1228
|
+
return { postgresOk, ollamaOk, chatModel };
|
|
1229
|
+
}
|
|
1188
1230
|
var { version } = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf-8"));
|
|
1189
1231
|
var CONFIG_FILE = ".memory-core.json";
|
|
1190
1232
|
function readProjectConfig() {
|
|
@@ -1207,27 +1249,88 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1207
1249
|
const envPath = join6(process.cwd(), ".memory-core.env");
|
|
1208
1250
|
const hasEnv = existsSync6(envPath) || existsSync6(join6(process.cwd(), ".env")) || !!process.env.DATABASE_URL;
|
|
1209
1251
|
if (!hasEnv) {
|
|
1210
|
-
console.log(chalk3.dim(" No .memory-core.env found \u2014 let's set up your
|
|
1252
|
+
console.log(chalk3.dim(" No .memory-core.env found \u2014 let's set up your connection.\n"));
|
|
1211
1253
|
const dbUser = process.env.USER ?? process.env.USERNAME ?? "postgres";
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1254
|
+
let dbUrl = "";
|
|
1255
|
+
while (true) {
|
|
1256
|
+
dbUrl = await input({
|
|
1257
|
+
message: "PostgreSQL connection URL?",
|
|
1258
|
+
default: dbUrl || `postgresql://${dbUser}@localhost:5432/memory_core`
|
|
1259
|
+
});
|
|
1260
|
+
const pgSpinner = ora(" Testing PostgreSQL connection\u2026").start();
|
|
1261
|
+
try {
|
|
1262
|
+
const { Pool: Pool2 } = (await import("pg")).default;
|
|
1263
|
+
const testPool = new Pool2({ connectionString: dbUrl, connectionTimeoutMillis: 5e3 });
|
|
1264
|
+
await testPool.query("SELECT 1");
|
|
1265
|
+
await testPool.end();
|
|
1266
|
+
pgSpinner.succeed(chalk3.green("PostgreSQL connected"));
|
|
1267
|
+
break;
|
|
1268
|
+
} catch (err) {
|
|
1269
|
+
pgSpinner.fail(chalk3.red(`Cannot connect: ${err.message}`));
|
|
1270
|
+
console.log(chalk3.yellow(" Please check that PostgreSQL is running and the URL is correct.\n"));
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
let ollamaUrl = "";
|
|
1274
|
+
while (true) {
|
|
1275
|
+
ollamaUrl = await input({
|
|
1276
|
+
message: "Ollama URL?",
|
|
1277
|
+
default: ollamaUrl || "http://localhost:11434"
|
|
1278
|
+
});
|
|
1279
|
+
const ollamaSpinner = ora(" Testing Ollama connection\u2026").start();
|
|
1280
|
+
try {
|
|
1281
|
+
const res = await fetch(`${ollamaUrl}/api/tags`, { signal: AbortSignal.timeout(5e3) });
|
|
1282
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1283
|
+
ollamaSpinner.succeed(chalk3.green("Ollama connected"));
|
|
1284
|
+
break;
|
|
1285
|
+
} catch (err) {
|
|
1286
|
+
ollamaSpinner.fail(chalk3.red(`Cannot reach Ollama: ${err.message}`));
|
|
1287
|
+
console.log(chalk3.yellow(" Make sure Ollama is running: ollama serve\n"));
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
let chatModel = "";
|
|
1291
|
+
while (true) {
|
|
1292
|
+
const chatModelChoice = await select({
|
|
1293
|
+
message: "Which Ollama model for code checking?",
|
|
1294
|
+
choices: [
|
|
1295
|
+
{ name: "llama3.2 (fast, 2GB, recommended for most machines)", value: "llama3.2" },
|
|
1296
|
+
{ name: "qwen2.5-coder (better code understanding, 4.7GB)", value: "qwen2.5-coder" },
|
|
1297
|
+
{ name: "mistral (balanced, 4.1GB)", value: "mistral" },
|
|
1298
|
+
{ name: "codellama (code-focused, 3.8GB)", value: "codellama" },
|
|
1299
|
+
{ name: "Other (enter manually)", value: "__custom__" }
|
|
1300
|
+
]
|
|
1301
|
+
});
|
|
1302
|
+
chatModel = chatModelChoice === "__custom__" ? await input({ message: "Model name?", default: "llama3.2" }) : chatModelChoice;
|
|
1303
|
+
const modelSpinner = ora(` Checking if ${chatModel} is installed\u2026`).start();
|
|
1304
|
+
try {
|
|
1305
|
+
const res = await fetch(`${ollamaUrl}/api/tags`, { signal: AbortSignal.timeout(5e3) });
|
|
1306
|
+
const data = await res.json();
|
|
1307
|
+
const installed = (data.models ?? []).some(
|
|
1308
|
+
(m) => m.name === chatModel || m.name.startsWith(`${chatModel}:`)
|
|
1309
|
+
);
|
|
1310
|
+
if (installed) {
|
|
1311
|
+
modelSpinner.succeed(chalk3.green(`${chatModel} is installed and ready`));
|
|
1312
|
+
break;
|
|
1313
|
+
} else {
|
|
1314
|
+
modelSpinner.fail(chalk3.red(`${chatModel} is not installed in your Ollama`));
|
|
1315
|
+
console.log(chalk3.yellow(` Run: ollama pull ${chatModel} \u2014 or pick a different model.
|
|
1316
|
+
`));
|
|
1317
|
+
}
|
|
1318
|
+
} catch {
|
|
1319
|
+
modelSpinner.warn(chalk3.yellow("Could not verify model \u2014 continuing anyway"));
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1220
1323
|
const envContent = [
|
|
1221
1324
|
`DATABASE_URL=${dbUrl}`,
|
|
1222
1325
|
`OLLAMA_URL=${ollamaUrl}`,
|
|
1223
1326
|
`OLLAMA_MODEL=nomic-embed-text`,
|
|
1224
|
-
`OLLAMA_CHAT_MODEL
|
|
1327
|
+
`OLLAMA_CHAT_MODEL=${chatModel}`
|
|
1225
1328
|
].join("\n") + "\n";
|
|
1226
1329
|
writeFileSync3(envPath, envContent);
|
|
1227
1330
|
process.env.DATABASE_URL = dbUrl;
|
|
1228
1331
|
process.env.OLLAMA_URL = ollamaUrl;
|
|
1229
1332
|
process.env.OLLAMA_MODEL = "nomic-embed-text";
|
|
1230
|
-
process.env.OLLAMA_CHAT_MODEL =
|
|
1333
|
+
process.env.OLLAMA_CHAT_MODEL = chatModel;
|
|
1231
1334
|
const gitignorePath = join6(process.cwd(), ".gitignore");
|
|
1232
1335
|
if (existsSync6(gitignorePath)) {
|
|
1233
1336
|
const gi = readFileSync5(gitignorePath, "utf-8");
|
|
@@ -1335,7 +1438,12 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1335
1438
|
);
|
|
1336
1439
|
writeProjectConfig(config2);
|
|
1337
1440
|
spinner.succeed(`Generated ${written.length} files`);
|
|
1338
|
-
|
|
1441
|
+
const status = await checkConnections(
|
|
1442
|
+
process.env.DATABASE_URL ?? "",
|
|
1443
|
+
process.env.OLLAMA_URL ?? "http://localhost:11434",
|
|
1444
|
+
process.env.OLLAMA_CHAT_MODEL ?? "llama3.2"
|
|
1445
|
+
);
|
|
1446
|
+
printBanner(config2.projectName, written.length, status);
|
|
1339
1447
|
await closePool();
|
|
1340
1448
|
});
|
|
1341
1449
|
program.command("sync").description("Re-pull memories and regenerate all AI agent files").action(async () => {
|