hippo-memory 1.61.0 → 1.62.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 (57) hide show
  1. package/README.md +28 -53
  2. package/dist/agent-memories/apply.d.ts +1 -1
  3. package/dist/agent-memories/claude-code.d.ts +3 -1
  4. package/dist/agent-memories/claude-code.js +53 -9
  5. package/dist/agent-memories/sync.d.ts +3 -3
  6. package/dist/agent-memories/sync.js +14 -6
  7. package/dist/agent-memories/types.d.ts +0 -2
  8. package/dist/api/assemble.js +55 -54
  9. package/dist/api/context-select.d.ts +49 -0
  10. package/dist/api/context-select.js +344 -0
  11. package/dist/api/context.d.ts +2 -2
  12. package/dist/api/context.js +195 -522
  13. package/dist/api/drill-down.js +36 -33
  14. package/dist/api/promote.js +55 -66
  15. package/dist/api/recall.js +303 -438
  16. package/dist/api/sleep.js +203 -218
  17. package/dist/capture/compact.d.ts +1 -1
  18. package/dist/capture/compact.js +2 -2
  19. package/dist/cli/briefs.js +324 -306
  20. package/dist/cli/context.js +44 -34
  21. package/dist/cli/continuity.js +283 -271
  22. package/dist/cli/curate.js +35 -34
  23. package/dist/cli/decisions.js +333 -333
  24. package/dist/cli/explain.js +66 -60
  25. package/dist/cli/maintenance.js +62 -51
  26. package/dist/cli/playbooks.js +387 -370
  27. package/dist/cli/projects.js +8 -5
  28. package/dist/cli/recall.js +28 -43
  29. package/dist/cli/remember.js +113 -70
  30. package/dist/cli/session-hooks.js +100 -90
  31. package/dist/cli/setup.js +267 -246
  32. package/dist/cli/status.js +73 -64
  33. package/dist/cli/transfer.js +85 -99
  34. package/dist/compaction-record.d.ts +0 -2
  35. package/dist/compaction-record.js +1 -1
  36. package/dist/customer-notes.js +77 -68
  37. package/dist/dag.js +222 -186
  38. package/dist/decisions.js +93 -76
  39. package/dist/doctor.js +11 -7
  40. package/dist/goals.js +99 -86
  41. package/dist/incidents.js +45 -38
  42. package/dist/policies.js +85 -68
  43. package/dist/processes.js +87 -71
  44. package/dist/project-briefs.js +135 -108
  45. package/dist/project-merge.d.ts +12 -4
  46. package/dist/project-merge.js +130 -45
  47. package/dist/shared.d.ts +9 -0
  48. package/dist/shared.js +10 -8
  49. package/dist/skills.js +81 -65
  50. package/dist/store/search-rows.d.ts +2 -2
  51. package/dist/store/search-rows.js +15 -9
  52. package/dist/version.d.ts +1 -1
  53. package/dist/version.js +1 -1
  54. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  55. package/extensions/openclaw-plugin/package.json +1 -1
  56. package/openclaw.plugin.json +1 -1
  57. package/package.json +1 -1
@@ -63,261 +63,271 @@ export function cmdSnapshot(hippoRoot, args, flags) {
63
63
  printError('Usage: hippo snapshot <save|show|clear>');
64
64
  process.exit(1);
65
65
  }
66
+ function sessionLog(hippoRoot, s, flags) {
67
+ const eventType = String(flags['type'] ?? 'note').trim();
68
+ const content = String(flags['content'] ?? '').trim();
69
+ if (!s.sessionId || !content) {
70
+ printError('Usage: hippo session log --id <session-id> --content <text> [--type <type>] [--task <task>] [--source <source>]');
71
+ process.exit(1);
72
+ }
73
+ const event = appendSessionEvent(hippoRoot, resolveTenantId({}), {
74
+ session_id: s.sessionId,
75
+ task: s.task || null,
76
+ event_type: eventType || 'note',
77
+ content,
78
+ source: String(flags['source'] ?? 'cli'),
79
+ });
80
+ console.log(`Logged session event #${event.id}`);
81
+ console.log(` Session: ${event.session_id}`);
82
+ console.log(` Type: ${event.event_type}`);
83
+ }
84
+ function sessionShow(hippoRoot, s, flags) {
85
+ const events = listSessionEvents(hippoRoot, resolveTenantId({}), {
86
+ session_id: s.sessionId || undefined,
87
+ task: s.task || undefined,
88
+ limit: s.limit,
89
+ });
90
+ if (flags['json']) {
91
+ console.log(JSON.stringify({ events }, null, 2));
92
+ return;
93
+ }
94
+ printSessionEvents(events);
95
+ }
96
+ function sessionLatest(hippoRoot, s, flags) {
97
+ const snapshot = loadActiveTaskSnapshot(hippoRoot, resolveTenantId({}));
98
+ const events = listSessionEvents(hippoRoot, resolveTenantId({}), {
99
+ session_id: s.sessionId || snapshot?.session_id || undefined,
100
+ limit: s.limit,
101
+ });
102
+ if (flags['json']) {
103
+ console.log(JSON.stringify({ snapshot: snapshot ?? null, events }, null, 2));
104
+ return;
105
+ }
106
+ if (snapshot) {
107
+ printActiveTaskSnapshot(snapshot);
108
+ }
109
+ else {
110
+ console.log('No active task snapshot.');
111
+ console.log('');
112
+ }
113
+ printSessionEvents(events);
114
+ }
115
+ function sessionComplete(hippoRoot, s, flags) {
116
+ const { sessionId, task } = s;
117
+ const outcomeRaw = String(flags['outcome'] ?? '').trim();
118
+ const summary = String(flags['summary'] ?? '').trim();
119
+ if (!sessionId) {
120
+ printError('Usage: hippo session complete --session <session-id> --outcome <success|failure|partial> [--summary "..."]');
121
+ process.exit(1);
122
+ }
123
+ if (!isHandoffOutcome(outcomeRaw)) {
124
+ printError(`Invalid outcome: "${outcomeRaw}". Must be one of: success, failure, partial.`);
125
+ process.exit(1);
126
+ }
127
+ const outcome = outcomeRaw;
128
+ const metadata = { ended_at: new Date().toISOString() };
129
+ if (summary)
130
+ metadata.summary = summary;
131
+ const event = appendSessionEvent(hippoRoot, resolveTenantId({}), {
132
+ session_id: sessionId,
133
+ task: task || null,
134
+ event_type: 'session_complete',
135
+ content: outcome,
136
+ source: String(flags['source'] ?? 'cli'),
137
+ metadata,
138
+ });
139
+ console.log(`Completed session ${event.session_id} with outcome=${outcome} (event #${event.id})`);
140
+ const stamped = stampHandoffOutcome(hippoRoot, resolveTenantId({}), sessionId, outcome);
141
+ if (stamped > 0) {
142
+ console.log(`Stamped outcome on handoff for session ${sessionId}`);
143
+ }
144
+ }
66
145
  export function cmdSession(hippoRoot, args, flags) {
67
146
  requireInit(hippoRoot);
68
147
  const subcommand = args[0] ?? 'show';
69
148
  const sessionId = String(flags['id'] ?? flags['session'] ?? '').trim();
70
149
  const task = String(flags['task'] ?? '').trim();
71
150
  const limit = Math.max(1, parseInt(String(flags['limit'] ?? '8'), 10) || 8);
72
- if (subcommand === 'log') {
73
- const eventType = String(flags['type'] ?? 'note').trim();
74
- const content = String(flags['content'] ?? '').trim();
75
- if (!sessionId || !content) {
76
- printError('Usage: hippo session log --id <session-id> --content <text> [--type <type>] [--task <task>] [--source <source>]');
77
- process.exit(1);
78
- }
79
- const event = appendSessionEvent(hippoRoot, resolveTenantId({}), {
80
- session_id: sessionId,
81
- task: task || null,
82
- event_type: eventType || 'note',
83
- content,
84
- source: String(flags['source'] ?? 'cli'),
85
- });
86
- console.log(`Logged session event #${event.id}`);
87
- console.log(` Session: ${event.session_id}`);
88
- console.log(` Type: ${event.event_type}`);
151
+ const s = { sessionId, task, limit };
152
+ if (subcommand === 'log')
153
+ return sessionLog(hippoRoot, s, flags);
154
+ if (subcommand === 'show')
155
+ return sessionShow(hippoRoot, s, flags);
156
+ if (subcommand === 'latest')
157
+ return sessionLatest(hippoRoot, s, flags);
158
+ if (subcommand === 'complete')
159
+ return sessionComplete(hippoRoot, s, flags);
160
+ if (subcommand === 'resume')
161
+ return sessionResume(hippoRoot, sessionId);
162
+ printError('Usage: hippo session <log|show|latest|resume|complete>');
163
+ process.exit(1);
164
+ }
165
+ function sessionResume(hippoRoot, sessionId) {
166
+ const handoff = loadLatestHandoff(hippoRoot, resolveTenantId({}), sessionId || undefined);
167
+ if (!handoff) {
168
+ console.log('No handoff to resume from.');
89
169
  return;
90
170
  }
91
- if (subcommand === 'show') {
92
- const events = listSessionEvents(hippoRoot, resolveTenantId({}), {
93
- session_id: sessionId || undefined,
94
- task: task || undefined,
95
- limit,
96
- });
97
- if (flags['json']) {
98
- console.log(JSON.stringify({ events }, null, 2));
99
- return;
100
- }
101
- printSessionEvents(events);
102
- return;
171
+ const lines = [
172
+ '## Session Handoff (resumed)',
173
+ '',
174
+ `- Session: ${handoff.sessionId}`,
175
+ `- Updated: ${handoff.updatedAt}`,
176
+ ];
177
+ if (handoff.taskId)
178
+ lines.push(`- Task: ${handoff.taskId}`);
179
+ if (handoff.repoRoot)
180
+ lines.push(`- Repo: ${handoff.repoRoot}`);
181
+ if (handoff.outcome)
182
+ lines.push(`- Outcome: ${handoff.outcome}`);
183
+ if (handoff.targetRuntime)
184
+ lines.push(`- Target runtime: ${handoff.targetRuntime}`);
185
+ if (handoff.cardId)
186
+ lines.push(`- Card: ${handoff.cardId}`);
187
+ lines.push('', '### Summary', handoff.summary);
188
+ if (handoff.nextAction) {
189
+ lines.push('', '### Next action', handoff.nextAction);
103
190
  }
104
- if (subcommand === 'latest') {
105
- const snapshot = loadActiveTaskSnapshot(hippoRoot, resolveTenantId({}));
106
- const events = listSessionEvents(hippoRoot, resolveTenantId({}), {
107
- session_id: sessionId || snapshot?.session_id || undefined,
108
- limit,
109
- });
110
- if (flags['json']) {
111
- console.log(JSON.stringify({ snapshot: snapshot ?? null, events }, null, 2));
112
- return;
191
+ if (handoff.artifacts && handoff.artifacts.length > 0) {
192
+ lines.push('', '### Artifacts');
193
+ for (const artifact of handoff.artifacts) {
194
+ lines.push(`- ${artifact}`);
113
195
  }
114
- if (snapshot) {
115
- printActiveTaskSnapshot(snapshot);
116
- }
117
- else {
118
- console.log('No active task snapshot.');
119
- console.log('');
196
+ }
197
+ if (handoff.constraints && handoff.constraints.length > 0) {
198
+ lines.push('', '### Constraints');
199
+ for (const constraint of handoff.constraints) {
200
+ lines.push(`- ${constraint}`);
120
201
  }
121
- printSessionEvents(events);
122
- return;
123
202
  }
124
- if (subcommand === 'complete') {
125
- const outcomeRaw = String(flags['outcome'] ?? '').trim();
126
- const summary = String(flags['summary'] ?? '').trim();
127
- if (!sessionId) {
128
- printError('Usage: hippo session complete --session <session-id> --outcome <success|failure|partial> [--summary "..."]');
203
+ if (handoff.evidence) {
204
+ lines.push('', '### Evidence', formatHandoffEvidenceLine(handoff.evidence));
205
+ }
206
+ lines.push('');
207
+ console.log(lines.join('\n'));
208
+ }
209
+ /** A repeatable flag as a list: absent is empty, one value is a singleton. */
210
+ function flagList(value) {
211
+ return Array.isArray(value) ? value : (typeof value === 'string' ? [value] : []);
212
+ }
213
+ function handoffCreate(hippoRoot, flags) {
214
+ const summary = String(flags['summary'] ?? '').trim();
215
+ if (!summary) {
216
+ printError('Usage: hippo handoff create --summary "..." [--next "..."] [--session <id>] [--task <id>] [--artifact <path>...] [--constraint <text>...] [--outcome <success|failure|partial>] [--target-runtime <name>] [--card-id <id>] [--tests <pass|fail|unknown>]');
217
+ process.exit(1);
218
+ }
219
+ const outcomeRaw = flags['outcome'];
220
+ if (outcomeRaw !== undefined && !isHandoffOutcome(outcomeRaw)) {
221
+ printError(`Invalid outcome: "${String(outcomeRaw)}". Must be one of: success, failure, partial.`);
222
+ process.exit(1);
223
+ }
224
+ const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || `fallback-${Date.now()}-${process.pid}`;
225
+ const nextAction = String(flags['next'] ?? '').trim() || undefined;
226
+ const taskId = String(flags['task'] ?? '').trim() || undefined;
227
+ const artifacts = flagList(flags['artifact']);
228
+ const constraints = flagList(flags['constraint']);
229
+ for (const name of ['target-runtime', 'card-id']) {
230
+ // parseArgs turns a value-less flag into `true`; refuse rather than store "true".
231
+ if (flags[name] === true) {
232
+ printError(`--${name} needs a value`);
129
233
  process.exit(1);
130
234
  }
131
- if (!isHandoffOutcome(outcomeRaw)) {
132
- printError(`Invalid outcome: "${outcomeRaw}". Must be one of: success, failure, partial.`);
133
- process.exit(1);
235
+ }
236
+ const targetRuntime = String(flags['target-runtime'] ?? '').trim() || undefined;
237
+ const cardId = String(flags['card-id'] ?? '').trim() || undefined;
238
+ const testStatus = String(flags['tests'] ?? '').trim();
239
+ const evidence = collectHandoffEvidence(process.cwd(), testStatus === 'pass' || testStatus === 'fail' ? testStatus : 'unknown');
240
+ const handoff = saveSessionHandoff(hippoRoot, resolveTenantId({}), {
241
+ version: 1,
242
+ sessionId,
243
+ repoRoot: process.cwd(),
244
+ taskId,
245
+ summary,
246
+ nextAction,
247
+ artifacts,
248
+ constraints,
249
+ evidence,
250
+ // SAFETY: isHandoffOutcome above already refused any non-matching value.
251
+ outcome: outcomeRaw,
252
+ targetRuntime,
253
+ cardId,
254
+ });
255
+ printCreatedHandoff(handoff);
256
+ }
257
+ function printCreatedHandoff(handoff) {
258
+ console.log(`Created session handoff for session ${handoff.sessionId}`);
259
+ console.log(` Summary: ${handoff.summary}`);
260
+ if (handoff.nextAction)
261
+ console.log(` Next: ${handoff.nextAction}`);
262
+ if (handoff.artifacts && handoff.artifacts.length > 0) {
263
+ console.log(` Artifacts: ${handoff.artifacts.join(', ')}`);
264
+ }
265
+ if (handoff.constraints && handoff.constraints.length > 0) {
266
+ console.log(` Constraints: ${handoff.constraints.join(', ')}`);
267
+ }
268
+ if (handoff.outcome)
269
+ console.log(` Outcome: ${handoff.outcome}`);
270
+ if (handoff.targetRuntime)
271
+ console.log(` Target runtime: ${handoff.targetRuntime}`);
272
+ if (handoff.cardId)
273
+ console.log(` Card: ${handoff.cardId}`);
274
+ if (handoff.evidence)
275
+ console.log(` Evidence: ${formatHandoffEvidenceLine(handoff.evidence)}`);
276
+ }
277
+ function handoffLatest(hippoRoot, flags) {
278
+ const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || undefined;
279
+ const handoff = loadLatestHandoff(hippoRoot, resolveTenantId({}), sessionId);
280
+ if (!handoff) {
281
+ if (flags['json']) {
282
+ console.log(JSON.stringify({ handoff: null }));
134
283
  }
135
- const outcome = outcomeRaw;
136
- const metadata = { ended_at: new Date().toISOString() };
137
- if (summary)
138
- metadata.summary = summary;
139
- const event = appendSessionEvent(hippoRoot, resolveTenantId({}), {
140
- session_id: sessionId,
141
- task: task || null,
142
- event_type: 'session_complete',
143
- content: outcome,
144
- source: String(flags['source'] ?? 'cli'),
145
- metadata,
146
- });
147
- console.log(`Completed session ${event.session_id} with outcome=${outcome} (event #${event.id})`);
148
- const stamped = stampHandoffOutcome(hippoRoot, resolveTenantId({}), sessionId, outcome);
149
- if (stamped > 0) {
150
- console.log(`Stamped outcome on handoff for session ${sessionId}`);
284
+ else {
285
+ console.log('No session handoff found.');
151
286
  }
152
287
  return;
153
288
  }
154
- if (subcommand === 'resume') {
155
- const handoff = loadLatestHandoff(hippoRoot, resolveTenantId({}), sessionId || undefined);
156
- if (!handoff) {
157
- console.log('No handoff to resume from.');
158
- return;
159
- }
160
- const lines = [
161
- '## Session Handoff (resumed)',
162
- '',
163
- `- Session: ${handoff.sessionId}`,
164
- `- Updated: ${handoff.updatedAt}`,
165
- ];
166
- if (handoff.taskId)
167
- lines.push(`- Task: ${handoff.taskId}`);
168
- if (handoff.repoRoot)
169
- lines.push(`- Repo: ${handoff.repoRoot}`);
170
- if (handoff.outcome)
171
- lines.push(`- Outcome: ${handoff.outcome}`);
172
- if (handoff.targetRuntime)
173
- lines.push(`- Target runtime: ${handoff.targetRuntime}`);
174
- if (handoff.cardId)
175
- lines.push(`- Card: ${handoff.cardId}`);
176
- lines.push('', '### Summary', handoff.summary);
177
- if (handoff.nextAction) {
178
- lines.push('', '### Next action', handoff.nextAction);
179
- }
180
- if (handoff.artifacts && handoff.artifacts.length > 0) {
181
- lines.push('', '### Artifacts');
182
- for (const artifact of handoff.artifacts) {
183
- lines.push(`- ${artifact}`);
184
- }
185
- }
186
- if (handoff.constraints && handoff.constraints.length > 0) {
187
- lines.push('', '### Constraints');
188
- for (const constraint of handoff.constraints) {
189
- lines.push(`- ${constraint}`);
190
- }
191
- }
192
- if (handoff.evidence) {
193
- lines.push('', '### Evidence', formatHandoffEvidenceLine(handoff.evidence));
194
- }
195
- lines.push('');
196
- console.log(lines.join('\n'));
289
+ if (flags['json']) {
290
+ console.log(JSON.stringify({ handoff }, null, 2));
197
291
  return;
198
292
  }
199
- printError('Usage: hippo session <log|show|latest|resume|complete>');
200
- process.exit(1);
293
+ printHandoff(handoff);
201
294
  }
202
- export function cmdHandoff(hippoRoot, args, flags) {
203
- requireInit(hippoRoot);
204
- const subcommand = args[0] ?? 'latest';
205
- if (subcommand === 'create') {
206
- const summary = String(flags['summary'] ?? '').trim();
207
- if (!summary) {
208
- printError('Usage: hippo handoff create --summary "..." [--next "..."] [--session <id>] [--task <id>] [--artifact <path>...] [--constraint <text>...] [--outcome <success|failure|partial>] [--target-runtime <name>] [--card-id <id>] [--tests <pass|fail|unknown>]');
209
- process.exit(1);
210
- }
211
- const outcomeRaw = flags['outcome'];
212
- if (outcomeRaw !== undefined && !isHandoffOutcome(outcomeRaw)) {
213
- printError(`Invalid outcome: "${String(outcomeRaw)}". Must be one of: success, failure, partial.`);
214
- process.exit(1);
215
- }
216
- const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || `fallback-${Date.now()}-${process.pid}`;
217
- const nextAction = String(flags['next'] ?? '').trim() || undefined;
218
- const taskId = String(flags['task'] ?? '').trim() || undefined;
219
- const artifactFlag = flags['artifact'];
220
- const artifacts = Array.isArray(artifactFlag)
221
- ? artifactFlag
222
- : (typeof artifactFlag === 'string' ? [artifactFlag] : []);
223
- const constraintFlag = flags['constraint'];
224
- const isFlagString = (v) => typeof v === 'string';
225
- const constraints = Array.isArray(constraintFlag)
226
- ? constraintFlag
227
- : (isFlagString(constraintFlag) ? [constraintFlag] : []);
228
- for (const name of ['target-runtime', 'card-id']) {
229
- // parseArgs turns a value-less flag into `true`; refuse rather than store "true".
230
- if (flags[name] === true) {
231
- printError(`--${name} needs a value`);
232
- process.exit(1);
233
- }
234
- }
235
- const targetRuntime = String(flags['target-runtime'] ?? '').trim() || undefined;
236
- const cardId = String(flags['card-id'] ?? '').trim() || undefined;
237
- const testStatus = String(flags['tests'] ?? '').trim();
238
- const evidence = collectHandoffEvidence(process.cwd(), testStatus === 'pass' || testStatus === 'fail' ? testStatus : 'unknown');
239
- const handoff = saveSessionHandoff(hippoRoot, resolveTenantId({}), {
240
- version: 1,
241
- sessionId,
242
- repoRoot: process.cwd(),
243
- taskId,
244
- summary,
245
- nextAction,
246
- artifacts,
247
- constraints,
248
- evidence,
249
- // SAFETY: isHandoffOutcome above already refused any non-matching value.
250
- outcome: outcomeRaw,
251
- targetRuntime,
252
- cardId,
253
- });
254
- console.log(`Created session handoff for session ${handoff.sessionId}`);
255
- console.log(` Summary: ${handoff.summary}`);
256
- if (handoff.nextAction)
257
- console.log(` Next: ${handoff.nextAction}`);
258
- if (handoff.artifacts && handoff.artifacts.length > 0) {
259
- console.log(` Artifacts: ${handoff.artifacts.join(', ')}`);
260
- }
261
- if (handoff.constraints && handoff.constraints.length > 0) {
262
- console.log(` Constraints: ${handoff.constraints.join(', ')}`);
263
- }
264
- if (handoff.outcome)
265
- console.log(` Outcome: ${handoff.outcome}`);
266
- if (handoff.targetRuntime)
267
- console.log(` Target runtime: ${handoff.targetRuntime}`);
268
- if (handoff.cardId)
269
- console.log(` Card: ${handoff.cardId}`);
270
- if (handoff.evidence)
271
- console.log(` Evidence: ${formatHandoffEvidenceLine(handoff.evidence)}`);
272
- return;
295
+ function handoffShow(hippoRoot, args, flags) {
296
+ const idArg = args[1];
297
+ if (!idArg) {
298
+ printError('Usage: hippo handoff show <id> [--json]');
299
+ process.exit(1);
273
300
  }
274
- if (subcommand === 'latest') {
275
- const sessionId = String(flags['session'] ?? flags['id'] ?? '').trim() || undefined;
276
- const handoff = loadLatestHandoff(hippoRoot, resolveTenantId({}), sessionId);
277
- if (!handoff) {
278
- if (flags['json']) {
279
- console.log(JSON.stringify({ handoff: null }));
280
- }
281
- else {
282
- console.log('No session handoff found.');
283
- }
284
- return;
285
- }
301
+ const handoffId = parseInt(idArg, 10);
302
+ if (!Number.isFinite(handoffId) || handoffId <= 0) {
303
+ printError(`Invalid handoff ID: ${idArg}`);
304
+ process.exit(1);
305
+ }
306
+ const handoff = loadHandoffById(hippoRoot, resolveTenantId({}), handoffId);
307
+ if (!handoff) {
286
308
  if (flags['json']) {
287
- console.log(JSON.stringify({ handoff }, null, 2));
288
- return;
309
+ console.log(JSON.stringify({ handoff: null }));
310
+ }
311
+ else {
312
+ console.log(`No handoff found with ID ${handoffId}.`);
289
313
  }
290
- printHandoff(handoff);
291
314
  return;
292
315
  }
293
- if (subcommand === 'show') {
294
- const idArg = args[1];
295
- if (!idArg) {
296
- printError('Usage: hippo handoff show <id> [--json]');
297
- process.exit(1);
298
- }
299
- const handoffId = parseInt(idArg, 10);
300
- if (!Number.isFinite(handoffId) || handoffId <= 0) {
301
- printError(`Invalid handoff ID: ${idArg}`);
302
- process.exit(1);
303
- }
304
- const handoff = loadHandoffById(hippoRoot, resolveTenantId({}), handoffId);
305
- if (!handoff) {
306
- if (flags['json']) {
307
- console.log(JSON.stringify({ handoff: null }));
308
- }
309
- else {
310
- console.log(`No handoff found with ID ${handoffId}.`);
311
- }
312
- return;
313
- }
314
- if (flags['json']) {
315
- console.log(JSON.stringify({ handoff }, null, 2));
316
- return;
317
- }
318
- printHandoff(handoff);
316
+ if (flags['json']) {
317
+ console.log(JSON.stringify({ handoff }, null, 2));
319
318
  return;
320
319
  }
320
+ printHandoff(handoff);
321
+ }
322
+ export function cmdHandoff(hippoRoot, args, flags) {
323
+ requireInit(hippoRoot);
324
+ const subcommand = args[0] ?? 'latest';
325
+ if (subcommand === 'create')
326
+ return handoffCreate(hippoRoot, flags);
327
+ if (subcommand === 'latest')
328
+ return handoffLatest(hippoRoot, flags);
329
+ if (subcommand === 'show')
330
+ return handoffShow(hippoRoot, args, flags);
321
331
  printError('Usage: hippo handoff <create|latest|show>');
322
332
  process.exit(1);
323
333
  }
@@ -381,50 +391,10 @@ export function cmdCurrent(hippoRoot, args, flags) {
381
391
  export function cmdWm(hippoRoot, args, flags) {
382
392
  requireInit(hippoRoot);
383
393
  const subcommand = args[0] ?? '';
384
- if (subcommand === 'push') {
385
- const scope = String(flags['scope'] ?? 'default').trim();
386
- const content = String(flags['content'] ?? '').trim();
387
- const importance = parseFloat(String(flags['importance'] ?? '0.5'));
388
- const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
389
- const taskId = flags['task'] ? String(flags['task']).trim() : undefined;
390
- if (!content) {
391
- printError('Usage: hippo wm push --scope <scope> --content "..." [--importance 0.8] [--session <id>] [--task <id>]');
392
- process.exit(1);
393
- }
394
- const id = wmPush(hippoRoot, {
395
- scope,
396
- content,
397
- importance: Number.isFinite(importance) ? importance : 0.5,
398
- sessionId,
399
- taskId,
400
- });
401
- console.log(`Pushed working memory #${id} (scope=${scope}, importance=${Number.isFinite(importance) ? importance : 0.5})`);
402
- return;
403
- }
404
- if (subcommand === 'read') {
405
- const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
406
- const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
407
- const limit = parseInt(String(flags['limit'] ?? '20'), 10) || 20;
408
- const items = wmRead(hippoRoot, { scope, sessionId, limit });
409
- if (flags['json']) {
410
- console.log(JSON.stringify({ items }, null, 2));
411
- return;
412
- }
413
- if (items.length === 0) {
414
- console.log('No working memory entries.');
415
- return;
416
- }
417
- console.log(`Working memory (${items.length} entries):\n`);
418
- for (const item of items) {
419
- const sessionLabel = item.sessionId ? ` session=${item.sessionId}` : '';
420
- const taskLabel = item.taskId ? ` task=${item.taskId}` : '';
421
- console.log(` #${item.id} [${item.scope}] importance=${item.importance}${sessionLabel}${taskLabel}`);
422
- console.log(` ${item.content}`);
423
- console.log(` created=${item.createdAt}`);
424
- console.log('');
425
- }
426
- return;
427
- }
394
+ if (subcommand === 'push')
395
+ return wmPushCmd(hippoRoot, flags);
396
+ if (subcommand === 'read')
397
+ return wmReadCmd(hippoRoot, flags);
428
398
  if (subcommand === 'clear') {
429
399
  const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
430
400
  const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
@@ -442,4 +412,46 @@ export function cmdWm(hippoRoot, args, flags) {
442
412
  printError('Usage: hippo wm <push|read|clear|flush>');
443
413
  process.exit(1);
444
414
  }
415
+ function wmPushCmd(hippoRoot, flags) {
416
+ const scope = String(flags['scope'] ?? 'default').trim();
417
+ const content = String(flags['content'] ?? '').trim();
418
+ const importance = parseFloat(String(flags['importance'] ?? '0.5'));
419
+ const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
420
+ const taskId = flags['task'] ? String(flags['task']).trim() : undefined;
421
+ if (!content) {
422
+ printError('Usage: hippo wm push --scope <scope> --content "..." [--importance 0.8] [--session <id>] [--task <id>]');
423
+ process.exit(1);
424
+ }
425
+ const id = wmPush(hippoRoot, {
426
+ scope,
427
+ content,
428
+ importance: Number.isFinite(importance) ? importance : 0.5,
429
+ sessionId,
430
+ taskId,
431
+ });
432
+ console.log(`Pushed working memory #${id} (scope=${scope}, importance=${Number.isFinite(importance) ? importance : 0.5})`);
433
+ }
434
+ function wmReadCmd(hippoRoot, flags) {
435
+ const scope = flags['scope'] ? String(flags['scope']).trim() : undefined;
436
+ const sessionId = flags['session'] ? String(flags['session']).trim() : undefined;
437
+ const limit = parseInt(String(flags['limit'] ?? '20'), 10) || 20;
438
+ const items = wmRead(hippoRoot, { scope, sessionId, limit });
439
+ if (flags['json']) {
440
+ console.log(JSON.stringify({ items }, null, 2));
441
+ return;
442
+ }
443
+ if (items.length === 0) {
444
+ console.log('No working memory entries.');
445
+ return;
446
+ }
447
+ console.log(`Working memory (${items.length} entries):\n`);
448
+ for (const item of items) {
449
+ const sessionLabel = item.sessionId ? ` session=${item.sessionId}` : '';
450
+ const taskLabel = item.taskId ? ` task=${item.taskId}` : '';
451
+ console.log(` #${item.id} [${item.scope}] importance=${item.importance}${sessionLabel}${taskLabel}`);
452
+ console.log(` ${item.content}`);
453
+ console.log(` created=${item.createdAt}`);
454
+ console.log('');
455
+ }
456
+ }
445
457
  //# sourceMappingURL=continuity.js.map