@ivotoby/postgram-cli 1.30.0 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +6 -0
- package/dist/pgm.js +89 -4
- package/package.json +2 -1
package/dist/client.js
CHANGED
|
@@ -49,6 +49,12 @@ export function createPgmClient(options) {
|
|
|
49
49
|
body: input
|
|
50
50
|
});
|
|
51
51
|
},
|
|
52
|
+
groomSessionContext(input) {
|
|
53
|
+
return request(options, '/api/memory/session-context/groom', {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: input
|
|
56
|
+
});
|
|
57
|
+
},
|
|
52
58
|
recallEntity(id, input = {}) {
|
|
53
59
|
const params = new URLSearchParams();
|
|
54
60
|
if (input.owner) {
|
package/dist/pgm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
-
import { createWriteStream } from 'node:fs';
|
|
3
|
+
import { createWriteStream, readFileSync } from 'node:fs';
|
|
4
4
|
import { mkdir, readFile as fsReadFile, stat } from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { Command } from 'commander';
|
|
@@ -10,6 +10,11 @@ import { handleCliFailure, isJsonMode, parseCommaList, parseJsonObject, printHum
|
|
|
10
10
|
import { AppError, ErrorCode } from './errors.js';
|
|
11
11
|
import { buildSyncManifest } from './sync-walk.js';
|
|
12
12
|
import { compactEdgeResponse, compactEntityListResponse, compactGraphResponse, compactSearchResponse, compactStoredEntityResponse, entityListResponseToToon, graphResponseToToon, searchResponseToToon } from './search-output.js';
|
|
13
|
+
function readCliVersion() {
|
|
14
|
+
const rawPackageJson = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
|
|
15
|
+
const packageJson = JSON.parse(rawPackageJson);
|
|
16
|
+
return packageJson.version;
|
|
17
|
+
}
|
|
13
18
|
function formatStoredEntity(entity) {
|
|
14
19
|
return [
|
|
15
20
|
`${entity.type} ${shortId(entity.id)}${entity.status ? ` [${entity.status}]` : ''}`,
|
|
@@ -64,6 +69,43 @@ function validateToonOptions(options, json) {
|
|
|
64
69
|
throw new AppError(ErrorCode.VALIDATION, '--toon cannot be combined with --json or --full-response');
|
|
65
70
|
}
|
|
66
71
|
}
|
|
72
|
+
function parseDurationMs(value) {
|
|
73
|
+
const match = /^(\d+)([mhd])$/i.exec(value.trim());
|
|
74
|
+
if (!match) {
|
|
75
|
+
throw new AppError(ErrorCode.VALIDATION, `Invalid duration '${value}'. Use format like '15m', '2h', or '7d'.`);
|
|
76
|
+
}
|
|
77
|
+
const [, amountText, unitText] = match;
|
|
78
|
+
const amount = Number(amountText);
|
|
79
|
+
const unit = unitText.toLowerCase();
|
|
80
|
+
const milliseconds = unit === 'm'
|
|
81
|
+
? amount * 60 * 1000
|
|
82
|
+
: unit === 'h'
|
|
83
|
+
? amount * 60 * 60 * 1000
|
|
84
|
+
: amount * 24 * 60 * 60 * 1000;
|
|
85
|
+
if (milliseconds > 3650 * 24 * 60 * 60 * 1000) {
|
|
86
|
+
throw new AppError(ErrorCode.VALIDATION, `Duration '${value}' exceeds the maximum allowed (3650 days / ~10 years).`);
|
|
87
|
+
}
|
|
88
|
+
return milliseconds;
|
|
89
|
+
}
|
|
90
|
+
function formatGroomCandidates(candidates) {
|
|
91
|
+
if (candidates.length === 0) {
|
|
92
|
+
return ['No eligible session-context memories'];
|
|
93
|
+
}
|
|
94
|
+
const lines = [`Would archive ${candidates.length} session-context memories`];
|
|
95
|
+
for (const candidate of candidates) {
|
|
96
|
+
const metadata = candidate.metadata;
|
|
97
|
+
lines.push([
|
|
98
|
+
` ${shortId(candidate.id)} ${candidate.createdAt.slice(0, 10)}`,
|
|
99
|
+
candidate.tags.length ? `tags=${candidate.tags.join(',')}` : 'tags=-',
|
|
100
|
+
metadata.topic ? `topic=${metadata.topic}` : undefined,
|
|
101
|
+
metadata.session_id ? `session=${metadata.session_id}` : undefined,
|
|
102
|
+
candidate.content ? `content=${candidate.content}` : 'content=-'
|
|
103
|
+
]
|
|
104
|
+
.filter(Boolean)
|
|
105
|
+
.join(' | '));
|
|
106
|
+
}
|
|
107
|
+
return lines;
|
|
108
|
+
}
|
|
67
109
|
async function resolveStoreContent(content) {
|
|
68
110
|
if (content !== undefined) {
|
|
69
111
|
return content;
|
|
@@ -202,6 +244,7 @@ const program = new Command();
|
|
|
202
244
|
program
|
|
203
245
|
.name('pgm')
|
|
204
246
|
.description('Postgram human CLI')
|
|
247
|
+
.version(readCliVersion())
|
|
205
248
|
.option('--json', 'emit JSON output');
|
|
206
249
|
program
|
|
207
250
|
.command('store')
|
|
@@ -259,7 +302,6 @@ program
|
|
|
259
302
|
.option('--expand-graph', 'include graph-connected entities in results')
|
|
260
303
|
.option('--include-archived', 'include archived entities in results')
|
|
261
304
|
.option('--memory-role <role>', 'memory role filter: durable_memory or session_context')
|
|
262
|
-
.option('--include-other-clients-session-context', 'include session context from other clients')
|
|
263
305
|
.option('--full-response', 'emit the full API response instead of compact default output when used with --json')
|
|
264
306
|
.option('--toon', 'emit compact TOON output for lower agent token use; formatting is applied in the CLI, not the API')
|
|
265
307
|
.action(async (query, options, command) => {
|
|
@@ -282,8 +324,7 @@ program
|
|
|
282
324
|
recency_weight: Number(options.recencyWeight),
|
|
283
325
|
expand_graph: options.expandGraph === true ? true : undefined,
|
|
284
326
|
include_archived: options.includeArchived === true ? true : undefined,
|
|
285
|
-
memory_role: options.memoryRole
|
|
286
|
-
include_other_clients_session_context: options.includeOtherClientsSessionContext === true ? true : undefined
|
|
327
|
+
memory_role: options.memoryRole
|
|
287
328
|
});
|
|
288
329
|
if (options.toon === true) {
|
|
289
330
|
return searchResponseToToon(compactSearchResponse(body));
|
|
@@ -299,6 +340,50 @@ program
|
|
|
299
340
|
const memoryCommand = program
|
|
300
341
|
.command('memory')
|
|
301
342
|
.description('Memory-specific commands');
|
|
343
|
+
memoryCommand
|
|
344
|
+
.command('groom')
|
|
345
|
+
.description('Preview or archive stale session-context memories for the authenticated client')
|
|
346
|
+
.option('--dry-run', 'preview without mutating')
|
|
347
|
+
.option('--older-than <duration>', 'only include memories older than this (e.g. 15m, 2h, 7d)', '7d')
|
|
348
|
+
.option('--limit <limit>', 'maximum candidates', '50')
|
|
349
|
+
.option('--topic <topic>', 'filter by topic')
|
|
350
|
+
.option('--session-id <sessionId>', 'filter by session id')
|
|
351
|
+
.option('--tag <tag>', 'filter by tag (repeatable)', (value, previous = []) => {
|
|
352
|
+
previous.push(value);
|
|
353
|
+
return previous;
|
|
354
|
+
}, [])
|
|
355
|
+
.option('--yes', 'confirm archive mutation')
|
|
356
|
+
.action(async (options, command) => {
|
|
357
|
+
await runWithClient(command, async (client, json) => {
|
|
358
|
+
const limit = Number.parseInt(options.limit, 10);
|
|
359
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
360
|
+
throw new AppError(ErrorCode.VALIDATION, '--limit must be a positive integer');
|
|
361
|
+
}
|
|
362
|
+
if (options.dryRun !== true && options.yes !== true) {
|
|
363
|
+
throw new AppError(ErrorCode.VALIDATION, '--yes is required outside dry-run');
|
|
364
|
+
}
|
|
365
|
+
const body = await client.groomSessionContext({
|
|
366
|
+
dry_run: options.dryRun === true,
|
|
367
|
+
confirmed: options.dryRun === true ? undefined : true,
|
|
368
|
+
older_than_ms: parseDurationMs(options.olderThan),
|
|
369
|
+
limit,
|
|
370
|
+
topic: options.topic,
|
|
371
|
+
session_id: options.sessionId,
|
|
372
|
+
tags: options.tag
|
|
373
|
+
});
|
|
374
|
+
if (json) {
|
|
375
|
+
return body;
|
|
376
|
+
}
|
|
377
|
+
if (body.dryRun) {
|
|
378
|
+
return formatGroomCandidates(body.eligible ?? []);
|
|
379
|
+
}
|
|
380
|
+
return [
|
|
381
|
+
`Archived ${body.archived} session-context memories`,
|
|
382
|
+
` promoted: ${body.promoted}`,
|
|
383
|
+
` skipped: ${body.skipped}`
|
|
384
|
+
];
|
|
385
|
+
});
|
|
386
|
+
});
|
|
302
387
|
memoryCommand
|
|
303
388
|
.command('session-context')
|
|
304
389
|
.alias('session')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ivotoby/postgram-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.0",
|
|
4
4
|
"description": "Postgram CLI — store, search, and manage entities from the command line",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsc -p tsconfig.build.json",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
36
37
|
"prepublishOnly": "npm run build",
|
|
37
38
|
"test": "vitest run",
|
|
38
39
|
"test:watch": "vitest",
|