gnosys 5.11.3 → 5.12.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 +332 -5151
- package/dist/index.js +364 -235
- package/dist/lib/addCommand.d.ts +9 -0
- package/dist/lib/addCommand.js +103 -0
- package/dist/lib/addStructuredCommand.d.ts +16 -0
- package/dist/lib/addStructuredCommand.js +103 -0
- package/dist/lib/ambiguityCommand.d.ts +4 -0
- package/dist/lib/ambiguityCommand.js +36 -0
- package/dist/lib/apiKeyVault.d.ts +78 -0
- package/dist/lib/apiKeyVault.js +447 -0
- package/dist/lib/askCommand.d.ts +13 -0
- package/dist/lib/askCommand.js +145 -0
- package/dist/lib/audioExtract.js +4 -1
- package/dist/lib/auditCommand.d.ts +7 -0
- package/dist/lib/auditCommand.js +27 -0
- package/dist/lib/backupCommand.d.ts +6 -0
- package/dist/lib/backupCommand.js +54 -0
- package/dist/lib/bootstrapCommand.d.ts +15 -0
- package/dist/lib/bootstrapCommand.js +51 -0
- package/dist/lib/briefingCommand.d.ts +7 -0
- package/dist/lib/briefingCommand.js +92 -0
- package/dist/lib/centralizeCommand.d.ts +5 -0
- package/dist/lib/centralizeCommand.js +16 -0
- package/dist/lib/chatCommand.d.ts +12 -0
- package/dist/lib/chatCommand.js +46 -0
- package/dist/lib/checkCommand.d.ts +4 -0
- package/dist/lib/checkCommand.js +133 -0
- package/dist/lib/clientReadOverlay.d.ts +27 -0
- package/dist/lib/clientReadOverlay.js +73 -0
- package/dist/lib/clientReadResolve.d.ts +32 -0
- package/dist/lib/clientReadResolve.js +84 -0
- package/dist/lib/commitContextCommand.d.ts +9 -0
- package/dist/lib/commitContextCommand.js +142 -0
- package/dist/lib/config.d.ts +43 -3
- package/dist/lib/config.js +58 -57
- package/dist/lib/configCommand.d.ts +10 -0
- package/dist/lib/configCommand.js +321 -0
- package/dist/lib/connectCommand.d.ts +8 -0
- package/dist/lib/connectCommand.js +19 -0
- package/dist/lib/db.d.ts +52 -0
- package/dist/lib/db.js +169 -1
- package/dist/lib/dearchiveCommand.d.ts +7 -0
- package/dist/lib/dearchiveCommand.js +41 -0
- package/dist/lib/discoverCommand.d.ts +9 -0
- package/dist/lib/discoverCommand.js +87 -0
- package/dist/lib/doctorCommand.d.ts +6 -0
- package/dist/lib/doctorCommand.js +256 -0
- package/dist/lib/dream.d.ts +42 -2
- package/dist/lib/dream.js +290 -30
- package/dist/lib/dreamCommand.d.ts +10 -0
- package/dist/lib/dreamCommand.js +195 -0
- package/dist/lib/dreamLaunchd.d.ts +2 -0
- package/dist/lib/dreamLaunchd.js +72 -0
- package/dist/lib/dreamLogCommand.d.ts +10 -0
- package/dist/lib/dreamLogCommand.js +58 -0
- package/dist/lib/dreamReport.d.ts +7 -0
- package/dist/lib/dreamReport.js +114 -0
- package/dist/lib/dreamRunLog.d.ts +121 -0
- package/dist/lib/dreamRunLog.js +212 -0
- package/dist/lib/embeddings.js +3 -0
- package/dist/lib/exportCommand.d.ts +18 -0
- package/dist/lib/exportCommand.js +101 -0
- package/dist/lib/fsearchCommand.d.ts +8 -0
- package/dist/lib/fsearchCommand.js +44 -0
- package/dist/lib/graphCommand.d.ts +4 -0
- package/dist/lib/graphCommand.js +68 -0
- package/dist/lib/helperGenerateCommand.d.ts +5 -0
- package/dist/lib/helperGenerateCommand.js +27 -0
- package/dist/lib/historyCommand.d.ts +5 -0
- package/dist/lib/historyCommand.js +51 -0
- package/dist/lib/hybridSearchCommand.d.ts +12 -0
- package/dist/lib/hybridSearchCommand.js +95 -0
- package/dist/lib/ideMcpInstall.d.ts +30 -0
- package/dist/lib/ideMcpInstall.js +102 -0
- package/dist/lib/importCommand.d.ts +16 -0
- package/dist/lib/importCommand.js +89 -0
- package/dist/lib/importProjectCommand.d.ts +6 -0
- package/dist/lib/importProjectCommand.js +43 -0
- package/dist/lib/ingestCommand.d.ts +13 -0
- package/dist/lib/ingestCommand.js +95 -0
- package/dist/lib/installOutput.d.ts +36 -0
- package/dist/lib/installOutput.js +55 -0
- package/dist/lib/lensCommand.d.ts +20 -0
- package/dist/lib/lensCommand.js +61 -0
- package/dist/lib/lensing.d.ts +1 -0
- package/dist/lib/lensing.js +50 -9
- package/dist/lib/linksCommand.d.ts +7 -0
- package/dist/lib/linksCommand.js +48 -0
- package/dist/lib/listCommand.d.ts +8 -0
- package/dist/lib/listCommand.js +74 -0
- package/dist/lib/llm.d.ts +1 -1
- package/dist/lib/llm.js +26 -8
- package/dist/lib/localDiskCheck.d.ts +17 -0
- package/dist/lib/localDiskCheck.js +54 -0
- package/dist/lib/machineConfig.d.ts +11 -1
- package/dist/lib/machineConfig.js +16 -0
- package/dist/lib/machineRegistry.d.ts +61 -0
- package/dist/lib/machineRegistry.js +80 -0
- package/dist/lib/maintainCommand.d.ts +8 -0
- package/dist/lib/maintainCommand.js +34 -0
- package/dist/lib/masterLease.d.ts +20 -0
- package/dist/lib/masterLease.js +68 -0
- package/dist/lib/migrateCommand.d.ts +7 -0
- package/dist/lib/migrateCommand.js +158 -0
- package/dist/lib/migrateDbCommand.d.ts +9 -0
- package/dist/lib/migrateDbCommand.js +94 -0
- package/dist/lib/modelValidation.d.ts +5 -0
- package/dist/lib/modelValidation.js +27 -0
- package/dist/lib/openrouterTiers.d.ts +29 -0
- package/dist/lib/openrouterTiers.js +113 -0
- package/dist/lib/prefCommand.d.ts +10 -0
- package/dist/lib/prefCommand.js +118 -0
- package/dist/lib/projectsCommand.d.ts +8 -0
- package/dist/lib/projectsCommand.js +131 -0
- package/dist/lib/readCommand.d.ts +7 -0
- package/dist/lib/readCommand.js +62 -0
- package/dist/lib/recall.d.ts +3 -0
- package/dist/lib/recall.js +19 -4
- package/dist/lib/recallCommand.d.ts +11 -0
- package/dist/lib/recallCommand.js +112 -0
- package/dist/lib/reflectCommand.d.ts +8 -0
- package/dist/lib/reflectCommand.js +61 -0
- package/dist/lib/reindexCommand.d.ts +4 -0
- package/dist/lib/reindexCommand.js +34 -0
- package/dist/lib/reindexGraphCommand.d.ts +4 -0
- package/dist/lib/reindexGraphCommand.js +12 -0
- package/dist/lib/reinforceCommand.d.ts +8 -0
- package/dist/lib/reinforceCommand.js +40 -0
- package/dist/lib/remote.d.ts +5 -1
- package/dist/lib/remote.js +5 -1
- package/dist/lib/remoteWizard.d.ts +24 -5
- package/dist/lib/remoteWizard.js +308 -319
- package/dist/lib/restoreCommand.d.ts +5 -0
- package/dist/lib/restoreCommand.js +35 -0
- package/dist/lib/sandboxStartCommand.d.ts +6 -0
- package/dist/lib/sandboxStartCommand.js +25 -0
- package/dist/lib/sandboxStatusCommand.d.ts +4 -0
- package/dist/lib/sandboxStatusCommand.js +24 -0
- package/dist/lib/sandboxStopCommand.d.ts +4 -0
- package/dist/lib/sandboxStopCommand.js +21 -0
- package/dist/lib/searchCommand.d.ts +9 -0
- package/dist/lib/searchCommand.js +90 -0
- package/dist/lib/semanticSearchCommand.d.ts +8 -0
- package/dist/lib/semanticSearchCommand.js +52 -0
- package/dist/lib/setup/configSetRender.js +2 -0
- package/dist/lib/setup/providerGlyphs.d.ts +19 -0
- package/dist/lib/setup/providerGlyphs.js +42 -0
- package/dist/lib/setup/remoteRender.d.ts +31 -1
- package/dist/lib/setup/remoteRender.js +95 -4
- package/dist/lib/setup/sections/ides.d.ts +7 -0
- package/dist/lib/setup/sections/ides.js +24 -2
- package/dist/lib/setup/sections/providers.d.ts +17 -0
- package/dist/lib/setup/sections/providers.js +255 -0
- package/dist/lib/setup/sections/routing.d.ts +2 -6
- package/dist/lib/setup/sections/routing.js +33 -85
- package/dist/lib/setup/sections/taskRoutingEditor.d.ts +17 -0
- package/dist/lib/setup/sections/taskRoutingEditor.js +149 -0
- package/dist/lib/setup/summary.d.ts +9 -0
- package/dist/lib/setup/summary.js +51 -37
- package/dist/lib/setup/ui/status.d.ts +1 -0
- package/dist/lib/setup/ui/status.js +2 -0
- package/dist/lib/setup.d.ts +108 -3
- package/dist/lib/setup.js +813 -303
- package/dist/lib/setupKeys.d.ts +42 -0
- package/dist/lib/setupKeys.js +564 -0
- package/dist/lib/setupRemoteCommand.d.ts +4 -0
- package/dist/lib/setupRemoteCommand.js +28 -0
- package/dist/lib/setupRemotePullCommand.d.ts +5 -0
- package/dist/lib/setupRemotePullCommand.js +52 -0
- package/dist/lib/setupRemotePushCommand.d.ts +5 -0
- package/dist/lib/setupRemotePushCommand.js +57 -0
- package/dist/lib/setupRemoteResolveCommand.d.ts +4 -0
- package/dist/lib/setupRemoteResolveCommand.js +48 -0
- package/dist/lib/setupRemoteStatusCommand.d.ts +4 -0
- package/dist/lib/setupRemoteStatusCommand.js +73 -0
- package/dist/lib/setupRemoteSyncCommand.d.ts +6 -0
- package/dist/lib/setupRemoteSyncCommand.js +65 -0
- package/dist/lib/setupSyncProjectsCommand.d.ts +4 -0
- package/dist/lib/setupSyncProjectsCommand.js +292 -0
- package/dist/lib/staleCommand.d.ts +8 -0
- package/dist/lib/staleCommand.js +34 -0
- package/dist/lib/statsCommand.d.ts +6 -0
- package/dist/lib/statsCommand.js +142 -0
- package/dist/lib/statusCommand.d.ts +18 -0
- package/dist/lib/statusCommand.js +250 -0
- package/dist/lib/storesCommand.d.ts +2 -0
- package/dist/lib/storesCommand.js +4 -0
- package/dist/lib/syncClient.d.ts +47 -0
- package/dist/lib/syncClient.js +212 -0
- package/dist/lib/syncCommand.d.ts +6 -0
- package/dist/lib/syncCommand.js +57 -0
- package/dist/lib/syncDoctorCommand.d.ts +5 -0
- package/dist/lib/syncDoctorCommand.js +100 -0
- package/dist/lib/syncIngest.d.ts +19 -0
- package/dist/lib/syncIngest.js +152 -0
- package/dist/lib/syncIngestLaunchd.d.ts +8 -0
- package/dist/lib/syncIngestLaunchd.js +93 -0
- package/dist/lib/syncIngestStartup.d.ts +5 -0
- package/dist/lib/syncIngestStartup.js +29 -0
- package/dist/lib/syncIngestSystemd.d.ts +10 -0
- package/dist/lib/syncIngestSystemd.js +97 -0
- package/dist/lib/syncIngestTimer.d.ts +8 -0
- package/dist/lib/syncIngestTimer.js +27 -0
- package/dist/lib/syncIngestTimerCommand.d.ts +7 -0
- package/dist/lib/syncIngestTimerCommand.js +83 -0
- package/dist/lib/syncLock.d.ts +6 -0
- package/dist/lib/syncLock.js +74 -0
- package/dist/lib/syncSnapshot.d.ts +30 -0
- package/dist/lib/syncSnapshot.js +184 -0
- package/dist/lib/syncStaging.d.ts +81 -0
- package/dist/lib/syncStaging.js +239 -0
- package/dist/lib/tagsAddCommand.d.ts +8 -0
- package/dist/lib/tagsAddCommand.js +18 -0
- package/dist/lib/tagsCommand.d.ts +4 -0
- package/dist/lib/tagsCommand.js +16 -0
- package/dist/lib/timelineCommand.d.ts +7 -0
- package/dist/lib/timelineCommand.js +49 -0
- package/dist/lib/traceCommand.d.ts +6 -0
- package/dist/lib/traceCommand.js +39 -0
- package/dist/lib/traverseCommand.d.ts +6 -0
- package/dist/lib/traverseCommand.js +58 -0
- package/dist/lib/updateCommand.d.ts +13 -0
- package/dist/lib/updateCommand.js +67 -0
- package/dist/lib/updateStatusCommand.d.ts +5 -0
- package/dist/lib/updateStatusCommand.js +38 -0
- package/dist/lib/webAddCommand.d.ts +8 -0
- package/dist/lib/webAddCommand.js +55 -0
- package/dist/lib/webBuildCommand.d.ts +10 -0
- package/dist/lib/webBuildCommand.js +65 -0
- package/dist/lib/webBuildIndexCommand.d.ts +8 -0
- package/dist/lib/webBuildIndexCommand.js +37 -0
- package/dist/lib/webIngestCommand.d.ts +11 -0
- package/dist/lib/webIngestCommand.js +51 -0
- package/dist/lib/webInitCommand.d.ts +9 -0
- package/dist/lib/webInitCommand.js +167 -0
- package/dist/lib/webRemoveCommand.d.ts +5 -0
- package/dist/lib/webRemoveCommand.js +41 -0
- package/dist/lib/webStatusCommand.d.ts +5 -0
- package/dist/lib/webStatusCommand.js +94 -0
- package/dist/lib/webUpdateCommand.d.ts +7 -0
- package/dist/lib/webUpdateCommand.js +72 -0
- package/dist/lib/workingSetCommand.d.ts +6 -0
- package/dist/lib/workingSetCommand.js +37 -0
- package/package.json +2 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { GnosysDB } from "./db.js";
|
|
2
|
+
export async function runSetupRemotePullCommand(opts) {
|
|
3
|
+
let centralDb = null;
|
|
4
|
+
try {
|
|
5
|
+
centralDb = GnosysDB.openLocal();
|
|
6
|
+
if (!centralDb.isAvailable()) {
|
|
7
|
+
console.error("Central DB not available.");
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const remotePath = centralDb.getMeta("remote_path");
|
|
12
|
+
if (!remotePath) {
|
|
13
|
+
console.error("Remote not configured.");
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const { RemoteSync: RemoteSyncCtor } = await import("./remote.js");
|
|
18
|
+
const { withHeartbeat } = await import("./heartbeat.js");
|
|
19
|
+
const { createProgress } = await import("./progress.js");
|
|
20
|
+
const progress = createProgress(!!opts.verbose);
|
|
21
|
+
let sync = null;
|
|
22
|
+
try {
|
|
23
|
+
sync = new RemoteSyncCtor(centralDb, remotePath);
|
|
24
|
+
const runPull = () => sync.pull({
|
|
25
|
+
strategy: opts.newerWins ? "newer-wins" : "skip-and-flag",
|
|
26
|
+
onProgress: progress.noop ? undefined : progress.emit.bind(progress),
|
|
27
|
+
});
|
|
28
|
+
const result = opts.verbose
|
|
29
|
+
? await runPull()
|
|
30
|
+
: await withHeartbeat("Pulling from remote", runPull);
|
|
31
|
+
const projParts = (result.projectsPulled || 0) > 0 ? ` | Projects pulled: ${result.projectsPulled}` : "";
|
|
32
|
+
const auditParts = (result.auditPulled || 0) > 0 ? ` | Audit pulled: ${result.auditPulled}` : "";
|
|
33
|
+
console.log(`Pulled: ${result.pulled} | Skipped: ${result.skipped} | Conflicts: ${result.conflicts.length}${projParts}${auditParts}`);
|
|
34
|
+
if (result.errors.length > 0) {
|
|
35
|
+
console.log("\nErrors:");
|
|
36
|
+
for (const e of result.errors)
|
|
37
|
+
console.log(` ${e}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
sync?.closeRemote();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
centralDb?.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { GnosysDB } from "./db.js";
|
|
2
|
+
export async function runSetupRemotePushCommand(opts) {
|
|
3
|
+
let centralDb = null;
|
|
4
|
+
try {
|
|
5
|
+
centralDb = GnosysDB.openLocal();
|
|
6
|
+
if (!centralDb.isAvailable()) {
|
|
7
|
+
console.error("Central DB not available.");
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const remotePath = centralDb.getMeta("remote_path");
|
|
12
|
+
if (!remotePath) {
|
|
13
|
+
console.error("Remote not configured.");
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const { RemoteSync: RemoteSyncCtor } = await import("./remote.js");
|
|
18
|
+
const { withHeartbeat } = await import("./heartbeat.js");
|
|
19
|
+
const { createProgress } = await import("./progress.js");
|
|
20
|
+
const progress = createProgress(!!opts.verbose);
|
|
21
|
+
let sync = null;
|
|
22
|
+
try {
|
|
23
|
+
sync = new RemoteSyncCtor(centralDb, remotePath);
|
|
24
|
+
const runPush = () => sync.push({
|
|
25
|
+
strategy: opts.newerWins ? "newer-wins" : "skip-and-flag",
|
|
26
|
+
onProgress: progress.noop ? undefined : progress.emit.bind(progress),
|
|
27
|
+
});
|
|
28
|
+
const result = opts.verbose
|
|
29
|
+
? await runPush()
|
|
30
|
+
: await withHeartbeat("Pushing to remote", runPush);
|
|
31
|
+
const projParts = (result.projectsPushed || 0) > 0 ? ` | Projects pushed: ${result.projectsPushed}` : "";
|
|
32
|
+
const auditParts = (result.auditPushed || 0) > 0 ? ` | Audit pushed: ${result.auditPushed}` : "";
|
|
33
|
+
console.log(`Pushed: ${result.pushed} | Skipped: ${result.skipped} | Conflicts: ${result.conflicts.length}${projParts}${auditParts}`);
|
|
34
|
+
if (result.errors.length > 0) {
|
|
35
|
+
console.log("\nErrors:");
|
|
36
|
+
for (const e of result.errors)
|
|
37
|
+
console.log(` ${e}`);
|
|
38
|
+
}
|
|
39
|
+
if (result.conflicts.length > 0) {
|
|
40
|
+
console.log("\nConflicts flagged (run 'gnosys setup remote status' for details):");
|
|
41
|
+
for (const c of result.conflicts)
|
|
42
|
+
console.log(` ${c.memoryId} — ${c.title}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
sync?.closeRemote();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
centralDb?.close();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { GnosysDB } from "./db.js";
|
|
2
|
+
export async function runSetupRemoteResolveCommand(memoryId, opts) {
|
|
3
|
+
if (opts.keep !== "local" && opts.keep !== "remote") {
|
|
4
|
+
console.error(`--keep must be 'local' or 'remote' (got: ${opts.keep})`);
|
|
5
|
+
process.exitCode = 1;
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
let centralDb = null;
|
|
9
|
+
try {
|
|
10
|
+
centralDb = GnosysDB.openLocal();
|
|
11
|
+
if (!centralDb.isAvailable()) {
|
|
12
|
+
console.error("Central DB not available.");
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const remotePath = centralDb.getMeta("remote_path");
|
|
17
|
+
if (!remotePath) {
|
|
18
|
+
console.error("Remote not configured.");
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const { RemoteSync: RemoteSyncCtor } = await import("./remote.js");
|
|
23
|
+
let sync = null;
|
|
24
|
+
try {
|
|
25
|
+
sync = new RemoteSyncCtor(centralDb, remotePath);
|
|
26
|
+
const result = await sync.resolve(memoryId, opts.keep);
|
|
27
|
+
if (result.ok) {
|
|
28
|
+
console.log(`Resolved ${memoryId}: kept ${opts.keep} version.`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.error(`Failed to resolve: ${result.error}`);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
sync?.closeRemote();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
centralDb?.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { GnosysDB } from "./db.js";
|
|
2
|
+
export async function runSetupRemoteStatusCommand(opts) {
|
|
3
|
+
let centralDb = null;
|
|
4
|
+
try {
|
|
5
|
+
centralDb = GnosysDB.openLocal();
|
|
6
|
+
if (!centralDb.isAvailable()) {
|
|
7
|
+
console.error("Central DB not available.");
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const { getConfiguredRemotePath } = await import("./remote.js");
|
|
12
|
+
const remotePath = getConfiguredRemotePath(centralDb);
|
|
13
|
+
if (!remotePath) {
|
|
14
|
+
if (opts.json) {
|
|
15
|
+
console.log(JSON.stringify({ configured: false, message: "Remote not configured. Run 'gnosys setup remote'." }, null, 2));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.log("Remote sync: not configured.");
|
|
19
|
+
console.log("Run 'gnosys setup remote' to set up multi-machine sync.");
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const mc = (await import("./machineConfig.js")).readMachineConfig();
|
|
24
|
+
if (mc?.remote.role) {
|
|
25
|
+
const { getV13SyncStatus } = await import("./syncClient.js");
|
|
26
|
+
const v13 = getV13SyncStatus(centralDb);
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
console.log(JSON.stringify(v13, null, 2));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(`Multi-machine sync (${v13.role}) — ${v13.masterPath}`);
|
|
32
|
+
for (const line of v13.lines)
|
|
33
|
+
console.log(line);
|
|
34
|
+
if (v13.snapshotAge)
|
|
35
|
+
console.log(`Snapshot as of ${v13.snapshotAge}`);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { RemoteSync: RemoteSyncCtor, formatStatus } = await import("./remote.js");
|
|
40
|
+
const { withHeartbeat } = await import("./heartbeat.js");
|
|
41
|
+
let sync = null;
|
|
42
|
+
try {
|
|
43
|
+
sync = new RemoteSyncCtor(centralDb, remotePath);
|
|
44
|
+
const status = await withHeartbeat("Checking remote sync status", () => sync.getStatus());
|
|
45
|
+
if (opts.json) {
|
|
46
|
+
console.log(JSON.stringify(status, null, 2));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log(formatStatus(status));
|
|
50
|
+
if (status.conflicts.length > 0) {
|
|
51
|
+
console.log("\nConflicts:");
|
|
52
|
+
for (const c of status.conflicts) {
|
|
53
|
+
console.log(` ${c.memoryId}: ${c.title}`);
|
|
54
|
+
console.log(` local: ${c.localModified}`);
|
|
55
|
+
console.log(` remote: ${c.remoteModified}`);
|
|
56
|
+
}
|
|
57
|
+
console.log("\nResolve with: gnosys setup remote resolve <memory-id> --keep <local|remote>");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
sync?.closeRemote();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
centralDb?.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { GnosysDB } from "./db.js";
|
|
2
|
+
export async function runSetupRemoteSyncCommand(opts) {
|
|
3
|
+
let centralDb = null;
|
|
4
|
+
try {
|
|
5
|
+
centralDb = GnosysDB.openLocal();
|
|
6
|
+
if (!centralDb.isAvailable()) {
|
|
7
|
+
if (!opts.auto)
|
|
8
|
+
console.error("Central DB not available.");
|
|
9
|
+
process.exitCode = 1;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const remotePath = centralDb.getMeta("remote_path");
|
|
13
|
+
if (!remotePath) {
|
|
14
|
+
if (!opts.auto)
|
|
15
|
+
console.error("Remote not configured.");
|
|
16
|
+
process.exitCode = opts.auto ? 0 : 1;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const { RemoteSync: RemoteSyncCtor } = await import("./remote.js");
|
|
20
|
+
const { withHeartbeat } = await import("./heartbeat.js");
|
|
21
|
+
const { createProgress } = await import("./progress.js");
|
|
22
|
+
const progress = createProgress(!!opts.verbose);
|
|
23
|
+
let sync = null;
|
|
24
|
+
try {
|
|
25
|
+
sync = new RemoteSyncCtor(centralDb, remotePath);
|
|
26
|
+
const runSync = () => sync.sync({
|
|
27
|
+
auto: opts.auto,
|
|
28
|
+
strategy: opts.newerWins ? "newer-wins" : "skip-and-flag",
|
|
29
|
+
onProgress: progress.noop ? undefined : progress.emit.bind(progress),
|
|
30
|
+
});
|
|
31
|
+
const result = opts.auto || opts.verbose
|
|
32
|
+
? await runSync()
|
|
33
|
+
: await withHeartbeat("Syncing with remote", runSync);
|
|
34
|
+
if (!opts.auto || result.conflicts.length > 0 || result.errors.length > 0) {
|
|
35
|
+
const pp = result.projectsPushed || 0;
|
|
36
|
+
const pl = result.projectsPulled || 0;
|
|
37
|
+
const ap = result.auditPushed || 0;
|
|
38
|
+
const al = result.auditPulled || 0;
|
|
39
|
+
const projParts = pp + pl > 0 ? ` | Projects: ↑${pp}/↓${pl}` : "";
|
|
40
|
+
const auditParts = ap + al > 0 ? ` | Audit: ↑${ap}/↓${al}` : "";
|
|
41
|
+
console.log(`Pushed: ${result.pushed} | Pulled: ${result.pulled} | Conflicts: ${result.conflicts.length}${projParts}${auditParts}`);
|
|
42
|
+
if (result.errors.length > 0) {
|
|
43
|
+
console.log("\nErrors:");
|
|
44
|
+
for (const e of result.errors)
|
|
45
|
+
console.log(` ${e}`);
|
|
46
|
+
}
|
|
47
|
+
if (result.conflicts.length > 0) {
|
|
48
|
+
console.log("\nConflicts need resolution (run 'gnosys setup remote status' for details).");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
sync?.closeRemote();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (!opts.auto)
|
|
58
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
centralDb?.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { GnosysDB } from "./db.js";
|
|
6
|
+
import { GnosysResolver } from "./resolver.js";
|
|
7
|
+
import { createProjectIdentity } from "./projectIdentity.js";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
async function packageVersion() {
|
|
11
|
+
const pkgPath = path.resolve(__dirname, "..", "..", "package.json");
|
|
12
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
|
|
13
|
+
return pkg.version;
|
|
14
|
+
}
|
|
15
|
+
export async function runSetupSyncProjectsCommand(opts) {
|
|
16
|
+
const currentVersion = await packageVersion();
|
|
17
|
+
// v5.9.3 Screen 10 — Header + leading spinner + hierarchical sections.
|
|
18
|
+
const { renderSyncHeader, renderUpgradedSection, renderSkippedSection, renderFailedSection, renderMachinesSection, renderDivider, renderDoneLine, renderDashboardSummary, } = await import("./setup/syncProjectsRender.js");
|
|
19
|
+
const { Spinner } = await import("./setup/ui/spinner.js");
|
|
20
|
+
console.log("");
|
|
21
|
+
console.log(renderSyncHeader(currentVersion));
|
|
22
|
+
console.log("");
|
|
23
|
+
// 1. Read registered projects from file registry AND central DB
|
|
24
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
25
|
+
const registryPath = path.join(home, ".config", "gnosys", "projects.json");
|
|
26
|
+
let fileProjects = [];
|
|
27
|
+
try {
|
|
28
|
+
fileProjects = JSON.parse(await fs.readFile(registryPath, "utf-8"));
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// No file registry yet
|
|
32
|
+
}
|
|
33
|
+
// Also check central DB for projects not in the file registry. Also
|
|
34
|
+
// capture project titles so the Screen 10 row labels can use the
|
|
35
|
+
// human-readable name where available.
|
|
36
|
+
let dbProjects = [];
|
|
37
|
+
const titleByDir = new Map();
|
|
38
|
+
try {
|
|
39
|
+
const centralDb = GnosysDB.openCentral();
|
|
40
|
+
if (centralDb.isAvailable()) {
|
|
41
|
+
const allProjects = centralDb.getAllProjects();
|
|
42
|
+
dbProjects = allProjects.map((p) => p.working_directory);
|
|
43
|
+
for (const p of allProjects)
|
|
44
|
+
titleByDir.set(p.working_directory, p.name);
|
|
45
|
+
centralDb.close();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// non-critical
|
|
50
|
+
}
|
|
51
|
+
// Merge: deduplicate by resolved path
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
const projects = [];
|
|
54
|
+
for (const p of [...fileProjects, ...dbProjects]) {
|
|
55
|
+
const resolved = path.resolve(p);
|
|
56
|
+
if (!seen.has(resolved)) {
|
|
57
|
+
seen.add(resolved);
|
|
58
|
+
projects.push(resolved);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (projects.length === 0) {
|
|
62
|
+
console.log(" no registered projects found");
|
|
63
|
+
console.log(" run `gnosys init` in each project first");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Lead-in spinner: shows we're churning through the registry. Resolves
|
|
67
|
+
// to ✓ summary after the iteration loop completes (or fail on hard error).
|
|
68
|
+
const syncSpinner = Spinner(`syncing ${projects.length} registered projects…`);
|
|
69
|
+
// Sync the merged list back to file registry
|
|
70
|
+
try {
|
|
71
|
+
await fs.mkdir(path.dirname(registryPath), { recursive: true });
|
|
72
|
+
await fs.writeFile(registryPath, JSON.stringify(projects, null, 2), "utf-8");
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// non-critical
|
|
76
|
+
}
|
|
77
|
+
// 2. Iterate and upgrade each project that exists on this machine
|
|
78
|
+
const upgraded = [];
|
|
79
|
+
const skipped = [];
|
|
80
|
+
const failed = [];
|
|
81
|
+
for (const projectDir of projects) {
|
|
82
|
+
// Skip test/temp directories
|
|
83
|
+
if (projectDir.startsWith("/tmp/") || projectDir.startsWith("/private/tmp/") || projectDir.startsWith("/var/folders/") || projectDir.startsWith("/private/var/folders/")) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const storePath = path.join(projectDir, ".gnosys");
|
|
87
|
+
try {
|
|
88
|
+
await fs.stat(storePath);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
skipped.push(projectDir);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
// Re-create project identity (re-syncs with central DB)
|
|
96
|
+
let centralDb = null;
|
|
97
|
+
try {
|
|
98
|
+
centralDb = GnosysDB.openCentral();
|
|
99
|
+
if (!centralDb.isAvailable())
|
|
100
|
+
centralDb = null;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
centralDb = null;
|
|
104
|
+
}
|
|
105
|
+
await createProjectIdentity(projectDir, { centralDb: centralDb || undefined });
|
|
106
|
+
// Re-register in file-based registry (idempotent)
|
|
107
|
+
const tempResolver = new GnosysResolver();
|
|
108
|
+
await tempResolver.registerProject(projectDir);
|
|
109
|
+
// Re-generate agent rules for all detected IDEs
|
|
110
|
+
if (centralDb) {
|
|
111
|
+
const { syncToTarget } = await import("./rulesGen.js");
|
|
112
|
+
const { readProjectIdentity } = await import("./projectIdentity.js");
|
|
113
|
+
const identity = await readProjectIdentity(projectDir);
|
|
114
|
+
const projectId = identity?.projectId || null;
|
|
115
|
+
try {
|
|
116
|
+
await syncToTarget(centralDb, projectDir, "all", projectId);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Some projects may not have IDE configs — that's ok
|
|
120
|
+
}
|
|
121
|
+
centralDb.close();
|
|
122
|
+
}
|
|
123
|
+
// Configure IDE hooks for automatic memory recall
|
|
124
|
+
const { configureIdeHooks } = await import("./projectIdentity.js");
|
|
125
|
+
await configureIdeHooks(projectDir);
|
|
126
|
+
upgraded.push(projectDir);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
failed.push(`${projectDir} (${err.message})`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Stop the lead-in spinner now that the iteration is done. Resolved
|
|
133
|
+
// before any per-section output so the cursor is on a fresh line.
|
|
134
|
+
syncSpinner.ok(`synced ${projects.length} registered projects`, `${upgraded.length} upgraded · ${skipped.length} skipped · ${failed.length} failed`);
|
|
135
|
+
// 3. Update global agent rules
|
|
136
|
+
try {
|
|
137
|
+
let centralDb = null;
|
|
138
|
+
try {
|
|
139
|
+
centralDb = GnosysDB.openCentral();
|
|
140
|
+
if (!centralDb.isAvailable())
|
|
141
|
+
centralDb = null;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
centralDb = null;
|
|
145
|
+
}
|
|
146
|
+
if (centralDb) {
|
|
147
|
+
const { syncToTarget } = await import("./rulesGen.js");
|
|
148
|
+
await syncToTarget(centralDb, process.cwd(), "global", null);
|
|
149
|
+
centralDb.close();
|
|
150
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
151
|
+
printStatus("ok", "global agent rules updated", "~/.claude/CLAUDE.md");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
156
|
+
printStatus("warn", "could not update global agent rules");
|
|
157
|
+
}
|
|
158
|
+
// 4. Stamp the central DB with current version and machine info
|
|
159
|
+
try {
|
|
160
|
+
const centralDb = GnosysDB.openCentral();
|
|
161
|
+
if (centralDb.isAvailable()) {
|
|
162
|
+
const hostname = os.hostname();
|
|
163
|
+
centralDb.setMeta("app_version", currentVersion);
|
|
164
|
+
centralDb.setMeta("last_upgrade", new Date().toISOString());
|
|
165
|
+
centralDb.setMeta("upgraded_by", hostname);
|
|
166
|
+
// Record this machine in the connected-machines registry. Keyed by
|
|
167
|
+
// hostname, but we pass machineId + any previous hostnames so a renamed
|
|
168
|
+
// machine prunes its own orphaned entry instead of showing up twice.
|
|
169
|
+
const { ensureMachineConfig } = await import("./machineConfig.js");
|
|
170
|
+
const { recordMachine } = await import("./machineRegistry.js");
|
|
171
|
+
const machine = ensureMachineConfig().config;
|
|
172
|
+
recordMachine(centralDb, {
|
|
173
|
+
hostname,
|
|
174
|
+
version: currentVersion,
|
|
175
|
+
machineId: machine.machineId,
|
|
176
|
+
aliases: machine.previousHostnames,
|
|
177
|
+
});
|
|
178
|
+
centralDb.close();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// non-critical
|
|
183
|
+
}
|
|
184
|
+
// 5. Report — v5.9.3 Screen 10 hierarchical layout. Section helpers
|
|
185
|
+
// turn the raw path arrays into ProjectRow lists (title + fullPath)
|
|
186
|
+
// and emit dividers between groups.
|
|
187
|
+
function rowFor(p) {
|
|
188
|
+
const title = titleByDir.get(p) ?? titleByDir.get(path.resolve(p)) ?? path.basename(p);
|
|
189
|
+
return { title, fullPath: p };
|
|
190
|
+
}
|
|
191
|
+
const upgradedRows = upgraded.map(rowFor);
|
|
192
|
+
const skippedRows = skipped.map(rowFor);
|
|
193
|
+
const failedRows = failed.map((f) => {
|
|
194
|
+
// failed entries are "<path> (<err>)" — extract path for the title.
|
|
195
|
+
const match = f.match(/^(.+?)\s\((.+)\)$/);
|
|
196
|
+
const projectPath = match ? match[1] : f;
|
|
197
|
+
return { title: titleByDir.get(projectPath) ?? path.basename(projectPath), fullPath: f };
|
|
198
|
+
});
|
|
199
|
+
console.log("");
|
|
200
|
+
for (const line of renderUpgradedSection(upgradedRows))
|
|
201
|
+
console.log(line);
|
|
202
|
+
if (upgradedRows.length > 0 && (skippedRows.length > 0 || failedRows.length > 0)) {
|
|
203
|
+
console.log("");
|
|
204
|
+
}
|
|
205
|
+
for (const line of renderSkippedSection(skippedRows))
|
|
206
|
+
console.log(line);
|
|
207
|
+
if (failedRows.length > 0) {
|
|
208
|
+
console.log("");
|
|
209
|
+
for (const line of renderFailedSection(failedRows))
|
|
210
|
+
console.log(line);
|
|
211
|
+
}
|
|
212
|
+
// Connected-machines callout (separate divider per design spec).
|
|
213
|
+
let machineLines = [];
|
|
214
|
+
try {
|
|
215
|
+
const centralDb = GnosysDB.openCentral();
|
|
216
|
+
if (centralDb.isAvailable()) {
|
|
217
|
+
const { readMachineRegistry } = await import("./machineRegistry.js");
|
|
218
|
+
const machines = readMachineRegistry(centralDb);
|
|
219
|
+
const entries = Object.entries(machines);
|
|
220
|
+
if (entries.length > 0) {
|
|
221
|
+
const currentHost = os.hostname();
|
|
222
|
+
const machineRows = entries.map(([host, info]) => ({
|
|
223
|
+
hostname: host,
|
|
224
|
+
version: info.version,
|
|
225
|
+
lastSeen: info.lastSeen,
|
|
226
|
+
isCurrent: host === currentHost,
|
|
227
|
+
}));
|
|
228
|
+
machineLines = renderMachinesSection(machineRows, currentVersion);
|
|
229
|
+
}
|
|
230
|
+
centralDb.close();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// non-critical
|
|
235
|
+
}
|
|
236
|
+
if (machineLines.length > 0) {
|
|
237
|
+
console.log("");
|
|
238
|
+
console.log(renderDivider());
|
|
239
|
+
console.log("");
|
|
240
|
+
for (const line of machineLines)
|
|
241
|
+
console.log(line);
|
|
242
|
+
}
|
|
243
|
+
console.log("");
|
|
244
|
+
console.log(renderDivider());
|
|
245
|
+
console.log("");
|
|
246
|
+
console.log(renderDoneLine(currentVersion));
|
|
247
|
+
if (skippedRows.length > 0) {
|
|
248
|
+
// v5.9.3 Phase H: offer one-keystroke cleanup. Stays interactive
|
|
249
|
+
// by default; users on a TTY get the prompt, non-TTY runs silently
|
|
250
|
+
// (sync-projects is sometimes invoked from CI).
|
|
251
|
+
console.log("");
|
|
252
|
+
if (process.stdout.isTTY) {
|
|
253
|
+
try {
|
|
254
|
+
const { cleanupRegistry } = await import("./cleanup.js");
|
|
255
|
+
await cleanupRegistry({ interactive: true });
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
259
|
+
printStatus("warn", "cleanup skipped", err instanceof Error ? err.message : String(err));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
264
|
+
printStatus("progress", "tip", "run `gnosys cleanup` to remove stale entries");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// 6. Regenerate portfolio dashboard
|
|
268
|
+
if (!opts.skipDashboard) {
|
|
269
|
+
try {
|
|
270
|
+
const dashboardPath = path.join(home, "gnosys-dashboard.html");
|
|
271
|
+
const dashboardMdPath = path.join(home, "gnosys-dashboard.md");
|
|
272
|
+
const centralDb = GnosysDB.openCentral();
|
|
273
|
+
if (centralDb.isAvailable()) {
|
|
274
|
+
const { generatePortfolio, formatPortfolioMarkdown } = await import("./portfolio.js");
|
|
275
|
+
const { generatePortfolioHtml } = await import("./portfolioHtml.js");
|
|
276
|
+
const report = generatePortfolio(centralDb);
|
|
277
|
+
await fs.writeFile(dashboardPath, generatePortfolioHtml(report, dashboardPath), "utf-8");
|
|
278
|
+
await fs.writeFile(dashboardMdPath, formatPortfolioMarkdown(report), "utf-8");
|
|
279
|
+
centralDb.close();
|
|
280
|
+
console.log("");
|
|
281
|
+
for (const line of renderDashboardSummary(dashboardPath, dashboardMdPath)) {
|
|
282
|
+
console.log(line);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
288
|
+
console.log("");
|
|
289
|
+
printStatus("warn", "could not regenerate portfolio dashboard");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GnosysResolver } from "./resolver.js";
|
|
2
|
+
export type StaleCommandOptions = {
|
|
3
|
+
days: string;
|
|
4
|
+
limit: string;
|
|
5
|
+
};
|
|
6
|
+
type GetResolver = () => Promise<GnosysResolver>;
|
|
7
|
+
export declare function runStaleCommand(getResolver: GetResolver, opts: StaleCommandOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export async function runStaleCommand(getResolver, opts) {
|
|
2
|
+
const resolver = await getResolver();
|
|
3
|
+
const threshold = parseInt(opts.days);
|
|
4
|
+
const cutoff = new Date();
|
|
5
|
+
cutoff.setDate(cutoff.getDate() - threshold);
|
|
6
|
+
const cutoffStr = cutoff.toISOString().split("T")[0];
|
|
7
|
+
const allMemories = await resolver.getAllMemories();
|
|
8
|
+
const stale = allMemories
|
|
9
|
+
.filter((m) => {
|
|
10
|
+
const lastTouched = m.frontmatter.last_reviewed ||
|
|
11
|
+
m.frontmatter.modified;
|
|
12
|
+
return lastTouched && lastTouched < cutoffStr;
|
|
13
|
+
})
|
|
14
|
+
.sort((a, b) => {
|
|
15
|
+
const aDate = a.frontmatter.last_reviewed ||
|
|
16
|
+
a.frontmatter.modified;
|
|
17
|
+
const bDate = b.frontmatter.last_reviewed ||
|
|
18
|
+
b.frontmatter.modified;
|
|
19
|
+
return (aDate || "").localeCompare(bDate || "");
|
|
20
|
+
})
|
|
21
|
+
.slice(0, parseInt(opts.limit));
|
|
22
|
+
if (stale.length === 0) {
|
|
23
|
+
console.log(`No memories older than ${threshold} days.`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log(`${stale.length} memories not touched in ${threshold}+ days:\n`);
|
|
27
|
+
for (const m of stale) {
|
|
28
|
+
const lr = m.frontmatter.last_reviewed;
|
|
29
|
+
console.log(` ${m.frontmatter.title}`);
|
|
30
|
+
console.log(` ${m.sourceLabel}:${m.relativePath}`);
|
|
31
|
+
console.log(` Modified: ${m.frontmatter.modified}${lr ? `, Reviewed: ${lr}` : ""}`);
|
|
32
|
+
console.log();
|
|
33
|
+
}
|
|
34
|
+
}
|