@tpsdev-ai/flair 0.53.0 → 0.54.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 (97) hide show
  1. package/README.md +4 -1
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +1791 -15648
  4. package/dist/commands/agent.js +453 -0
  5. package/dist/commands/attention.js +121 -0
  6. package/dist/commands/backup.js +115 -0
  7. package/dist/commands/bootstrap.js +91 -0
  8. package/dist/commands/bridge.js +608 -0
  9. package/dist/commands/deploy.js +180 -0
  10. package/dist/commands/doctor.js +1654 -0
  11. package/dist/commands/export.js +110 -0
  12. package/dist/commands/federation.js +1575 -0
  13. package/dist/commands/fleet.js +73 -0
  14. package/dist/commands/grant.js +109 -0
  15. package/dist/commands/hook.js +193 -0
  16. package/dist/commands/idp.js +193 -0
  17. package/dist/commands/import.js +134 -0
  18. package/dist/commands/init.js +1203 -0
  19. package/dist/commands/inspect.js +45 -0
  20. package/dist/commands/keys.js +187 -0
  21. package/dist/commands/mcp.js +707 -0
  22. package/dist/commands/memory.js +501 -0
  23. package/dist/commands/migrate-harness-memory.js +270 -0
  24. package/dist/commands/orgevent.js +138 -0
  25. package/dist/commands/presence.js +76 -0
  26. package/dist/commands/principal.js +338 -0
  27. package/dist/commands/quality.js +1164 -0
  28. package/dist/commands/reembed.js +296 -0
  29. package/dist/commands/relationship.js +76 -0
  30. package/dist/commands/rem.js +1048 -0
  31. package/dist/commands/restore.js +130 -0
  32. package/dist/commands/search.js +244 -0
  33. package/dist/commands/service.js +315 -0
  34. package/dist/commands/session.js +184 -0
  35. package/dist/commands/soul.js +155 -0
  36. package/dist/commands/status.js +914 -0
  37. package/dist/commands/test.js +93 -0
  38. package/dist/commands/uninstall.js +143 -0
  39. package/dist/commands/upgrade.js +1592 -0
  40. package/dist/commands/workspace.js +114 -0
  41. package/dist/deploy.js +24 -0
  42. package/dist/fabric-npm-install.js +87 -0
  43. package/dist/federation-verify.js +498 -0
  44. package/dist/fleet-verify.js +144 -21
  45. package/dist/install/clients.js +167 -0
  46. package/dist/lib/auth-resolve.js +76 -1
  47. package/dist/lib/daemon-liveness.js +131 -2
  48. package/dist/lib/doctor-config-path.js +61 -0
  49. package/dist/lib/doctor-federation-driver.js +189 -0
  50. package/dist/lib/doctor-run.js +40 -0
  51. package/dist/lib/entity-vocab-cli.js +3 -3
  52. package/dist/lib/federation-pair-identity.js +47 -0
  53. package/dist/lib/launchd-repair.js +5 -4
  54. package/dist/lib/ops-api-bind.js +115 -0
  55. package/dist/lib/owned-pins.js +219 -0
  56. package/dist/lib/uninstall-purge.js +218 -0
  57. package/dist/rem/restore.js +8 -10
  58. package/dist/resources/AgentReadPosition.js +74 -0
  59. package/dist/resources/Federation.js +8 -2
  60. package/dist/resources/Memory.js +4 -3
  61. package/dist/resources/MemoryBootstrap.js +41 -25
  62. package/dist/resources/MemoryCandidate.js +5 -6
  63. package/dist/resources/OrgEventCatchup.js +126 -47
  64. package/dist/resources/agent-read-position-lib.js +83 -0
  65. package/dist/resources/agent-read-position.js +120 -0
  66. package/dist/resources/embeddings-boot.js +32 -0
  67. package/dist/resources/federation-peer-liveness.js +73 -0
  68. package/dist/resources/health.js +68 -19
  69. package/dist/resources/mcp-tools.js +43 -279
  70. package/dist/resources/memory-visibility.js +3 -3
  71. package/dist/resources/migration-boot.js +59 -18
  72. package/dist/resources/migrations/embedding-stamp.js +20 -1
  73. package/dist/resources/migrations/recheck.js +43 -0
  74. package/dist/resources/migrations/runner.js +6 -1
  75. package/dist/resources/migrations/stamp-outstanding.js +171 -0
  76. package/dist/resources/migrations/visibility-backfill.js +2 -2
  77. package/dist/resources/org-event-catchup-lib.js +47 -0
  78. package/dist/resources/record-owner-guard.js +1 -0
  79. package/dist/stamp-migration-verify.js +163 -0
  80. package/dist/stamp-outstanding.js +144 -0
  81. package/docs/api-reference.md +4 -2
  82. package/docs/deploying-on-fabric.md +11 -10
  83. package/docs/deployment.md +3 -1
  84. package/docs/federation.md +19 -0
  85. package/docs/hosted-on-fabric.md +3 -3
  86. package/docs/quickstart.md +2 -1
  87. package/docs/releasing.md +15 -7
  88. package/docs/spoke-bringup.md +10 -5
  89. package/docs/standalone-local.md +3 -1
  90. package/docs/upgrade.md +25 -6
  91. package/node_modules/@tpsdev-ai/flair-tool-descriptors/LICENSE +19 -0
  92. package/node_modules/@tpsdev-ai/flair-tool-descriptors/README.md +22 -0
  93. package/node_modules/@tpsdev-ai/flair-tool-descriptors/dist/index.d.ts +70 -0
  94. package/node_modules/@tpsdev-ai/flair-tool-descriptors/dist/index.js +665 -0
  95. package/node_modules/@tpsdev-ai/flair-tool-descriptors/package.json +46 -0
  96. package/package.json +9 -4
  97. package/schemas/agent.graphql +15 -0
@@ -0,0 +1,134 @@
1
+ import { defaultKeysDir, resolveAdminUser } from "../lib/auth-resolve.js";
2
+ import * as render from "../render.js";
3
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import nacl from "tweetnacl";
5
+ let cli;
6
+ /** Bind the cli-locals this module depends on. */
7
+ export function bindCli(fns) {
8
+ cli = fns;
9
+ }
10
+ function b64url(...args) {
11
+ return cli.b64url(...args);
12
+ }
13
+ function privKeyPath(...args) {
14
+ return cli.privKeyPath(...args);
15
+ }
16
+ function resolveEffectiveOpsUrl(...args) {
17
+ return cli.resolveEffectiveOpsUrl(...args);
18
+ }
19
+ function resolveHttpPort(...args) {
20
+ return cli.resolveHttpPort(...args);
21
+ }
22
+ function resolveOpsPort(...args) {
23
+ return cli.resolveOpsPort(...args);
24
+ }
25
+ function seedAgentViaOpsApi(...args) {
26
+ return cli.seedAgentViaOpsApi(...args);
27
+ }
28
+ export function register(program) {
29
+ // ─── flair import ────────────────────────────────────────────────────────────
30
+ program
31
+ .command("import <path>")
32
+ .description("Import an agent from an export file into this Flair instance")
33
+ .option("--port <port>", "Harper HTTP port")
34
+ .option("--ops-port <port>", "Harper operations API port")
35
+ .option("--url <url>", "Flair base URL (overrides --port)")
36
+ .option("--ops-target <url>", "Explicit ops API URL for the Agent seed (env: FLAIR_OPS_TARGET; bypasses port derivation). Use when --url is remote and the ops port isn't HTTP-1.")
37
+ .option("--admin-pass <pass>", "Admin password (or set FLAIR_ADMIN_PASS env)")
38
+ .option("--admin-user <name>", "Admin username for Basic auth (env: FLAIR_ADMIN_USER; default: admin)")
39
+ .option("--keys-dir <dir>", "Keys directory", defaultKeysDir())
40
+ .action(async (importPath, opts) => {
41
+ const baseUrl = opts.url ?? `http://127.0.0.1:${resolveHttpPort(opts)}`;
42
+ const opsPort = resolveOpsPort(opts);
43
+ // Resolve where the Agent record is seeded. The Agent goes through the ops
44
+ // API (the REST surface has no Agent POST handler), so a remote --url import
45
+ // must NOT silently seed on localhost (#514 — split import). Precedence:
46
+ // 1. --ops-target / FLAIR_OPS_TARGET → use directly
47
+ // 2. --url given → derive ops URL from it (port-1 convention)
48
+ // 3. neither → localhost opsPort (preserves local default)
49
+ // The remote REST base (--url) is mapped to `target` for derivation.
50
+ const seedOpsTarget = resolveEffectiveOpsUrl({ target: opts.url, opsTarget: opts.opsTarget }) ?? opsPort;
51
+ const adminPass = opts.adminPass ?? process.env.FLAIR_ADMIN_PASS ?? "";
52
+ if (!adminPass) {
53
+ console.error("Error: --admin-pass or FLAIR_ADMIN_PASS required");
54
+ process.exit(1);
55
+ }
56
+ if (!existsSync(importPath)) {
57
+ console.error(`File not found: ${importPath}`);
58
+ process.exit(1);
59
+ }
60
+ const data = JSON.parse(readFileSync(importPath, "utf-8"));
61
+ if (data.type !== "agent-export") {
62
+ console.error("Error: not an agent export file. Use 'flair restore' for full backups.");
63
+ process.exit(1);
64
+ }
65
+ const agentId = data.agent?.id;
66
+ if (!agentId) {
67
+ console.error("Error: no agent ID in export");
68
+ process.exit(1);
69
+ }
70
+ console.log(`Importing agent '${agentId}'...`);
71
+ // Register agent (generates new key if export doesn't include one)
72
+ const keysDir = opts.keysDir ?? defaultKeysDir();
73
+ mkdirSync(keysDir, { recursive: true });
74
+ const privPath = privKeyPath(agentId, keysDir);
75
+ if (data.privateKey && !existsSync(privPath)) {
76
+ // Restore exported key
77
+ writeFileSync(privPath, data.privateKey);
78
+ chmodSync(privPath, 0o600);
79
+ console.log(` Key restored: ${privPath}`);
80
+ }
81
+ else if (!existsSync(privPath)) {
82
+ // Generate new key
83
+ const kp = nacl.sign.keyPair();
84
+ writeFileSync(privPath, Buffer.from(kp.secretKey.slice(0, 32)));
85
+ chmodSync(privPath, 0o600);
86
+ console.log(` New key generated: ${privPath}`);
87
+ }
88
+ else {
89
+ console.log(` Using existing key: ${privPath}`);
90
+ }
91
+ // Read public key for registration
92
+ const seed = readFileSync(privPath);
93
+ const decodedSeed = seed.length === 32 ? seed : Buffer.from(seed.toString("utf-8").trim(), "base64");
94
+ const pubKey = decodedSeed.length === 32
95
+ ? nacl.sign.keyPair.fromSeed(new Uint8Array(decodedSeed)).publicKey
96
+ : nacl.sign.keyPair.fromSeed(new Uint8Array(decodedSeed.subarray(0, 32))).publicKey;
97
+ const pubKeyB64url = b64url(pubKey);
98
+ // Register agent via ops API (remote when --url/--ops-target points off-box)
99
+ await seedAgentViaOpsApi(seedOpsTarget, agentId, pubKeyB64url, resolveAdminUser(opts.adminUser), adminPass);
100
+ console.log(typeof seedOpsTarget === "string"
101
+ ? ` Agent registered (ops: ${seedOpsTarget})`
102
+ : ` Agent registered`);
103
+ // Restore souls before memories: refuseLearnedSoulWrite matches Memory text.
104
+ const auth = `Basic ${Buffer.from(`${resolveAdminUser(opts.adminUser)}:${adminPass}`).toString("base64")}`;
105
+ let soulCount = 0;
106
+ for (const soul of data.souls ?? []) {
107
+ try {
108
+ await fetch(`${baseUrl}/Soul/${encodeURIComponent(soul.id)}`, {
109
+ method: "PUT",
110
+ headers: { "Content-Type": "application/json", Authorization: auth },
111
+ body: JSON.stringify(soul),
112
+ });
113
+ soulCount++;
114
+ }
115
+ catch { /* skip failures */ }
116
+ }
117
+ let memCount = 0;
118
+ for (const mem of data.memories ?? []) {
119
+ try {
120
+ await fetch(`${baseUrl}/Memory/${mem.id}`, {
121
+ method: "PUT",
122
+ headers: { "Content-Type": "application/json", Authorization: auth },
123
+ body: JSON.stringify(mem),
124
+ });
125
+ memCount++;
126
+ }
127
+ catch { /* skip failures */ }
128
+ }
129
+ console.log(`\n${render.icons.ok} ${render.wrap(render.c.green, `Agent '${agentId}' imported`)}`);
130
+ console.log(render.kv("Memories", `${render.wrap(render.c.bold, String(memCount))}${render.wrap(render.c.dim, `/${(data.memories ?? []).length}`)}`));
131
+ console.log(render.kv("Souls", `${render.wrap(render.c.bold, String(soulCount))}${render.wrap(render.c.dim, `/${(data.souls ?? []).length}`)}`));
132
+ console.log(render.kv("Key", render.wrap(render.c.dim, privPath)));
133
+ });
134
+ }