@rlabs-inc/memory 0.5.9 → 0.5.11
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/package.json +1 -1
- package/src/cli/commands/serve.ts +8 -0
- package/src/core/curator.ts +85 -0
- package/src/server/index.ts +7 -2
package/package.json
CHANGED
|
@@ -135,6 +135,14 @@ export async function serve(options: ServeOptions) {
|
|
|
135
135
|
console.log(c.muted(` Use 'memory migrate --dry-run' to preview changes first`))
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// Note for Gemini CLI API key auth users (OAuth users don't need this)
|
|
139
|
+
if (!process.env.GEMINI_API_KEY) {
|
|
140
|
+
console.log()
|
|
141
|
+
console.log(c.muted(` ${symbols.info} Using Gemini CLI with API key auth?`))
|
|
142
|
+
console.log(c.muted(` Run: GEMINI_API_KEY=your-key memory serve`))
|
|
143
|
+
console.log(c.muted(` (OAuth users can ignore this)`))
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
console.log()
|
|
139
147
|
console.log(c.muted(` Press Ctrl+C to stop`))
|
|
140
148
|
console.log()
|
package/src/core/curator.ts
CHANGED
|
@@ -818,6 +818,62 @@ This session has ended. Please curate the memories from this conversation accord
|
|
|
818
818
|
"curator",
|
|
819
819
|
);
|
|
820
820
|
|
|
821
|
+
// Temporarily disable hooks in project's .gemini/settings.json
|
|
822
|
+
// This prevents recursive hook triggering (env vars don't propagate to hook subprocesses)
|
|
823
|
+
const projectGeminiDir = cwd ? join(cwd, ".gemini") : null;
|
|
824
|
+
const projectSettingsPath = projectGeminiDir
|
|
825
|
+
? join(projectGeminiDir, "settings.json")
|
|
826
|
+
: null;
|
|
827
|
+
const backupSettingsPath = projectSettingsPath
|
|
828
|
+
? `${projectSettingsPath}.memory-backup`
|
|
829
|
+
: null;
|
|
830
|
+
let hadExistingSettings = false;
|
|
831
|
+
|
|
832
|
+
if (projectSettingsPath && projectGeminiDir) {
|
|
833
|
+
try {
|
|
834
|
+
// Backup existing settings if present
|
|
835
|
+
if (existsSync(projectSettingsPath)) {
|
|
836
|
+
hadExistingSettings = true;
|
|
837
|
+
const existingContent = await Bun.file(projectSettingsPath).text();
|
|
838
|
+
await Bun.write(backupSettingsPath!, existingContent);
|
|
839
|
+
logger.debug(
|
|
840
|
+
`Curator Gemini: Backed up existing settings to ${backupSettingsPath}`,
|
|
841
|
+
"curator",
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Ensure .gemini directory exists
|
|
846
|
+
if (!existsSync(projectGeminiDir)) {
|
|
847
|
+
const { mkdirSync } = await import("fs");
|
|
848
|
+
mkdirSync(projectGeminiDir, { recursive: true });
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Create temporary settings with hooks disabled
|
|
852
|
+
const tempSettings = {
|
|
853
|
+
hooks: {
|
|
854
|
+
disabled: [
|
|
855
|
+
"inject-memories",
|
|
856
|
+
"load-session-primer",
|
|
857
|
+
"curate-memories",
|
|
858
|
+
],
|
|
859
|
+
},
|
|
860
|
+
};
|
|
861
|
+
await Bun.write(
|
|
862
|
+
projectSettingsPath,
|
|
863
|
+
JSON.stringify(tempSettings, null, 2),
|
|
864
|
+
);
|
|
865
|
+
logger.debug(
|
|
866
|
+
`Curator Gemini: Created temporary settings with hooks disabled`,
|
|
867
|
+
"curator",
|
|
868
|
+
);
|
|
869
|
+
} catch (err: any) {
|
|
870
|
+
logger.debug(
|
|
871
|
+
`Curator Gemini: Could not manage settings file: ${err.message}`,
|
|
872
|
+
"curator",
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
821
877
|
// Execute CLI with system prompt via environment variable
|
|
822
878
|
// Must run from original project directory so --resume latest finds correct session
|
|
823
879
|
const proc = Bun.spawn(["gemini", ...args], {
|
|
@@ -839,6 +895,35 @@ This session has ended. Please curate the memories from this conversation accord
|
|
|
839
895
|
]);
|
|
840
896
|
const exitCode = await proc.exited;
|
|
841
897
|
|
|
898
|
+
// Cleanup: Restore original settings file
|
|
899
|
+
if (projectSettingsPath && backupSettingsPath) {
|
|
900
|
+
try {
|
|
901
|
+
const { unlinkSync } = await import("fs");
|
|
902
|
+
if (hadExistingSettings && existsSync(backupSettingsPath)) {
|
|
903
|
+
// Restore backup
|
|
904
|
+
const backupContent = await Bun.file(backupSettingsPath).text();
|
|
905
|
+
await Bun.write(projectSettingsPath, backupContent);
|
|
906
|
+
unlinkSync(backupSettingsPath);
|
|
907
|
+
logger.debug(
|
|
908
|
+
`Curator Gemini: Restored original settings from backup`,
|
|
909
|
+
"curator",
|
|
910
|
+
);
|
|
911
|
+
} else if (existsSync(projectSettingsPath)) {
|
|
912
|
+
// Delete temporary settings (there was no original)
|
|
913
|
+
unlinkSync(projectSettingsPath);
|
|
914
|
+
logger.debug(
|
|
915
|
+
`Curator Gemini: Removed temporary settings file`,
|
|
916
|
+
"curator",
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
} catch (err: any) {
|
|
920
|
+
logger.debug(
|
|
921
|
+
`Curator Gemini: Could not cleanup settings: ${err.message}`,
|
|
922
|
+
"curator",
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
842
927
|
logger.debug(`Curator Gemini: Exit code ${exitCode}`, "curator");
|
|
843
928
|
if (stderr && stderr.trim()) {
|
|
844
929
|
logger.debug(`Curator Gemini - stderr: ${stderr}`, "curator");
|
package/src/server/index.ts
CHANGED
|
@@ -241,12 +241,15 @@ export async function createServer(config: ServerConfig = {}) {
|
|
|
241
241
|
// Branch on CLI type - Gemini CLI vs Claude Code
|
|
242
242
|
if (body.cli_type === 'gemini-cli') {
|
|
243
243
|
// Use Gemini CLI for curation (no Claude dependency)
|
|
244
|
+
// Fallback to server's GEMINI_API_KEY if hook didn't pass one
|
|
245
|
+
// (hooks spawned by Gemini CLI may not inherit env vars)
|
|
246
|
+
const geminiApiKey = body.gemini_api_key || process.env.GEMINI_API_KEY
|
|
244
247
|
logger.debug('Using Gemini CLI for curation', 'server')
|
|
245
248
|
result = await curator.curateWithGeminiCLI(
|
|
246
249
|
body.claude_session_id,
|
|
247
250
|
body.trigger,
|
|
248
251
|
body.cwd, // Run from original project directory
|
|
249
|
-
|
|
252
|
+
geminiApiKey
|
|
250
253
|
)
|
|
251
254
|
} else {
|
|
252
255
|
// Default: Use Claude Code (session resume or transcript parsing)
|
|
@@ -303,13 +306,15 @@ export async function createServer(config: ServerConfig = {}) {
|
|
|
303
306
|
let managementResult
|
|
304
307
|
if (cliType === 'gemini-cli') {
|
|
305
308
|
// Use Gemini CLI for management (no Claude dependency)
|
|
309
|
+
// Use same API key fallback as curation (hooks don't inherit env vars)
|
|
310
|
+
const geminiApiKey = body.gemini_api_key || process.env.GEMINI_API_KEY
|
|
306
311
|
logger.debug('Using Gemini CLI for management', 'server')
|
|
307
312
|
managementResult = await manager.manageWithGeminiCLI(
|
|
308
313
|
body.project_id,
|
|
309
314
|
sessionNumber,
|
|
310
315
|
result,
|
|
311
316
|
storagePaths,
|
|
312
|
-
|
|
317
|
+
geminiApiKey
|
|
313
318
|
)
|
|
314
319
|
} else {
|
|
315
320
|
// Use Claude Agent SDK mode - more reliable than CLI
|