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.
Files changed (244) hide show
  1. package/dist/cli.js +332 -5151
  2. package/dist/index.js +364 -235
  3. package/dist/lib/addCommand.d.ts +9 -0
  4. package/dist/lib/addCommand.js +103 -0
  5. package/dist/lib/addStructuredCommand.d.ts +16 -0
  6. package/dist/lib/addStructuredCommand.js +103 -0
  7. package/dist/lib/ambiguityCommand.d.ts +4 -0
  8. package/dist/lib/ambiguityCommand.js +36 -0
  9. package/dist/lib/apiKeyVault.d.ts +78 -0
  10. package/dist/lib/apiKeyVault.js +447 -0
  11. package/dist/lib/askCommand.d.ts +13 -0
  12. package/dist/lib/askCommand.js +145 -0
  13. package/dist/lib/audioExtract.js +4 -1
  14. package/dist/lib/auditCommand.d.ts +7 -0
  15. package/dist/lib/auditCommand.js +27 -0
  16. package/dist/lib/backupCommand.d.ts +6 -0
  17. package/dist/lib/backupCommand.js +54 -0
  18. package/dist/lib/bootstrapCommand.d.ts +15 -0
  19. package/dist/lib/bootstrapCommand.js +51 -0
  20. package/dist/lib/briefingCommand.d.ts +7 -0
  21. package/dist/lib/briefingCommand.js +92 -0
  22. package/dist/lib/centralizeCommand.d.ts +5 -0
  23. package/dist/lib/centralizeCommand.js +16 -0
  24. package/dist/lib/chatCommand.d.ts +12 -0
  25. package/dist/lib/chatCommand.js +46 -0
  26. package/dist/lib/checkCommand.d.ts +4 -0
  27. package/dist/lib/checkCommand.js +133 -0
  28. package/dist/lib/clientReadOverlay.d.ts +27 -0
  29. package/dist/lib/clientReadOverlay.js +73 -0
  30. package/dist/lib/clientReadResolve.d.ts +32 -0
  31. package/dist/lib/clientReadResolve.js +84 -0
  32. package/dist/lib/commitContextCommand.d.ts +9 -0
  33. package/dist/lib/commitContextCommand.js +142 -0
  34. package/dist/lib/config.d.ts +43 -3
  35. package/dist/lib/config.js +58 -57
  36. package/dist/lib/configCommand.d.ts +10 -0
  37. package/dist/lib/configCommand.js +321 -0
  38. package/dist/lib/connectCommand.d.ts +8 -0
  39. package/dist/lib/connectCommand.js +19 -0
  40. package/dist/lib/db.d.ts +52 -0
  41. package/dist/lib/db.js +169 -1
  42. package/dist/lib/dearchiveCommand.d.ts +7 -0
  43. package/dist/lib/dearchiveCommand.js +41 -0
  44. package/dist/lib/discoverCommand.d.ts +9 -0
  45. package/dist/lib/discoverCommand.js +87 -0
  46. package/dist/lib/doctorCommand.d.ts +6 -0
  47. package/dist/lib/doctorCommand.js +256 -0
  48. package/dist/lib/dream.d.ts +42 -2
  49. package/dist/lib/dream.js +290 -30
  50. package/dist/lib/dreamCommand.d.ts +10 -0
  51. package/dist/lib/dreamCommand.js +195 -0
  52. package/dist/lib/dreamLaunchd.d.ts +2 -0
  53. package/dist/lib/dreamLaunchd.js +72 -0
  54. package/dist/lib/dreamLogCommand.d.ts +10 -0
  55. package/dist/lib/dreamLogCommand.js +58 -0
  56. package/dist/lib/dreamReport.d.ts +7 -0
  57. package/dist/lib/dreamReport.js +114 -0
  58. package/dist/lib/dreamRunLog.d.ts +121 -0
  59. package/dist/lib/dreamRunLog.js +212 -0
  60. package/dist/lib/embeddings.js +3 -0
  61. package/dist/lib/exportCommand.d.ts +18 -0
  62. package/dist/lib/exportCommand.js +101 -0
  63. package/dist/lib/fsearchCommand.d.ts +8 -0
  64. package/dist/lib/fsearchCommand.js +44 -0
  65. package/dist/lib/graphCommand.d.ts +4 -0
  66. package/dist/lib/graphCommand.js +68 -0
  67. package/dist/lib/helperGenerateCommand.d.ts +5 -0
  68. package/dist/lib/helperGenerateCommand.js +27 -0
  69. package/dist/lib/historyCommand.d.ts +5 -0
  70. package/dist/lib/historyCommand.js +51 -0
  71. package/dist/lib/hybridSearchCommand.d.ts +12 -0
  72. package/dist/lib/hybridSearchCommand.js +95 -0
  73. package/dist/lib/ideMcpInstall.d.ts +30 -0
  74. package/dist/lib/ideMcpInstall.js +102 -0
  75. package/dist/lib/importCommand.d.ts +16 -0
  76. package/dist/lib/importCommand.js +89 -0
  77. package/dist/lib/importProjectCommand.d.ts +6 -0
  78. package/dist/lib/importProjectCommand.js +43 -0
  79. package/dist/lib/ingestCommand.d.ts +13 -0
  80. package/dist/lib/ingestCommand.js +95 -0
  81. package/dist/lib/installOutput.d.ts +36 -0
  82. package/dist/lib/installOutput.js +55 -0
  83. package/dist/lib/lensCommand.d.ts +20 -0
  84. package/dist/lib/lensCommand.js +61 -0
  85. package/dist/lib/lensing.d.ts +1 -0
  86. package/dist/lib/lensing.js +50 -9
  87. package/dist/lib/linksCommand.d.ts +7 -0
  88. package/dist/lib/linksCommand.js +48 -0
  89. package/dist/lib/listCommand.d.ts +8 -0
  90. package/dist/lib/listCommand.js +74 -0
  91. package/dist/lib/llm.d.ts +1 -1
  92. package/dist/lib/llm.js +26 -8
  93. package/dist/lib/localDiskCheck.d.ts +17 -0
  94. package/dist/lib/localDiskCheck.js +54 -0
  95. package/dist/lib/machineConfig.d.ts +11 -1
  96. package/dist/lib/machineConfig.js +16 -0
  97. package/dist/lib/machineRegistry.d.ts +61 -0
  98. package/dist/lib/machineRegistry.js +80 -0
  99. package/dist/lib/maintainCommand.d.ts +8 -0
  100. package/dist/lib/maintainCommand.js +34 -0
  101. package/dist/lib/masterLease.d.ts +20 -0
  102. package/dist/lib/masterLease.js +68 -0
  103. package/dist/lib/migrateCommand.d.ts +7 -0
  104. package/dist/lib/migrateCommand.js +158 -0
  105. package/dist/lib/migrateDbCommand.d.ts +9 -0
  106. package/dist/lib/migrateDbCommand.js +94 -0
  107. package/dist/lib/modelValidation.d.ts +5 -0
  108. package/dist/lib/modelValidation.js +27 -0
  109. package/dist/lib/openrouterTiers.d.ts +29 -0
  110. package/dist/lib/openrouterTiers.js +113 -0
  111. package/dist/lib/prefCommand.d.ts +10 -0
  112. package/dist/lib/prefCommand.js +118 -0
  113. package/dist/lib/projectsCommand.d.ts +8 -0
  114. package/dist/lib/projectsCommand.js +131 -0
  115. package/dist/lib/readCommand.d.ts +7 -0
  116. package/dist/lib/readCommand.js +62 -0
  117. package/dist/lib/recall.d.ts +3 -0
  118. package/dist/lib/recall.js +19 -4
  119. package/dist/lib/recallCommand.d.ts +11 -0
  120. package/dist/lib/recallCommand.js +112 -0
  121. package/dist/lib/reflectCommand.d.ts +8 -0
  122. package/dist/lib/reflectCommand.js +61 -0
  123. package/dist/lib/reindexCommand.d.ts +4 -0
  124. package/dist/lib/reindexCommand.js +34 -0
  125. package/dist/lib/reindexGraphCommand.d.ts +4 -0
  126. package/dist/lib/reindexGraphCommand.js +12 -0
  127. package/dist/lib/reinforceCommand.d.ts +8 -0
  128. package/dist/lib/reinforceCommand.js +40 -0
  129. package/dist/lib/remote.d.ts +5 -1
  130. package/dist/lib/remote.js +5 -1
  131. package/dist/lib/remoteWizard.d.ts +24 -5
  132. package/dist/lib/remoteWizard.js +308 -319
  133. package/dist/lib/restoreCommand.d.ts +5 -0
  134. package/dist/lib/restoreCommand.js +35 -0
  135. package/dist/lib/sandboxStartCommand.d.ts +6 -0
  136. package/dist/lib/sandboxStartCommand.js +25 -0
  137. package/dist/lib/sandboxStatusCommand.d.ts +4 -0
  138. package/dist/lib/sandboxStatusCommand.js +24 -0
  139. package/dist/lib/sandboxStopCommand.d.ts +4 -0
  140. package/dist/lib/sandboxStopCommand.js +21 -0
  141. package/dist/lib/searchCommand.d.ts +9 -0
  142. package/dist/lib/searchCommand.js +90 -0
  143. package/dist/lib/semanticSearchCommand.d.ts +8 -0
  144. package/dist/lib/semanticSearchCommand.js +52 -0
  145. package/dist/lib/setup/configSetRender.js +2 -0
  146. package/dist/lib/setup/providerGlyphs.d.ts +19 -0
  147. package/dist/lib/setup/providerGlyphs.js +42 -0
  148. package/dist/lib/setup/remoteRender.d.ts +31 -1
  149. package/dist/lib/setup/remoteRender.js +95 -4
  150. package/dist/lib/setup/sections/ides.d.ts +7 -0
  151. package/dist/lib/setup/sections/ides.js +24 -2
  152. package/dist/lib/setup/sections/providers.d.ts +17 -0
  153. package/dist/lib/setup/sections/providers.js +255 -0
  154. package/dist/lib/setup/sections/routing.d.ts +2 -6
  155. package/dist/lib/setup/sections/routing.js +33 -85
  156. package/dist/lib/setup/sections/taskRoutingEditor.d.ts +17 -0
  157. package/dist/lib/setup/sections/taskRoutingEditor.js +149 -0
  158. package/dist/lib/setup/summary.d.ts +9 -0
  159. package/dist/lib/setup/summary.js +51 -37
  160. package/dist/lib/setup/ui/status.d.ts +1 -0
  161. package/dist/lib/setup/ui/status.js +2 -0
  162. package/dist/lib/setup.d.ts +108 -3
  163. package/dist/lib/setup.js +813 -303
  164. package/dist/lib/setupKeys.d.ts +42 -0
  165. package/dist/lib/setupKeys.js +564 -0
  166. package/dist/lib/setupRemoteCommand.d.ts +4 -0
  167. package/dist/lib/setupRemoteCommand.js +28 -0
  168. package/dist/lib/setupRemotePullCommand.d.ts +5 -0
  169. package/dist/lib/setupRemotePullCommand.js +52 -0
  170. package/dist/lib/setupRemotePushCommand.d.ts +5 -0
  171. package/dist/lib/setupRemotePushCommand.js +57 -0
  172. package/dist/lib/setupRemoteResolveCommand.d.ts +4 -0
  173. package/dist/lib/setupRemoteResolveCommand.js +48 -0
  174. package/dist/lib/setupRemoteStatusCommand.d.ts +4 -0
  175. package/dist/lib/setupRemoteStatusCommand.js +73 -0
  176. package/dist/lib/setupRemoteSyncCommand.d.ts +6 -0
  177. package/dist/lib/setupRemoteSyncCommand.js +65 -0
  178. package/dist/lib/setupSyncProjectsCommand.d.ts +4 -0
  179. package/dist/lib/setupSyncProjectsCommand.js +292 -0
  180. package/dist/lib/staleCommand.d.ts +8 -0
  181. package/dist/lib/staleCommand.js +34 -0
  182. package/dist/lib/statsCommand.d.ts +6 -0
  183. package/dist/lib/statsCommand.js +142 -0
  184. package/dist/lib/statusCommand.d.ts +18 -0
  185. package/dist/lib/statusCommand.js +250 -0
  186. package/dist/lib/storesCommand.d.ts +2 -0
  187. package/dist/lib/storesCommand.js +4 -0
  188. package/dist/lib/syncClient.d.ts +47 -0
  189. package/dist/lib/syncClient.js +212 -0
  190. package/dist/lib/syncCommand.d.ts +6 -0
  191. package/dist/lib/syncCommand.js +57 -0
  192. package/dist/lib/syncDoctorCommand.d.ts +5 -0
  193. package/dist/lib/syncDoctorCommand.js +100 -0
  194. package/dist/lib/syncIngest.d.ts +19 -0
  195. package/dist/lib/syncIngest.js +152 -0
  196. package/dist/lib/syncIngestLaunchd.d.ts +8 -0
  197. package/dist/lib/syncIngestLaunchd.js +93 -0
  198. package/dist/lib/syncIngestStartup.d.ts +5 -0
  199. package/dist/lib/syncIngestStartup.js +29 -0
  200. package/dist/lib/syncIngestSystemd.d.ts +10 -0
  201. package/dist/lib/syncIngestSystemd.js +97 -0
  202. package/dist/lib/syncIngestTimer.d.ts +8 -0
  203. package/dist/lib/syncIngestTimer.js +27 -0
  204. package/dist/lib/syncIngestTimerCommand.d.ts +7 -0
  205. package/dist/lib/syncIngestTimerCommand.js +83 -0
  206. package/dist/lib/syncLock.d.ts +6 -0
  207. package/dist/lib/syncLock.js +74 -0
  208. package/dist/lib/syncSnapshot.d.ts +30 -0
  209. package/dist/lib/syncSnapshot.js +184 -0
  210. package/dist/lib/syncStaging.d.ts +81 -0
  211. package/dist/lib/syncStaging.js +239 -0
  212. package/dist/lib/tagsAddCommand.d.ts +8 -0
  213. package/dist/lib/tagsAddCommand.js +18 -0
  214. package/dist/lib/tagsCommand.d.ts +4 -0
  215. package/dist/lib/tagsCommand.js +16 -0
  216. package/dist/lib/timelineCommand.d.ts +7 -0
  217. package/dist/lib/timelineCommand.js +49 -0
  218. package/dist/lib/traceCommand.d.ts +6 -0
  219. package/dist/lib/traceCommand.js +39 -0
  220. package/dist/lib/traverseCommand.d.ts +6 -0
  221. package/dist/lib/traverseCommand.js +58 -0
  222. package/dist/lib/updateCommand.d.ts +13 -0
  223. package/dist/lib/updateCommand.js +67 -0
  224. package/dist/lib/updateStatusCommand.d.ts +5 -0
  225. package/dist/lib/updateStatusCommand.js +38 -0
  226. package/dist/lib/webAddCommand.d.ts +8 -0
  227. package/dist/lib/webAddCommand.js +55 -0
  228. package/dist/lib/webBuildCommand.d.ts +10 -0
  229. package/dist/lib/webBuildCommand.js +65 -0
  230. package/dist/lib/webBuildIndexCommand.d.ts +8 -0
  231. package/dist/lib/webBuildIndexCommand.js +37 -0
  232. package/dist/lib/webIngestCommand.d.ts +11 -0
  233. package/dist/lib/webIngestCommand.js +51 -0
  234. package/dist/lib/webInitCommand.d.ts +9 -0
  235. package/dist/lib/webInitCommand.js +167 -0
  236. package/dist/lib/webRemoveCommand.d.ts +5 -0
  237. package/dist/lib/webRemoveCommand.js +41 -0
  238. package/dist/lib/webStatusCommand.d.ts +5 -0
  239. package/dist/lib/webStatusCommand.js +94 -0
  240. package/dist/lib/webUpdateCommand.d.ts +7 -0
  241. package/dist/lib/webUpdateCommand.js +72 -0
  242. package/dist/lib/workingSetCommand.d.ts +6 -0
  243. package/dist/lib/workingSetCommand.js +37 -0
  244. package/package.json +2 -1
@@ -0,0 +1,239 @@
1
+ /**
2
+ * v13 hardened JSON staging for multi-machine sync.
3
+ *
4
+ * Clients write small JSON files under master-folder/.gnosys-staging/<machineId>/.
5
+ * Master ingest walks files ordered by ledger firstSeenAt (see GnosysDB.sync_staging_ledger).
6
+ */
7
+ import { createHash, randomBytes } from "crypto";
8
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, } from "fs";
9
+ import path from "path";
10
+ import { atomicWriteFileSync } from "./atomicWrite.js";
11
+ /** Current staged-memory JSON schema version. */
12
+ export const STAGING_SCHEMA_VERSION = 1;
13
+ export const KNOWN_STAGING_SCHEMA_VERSIONS = new Set([STAGING_SCHEMA_VERSION]);
14
+ export const UNKNOWN_SCHEMA_MESSAGE = "Update your master machine to a newer version of Gnosys.";
15
+ const STAGING_DIR = ".gnosys-staging";
16
+ const FAILED_DIR = "failed";
17
+ const PRESENCE_FILE = ".presence.json";
18
+ export function stagingRoot(masterPath) {
19
+ return path.join(masterPath, STAGING_DIR);
20
+ }
21
+ export function machineStagingDir(masterPath, machineId) {
22
+ return path.join(stagingRoot(masterPath), machineId);
23
+ }
24
+ /** Alias used by remoteWizard and tests. */
25
+ export const stagingDirForMachine = machineStagingDir;
26
+ export function clientPresencePath(masterPath, machineId) {
27
+ return path.join(machineStagingDir(masterPath, machineId), PRESENCE_FILE);
28
+ }
29
+ export function failedQuarantineDir(masterPath, machineId) {
30
+ return path.join(machineStagingDir(masterPath, machineId), FAILED_DIR);
31
+ }
32
+ export function buildStagingFileName(memoryUlid, unixMs = Date.now()) {
33
+ return `${unixMs}-${memoryUlid}.json`;
34
+ }
35
+ /** SHA-256 of canonical JSON body (all fields except checksum). */
36
+ export function stagingPayloadChecksum(body) {
37
+ const canonical = JSON.stringify({
38
+ schemaVersion: body.schemaVersion,
39
+ id: body.id,
40
+ title: body.title,
41
+ category: body.category,
42
+ content: body.content,
43
+ tags: body.tags,
44
+ project_id: body.project_id,
45
+ scope: body.scope,
46
+ machineId: body.machineId,
47
+ writtenAt: body.writtenAt,
48
+ });
49
+ return createHash("sha256").update(canonical, "utf-8").digest("hex");
50
+ }
51
+ export function buildStagedMemoryPayload(input) {
52
+ const bodyWithoutChecksum = {
53
+ schemaVersion: input.schemaVersion ?? STAGING_SCHEMA_VERSION,
54
+ id: input.id,
55
+ title: input.title,
56
+ category: input.category,
57
+ content: input.content,
58
+ tags: input.tags ?? [],
59
+ project_id: input.project_id ?? null,
60
+ scope: input.scope ?? "project",
61
+ machineId: input.machineId,
62
+ writtenAt: input.writtenAt ?? new Date().toISOString(),
63
+ };
64
+ return {
65
+ ...bodyWithoutChecksum,
66
+ checksum: stagingPayloadChecksum(bodyWithoutChecksum),
67
+ };
68
+ }
69
+ /**
70
+ * Atomically write a staged memory JSON file (`.tmp` in the same directory, then rename).
71
+ * Returns the final file path relative to the machine staging dir.
72
+ */
73
+ export function writeStagedMemoryFile(masterPath, machineId, payload) {
74
+ const dir = machineStagingDir(masterPath, machineId);
75
+ mkdirSync(dir, { recursive: true });
76
+ const fileName = buildStagingFileName(payload.id);
77
+ const dest = path.join(dir, fileName);
78
+ const tmp = path.join(dir, `.${fileName}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
79
+ const data = JSON.stringify(payload, null, 2) + "\n";
80
+ try {
81
+ atomicWriteFileSync(tmp, data);
82
+ // read-back verify before rename (catches torn/partial writes on share)
83
+ const roundTrip = readFileSync(tmp, "utf-8");
84
+ const parsed = parseStagedFileContent(roundTrip, dest);
85
+ if (!parsed.ok) {
86
+ throw new Error(parsed.reason);
87
+ }
88
+ renameSync(tmp, dest);
89
+ return fileName;
90
+ }
91
+ catch (err) {
92
+ try {
93
+ if (existsSync(tmp))
94
+ unlinkSync(tmp);
95
+ }
96
+ catch {
97
+ // ignore
98
+ }
99
+ throw err;
100
+ }
101
+ }
102
+ function parseStagedFileContent(raw, filePath) {
103
+ let json;
104
+ try {
105
+ json = JSON.parse(raw);
106
+ }
107
+ catch {
108
+ return { ok: false, filePath, reason: "invalid JSON", quarantine: true };
109
+ }
110
+ if (!json || typeof json !== "object") {
111
+ return { ok: false, filePath, reason: "payload is not an object", quarantine: true };
112
+ }
113
+ const o = json;
114
+ const schemaVersion = typeof o.schemaVersion === "number" ? o.schemaVersion : -1;
115
+ if (!KNOWN_STAGING_SCHEMA_VERSIONS.has(schemaVersion)) {
116
+ return {
117
+ ok: false,
118
+ filePath,
119
+ reason: UNKNOWN_SCHEMA_MESSAGE,
120
+ quarantine: true,
121
+ };
122
+ }
123
+ const id = typeof o.id === "string" ? o.id : "";
124
+ const checksum = typeof o.checksum === "string" ? o.checksum : "";
125
+ const payload = {
126
+ schemaVersion,
127
+ id,
128
+ title: String(o.title ?? ""),
129
+ category: String(o.category ?? ""),
130
+ content: String(o.content ?? ""),
131
+ tags: Array.isArray(o.tags) ? o.tags.filter((t) => typeof t === "string") : [],
132
+ project_id: typeof o.project_id === "string" ? o.project_id : null,
133
+ scope: typeof o.scope === "string" ? o.scope : "project",
134
+ machineId: String(o.machineId ?? ""),
135
+ writtenAt: String(o.writtenAt ?? ""),
136
+ checksum,
137
+ };
138
+ const expected = stagingPayloadChecksum(payload);
139
+ if (!checksum || expected !== checksum) {
140
+ return { ok: false, filePath, reason: "checksum mismatch", quarantine: true };
141
+ }
142
+ if (!id) {
143
+ return { ok: false, filePath, reason: "missing memory id (ULID)", quarantine: true };
144
+ }
145
+ return { ok: true, payload, filePath };
146
+ }
147
+ export function parseStagedFile(filePath) {
148
+ try {
149
+ const raw = readFileSync(filePath, "utf-8");
150
+ return parseStagedFileContent(raw, filePath);
151
+ }
152
+ catch (err) {
153
+ return {
154
+ ok: false,
155
+ filePath,
156
+ reason: err instanceof Error ? err.message : String(err),
157
+ quarantine: true,
158
+ };
159
+ }
160
+ }
161
+ /** Move a bad staging file into machineId/failed/ (does not delete). */
162
+ export function quarantineStagingFile(filePath, masterPath, machineId) {
163
+ const failedDir = failedQuarantineDir(masterPath, machineId);
164
+ mkdirSync(failedDir, { recursive: true });
165
+ const base = path.basename(filePath);
166
+ const dest = path.join(failedDir, base);
167
+ if (existsSync(dest)) {
168
+ const stamped = `${Date.now()}-${base}`;
169
+ renameSync(filePath, path.join(failedDir, stamped));
170
+ return path.join(failedDir, stamped);
171
+ }
172
+ renameSync(filePath, dest);
173
+ return dest;
174
+ }
175
+ /** Move stale `.tmp` files in a machine staging dir into `failed/`. */
176
+ export function quarantineStaleTmpFiles(masterPath, machineId) {
177
+ const dir = machineStagingDir(masterPath, machineId);
178
+ if (!existsSync(dir))
179
+ return 0;
180
+ let moved = 0;
181
+ for (const name of readdirSync(dir)) {
182
+ if (!name.endsWith(".tmp"))
183
+ continue;
184
+ quarantineStagingFile(path.join(dir, name), masterPath, machineId);
185
+ moved++;
186
+ }
187
+ return moved;
188
+ }
189
+ export function countFailedStagingFiles(masterPath, machineId) {
190
+ const failedDir = failedQuarantineDir(masterPath, machineId);
191
+ if (!existsSync(failedDir))
192
+ return 0;
193
+ try {
194
+ return readdirSync(failedDir).filter((n) => n.endsWith(".json") || n.endsWith(".tmp")).length;
195
+ }
196
+ catch {
197
+ return 0;
198
+ }
199
+ }
200
+ /**
201
+ * List pending `.json` staging files for a machine (excludes failed/, tmp, presence).
202
+ * Sort by ledger firstSeenAt when db is provided, else by filename timestamp prefix.
203
+ */
204
+ export function listPendingStagingQueue(masterPath, machineId, masterDb) {
205
+ const dir = machineStagingDir(masterPath, machineId);
206
+ if (!existsSync(dir))
207
+ return [];
208
+ const entries = [];
209
+ for (const name of readdirSync(dir)) {
210
+ if (name === FAILED_DIR || name === PRESENCE_FILE || name.endsWith(".tmp"))
211
+ continue;
212
+ if (!name.endsWith(".json"))
213
+ continue;
214
+ const filePath = path.join(dir, name);
215
+ const ulid = name.replace(/^\d+-/, "").replace(/\.json$/, "");
216
+ const stagingKey = `${machineId}/${name}`;
217
+ const firstSeen = masterDb?.isAvailable() ? masterDb.getStagingLedgerFirstSeenAt(stagingKey) : null;
218
+ const sortKey = firstSeen ? `${firstSeen}\0${name}` : name;
219
+ entries.push({ filePath, fileName: name, memoryUlid: ulid, sortKey });
220
+ }
221
+ entries.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
222
+ return entries;
223
+ }
224
+ /** Master read-back: memory row exists after ingest before deleting staging file. */
225
+ export function verifyMemoryExistsInDb(db, memoryUlid) {
226
+ if (!db.isAvailable())
227
+ return false;
228
+ return db.getMemory(memoryUlid) !== null;
229
+ }
230
+ /** Record first observation in the master ledger (idempotent upsert without clobbering status). */
231
+ export function observeStagingFile(masterDb, machineId, fileName, memoryUlid) {
232
+ const stagingKey = `${machineId}/${fileName}`;
233
+ masterDb.recordStagingLedgerEntry({
234
+ stagingKey,
235
+ machineId,
236
+ memoryUlid,
237
+ firstSeenAt: new Date().toISOString(),
238
+ });
239
+ }
@@ -0,0 +1,8 @@
1
+ import type { GnosysResolver } from "./resolver.js";
2
+ export type TagsAddCommandOptions = {
3
+ category: string;
4
+ tag: string;
5
+ };
6
+ type GetResolver = () => Promise<GnosysResolver>;
7
+ export declare function runTagsAddCommand(getResolver: GetResolver, opts: TagsAddCommandOptions): Promise<void>;
8
+ export {};
@@ -0,0 +1,18 @@
1
+ import { GnosysTagRegistry } from "./tags.js";
2
+ export async function runTagsAddCommand(getResolver, opts) {
3
+ const resolver = await getResolver();
4
+ const writeTarget = resolver.getWriteTarget();
5
+ if (!writeTarget) {
6
+ console.error("No store found.");
7
+ process.exit(1);
8
+ }
9
+ const tagRegistry = new GnosysTagRegistry(writeTarget.store.getStorePath());
10
+ await tagRegistry.load();
11
+ const added = await tagRegistry.addTag(opts.category, opts.tag);
12
+ if (added) {
13
+ console.log(`Tag '${opts.tag}' added to category '${opts.category}'.`);
14
+ }
15
+ else {
16
+ console.log(`Tag '${opts.tag}' already exists in '${opts.category}'.`);
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ import type { GnosysResolver } from "./resolver.js";
2
+ type GetResolver = () => Promise<GnosysResolver>;
3
+ export declare function runTagsCommand(getResolver: GetResolver): Promise<void>;
4
+ export {};
@@ -0,0 +1,16 @@
1
+ import { GnosysTagRegistry } from "./tags.js";
2
+ export async function runTagsCommand(getResolver) {
3
+ const resolver = await getResolver();
4
+ const writeTarget = resolver.getWriteTarget();
5
+ if (!writeTarget) {
6
+ console.error("No store found.");
7
+ process.exit(1);
8
+ }
9
+ const tagRegistry = new GnosysTagRegistry(writeTarget.store.getStorePath());
10
+ await tagRegistry.load();
11
+ const registry = tagRegistry.getRegistry();
12
+ for (const [category, tags] of Object.entries(registry)) {
13
+ console.log(`\n${category}:`);
14
+ console.log(` ${tags.sort().join(", ")}`);
15
+ }
16
+ }
@@ -0,0 +1,7 @@
1
+ export type TimelineCommandOptions = {
2
+ period: string;
3
+ project?: string;
4
+ limitTitles: string;
5
+ json?: boolean;
6
+ };
7
+ export declare function runTimelineCommand(opts: TimelineCommandOptions): Promise<void>;
@@ -0,0 +1,49 @@
1
+ import { GnosysDB } from "./db.js";
2
+ import { groupDbByPeriod } from "./timeline.js";
3
+ function outputResult(json, data, humanFn) {
4
+ if (json) {
5
+ console.log(JSON.stringify(data, null, 2));
6
+ }
7
+ else {
8
+ humanFn();
9
+ }
10
+ }
11
+ export async function runTimelineCommand(opts) {
12
+ const centralDb = GnosysDB.openCentral();
13
+ if (!centralDb.isAvailable()) {
14
+ console.error("Central DB unavailable.");
15
+ process.exit(1);
16
+ }
17
+ try {
18
+ const memories = opts.project
19
+ ? centralDb.getMemoriesByProject(opts.project)
20
+ : centralDb.getActiveMemories();
21
+ if (memories.length === 0) {
22
+ outputResult(!!opts.json, { period: opts.period, count: 0, entries: [] }, () => {
23
+ console.log("No memories found.");
24
+ });
25
+ return;
26
+ }
27
+ const entries = groupDbByPeriod(memories, opts.period);
28
+ const titleLimit = Math.max(0, parseInt(opts.limitTitles, 10) || 5);
29
+ outputResult(!!opts.json, { period: opts.period, count: memories.length, entries }, () => {
30
+ console.log(`Knowledge Timeline (by ${opts.period}, ${memories.length} memories):\n`);
31
+ for (const entry of entries) {
32
+ const parts = [];
33
+ if (entry.created > 0)
34
+ parts.push(`${entry.created} created`);
35
+ if (entry.modified > 0)
36
+ parts.push(`${entry.modified} modified`);
37
+ console.log(` ${entry.period}: ${parts.join(", ")}`);
38
+ if (entry.titles.length > 0 && entry.titles.length <= titleLimit) {
39
+ for (const t of entry.titles) {
40
+ console.log(` + ${t}`);
41
+ }
42
+ }
43
+ }
44
+ });
45
+ }
46
+ finally {
47
+ centralDb.close();
48
+ }
49
+ }
@@ -0,0 +1,6 @@
1
+ export type TraceCommandOptions = {
2
+ maxFiles?: string;
3
+ projectId?: string;
4
+ json?: boolean;
5
+ };
6
+ export declare function runTraceCommand(directory: string, opts: TraceCommandOptions): Promise<void>;
@@ -0,0 +1,39 @@
1
+ export async function runTraceCommand(directory, opts) {
2
+ let db;
3
+ try {
4
+ const { traceCodebase } = await import("./trace.js");
5
+ const { GnosysDB: GnosysDBClass } = await import("./db.js");
6
+ const dbDir = GnosysDBClass.getCentralDbDir();
7
+ db = new GnosysDBClass(dbDir);
8
+ if (!db.isAvailable()) {
9
+ console.error("Error: GnosysDB not available. Install it with: npm install better-sqlite3");
10
+ process.exit(1);
11
+ }
12
+ const result = traceCodebase(db, directory, {
13
+ projectId: opts.projectId,
14
+ maxFiles: opts.maxFiles ? parseInt(opts.maxFiles, 10) : undefined,
15
+ });
16
+ if (opts.json) {
17
+ console.log(JSON.stringify(result, null, 2));
18
+ }
19
+ else {
20
+ console.log(`Trace complete:`);
21
+ console.log(` Files scanned: ${result.filesScanned}`);
22
+ console.log(` Functions found: ${result.functionsFound}`);
23
+ console.log(` Memories created: ${result.memoriesCreated}`);
24
+ console.log(` Relationships created: ${result.relationshipsCreated}`);
25
+ }
26
+ }
27
+ catch (err) {
28
+ if (opts.json) {
29
+ console.log(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
30
+ }
31
+ else {
32
+ console.error(`Trace failed: ${err instanceof Error ? err.message : err}`);
33
+ }
34
+ process.exit(1);
35
+ }
36
+ finally {
37
+ db?.close();
38
+ }
39
+ }
@@ -0,0 +1,6 @@
1
+ export type TraverseCommandOptions = {
2
+ depth?: string;
3
+ relTypes?: string;
4
+ json?: boolean;
5
+ };
6
+ export declare function runTraverseCommand(memoryId: string, opts: TraverseCommandOptions): Promise<void>;
@@ -0,0 +1,58 @@
1
+ export async function runTraverseCommand(memoryId, opts) {
2
+ let db;
3
+ try {
4
+ const { GnosysDB: GnosysDBClass } = await import("./db.js");
5
+ const { handleRequest } = await import("../sandbox/server.js");
6
+ const dbDir = GnosysDBClass.getCentralDbDir();
7
+ db = new GnosysDBClass(dbDir);
8
+ if (!db.isAvailable()) {
9
+ console.error("Error: GnosysDB not available. Install it with: npm install better-sqlite3");
10
+ process.exit(1);
11
+ }
12
+ const params = {
13
+ id: memoryId,
14
+ depth: opts.depth ? parseInt(opts.depth, 10) : 3,
15
+ };
16
+ if (opts.relTypes)
17
+ params.rel_types = opts.relTypes.split(",").map((s) => s.trim());
18
+ const res = handleRequest(db, {
19
+ id: "cli-traverse",
20
+ method: "traverse",
21
+ params,
22
+ });
23
+ if (!res.ok) {
24
+ if (opts.json) {
25
+ console.log(JSON.stringify({ ok: false, error: res.error }));
26
+ }
27
+ else {
28
+ console.error(`Traverse failed: ${res.error}`);
29
+ }
30
+ process.exit(1);
31
+ }
32
+ const result = res.result;
33
+ if (opts.json) {
34
+ console.log(JSON.stringify(result, null, 2));
35
+ }
36
+ else {
37
+ console.log(`Traversal from ${memoryId} (depth: ${result.depth}):`);
38
+ console.log(` Total nodes: ${result.total}\n`);
39
+ for (const node of result.nodes) {
40
+ const indent = " ".repeat(node.depth + 1);
41
+ const via = node.via_rel ? ` ← [${node.via_rel}] from ${node.via_from}` : " (root)";
42
+ console.log(`${indent}${node.id}: ${node.title} (conf: ${node.confidence.toFixed(2)})${via}`);
43
+ }
44
+ }
45
+ }
46
+ catch (err) {
47
+ if (opts.json) {
48
+ console.log(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
49
+ }
50
+ else {
51
+ console.error(`Traverse failed: ${err instanceof Error ? err.message : err}`);
52
+ }
53
+ process.exit(1);
54
+ }
55
+ finally {
56
+ db?.close();
57
+ }
58
+ }
@@ -0,0 +1,13 @@
1
+ import type { GnosysResolver } from "./resolver.js";
2
+ export type UpdateCommandOptions = {
3
+ title?: string;
4
+ status?: string;
5
+ confidence?: string;
6
+ relevance?: string;
7
+ supersedes?: string;
8
+ supersededBy?: string;
9
+ content?: string;
10
+ };
11
+ type GetResolver = () => Promise<GnosysResolver>;
12
+ export declare function runUpdateCommand(getResolver: GetResolver, memoryPath: string, opts: UpdateCommandOptions): Promise<void>;
13
+ export {};
@@ -0,0 +1,67 @@
1
+ import { GnosysDB } from "./db.js";
2
+ export async function runUpdateCommand(getResolver, memoryPath, opts) {
3
+ let memoryId;
4
+ let currentTitle;
5
+ let centralDb = null;
6
+ try {
7
+ centralDb = GnosysDB.openCentral();
8
+ }
9
+ catch {
10
+ /* handled below */
11
+ }
12
+ if (centralDb?.isAvailable()) {
13
+ const dbMem = centralDb.getMemory(memoryPath);
14
+ if (dbMem) {
15
+ memoryId = dbMem.id;
16
+ currentTitle = dbMem.title;
17
+ }
18
+ else {
19
+ const resolver = await getResolver();
20
+ const memory = await resolver.readMemory(memoryPath);
21
+ if (!memory || !memory.frontmatter.id) {
22
+ console.error(`Memory not found: ${memoryPath}`);
23
+ centralDb?.close();
24
+ process.exit(1);
25
+ }
26
+ memoryId = memory.frontmatter.id;
27
+ currentTitle = memory.frontmatter.title || memoryPath;
28
+ }
29
+ }
30
+ else {
31
+ console.error("Central DB not available.");
32
+ process.exit(1);
33
+ }
34
+ const updates = {};
35
+ if (opts.title !== undefined)
36
+ updates.title = opts.title;
37
+ if (opts.status !== undefined)
38
+ updates.status = opts.status;
39
+ if (opts.confidence !== undefined)
40
+ updates.confidence = parseFloat(opts.confidence);
41
+ if (opts.relevance !== undefined)
42
+ updates.relevance = opts.relevance;
43
+ if (opts.supersedes !== undefined)
44
+ updates.supersedes = opts.supersedes;
45
+ if (opts.supersededBy !== undefined)
46
+ updates.superseded_by = opts.supersededBy;
47
+ const fullContent = opts.content
48
+ ? `# ${opts.title || currentTitle}\n\n${opts.content}`
49
+ : undefined;
50
+ try {
51
+ const { syncUpdateToDb } = await import("./dbWrite.js");
52
+ syncUpdateToDb(centralDb, memoryId, updates, fullContent);
53
+ if (opts.supersedes) {
54
+ syncUpdateToDb(centralDb, opts.supersedes, { superseded_by: memoryId, status: "superseded" });
55
+ console.log(`Cross-linked: ${opts.supersedes} marked as superseded.`);
56
+ }
57
+ }
58
+ finally {
59
+ centralDb?.close();
60
+ }
61
+ const changedFields = Object.keys(updates);
62
+ if (opts.content)
63
+ changedFields.push("content");
64
+ console.log(`Memory updated: ${opts.title || currentTitle}`);
65
+ console.log(`ID: ${memoryId}`);
66
+ console.log(`Changed: ${changedFields.join(", ")}`);
67
+ }
@@ -0,0 +1,5 @@
1
+ export type UpdateStatusCommandOptions = {
2
+ directory?: string;
3
+ project?: string;
4
+ };
5
+ export declare function runUpdateStatusCommand(opts: UpdateStatusCommandOptions): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import { GnosysDB } from "./db.js";
2
+ export async function runUpdateStatusCommand(opts) {
3
+ let centralDb = null;
4
+ try {
5
+ centralDb = GnosysDB.openCentral();
6
+ if (!centralDb.isAvailable()) {
7
+ console.error("Central DB not available.");
8
+ process.exitCode = 1;
9
+ return;
10
+ }
11
+ const { detectCurrentProject } = await import("./federated.js");
12
+ const { generateStatusPrompt } = await import("./portfolio.js");
13
+ let pid = opts.project || null;
14
+ if (!pid)
15
+ pid = await detectCurrentProject(centralDb, opts.directory || undefined);
16
+ if (!pid) {
17
+ console.error("No project specified and none detected.");
18
+ process.exitCode = 1;
19
+ return;
20
+ }
21
+ const project = centralDb.getProject(pid);
22
+ if (!project) {
23
+ console.error(`Project not found: ${pid}`);
24
+ process.exitCode = 1;
25
+ return;
26
+ }
27
+ const prompt = generateStatusPrompt(project.name, project.working_directory);
28
+ console.log(prompt);
29
+ }
30
+ catch (err) {
31
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
32
+ process.exitCode = 1;
33
+ return;
34
+ }
35
+ finally {
36
+ centralDb?.close();
37
+ }
38
+ }
@@ -0,0 +1,8 @@
1
+ import type { GetWebStorePath } from "./webInitCommand.js";
2
+ export type WebAddCommandOptions = {
3
+ category?: string;
4
+ llm: boolean;
5
+ reindex: boolean;
6
+ json?: boolean;
7
+ };
8
+ export declare function runWebAddCommand(getWebStorePath: GetWebStorePath, url: string, opts: WebAddCommandOptions): Promise<void>;
@@ -0,0 +1,55 @@
1
+ import path from "path";
2
+ export async function runWebAddCommand(getWebStorePath, url, opts) {
3
+ try {
4
+ const { loadConfig } = await import("./config.js");
5
+ const { ingestUrl } = await import("./webIngest.js");
6
+ const { buildIndex, writeIndex } = await import("./webIndex.js");
7
+ const gnosysConfig = await loadConfig(await getWebStorePath());
8
+ const webConfig = gnosysConfig.web;
9
+ if (!webConfig) {
10
+ throw new Error("No web configuration found in gnosys.json. Run 'gnosys web init' first.");
11
+ }
12
+ const categories = opts.category
13
+ ? { ...webConfig.categories, "/*": opts.category }
14
+ : webConfig.categories;
15
+ const result = await ingestUrl(url, {
16
+ source: "urls",
17
+ outputDir: webConfig.outputDir,
18
+ categories,
19
+ llmEnrich: opts.llm ? webConfig.llmEnrich : false,
20
+ concurrency: 1,
21
+ crawlDelayMs: 0,
22
+ }, gnosysConfig);
23
+ // Rebuild index unless --no-reindex
24
+ if (opts.reindex && result.added.length + result.updated.length > 0) {
25
+ const index = await buildIndex(webConfig.outputDir);
26
+ await writeIndex(index, path.join(webConfig.outputDir, "gnosys-index.json"));
27
+ }
28
+ if (opts.json) {
29
+ console.log(JSON.stringify(result, null, 2));
30
+ }
31
+ else {
32
+ if (result.added.length > 0) {
33
+ console.log(`Added: ${result.added[0]}`);
34
+ }
35
+ else if (result.updated.length > 0) {
36
+ console.log(`Updated: ${result.updated[0]}`);
37
+ }
38
+ else if (result.unchanged.length > 0) {
39
+ console.log(`Unchanged (content identical)`);
40
+ }
41
+ if (result.errors.length > 0) {
42
+ console.error(`Error: ${result.errors[0].error}`);
43
+ }
44
+ }
45
+ }
46
+ catch (err) {
47
+ if (opts.json) {
48
+ console.log(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
49
+ }
50
+ else {
51
+ console.error(`Web add failed: ${err instanceof Error ? err.message : err}`);
52
+ }
53
+ process.exit(1);
54
+ }
55
+ }
@@ -0,0 +1,10 @@
1
+ import type { GetWebStorePath } from "./webInitCommand.js";
2
+ export type WebBuildCommandOptions = {
3
+ source?: string;
4
+ prune?: boolean;
5
+ llm: boolean;
6
+ concurrency: string;
7
+ dryRun?: boolean;
8
+ json?: boolean;
9
+ };
10
+ export declare function runWebBuildCommand(getWebStorePath: GetWebStorePath, opts: WebBuildCommandOptions): Promise<void>;