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.
- package/README.md +28 -53
- package/dist/agent-memories/apply.d.ts +1 -1
- package/dist/agent-memories/claude-code.d.ts +3 -1
- package/dist/agent-memories/claude-code.js +53 -9
- package/dist/agent-memories/sync.d.ts +3 -3
- package/dist/agent-memories/sync.js +14 -6
- package/dist/agent-memories/types.d.ts +0 -2
- package/dist/api/assemble.js +55 -54
- package/dist/api/context-select.d.ts +49 -0
- package/dist/api/context-select.js +344 -0
- package/dist/api/context.d.ts +2 -2
- package/dist/api/context.js +195 -522
- package/dist/api/drill-down.js +36 -33
- package/dist/api/promote.js +55 -66
- package/dist/api/recall.js +303 -438
- package/dist/api/sleep.js +203 -218
- package/dist/capture/compact.d.ts +1 -1
- package/dist/capture/compact.js +2 -2
- package/dist/cli/briefs.js +324 -306
- package/dist/cli/context.js +44 -34
- package/dist/cli/continuity.js +283 -271
- package/dist/cli/curate.js +35 -34
- package/dist/cli/decisions.js +333 -333
- package/dist/cli/explain.js +66 -60
- package/dist/cli/maintenance.js +62 -51
- package/dist/cli/playbooks.js +387 -370
- package/dist/cli/projects.js +8 -5
- package/dist/cli/recall.js +28 -43
- package/dist/cli/remember.js +113 -70
- package/dist/cli/session-hooks.js +100 -90
- package/dist/cli/setup.js +267 -246
- package/dist/cli/status.js +73 -64
- package/dist/cli/transfer.js +85 -99
- package/dist/compaction-record.d.ts +0 -2
- package/dist/compaction-record.js +1 -1
- package/dist/customer-notes.js +77 -68
- package/dist/dag.js +222 -186
- package/dist/decisions.js +93 -76
- package/dist/doctor.js +11 -7
- package/dist/goals.js +99 -86
- package/dist/incidents.js +45 -38
- package/dist/policies.js +85 -68
- package/dist/processes.js +87 -71
- package/dist/project-briefs.js +135 -108
- package/dist/project-merge.d.ts +12 -4
- package/dist/project-merge.js +130 -45
- package/dist/shared.d.ts +9 -0
- package/dist/shared.js +10 -8
- package/dist/skills.js +81 -65
- package/dist/store/search-rows.d.ts +2 -2
- package/dist/store/search-rows.js +15 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/cli/continuity.js
CHANGED
|
@@ -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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
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 (
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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 (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
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 (
|
|
155
|
-
|
|
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
|
-
|
|
200
|
-
process.exit(1);
|
|
293
|
+
printHandoff(handoff);
|
|
201
294
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
|
288
|
-
|
|
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 (
|
|
294
|
-
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|