@tpsdev-ai/flair 0.5.0 → 0.5.1

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/cli.js +204 -2
  2. package/package.json +3 -1
package/dist/cli.js CHANGED
@@ -1579,6 +1579,198 @@ federation
1579
1579
  process.exit(1);
1580
1580
  }
1581
1581
  });
1582
+ // ─── flair rem ───────────────────────────────────────────────────────────────
1583
+ // Memory hygiene and reflection: light (NREM), rapid (REM), restorative (deep).
1584
+ const rem = program.command("rem").description("Memory hygiene and reflection");
1585
+ rem
1586
+ .command("light")
1587
+ .description("NREM — quick cleanup: delete expired, archive old, consolidate candidates")
1588
+ .option("--port <port>", "Harper HTTP port")
1589
+ .option("--agent <id>", "Agent ID (or FLAIR_AGENT_ID env)")
1590
+ .option("--dry-run", "Preview changes without applying them")
1591
+ .action(async (opts) => {
1592
+ const agentId = opts.agent || process.env.FLAIR_AGENT_ID;
1593
+ const dryRun = !!opts.dryRun;
1594
+ console.log(`\n-- rem light${dryRun ? " (dry run)" : ""} --`);
1595
+ if (agentId)
1596
+ console.log(`Agent: ${agentId}`);
1597
+ try {
1598
+ // Step 1: Maintenance — expire + archive
1599
+ const maint = await api("POST", "/MemoryMaintenance", {
1600
+ ...(agentId ? { agentId } : {}),
1601
+ dryRun,
1602
+ });
1603
+ if (maint.error) {
1604
+ console.error(`Maintenance error: ${maint.error}`);
1605
+ process.exit(1);
1606
+ }
1607
+ const s = maint.stats ?? {};
1608
+ console.log("\nCleanup");
1609
+ console.log(` Expired (deleted): ${s.expired ?? 0}`);
1610
+ console.log(` Archived (soft): ${s.archived ?? 0}`);
1611
+ console.log(` Total scanned: ${s.total ?? 0}`);
1612
+ if (s.errors)
1613
+ console.log(` Errors: ${s.errors}`);
1614
+ // Step 2: Consolidation candidates
1615
+ if (!agentId) {
1616
+ console.log("\nConsolidation skipped — no agent ID (pass --agent or set FLAIR_AGENT_ID)");
1617
+ return;
1618
+ }
1619
+ const consol = await api("POST", "/ConsolidateMemories", {
1620
+ agentId,
1621
+ scope: "all",
1622
+ });
1623
+ if (consol.error) {
1624
+ console.error(`Consolidation error: ${consol.error}`);
1625
+ process.exit(1);
1626
+ }
1627
+ const candidates = consol.candidates ?? [];
1628
+ const promote = candidates.filter((c) => c.suggestion === "promote");
1629
+ const archive = candidates.filter((c) => c.suggestion === "archive");
1630
+ console.log("\nConsolidation candidates");
1631
+ console.log(` Promote: ${promote.length}`);
1632
+ console.log(` Archive: ${archive.length}`);
1633
+ if (promote.length > 0) {
1634
+ console.log("\n Promote:");
1635
+ for (const c of promote) {
1636
+ console.log(` [${c.memory?.id ?? "?"}] ${c.reason}`);
1637
+ }
1638
+ }
1639
+ if (archive.length > 0) {
1640
+ console.log("\n Archive:");
1641
+ for (const c of archive) {
1642
+ console.log(` [${c.memory?.id ?? "?"}] ${c.reason}`);
1643
+ }
1644
+ }
1645
+ console.log(`\nDone.${dryRun ? " No changes applied (dry run)." : ""}`);
1646
+ }
1647
+ catch (err) {
1648
+ console.error(`Error: ${err.message}`);
1649
+ process.exit(1);
1650
+ }
1651
+ });
1652
+ rem
1653
+ .command("rapid")
1654
+ .description("REM — reflection/learning: generate a structured LLM reflection prompt")
1655
+ .option("--port <port>", "Harper HTTP port")
1656
+ .option("--agent <id>", "Agent ID (or FLAIR_AGENT_ID env)")
1657
+ .option("--focus <type>", "lessons_learned | patterns | decisions | errors", "lessons_learned")
1658
+ .option("--since <date>", "ISO timestamp lower bound (default: 24h ago)")
1659
+ .action(async (opts) => {
1660
+ const agentId = opts.agent || process.env.FLAIR_AGENT_ID;
1661
+ if (!agentId) {
1662
+ console.error("Error: --agent <id> or FLAIR_AGENT_ID env required");
1663
+ process.exit(1);
1664
+ }
1665
+ console.log(`\n-- rem rapid --`);
1666
+ console.log(`Agent: ${agentId} Focus: ${opts.focus}`);
1667
+ try {
1668
+ const body = {
1669
+ agentId,
1670
+ focus: opts.focus,
1671
+ };
1672
+ if (opts.since)
1673
+ body.since = opts.since;
1674
+ const result = await api("POST", "/ReflectMemories", body);
1675
+ if (result.error) {
1676
+ console.error(`Reflection error: ${result.error}`);
1677
+ process.exit(1);
1678
+ }
1679
+ console.log(`\nSource memories: ${result.count ?? 0}`);
1680
+ if (result.suggestedTags?.length) {
1681
+ console.log(`Tags: ${result.suggestedTags.join(", ")}`);
1682
+ }
1683
+ console.log("\n--- Reflection Prompt ---");
1684
+ console.log(result.prompt ?? "(no prompt returned)");
1685
+ console.log("--- End Prompt ---\n");
1686
+ console.log("Feed the prompt above to your LLM, then write insights back with:");
1687
+ console.log(" flair memory add --agent <id> --content <insight> --durability persistent");
1688
+ }
1689
+ catch (err) {
1690
+ console.error(`Error: ${err.message}`);
1691
+ process.exit(1);
1692
+ }
1693
+ });
1694
+ rem
1695
+ .command("restorative")
1696
+ .description("Deep audit: full maintenance + consolidation (olderThan=7d) + reflection")
1697
+ .option("--port <port>", "Harper HTTP port")
1698
+ .option("--agent <id>", "Agent ID (or FLAIR_AGENT_ID env)")
1699
+ .option("--dry-run", "Preview maintenance changes without applying them")
1700
+ .action(async (opts) => {
1701
+ const agentId = opts.agent || process.env.FLAIR_AGENT_ID;
1702
+ const dryRun = !!opts.dryRun;
1703
+ console.log(`\n== rem restorative${dryRun ? " (dry run)" : ""} ==`);
1704
+ if (agentId)
1705
+ console.log(`Agent: ${agentId}`);
1706
+ try {
1707
+ // Step 1: Maintenance
1708
+ console.log("\n[1/3] Maintenance...");
1709
+ const maint = await api("POST", "/MemoryMaintenance", {
1710
+ ...(agentId ? { agentId } : {}),
1711
+ dryRun,
1712
+ });
1713
+ if (maint.error) {
1714
+ console.error(`Maintenance error: ${maint.error}`);
1715
+ process.exit(1);
1716
+ }
1717
+ const s = maint.stats ?? {};
1718
+ console.log(` Expired: ${s.expired ?? 0} Archived: ${s.archived ?? 0} Scanned: ${s.total ?? 0}${s.errors ? ` Errors: ${s.errors}` : ""}`);
1719
+ // Step 2: Consolidation (skip if no agentId)
1720
+ if (agentId) {
1721
+ console.log("\n[2/3] Consolidation (scope=all, olderThan=7d)...");
1722
+ const consol = await api("POST", "/ConsolidateMemories", {
1723
+ agentId,
1724
+ scope: "all",
1725
+ olderThan: "7d",
1726
+ });
1727
+ if (consol.error) {
1728
+ console.error(`Consolidation error: ${consol.error}`);
1729
+ process.exit(1);
1730
+ }
1731
+ const candidates = consol.candidates ?? [];
1732
+ const promote = candidates.filter((c) => c.suggestion === "promote");
1733
+ const archive = candidates.filter((c) => c.suggestion === "archive");
1734
+ console.log(` Promote candidates: ${promote.length} Archive candidates: ${archive.length}`);
1735
+ for (const c of promote) {
1736
+ console.log(` promote [${c.memory?.id ?? "?"}] ${c.reason}`);
1737
+ }
1738
+ for (const c of archive) {
1739
+ console.log(` archive [${c.memory?.id ?? "?"}] ${c.reason}`);
1740
+ }
1741
+ }
1742
+ else {
1743
+ console.log("\n[2/3] Consolidation skipped — no agent ID");
1744
+ }
1745
+ // Step 3: Reflection
1746
+ if (agentId) {
1747
+ console.log("\n[3/3] Reflection (scope=all)...");
1748
+ const reflect = await api("POST", "/ReflectMemories", {
1749
+ agentId,
1750
+ scope: "all",
1751
+ });
1752
+ if (reflect.error) {
1753
+ console.error(`Reflection error: ${reflect.error}`);
1754
+ process.exit(1);
1755
+ }
1756
+ console.log(` Source memories: ${reflect.count ?? 0}`);
1757
+ if (reflect.suggestedTags?.length) {
1758
+ console.log(` Tags: ${reflect.suggestedTags.join(", ")}`);
1759
+ }
1760
+ console.log("\n--- Reflection Prompt ---");
1761
+ console.log(reflect.prompt ?? "(no prompt returned)");
1762
+ console.log("--- End Prompt ---");
1763
+ }
1764
+ else {
1765
+ console.log("\n[3/3] Reflection skipped — no agent ID");
1766
+ }
1767
+ console.log(`\nRestorative cycle complete.${dryRun ? " No changes applied (dry run)." : ""}`);
1768
+ }
1769
+ catch (err) {
1770
+ console.error(`Error: ${err.message}`);
1771
+ process.exit(1);
1772
+ }
1773
+ });
1582
1774
  // ─── flair status ─────────────────────────────────────────────────────────────
1583
1775
  program
1584
1776
  .command("status")
@@ -1592,9 +1784,19 @@ program
1592
1784
  const baseUrl = opts.url ?? `http://127.0.0.1:${port}`;
1593
1785
  let healthy = false;
1594
1786
  let healthData = null;
1595
- // 1. Basic health check (unauthenticated just { ok: true })
1787
+ // 1. Basic health check — try unauthenticated first, then with admin auth
1596
1788
  try {
1597
- const res = await fetch(`${baseUrl}/Health`, { signal: AbortSignal.timeout(5000) });
1789
+ let res = await fetch(`${baseUrl}/Health`, { signal: AbortSignal.timeout(5000) });
1790
+ if (!res.ok && res.status === 401) {
1791
+ // Harper requires auth (authorizeLocal: true) — retry with admin credentials
1792
+ const adminPass = process.env.FLAIR_ADMIN_PASS ?? process.env.HDB_ADMIN_PASSWORD;
1793
+ if (adminPass) {
1794
+ res = await fetch(`${baseUrl}/Health`, {
1795
+ headers: { Authorization: `Basic ${Buffer.from(`admin:${adminPass}`).toString("base64")}` },
1796
+ signal: AbortSignal.timeout(5000),
1797
+ });
1798
+ }
1799
+ }
1598
1800
  healthy = res.ok;
1599
1801
  }
1600
1802
  catch { /* unreachable */ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/flair",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -40,6 +40,7 @@
40
40
  "build:cli": "tsc -p tsconfig.cli.json --noCheck",
41
41
  "prepublishOnly": "npm run build && npm run build:cli",
42
42
  "test": "bun test",
43
+ "test:e2e": "playwright test",
43
44
  "release": "./scripts/release.sh"
44
45
  },
45
46
  "publishConfig": {
@@ -56,6 +57,7 @@
56
57
  "tweetnacl": "1.0.3"
57
58
  },
58
59
  "devDependencies": {
60
+ "@playwright/test": "^1.59.1",
59
61
  "@types/node": "24.11.0",
60
62
  "bun-types": "1.3.11",
61
63
  "typescript": "5.9.3"