gnosys 4.1.3 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@
6
6
  import { Command } from "commander";
7
7
  import path from "path";
8
8
  import fs from "fs/promises";
9
+ import os from "os";
9
10
  import { fileURLToPath } from "url";
10
11
  import dotenv from "dotenv";
11
12
  import { readFileSync, existsSync, copyFileSync } from "fs";
@@ -91,7 +92,25 @@ function outputResult(json, data, humanFn) {
91
92
  program
92
93
  .name("gnosys")
93
94
  .description("Gnosys — Persistent memory for AI agents. Sandbox-first runtime, central SQLite brain, federated search, reflection API, process tracing, preferences, Dream Mode, Obsidian export. Also runs as a full MCP server.")
94
- .version(pkg.version);
95
+ .version(pkg.version)
96
+ .hook("preAction", async () => {
97
+ // Check if central DB was upgraded to a newer version on another machine
98
+ try {
99
+ const centralDb = GnosysDB.openCentral();
100
+ if (centralDb.isAvailable()) {
101
+ const dbVersion = centralDb.getMeta("app_version");
102
+ if (dbVersion && dbVersion !== pkg.version) {
103
+ const upgradedBy = centralDb.getMeta("upgraded_by") || "another machine";
104
+ console.error(`\n⚠ Gnosys DB was upgraded to v${dbVersion} by ${upgradedBy}.` +
105
+ `\n You are running v${pkg.version}. Run: npm install -g gnosys && gnosys upgrade\n`);
106
+ }
107
+ centralDb.close();
108
+ }
109
+ }
110
+ catch {
111
+ // non-critical — don't block the command
112
+ }
113
+ });
95
114
  // ─── gnosys read <path> ──────────────────────────────────────────────────
96
115
  program
97
116
  .command("read <memoryPath>")
@@ -444,6 +463,9 @@ program
444
463
  projectName: opts.name,
445
464
  centralDb: centralDb || undefined,
446
465
  });
466
+ // Register in file-based project registry so resolver can find it
467
+ const tempResolver = new GnosysResolver();
468
+ await tempResolver.registerProject(targetDir);
447
469
  if (centralDb)
448
470
  centralDb.close();
449
471
  const action = isResync ? "re-synced" : "initialized";
@@ -1887,6 +1909,167 @@ program
1887
1909
  }
1888
1910
  });
1889
1911
  // NOTE: gnosys migrate is defined below (near the end) with --to-central support
1912
+ // ─── gnosys upgrade ─────────────────────────────────────────────────────
1913
+ program
1914
+ .command("upgrade")
1915
+ .description("Re-initialize all registered projects after a Gnosys version upgrade. Updates agent rules, project registry, and stamps the central DB with the current version.")
1916
+ .action(async () => {
1917
+ const currentVersion = pkg.version;
1918
+ console.log(`Gnosys v${currentVersion} — upgrading registered projects...\n`);
1919
+ // 1. Read registered projects
1920
+ const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
1921
+ const registryPath = path.join(home, ".config", "gnosys", "projects.json");
1922
+ let projects = [];
1923
+ try {
1924
+ projects = JSON.parse(await fs.readFile(registryPath, "utf-8"));
1925
+ }
1926
+ catch {
1927
+ console.log("No registered projects found. Run 'gnosys init' in each project first.");
1928
+ return;
1929
+ }
1930
+ // 2. Iterate and upgrade each project that exists on this machine
1931
+ const upgraded = [];
1932
+ const skipped = [];
1933
+ const failed = [];
1934
+ for (const projectDir of projects) {
1935
+ const storePath = path.join(projectDir, ".gnosys");
1936
+ try {
1937
+ await fs.stat(storePath);
1938
+ }
1939
+ catch {
1940
+ skipped.push(projectDir);
1941
+ continue;
1942
+ }
1943
+ try {
1944
+ // Re-create project identity (re-syncs with central DB)
1945
+ let centralDb = null;
1946
+ try {
1947
+ centralDb = GnosysDB.openCentral();
1948
+ if (!centralDb.isAvailable())
1949
+ centralDb = null;
1950
+ }
1951
+ catch {
1952
+ centralDb = null;
1953
+ }
1954
+ await createProjectIdentity(projectDir, { centralDb: centralDb || undefined });
1955
+ // Re-register in file-based registry (idempotent)
1956
+ const tempResolver = new GnosysResolver();
1957
+ await tempResolver.registerProject(projectDir);
1958
+ // Re-generate agent rules for all detected IDEs
1959
+ if (centralDb) {
1960
+ const { syncToTarget } = await import("./lib/rulesGen.js");
1961
+ const { readProjectIdentity } = await import("./lib/projectIdentity.js");
1962
+ const identity = await readProjectIdentity(projectDir);
1963
+ const projectId = identity?.projectId || null;
1964
+ try {
1965
+ await syncToTarget(centralDb, projectDir, "all", projectId);
1966
+ }
1967
+ catch {
1968
+ // Some projects may not have IDE configs — that's ok
1969
+ }
1970
+ centralDb.close();
1971
+ }
1972
+ upgraded.push(projectDir);
1973
+ }
1974
+ catch (err) {
1975
+ failed.push(`${projectDir} (${err.message})`);
1976
+ }
1977
+ }
1978
+ // 3. Update global agent rules
1979
+ try {
1980
+ let centralDb = null;
1981
+ try {
1982
+ centralDb = GnosysDB.openCentral();
1983
+ if (!centralDb.isAvailable())
1984
+ centralDb = null;
1985
+ }
1986
+ catch {
1987
+ centralDb = null;
1988
+ }
1989
+ if (centralDb) {
1990
+ const { syncToTarget } = await import("./lib/rulesGen.js");
1991
+ await syncToTarget(centralDb, process.cwd(), "global", null);
1992
+ centralDb.close();
1993
+ console.log(` ✓ Global agent rules updated (~/.claude/CLAUDE.md)`);
1994
+ }
1995
+ }
1996
+ catch {
1997
+ console.log(` ⚠ Could not update global agent rules`);
1998
+ }
1999
+ // 4. Stamp the central DB with current version and machine info
2000
+ try {
2001
+ const centralDb = GnosysDB.openCentral();
2002
+ if (centralDb.isAvailable()) {
2003
+ const hostname = os.hostname();
2004
+ centralDb.setMeta("app_version", currentVersion);
2005
+ centralDb.setMeta("last_upgrade", new Date().toISOString());
2006
+ centralDb.setMeta("upgraded_by", hostname);
2007
+ // Track all machines that have accessed this DB
2008
+ let machines = {};
2009
+ try {
2010
+ const raw = centralDb.getMeta("machines");
2011
+ if (raw)
2012
+ machines = JSON.parse(raw);
2013
+ }
2014
+ catch { /* fresh start */ }
2015
+ machines[hostname] = { version: currentVersion, lastSeen: new Date().toISOString() };
2016
+ centralDb.setMeta("machines", JSON.stringify(machines));
2017
+ centralDb.close();
2018
+ }
2019
+ }
2020
+ catch {
2021
+ // non-critical
2022
+ }
2023
+ // 5. Report
2024
+ console.log("");
2025
+ if (upgraded.length > 0) {
2026
+ console.log(`Upgraded (${upgraded.length}):`);
2027
+ for (const p of upgraded)
2028
+ console.log(` ✓ ${path.basename(p)} — ${p}`);
2029
+ }
2030
+ if (skipped.length > 0) {
2031
+ console.log(`\nSkipped — not on this machine (${skipped.length}):`);
2032
+ for (const p of skipped)
2033
+ console.log(` ○ ${path.basename(p)} — ${p}`);
2034
+ }
2035
+ if (failed.length > 0) {
2036
+ console.log(`\nFailed (${failed.length}):`);
2037
+ for (const f of failed)
2038
+ console.log(` ✗ ${f}`);
2039
+ }
2040
+ console.log(`\nDone. Central DB stamped with v${currentVersion}.`);
2041
+ // Show machine status from shared DB
2042
+ try {
2043
+ const centralDb = GnosysDB.openCentral();
2044
+ if (centralDb.isAvailable()) {
2045
+ const raw = centralDb.getMeta("machines");
2046
+ if (raw) {
2047
+ const machines = JSON.parse(raw);
2048
+ const entries = Object.entries(machines);
2049
+ if (entries.length > 1) {
2050
+ console.log(`\nConnected machines:`);
2051
+ for (const [host, info] of entries) {
2052
+ const isCurrent = host === os.hostname();
2053
+ const status = info.version === currentVersion ? "✓" : `⚠ v${info.version}`;
2054
+ console.log(` ${status} ${host}${isCurrent ? " (this machine)" : ""} — last seen ${info.lastSeen.split("T")[0]}`);
2055
+ }
2056
+ const behind = entries.filter(([, info]) => info.version !== currentVersion);
2057
+ if (behind.length > 0) {
2058
+ console.log(`\n ${behind.length} machine(s) need upgrading. Run 'npm install -g gnosys && gnosys upgrade' on each.`);
2059
+ }
2060
+ }
2061
+ }
2062
+ centralDb.close();
2063
+ }
2064
+ }
2065
+ catch {
2066
+ // non-critical
2067
+ }
2068
+ if (skipped.length > 0) {
2069
+ console.log(`\nNote: ${skipped.length} project(s) not found on this machine.`);
2070
+ console.log(`If they exist on another machine, run 'gnosys upgrade' there too.`);
2071
+ }
2072
+ });
1890
2073
  // ─── gnosys doctor ──────────────────────────────────────────────────────
1891
2074
  program
1892
2075
  .command("doctor")