@remnic/cli 9.69.53 → 9.69.54

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 (2) hide show
  1. package/dist/index.js +300 -12
  2. package/package.json +32 -32
package/dist/index.js CHANGED
@@ -1403,7 +1403,15 @@ async function runJournalVaultBinaryCommand(rest) {
1403
1403
  }
1404
1404
 
1405
1405
  // src/commands/activity-privacy.ts
1406
- import { parseFlexibleIsoTimestamp, shouldRetain } from "@remnic/core";
1406
+ import {
1407
+ ACTIVITY_DELETE_SCOPES,
1408
+ normalizeDropKeys,
1409
+ parseFlexibleIsoTimestamp,
1410
+ planActivityDeletion,
1411
+ redactActivityFields,
1412
+ resolveActivityGates,
1413
+ shouldRetain
1414
+ } from "@remnic/core";
1407
1415
  var defaultIo2 = {
1408
1416
  stdout: (line) => {
1409
1417
  process.stdout.write(`${line}
@@ -1415,9 +1423,18 @@ var defaultIo2 = {
1415
1423
  }
1416
1424
  };
1417
1425
  function activityPrivacyHelp() {
1418
- return `Usage: remnic activity-privacy retain --captured <iso> --now <iso> --days <n> [--enabled <true|false>]
1426
+ return `Usage: remnic activity-privacy <action> [options]
1419
1427
 
1420
- retain Print retain=true or retain=false. --days 0 keeps forever.
1428
+ retain --captured <iso> --now <iso> --days <n> [--enabled <true|false>]
1429
+ Print retain=true or retain=false. --days 0 keeps forever.
1430
+ delete --scope <name> [--scope <name>...] --now <iso> [--retention-days <n>] [--enabled <true|false>]
1431
+ Read {"scope","relPath","capturedAtMs"} JSON lines on stdin; print the
1432
+ deletion plan {"deletePaths","keptCount","refused"}. Dry-run only.
1433
+ Scopes: ${ACTIVITY_DELETE_SCOPES.join(", ")}.
1434
+ redact --keys <comma,list>
1435
+ Read one JSON object on stdin; print it without the listed keys.
1436
+ gates [--enabled <true|false>] [--analysis|--journal|--weekly|--export|--memory-creation <true|false>]
1437
+ Print the resolved gate set. Master off forces every gate off.
1421
1438
  `;
1422
1439
  }
1423
1440
  function parseEnabled(rest, io) {
@@ -1434,16 +1451,178 @@ function parseEnabled(rest, io) {
1434
1451
  io.stderr("activity-privacy: --enabled must be true or false");
1435
1452
  return void 0;
1436
1453
  }
1437
- function runActivityPrivacyCommand(rest, io = defaultIo2) {
1438
- if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h" || rest[0] === "help") {
1439
- io.stdout(activityPrivacyHelp().trimEnd());
1454
+ function flagValues(rest, flag) {
1455
+ const values = [];
1456
+ let missingValue = false;
1457
+ for (let i = 0; i < rest.length; i += 1) {
1458
+ if (rest[i] === flag) {
1459
+ const next = rest[i + 1];
1460
+ if (next === void 0 || next.startsWith("--")) {
1461
+ missingValue = true;
1462
+ } else {
1463
+ values.push(next);
1464
+ }
1465
+ }
1466
+ }
1467
+ return { values, missingValue };
1468
+ }
1469
+ function runActivityDeleteCommand(rest, candidateLines, io = defaultIo2) {
1470
+ const enabled = parseEnabled(rest, io);
1471
+ if (enabled === void 0) return 1;
1472
+ if (!enabled) {
1473
+ io.stderr("activity-privacy: activity is disabled; delete refused");
1474
+ return 1;
1475
+ }
1476
+ const { values: scopes, missingValue } = flagValues(rest, "--scope");
1477
+ if (missingValue) {
1478
+ io.stderr("activity-privacy: --scope requires a scope name");
1479
+ return 1;
1480
+ }
1481
+ if (scopes.length === 0) {
1482
+ io.stderr("activity-privacy: delete requires at least one --scope");
1483
+ return 1;
1484
+ }
1485
+ const nowRaw = resolveFlag(rest, "--now");
1486
+ if (nowRaw === void 0) {
1487
+ io.stderr("activity-privacy: delete requires --now <iso>");
1488
+ return 1;
1489
+ }
1490
+ const nowMs = parseFlexibleIsoTimestamp(nowRaw);
1491
+ if (nowMs === null) {
1492
+ io.stderr("activity-privacy: --now must be an ISO timestamp");
1493
+ return 1;
1494
+ }
1495
+ const daysRaw = resolveFlag(rest, "--retention-days");
1496
+ let retentionDays = 0;
1497
+ if (daysRaw !== void 0) {
1498
+ const days = Number(daysRaw);
1499
+ if (!Number.isInteger(days) || days < 0) {
1500
+ io.stderr("activity-privacy: --retention-days must be a non-negative integer");
1501
+ return 1;
1502
+ }
1503
+ retentionDays = days;
1504
+ }
1505
+ const candidates = [];
1506
+ let lineNo = 0;
1507
+ for (const line of candidateLines) {
1508
+ lineNo += 1;
1509
+ const text = line.trim();
1510
+ if (text.length === 0) continue;
1511
+ let parsed;
1512
+ try {
1513
+ parsed = JSON.parse(text);
1514
+ } catch {
1515
+ io.stderr(`activity-privacy: candidate line ${lineNo} is not valid JSON`);
1516
+ return 1;
1517
+ }
1518
+ const record2 = parsed;
1519
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof record2.scope !== "string" || typeof record2.relPath !== "string" || typeof record2.capturedAtMs !== "number" || !Number.isFinite(record2.capturedAtMs)) {
1520
+ io.stderr(
1521
+ `activity-privacy: candidate line ${lineNo} must be {"scope": string, "relPath": string, "capturedAtMs": number}`
1522
+ );
1523
+ return 1;
1524
+ }
1525
+ candidates.push({
1526
+ scope: record2.scope,
1527
+ relPath: record2.relPath,
1528
+ capturedAtMs: record2.capturedAtMs
1529
+ });
1530
+ }
1531
+ try {
1532
+ const plan = planActivityDeletion({ candidates, scopes, retentionDays, nowMs });
1533
+ io.stdout(JSON.stringify(plan));
1440
1534
  return 0;
1535
+ } catch (err) {
1536
+ io.stderr(`activity-privacy: ${err.message}`);
1537
+ return 1;
1538
+ }
1539
+ }
1540
+ function runActivityRedactCommand(rest, stdinLines, io = defaultIo2) {
1541
+ const keysRaw = resolveFlag(rest, "--keys");
1542
+ if (keysRaw === void 0) {
1543
+ io.stderr("activity-privacy: redact requires --keys <comma,list>");
1544
+ return 1;
1441
1545
  }
1442
- if (rest[0] !== "retain") {
1443
- io.stderr(`activity-privacy: unknown action "${rest[0]}".`);
1444
- io.stderr(activityPrivacyHelp().trimEnd());
1546
+ const text = stdinLines.join("\n").trim();
1547
+ if (text.length === 0) {
1548
+ io.stderr("activity-privacy: redact requires one JSON object on stdin");
1445
1549
  return 1;
1446
1550
  }
1551
+ let parsed;
1552
+ try {
1553
+ parsed = JSON.parse(text);
1554
+ } catch {
1555
+ io.stderr("activity-privacy: redact input is not valid JSON");
1556
+ return 1;
1557
+ }
1558
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1559
+ io.stderr("activity-privacy: redact input must be a JSON object");
1560
+ return 1;
1561
+ }
1562
+ const dropKeys = normalizeDropKeys(keysRaw.split(","));
1563
+ const redacted = redactActivityFields(parsed, { dropKeys });
1564
+ io.stdout(JSON.stringify(redacted));
1565
+ return 0;
1566
+ }
1567
+ var GATE_FLAGS = {
1568
+ "--analysis": "analysis",
1569
+ "--journal": "journal",
1570
+ "--weekly": "weekly",
1571
+ "--export": "export",
1572
+ "--memory-creation": "memoryCreation"
1573
+ };
1574
+ function runActivityGatesCommand(rest, io = defaultIo2) {
1575
+ const known = /* @__PURE__ */ new Set(["--enabled", ...Object.keys(GATE_FLAGS)]);
1576
+ for (const token of rest) {
1577
+ if (token.startsWith("--") && !known.has(token)) {
1578
+ io.stderr(`activity-privacy: unknown gate flag ${token}`);
1579
+ return 1;
1580
+ }
1581
+ }
1582
+ const parseGateValue = (flag) => {
1583
+ if (!hasFlag(rest, flag)) return { error: false };
1584
+ const raw = resolveFlag(rest, flag);
1585
+ if (raw === void 0) {
1586
+ io.stderr(`activity-privacy: ${flag} requires true or false`);
1587
+ return { error: true };
1588
+ }
1589
+ if (raw === "true") return { error: false, value: true };
1590
+ if (raw === "false") return { error: false, value: false };
1591
+ io.stderr(`activity-privacy: ${flag} must be true or false`);
1592
+ return { error: true };
1593
+ };
1594
+ const enabledResult = parseGateValue("--enabled");
1595
+ if (enabledResult.error) return 1;
1596
+ const gates = {};
1597
+ for (const [flag, gate] of Object.entries(GATE_FLAGS)) {
1598
+ const result = parseGateValue(flag);
1599
+ if (result.error) return 1;
1600
+ if (result.value !== void 0) gates[gate] = result.value;
1601
+ }
1602
+ const enabled = enabledResult.value ?? false;
1603
+ try {
1604
+ const resolved = resolveActivityGates({ enabled, gates });
1605
+ io.stdout(JSON.stringify(resolved));
1606
+ return 0;
1607
+ } catch (err) {
1608
+ io.stderr(`activity-privacy: ${err.message}`);
1609
+ return 1;
1610
+ }
1611
+ }
1612
+ function runActivityPrivacyCommand(rest, io = defaultIo2, stdinLines = []) {
1613
+ if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h" || rest[0] === "help") {
1614
+ io.stdout(activityPrivacyHelp().trimEnd());
1615
+ return 0;
1616
+ }
1617
+ if (rest[0] === "retain") return runRetain(rest, io);
1618
+ if (rest[0] === "delete") return runActivityDeleteCommand(rest, stdinLines, io);
1619
+ if (rest[0] === "redact") return runActivityRedactCommand(rest, stdinLines, io);
1620
+ if (rest[0] === "gates") return runActivityGatesCommand(rest, io);
1621
+ io.stderr(`activity-privacy: unknown action "${rest[0]}".`);
1622
+ io.stderr(activityPrivacyHelp().trimEnd());
1623
+ return 1;
1624
+ }
1625
+ function runRetain(rest, io) {
1447
1626
  const capturedRaw = resolveFlag(rest, "--captured");
1448
1627
  const nowRaw = resolveFlag(rest, "--now");
1449
1628
  const daysRaw = resolveFlag(rest, "--days");
@@ -1467,8 +1646,17 @@ function runActivityPrivacyCommand(rest, io = defaultIo2) {
1467
1646
  io.stdout(`retain=${shouldRetain(capturedAtMs, nowMs, days, enabled)}`);
1468
1647
  return 0;
1469
1648
  }
1649
+ async function readStdinLines() {
1650
+ const chunks = [];
1651
+ for await (const chunk of process.stdin) {
1652
+ chunks.push(chunk);
1653
+ }
1654
+ return Buffer.concat(chunks).toString("utf8").split("\n");
1655
+ }
1470
1656
  async function runActivityPrivacyBinaryCommand(rest) {
1471
- const code = runActivityPrivacyCommand(rest);
1657
+ const stdinNeeded = rest[0] === "delete" || rest[0] === "redact";
1658
+ const stdinLines = stdinNeeded && !process.stdin.isTTY ? await readStdinLines() : [];
1659
+ const code = runActivityPrivacyCommand(rest, defaultIo2, stdinLines);
1472
1660
  if (code !== 0) process.exitCode = code;
1473
1661
  }
1474
1662
 
@@ -1560,10 +1748,107 @@ async function runActivityExportBinaryCommand(rest) {
1560
1748
  if (code !== 0) process.exitCode = code;
1561
1749
  }
1562
1750
 
1751
+ // src/commands/activity-status.ts
1752
+ import { buildActivityHealth } from "@remnic/core";
1753
+ var defaultIo4 = {
1754
+ stdout: (line) => {
1755
+ process.stdout.write(`${line}
1756
+ `);
1757
+ },
1758
+ stderr: (line) => {
1759
+ process.stderr.write(`${line}
1760
+ `);
1761
+ }
1762
+ };
1763
+ function activityStatusHelp() {
1764
+ return `Usage: remnic activity-status [--enabled <true|false>] [--retention-days <n>] [--observations <n>]
1765
+ [--cards <n>] [--analysis <ok|failed|skipped|never>] [--source-revision <id>]
1766
+
1767
+ Print the content-free activity health snapshot as one JSON line.
1768
+ Defaults: enabled=false, retention-days=30, observations=0, cards=0,
1769
+ analysis=never, source-revision=null.
1770
+ `;
1771
+ }
1772
+ function parseBoolFlag(rest, flag, fallback, io) {
1773
+ const raw = resolveFlag(rest, flag);
1774
+ if (raw === void 0) {
1775
+ if (hasFlag(rest, flag)) {
1776
+ io.stderr(`activity-status: ${flag} requires true or false`);
1777
+ return void 0;
1778
+ }
1779
+ return fallback;
1780
+ }
1781
+ if (raw === "true") return true;
1782
+ if (raw === "false") return false;
1783
+ io.stderr(`activity-status: ${flag} must be true or false`);
1784
+ return void 0;
1785
+ }
1786
+ function parseCountFlag(rest, flag, field, fallback, io) {
1787
+ const raw = resolveFlag(rest, flag);
1788
+ if (raw === void 0) {
1789
+ if (hasFlag(rest, flag)) {
1790
+ io.stderr(`activity-status: ${field} must be a non-negative integer`);
1791
+ return void 0;
1792
+ }
1793
+ return fallback;
1794
+ }
1795
+ const value = Number(raw);
1796
+ if (!Number.isInteger(value) || value < 0) {
1797
+ io.stderr(`activity-status: ${field} must be a non-negative integer`);
1798
+ return void 0;
1799
+ }
1800
+ return value;
1801
+ }
1802
+ function runActivityStatusCommand(rest, io = defaultIo4) {
1803
+ if (rest[0] === "--help" || rest[0] === "-h" || rest[0] === "help") {
1804
+ io.stdout(activityStatusHelp().trimEnd());
1805
+ return 0;
1806
+ }
1807
+ const enabled = parseBoolFlag(rest, "--enabled", false, io);
1808
+ if (enabled === void 0) return 1;
1809
+ const retentionDays = parseCountFlag(rest, "--retention-days", "retentionDays", 30, io);
1810
+ if (retentionDays === void 0) return 1;
1811
+ const observationCount = parseCountFlag(rest, "--observations", "observationCount", 0, io);
1812
+ if (observationCount === void 0) return 1;
1813
+ const cardCount = parseCountFlag(rest, "--cards", "cardCount", 0, io);
1814
+ if (cardCount === void 0) return 1;
1815
+ const analysisRaw = resolveFlag(rest, "--analysis");
1816
+ if (hasFlag(rest, "--analysis") && analysisRaw === void 0) {
1817
+ io.stderr("activity-status: --analysis requires one of ok, failed, skipped, never");
1818
+ return 1;
1819
+ }
1820
+ if (analysisRaw !== void 0 && !["ok", "failed", "skipped", "never"].includes(analysisRaw)) {
1821
+ io.stderr(
1822
+ `activity-status: unknown analysis status ${JSON.stringify(analysisRaw)}; expected one of: ok, failed, skipped, never`
1823
+ );
1824
+ return 1;
1825
+ }
1826
+ const sourceRevision = resolveFlag(rest, "--source-revision");
1827
+ try {
1828
+ const snapshot = buildActivityHealth({
1829
+ enabled,
1830
+ retentionDays,
1831
+ sourceRevision,
1832
+ lastAnalysisStatus: analysisRaw ?? null,
1833
+ observationCount,
1834
+ cardCount
1835
+ });
1836
+ io.stdout(JSON.stringify(snapshot));
1837
+ return 0;
1838
+ } catch (err) {
1839
+ io.stderr(`activity-status: ${err.message}`);
1840
+ return 1;
1841
+ }
1842
+ }
1843
+ async function runActivityStatusBinaryCommand(rest) {
1844
+ const code = runActivityStatusCommand(rest);
1845
+ if (code !== 0) process.exitCode = code;
1846
+ }
1847
+
1563
1848
  // src/commands/vault-publish.ts
1564
1849
  import fs12 from "fs";
1565
1850
  import { applyManagedRegion } from "@remnic/core";
1566
- var defaultIo4 = {
1851
+ var defaultIo5 = {
1567
1852
  stdout: (line) => {
1568
1853
  process.stdout.write(`${line}
1569
1854
  `);
@@ -1579,7 +1864,7 @@ function vaultPublishHelp() {
1579
1864
  apply Replace the marked region. Missing markers print no_marker.
1580
1865
  `;
1581
1866
  }
1582
- function runVaultPublishCommand(rest, io = defaultIo4) {
1867
+ function runVaultPublishCommand(rest, io = defaultIo5) {
1583
1868
  if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h" || rest[0] === "help") {
1584
1869
  io.stdout(vaultPublishHelp().trimEnd());
1585
1870
  return 0;
@@ -18869,6 +19154,9 @@ Other:
18869
19154
  case "activity-export":
18870
19155
  await runActivityExportBinaryCommand(rest);
18871
19156
  break;
19157
+ case "activity-status":
19158
+ await runActivityStatusBinaryCommand(rest);
19159
+ break;
18872
19160
  case "vault-publish":
18873
19161
  await runVaultPublishBinaryCommand(rest);
18874
19162
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/cli",
3
- "version": "9.69.53",
3
+ "version": "9.69.54",
4
4
  "description": "CLI for Remnic memory — init, query, doctor, daemon management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,26 +26,26 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "yaml": "^2.4.2",
29
- "@remnic/plugin-pi": "^9.69.53",
30
- "@remnic/server": "^9.69.53",
31
- "@remnic/core": "^9.69.53"
29
+ "@remnic/core": "^9.69.54",
30
+ "@remnic/plugin-pi": "^9.69.54",
31
+ "@remnic/server": "^9.69.54"
32
32
  },
33
33
  "peerDependencies": {
34
- "@remnic/bench": "^9.69.53",
35
- "@remnic/plugin-openclaw": "^9.69.53",
36
- "@remnic/export-weclone": "^9.69.53",
37
- "@remnic/import-weclone": "^9.69.53",
38
- "@remnic/import-chatgpt": "^9.69.53",
39
- "@remnic/import-claude": "^9.69.53",
40
- "@remnic/import-gemini": "^9.69.53",
41
- "@remnic/import-lossless-claw": "^9.69.53",
42
- "@remnic/import-mem0": "^9.69.53",
43
- "@remnic/import-supermemory": "^9.69.53",
44
- "@remnic/import-okf": "^9.69.53",
45
- "@remnic/connector-limitless": "^9.69.53",
46
- "@remnic/connector-bee": "^9.69.53",
47
- "@remnic/connector-omi": "^9.69.53",
48
- "@remnic/capture-audio": "^9.69.53"
34
+ "@remnic/bench": "^9.69.54",
35
+ "@remnic/plugin-openclaw": "^9.69.54",
36
+ "@remnic/export-weclone": "^9.69.54",
37
+ "@remnic/import-weclone": "^9.69.54",
38
+ "@remnic/import-chatgpt": "^9.69.54",
39
+ "@remnic/import-claude": "^9.69.54",
40
+ "@remnic/import-gemini": "^9.69.54",
41
+ "@remnic/import-lossless-claw": "^9.69.54",
42
+ "@remnic/import-mem0": "^9.69.54",
43
+ "@remnic/import-supermemory": "^9.69.54",
44
+ "@remnic/import-okf": "^9.69.54",
45
+ "@remnic/connector-limitless": "^9.69.54",
46
+ "@remnic/connector-bee": "^9.69.54",
47
+ "@remnic/connector-omi": "^9.69.54",
48
+ "@remnic/capture-audio": "^9.69.54"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "@remnic/bench": {
@@ -97,19 +97,19 @@
97
97
  "devDependencies": {
98
98
  "tsup": "^8.5.1",
99
99
  "typescript": "^5.9.3",
100
- "@remnic/bench": "9.69.53",
101
- "@remnic/plugin-openclaw": "9.69.53",
102
- "@remnic/import-weclone": "9.69.53",
103
- "@remnic/import-chatgpt": "9.69.53",
104
- "@remnic/import-mem0": "9.69.53",
105
- "@remnic/export-weclone": "9.69.53",
106
- "@remnic/import-lossless-claw": "9.69.53",
107
- "@remnic/import-gemini": "9.69.53",
108
- "@remnic/import-claude": "9.69.53",
109
- "@remnic/import-supermemory": "9.69.53",
110
- "@remnic/connector-limitless": "9.69.53",
111
- "@remnic/connector-bee": "9.69.53",
112
- "@remnic/connector-omi": "9.69.53"
100
+ "@remnic/bench": "9.69.54",
101
+ "@remnic/plugin-openclaw": "9.69.54",
102
+ "@remnic/import-weclone": "9.69.54",
103
+ "@remnic/import-chatgpt": "9.69.54",
104
+ "@remnic/export-weclone": "9.69.54",
105
+ "@remnic/import-gemini": "9.69.54",
106
+ "@remnic/import-mem0": "9.69.54",
107
+ "@remnic/import-lossless-claw": "9.69.54",
108
+ "@remnic/import-claude": "9.69.54",
109
+ "@remnic/import-supermemory": "9.69.54",
110
+ "@remnic/connector-limitless": "9.69.54",
111
+ "@remnic/connector-bee": "9.69.54",
112
+ "@remnic/connector-omi": "9.69.54"
113
113
  },
114
114
  "license": "MIT",
115
115
  "repository": {