@tpsdev-ai/flair 0.28.0 → 0.30.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.
Files changed (102) hide show
  1. package/README.md +1 -1
  2. package/dist/bridges/builtins/index.js +1 -1
  3. package/dist/bridges/discover.js +1 -1
  4. package/dist/bridges/runtime/load-plugin.js +1 -1
  5. package/dist/bridges/scaffold.js +3 -3
  6. package/dist/bridges/types.js +1 -1
  7. package/dist/cli-shim.cjs +1 -1
  8. package/dist/cli.js +357 -130
  9. package/dist/deploy.js +29 -19
  10. package/dist/fabric-upgrade.js +61 -23
  11. package/dist/fleet-verify.js +3 -3
  12. package/dist/lib/mcp-enable.js +2 -2
  13. package/dist/rem/runner.js +2 -2
  14. package/dist/rem/scheduler.js +226 -17
  15. package/dist/resources/A2AAdapter.js +1 -1
  16. package/dist/resources/Admin.js +1 -1
  17. package/dist/resources/AdminConnectors.js +1 -1
  18. package/dist/resources/AdminDashboard.js +1 -1
  19. package/dist/resources/AdminIdp.js +1 -1
  20. package/dist/resources/AdminInstance.js +1 -1
  21. package/dist/resources/AdminMemory.js +1 -1
  22. package/dist/resources/AdminPrincipals.js +1 -1
  23. package/dist/resources/Agent.js +1 -1
  24. package/dist/resources/AgentCard.js +1 -1
  25. package/dist/resources/AgentSeed.js +1 -1
  26. package/dist/resources/AttentionQuery.js +1 -1
  27. package/dist/resources/Credential.js +1 -1
  28. package/dist/resources/Federation.js +1 -1
  29. package/dist/resources/Instance.js +1 -1
  30. package/dist/resources/Integration.js +1 -1
  31. package/dist/resources/MCPClientMetadata.js +1 -1
  32. package/dist/resources/Memory.js +1 -1
  33. package/dist/resources/MemoryBootstrap.js +1 -1
  34. package/dist/resources/MemoryCandidate.js +168 -0
  35. package/dist/resources/MemoryConsolidate.js +1 -1
  36. package/dist/resources/MemoryDedupStats.js +1 -1
  37. package/dist/resources/MemoryFeed.js +1 -1
  38. package/dist/resources/MemoryGrant.js +1 -1
  39. package/dist/resources/MemoryMaintenance.js +1 -1
  40. package/dist/resources/MemoryReflect.js +3 -3
  41. package/dist/resources/MemoryReindex.js +1 -1
  42. package/dist/resources/MemoryUsage.js +1 -1
  43. package/dist/resources/OAuth.js +1 -1
  44. package/dist/resources/OAuthClient.js +1 -1
  45. package/dist/resources/OrgEvent.js +1 -1
  46. package/dist/resources/OrgEventCatchup.js +1 -1
  47. package/dist/resources/OrgEventMaintenance.js +1 -1
  48. package/dist/resources/PairingToken.js +1 -1
  49. package/dist/resources/Peer.js +1 -1
  50. package/dist/resources/Presence.js +3 -3
  51. package/dist/resources/RecordUsage.js +16 -2
  52. package/dist/resources/Relationship.js +1 -1
  53. package/dist/resources/SemanticSearch.js +1 -1
  54. package/dist/resources/SkillScan.js +1 -1
  55. package/dist/resources/Soul.js +1 -1
  56. package/dist/resources/SoulFeed.js +1 -1
  57. package/dist/resources/WorkspaceLatest.js +1 -1
  58. package/dist/resources/WorkspaceState.js +1 -1
  59. package/dist/resources/XAA.js +1 -1
  60. package/dist/resources/a2a-url.js +1 -1
  61. package/dist/resources/agent-auth.js +1 -1
  62. package/dist/resources/agentcard-fields.js +1 -1
  63. package/dist/resources/auth-middleware.js +1 -1
  64. package/dist/resources/embeddings-boot.js +4 -4
  65. package/dist/resources/embeddings-provider.js +13 -43
  66. package/dist/resources/federation-cleanup.js +5 -5
  67. package/dist/resources/federation-nonce-store.js +5 -5
  68. package/dist/resources/health.js +29 -6
  69. package/dist/resources/instance-identity.js +1 -1
  70. package/dist/resources/mcp-client-metadata-fields.js +1 -1
  71. package/dist/resources/mcp-handler.js +1 -1
  72. package/dist/resources/mcp-oauth.js +2 -2
  73. package/dist/resources/mcp-tools.js +9 -1
  74. package/dist/resources/memory-read-scope.js +1 -1
  75. package/dist/resources/memory-reflect-lib.js +4 -4
  76. package/dist/resources/memory-visibility.js +3 -3
  77. package/dist/resources/migration-boot.js +1 -1
  78. package/dist/resources/migrations/embedding-stamp.js +3 -3
  79. package/dist/resources/migrations/graph-heal.js +2 -2
  80. package/dist/resources/migrations/ledger.js +1 -1
  81. package/dist/resources/migrations/registry.js +14 -5
  82. package/dist/resources/migrations/runner.js +64 -11
  83. package/dist/resources/migrations/synthetic-test-migration.js +1 -1
  84. package/dist/resources/migrations/visibility-backfill.js +232 -0
  85. package/dist/resources/models-dir.js +55 -0
  86. package/dist/resources/record-types.js +30 -2
  87. package/dist/resources/rerank-provider.js +24 -4
  88. package/dist/resources/semantic-retrieval-core.js +1 -1
  89. package/dist/resources/usage-recording.js +73 -7
  90. package/dist/resources/version.js +33 -0
  91. package/dist/src/rem/scheduler.js +449 -0
  92. package/docs/assets/flair-cross-orchestrator.cast +1 -1
  93. package/docs/bridges.md +3 -3
  94. package/docs/deployment.md +1 -0
  95. package/docs/mcp-clients.md +3 -1
  96. package/docs/n8n.md +1 -2
  97. package/docs/notes/rem-ux.md +1 -1
  98. package/docs/rem.md +2 -0
  99. package/docs/supply-chain-policy.md +4 -4
  100. package/docs/upgrade.md +2 -2
  101. package/package.json +4 -4
  102. package/schemas/memory.graphql +27 -12
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { resolveAgentAuth, allowVerified } from "./agent-auth.js";
3
3
  const FORBIDDEN = (msg) => new Response(JSON.stringify({ error: msg }), { status: 403, headers: { "Content-Type": "application/json" } });
4
4
  const UNAUTH = () => new Response(JSON.stringify({ error: "authentication required" }), { status: 401, headers: { "Content-Type": "application/json" } });
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from "@harperfast/harper";
1
+ import { Resource, databases } from "harper";
2
2
  import { mcpIssuer } from "./mcp-oauth-flag.js";
3
3
  import { agentPublicKeyToJwk, buildCimdDocument } from "./mcp-client-metadata-fields.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { patchRecord, withDetachedTxn } from "./table-helpers.js";
3
3
  import { isAdmin, resolveAgentAuth } from "./agent-auth.js";
4
4
  import { localInstanceId } from "./instance-identity.js";
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from "@harperfast/harper";
1
+ import { Resource, databases } from "harper";
2
2
  import { allowVerified, resolveAgentAuth } from "./agent-auth.js";
3
3
  import { getEmbedding } from "./embeddings-provider.js";
4
4
  import { wrapUntrusted } from "./content-safety.js";
@@ -0,0 +1,168 @@
1
+ import { databases } from "harper";
2
+ import { resolveAgentAuth } from "./agent-auth.js";
3
+ import { makeAuthGate, makeReadScope, makeByIdReadGate, resolveAuthGate, stampAttribution, FORBIDDEN, UNAUTH, } from "./record-type-kit.js";
4
+ import { RECORD_TYPES } from "./record-types.js";
5
+ // Parameterized from RECORD_TYPES.MemoryCandidate (record-types slice 2,
6
+ // flair#520) rather than a hand-typed "owner-only" literal — the registry is
7
+ // the single source of truth this class draws its read-scope mode from.
8
+ // Exported solely so test/unit/record-types-registry.test.ts's drift
9
+ // tripwire can introspect the composed resolver's tagged `.mode`/
10
+ // `.ownerField` against RECORD_TYPES.MemoryCandidate — not for any other
11
+ // runtime consumer.
12
+ export const memoryCandidateReadScope = makeReadScope(RECORD_TYPES.MemoryCandidate.readScope, RECORD_TYPES.MemoryCandidate.ownerField);
13
+ const memoryCandidateByIdReadGate = makeByIdReadGate(memoryCandidateReadScope);
14
+ // See makeAuthGate's doc (record-type-kit.ts): must be wired as a genuine
15
+ // prototype method below, never a class-field assignment.
16
+ const memoryCandidateAuthGate = makeAuthGate();
17
+ /**
18
+ * MemoryCandidate resource — closes flair#849.
19
+ *
20
+ * The schema (schemas/memory.graphql) declared `@table` for this type with
21
+ * no `@export` and no resource file at all, so it had NO REST surface —
22
+ * `flair rem candidates`/`promote`/`reject` (src/cli.ts) all 404'd on every
23
+ * call, a clean-room dogfood blocker. Adding bare `@export` would have
24
+ * reopened the exact P0 leak the memory-soul-read-gate family fix closed for
25
+ * every other agent-facing table: Harper's `Resource` default is
26
+ * `allowRead/allowCreate/allowUpdate/allowDelete(user) { return
27
+ * user?.role.permission.super_user }` (test/unit/resource-allow-decision.test.ts
28
+ * enforces every exported resource makes an explicit allow-decision instead
29
+ * of falling through to that default), so an unguarded `@export` is reachable
30
+ * by `authorizeLocal`'s forged loopback super_user and, once the global gate
31
+ * stops rejecting a genuinely anonymous remote caller, by that caller too.
32
+ *
33
+ * Read: identity-gated (allowRead — verified agents, admins, and trusted
34
+ * internal calls pass; anonymous HTTP denied) AND per-agent scoped
35
+ * ("owner-only" — see RECORD_TYPES.MemoryCandidate's doc comment for why: a
36
+ * candidate is an unreviewed draft distillation, not yet promoted, and must
37
+ * not be org-readable). Same "owner-only" composition Relationship.ts uses,
38
+ * parameterized from the registry — this is NOT MemoryGrant.ts's bespoke
39
+ * owner-OR-grantee model (MemoryCandidate has no second-party field).
40
+ *
41
+ * Write: post()/put()/delete() all self-enforce inline (no allowCreate/
42
+ * allowUpdate/allowDelete wrapper — same deliberate omission Memory.ts's
43
+ * allowRead() doc explains: adding an unverified allow* gate on top of
44
+ * self-enforcing methods risks regressing owner writes). Non-admin agents
45
+ * may create/modify only their OWN candidates (`agentId` no-forge
46
+ * attribution, "validate-truthy" — present+mismatched agentId is rejected,
47
+ * absent passes through, matching Memory.post()/put()'s exact idiom for the
48
+ * same single-owner-field shape) and may delete only their own candidates
49
+ * (mirrors MemoryGrant.ts's delete() ownership check). Internal calls (the
50
+ * FLAIR-NIGHTLY-REM staging writer — resources/MemoryReflect.ts's
51
+ * `databases.flair.MemoryCandidate.put(row)` — and resources/health.ts's
52
+ * pending-count read) and admin agents pass every method unfiltered, exactly
53
+ * like every other table this pattern covers.
54
+ */
55
+ export class MemoryCandidate extends databases.flair.MemoryCandidate {
56
+ /**
57
+ * Self-authorize now that the global gate is non-rejecting (memory-soul-
58
+ * read-gate family fix — same pattern as Memory.ts/Relationship.ts/
59
+ * WorkspaceState.ts/OrgEvent.ts/Soul.ts/MemoryGrant.ts). Harper routes
60
+ * `GET /MemoryCandidate/<id>` to get() and the collection describe
61
+ * (`GET /MemoryCandidate`) outside search(), so both must be gated here,
62
+ * not just search(). Per-record owner scoping happens in get() below; the
63
+ * collection scope is still in search().
64
+ */
65
+ allowRead() { return memoryCandidateAuthGate.call(this); }
66
+ /**
67
+ * Override get() to scope by-id reads the same way search() scopes
68
+ * collection reads. Never distinguishes "doesn't exist" from "exists but
69
+ * not yours" — both return 404, never 403, so a denied caller can't use
70
+ * get() to enumerate other agents' candidate ids (same discipline
71
+ * makeByIdReadGate documents, and MemoryGrant.ts's get() hand-rolls
72
+ * identically). `flair rem promote`/`flair rem reject` (src/cli.ts) both
73
+ * fetch a candidate by id before writing back — this is their read path.
74
+ */
75
+ async get(target) {
76
+ // Collection / query reads arrive as a RequestTarget with
77
+ // `isCollection === true`, and are governed by search() (same owner
78
+ // scoping). Only a genuine by-id get is ownership-checked below.
79
+ if (!target || (typeof target === "object" && target.isCollection)) {
80
+ return this.search(target);
81
+ }
82
+ return memoryCandidateByIdReadGate.call(this, target, (t) => super.get(t));
83
+ }
84
+ /**
85
+ * Scope collection reads to the caller's own candidates. This is the
86
+ * handler `flair rem candidates` reaches via `POST
87
+ * /MemoryCandidate/search_by_conditions` (src/cli.ts) — the agentId
88
+ * condition is wrapped as the OUTERMOST `and` block (Relationship.ts's
89
+ * same "Security Critical" discipline) so a caller-supplied `operator:
90
+ * "or"` in the request body cannot boolean-inject past the owner scope.
91
+ */
92
+ async search(query) {
93
+ const ctx = this.getContext?.();
94
+ const gate = await resolveAuthGate(ctx, UNAUTH());
95
+ if (gate.kind === "denied")
96
+ return gate.response;
97
+ if (gate.kind === "unfiltered")
98
+ return super.search(query);
99
+ // Non-admin agent: scope to own candidates only.
100
+ const scope = await memoryCandidateReadScope(gate.agentId);
101
+ const agentCondition = scope.condition;
102
+ if (!query?.conditions) {
103
+ return super.search({ conditions: [agentCondition], ...(query || {}) });
104
+ }
105
+ return super.search({
106
+ ...query,
107
+ conditions: [agentCondition, { conditions: query.conditions, operator: query.operator || "and" }],
108
+ operator: "and",
109
+ });
110
+ }
111
+ /**
112
+ * No shipped CLI path calls POST today (the FLAIR-NIGHTLY-REM staging
113
+ * writer uses an internal `.put()`, not `.post()` — see MemoryReflect.ts).
114
+ * Guarded anyway, on the same "don't leave any exported verb unguarded"
115
+ * discipline the rest of this file follows: anonymous denied; a non-admin
116
+ * agent may only stage a candidate attributed to itself.
117
+ */
118
+ async post(content) {
119
+ const ctx = this.getContext?.();
120
+ const auth = await resolveAgentAuth(ctx);
121
+ if (auth.kind === "anonymous")
122
+ return UNAUTH();
123
+ const attr = stampAttribution(auth, content, RECORD_TYPES.MemoryCandidate.ownerField, RECORD_TYPES.MemoryCandidate.attribution.post, "forbidden: cannot stage a memory candidate for another agent");
124
+ if (attr.denied)
125
+ return attr.denied;
126
+ return super.post(content);
127
+ }
128
+ /**
129
+ * `flair rem promote`/`flair rem reject` (src/cli.ts) both PUT the
130
+ * candidate row back with an updated status/reviewerId/reviewRationale/
131
+ * decidedAt, spreading the existing record (agentId included, unchanged).
132
+ * Non-admin: the no-forge attribution check rejects a PRESENT, mismatched
133
+ * agentId (an agent can't repurpose this endpoint to rewrite another
134
+ * agent's candidate) but never stamps one in — the promote/reject flow
135
+ * always carries the original agentId forward untouched.
136
+ */
137
+ async put(content) {
138
+ const ctx = this.getContext?.();
139
+ const auth = await resolveAgentAuth(ctx);
140
+ if (auth.kind === "anonymous")
141
+ return UNAUTH();
142
+ const attr = stampAttribution(auth, content, RECORD_TYPES.MemoryCandidate.ownerField, RECORD_TYPES.MemoryCandidate.attribution.put, "forbidden: cannot modify a memory candidate owned by another agent");
143
+ if (attr.denied)
144
+ return attr.denied;
145
+ return super.put(content);
146
+ }
147
+ /**
148
+ * No shipped CLI path calls DELETE today. Guarded on the same discipline
149
+ * as post() above — mirrors MemoryGrant.ts's delete(): owner-only,
150
+ * admin/internal unfiltered, a genuinely-missing id is a clean no-op
151
+ * super.delete() rather than a FORBIDDEN (no existence oracle).
152
+ */
153
+ async delete(id, context) {
154
+ const ctx = this.getContext?.();
155
+ const gate = await resolveAuthGate(ctx, UNAUTH());
156
+ if (gate.kind === "denied")
157
+ return gate.response;
158
+ if (gate.kind === "unfiltered")
159
+ return super.delete(id, context);
160
+ const record = await super.get(id);
161
+ if (!record)
162
+ return super.delete(id, context);
163
+ if (record[RECORD_TYPES.MemoryCandidate.ownerField] !== gate.agentId) {
164
+ return FORBIDDEN("forbidden: cannot delete a memory candidate owned by another agent");
165
+ }
166
+ return super.delete(id, context);
167
+ }
168
+ }
@@ -15,7 +15,7 @@
15
15
  * candidates Array<{ memory, suggestion, reason }>
16
16
  * prompt string
17
17
  */
18
- import { Resource, databases } from "@harperfast/harper";
18
+ import { Resource, databases } from "harper";
19
19
  import { isAdmin, allowVerified } from "./agent-auth.js";
20
20
  import { evaluate, parseDuration } from "./memory-consolidate-lib.js";
21
21
  export class ConsolidateMemories extends Resource {
@@ -52,7 +52,7 @@
52
52
  * agent's own memories; this one is never scoped that way — it reads every
53
53
  * agent's embeddings — so it follows the admin-gated precedent instead.
54
54
  */
55
- import { Resource, databases } from "@harperfast/harper";
55
+ import { Resource, databases } from "harper";
56
56
  import { mkdirSync, writeFileSync } from "node:fs";
57
57
  import { dirname } from "node:path";
58
58
  import { allowAdmin } from "./agent-auth.js";
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from "@harperfast/harper";
1
+ import { Resource, databases } from "harper";
2
2
  import { allowVerified } from "./agent-auth.js";
3
3
  import { computeContentHash, findExistingMemoryByContentHash } from "./memory-feed-lib.js";
4
4
  export class FeedMemories extends Resource {
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { resolveAgentAuth, allowVerified } from "./agent-auth.js";
3
3
  const FORBIDDEN = (msg) => new Response(JSON.stringify({ error: msg }), { status: 403, headers: { "Content-Type": "application/json" } });
4
4
  const UNAUTH = () => new Response(JSON.stringify({ error: "authentication required" }), { status: 401, headers: { "Content-Type": "application/json" } });
@@ -16,7 +16,7 @@
16
16
  * Migrated to the standard `extends Resource` shape with `allowCreate()`
17
17
  * to gate auth correctly.
18
18
  */
19
- import { Resource, databases } from "@harperfast/harper";
19
+ import { Resource, databases } from "harper";
20
20
  import { isAdmin } from "./agent-auth.js";
21
21
  export class MemoryMaintenance extends Resource {
22
22
  /** POST requires auth — either an agent acting on its own memories, or admin. */
@@ -5,7 +5,7 @@
5
5
  * reflection prompt for a human/agent to run through their own LLM, or (b)
6
6
  * with execute:true, runs the distillation server-side via Harper's models
7
7
  * facade and stages the results as MemoryCandidate rows for review. See
8
- * specs/FLAIR-NIGHTLY-REM-SLICE-2-DISTILLATION.md §3A (issue #707).
8
+ * issue #707 (§3A).
9
9
  *
10
10
  * Request:
11
11
  * agentId string — which agent to reflect on
@@ -36,7 +36,7 @@
36
36
  * Resource }` outright — see test/unit/resource-allow.test.ts). This
37
37
  * resource is a thin orchestrator over the lib's tested functions.
38
38
  */
39
- import { Resource, databases, models, logger } from "@harperfast/harper";
39
+ import { Resource, databases, models, logger } from "harper";
40
40
  import { randomBytes } from "node:crypto";
41
41
  import { isAdmin, allowVerified } from "./agent-auth.js";
42
42
  import { patchRecordSilent } from "./table-helpers.js";
@@ -143,7 +143,7 @@ export class ReflectMemories extends Resource {
143
143
  existingPendingClaims.push(c.claim);
144
144
  }
145
145
  const toStage = dedupeCandidates(outcome.candidates, existingPendingClaims);
146
- // generatedBy: GenerateResult in the pinned @harperfast/harper 5.1.17 has
146
+ // generatedBy: GenerateResult in the pinned harper 5.1.17 has
147
147
  // no model/backend-id field (content/finishReason/usage/toolCalls/trace
148
148
  // only) — the "from the generate result if available" branch is
149
149
  // unreachable in this version, so this always falls back to the
@@ -23,7 +23,7 @@
23
23
  *
24
24
  * This endpoint is idempotent: running it again finds zero drift.
25
25
  */
26
- import { Resource, databases } from "@harperfast/harper";
26
+ import { Resource, databases } from "harper";
27
27
  import { isAdmin, allowAdmin } from "./agent-auth.js";
28
28
  export class MemoryReindex extends Resource {
29
29
  // Admin-only: permit verified ADMIN agents (Basic-admin is super_user and
@@ -41,7 +41,7 @@
41
41
  * to expose "which agent used which memory" cross-agent, and narrowing this
42
42
  * costs nothing.
43
43
  */
44
- import { databases } from "@harperfast/harper";
44
+ import { databases } from "harper";
45
45
  import { resolveAgentAuth, allowVerified } from "./agent-auth.js";
46
46
  const FORBIDDEN = (msg) => new Response(JSON.stringify({ error: msg }), { status: 403, headers: { "Content-Type": "application/json" } });
47
47
  const UNAUTH = () => new Response(JSON.stringify({ error: "authentication required" }), { status: 401, headers: { "Content-Type": "application/json" } });
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from "@harperfast/harper";
1
+ import { Resource, databases } from "harper";
2
2
  import { createHash, randomBytes } from "node:crypto";
3
3
  import { handleJwtBearerGrant } from "./XAA.js";
4
4
  import { resolveAgentAuth } from "./agent-auth.js";
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { allowAdmin } from "./agent-auth.js";
3
3
  /**
4
4
  * OAuthClient holds registered OAuth client records (incl. secrets) — admin/system
@@ -10,7 +10,7 @@
10
10
  * requests slipped through once the gate stopped rejecting. resolveAgentAuth
11
11
  * distinguishes internal/agent/anonymous explicitly.
12
12
  */
13
- import { databases } from "@harperfast/harper";
13
+ import { databases } from "harper";
14
14
  import { resolveAgentAuth } from "./agent-auth.js";
15
15
  import { invalidEntitiesResponse } from "./entity-vocab.js";
16
16
  import { makeAuthGate, resolveAuthGate, stampAttribution, FORBIDDEN, UNAUTH, } from "./record-type-kit.js";
@@ -9,7 +9,7 @@
9
9
  * Sorted by createdAt ascending (oldest first for in-order processing).
10
10
  * Limit 50 events max.
11
11
  */
12
- import { Resource, databases } from "@harperfast/harper";
12
+ import { Resource, databases } from "harper";
13
13
  import { allowVerified, resolveAgentAuth } from "./agent-auth.js";
14
14
  export class OrgEventCatchup extends Resource {
15
15
  // Self-authorize via the Ed25519 agent verify (auth reshape removes the gate's
@@ -4,7 +4,7 @@
4
4
  * POST /OrgEventMaintenance/ — deletes all records where expiresAt < now.
5
5
  * Auth: admin only.
6
6
  */
7
- import { Resource, databases } from "@harperfast/harper";
7
+ import { Resource, databases } from "harper";
8
8
  import { allowAdmin } from "./agent-auth.js";
9
9
  export class OrgEventMaintenance extends Resource {
10
10
  // Admin-only: permit verified ADMIN agents (Basic-admin is super_user and
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { allowAdmin } from "./agent-auth.js";
3
3
  /**
4
4
  * PairingToken holds one-time federation pairing secrets — admin/system only,
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { allowAdmin } from "./agent-auth.js";
3
3
  /**
4
4
  * Peer holds federation peer records (URLs + credentials) — system/admin data,
@@ -26,7 +26,7 @@
26
26
  * content. get() additionally gates currentTask itself to verified
27
27
  * in-org agents only; see get()'s inline comment.
28
28
  */
29
- import { databases } from "@harperfast/harper";
29
+ import { databases } from "harper";
30
30
  import { existsSync, readFileSync } from "node:fs";
31
31
  import { dirname, join } from "node:path";
32
32
  import { fileURLToPath } from "node:url";
@@ -80,7 +80,7 @@ function resolveVersion() {
80
80
  return process.env.npm_package_version ?? "dev";
81
81
  }
82
82
  /**
83
- * Resolve the running @harperfast/harper version. Unlike flair's own
83
+ * Resolve the running harper version. Unlike flair's own
84
84
  * package.json (readable via a plain relative path above), Harper's package
85
85
  * only exports "." → dist/index.js — there's no "./package.json" subpath, so
86
86
  * requiring it directly throws (Node's exports-map enforcement). Resolve the
@@ -93,7 +93,7 @@ function resolveVersion() {
93
93
  function resolveHarperVersion() {
94
94
  try {
95
95
  const req = createRequire(import.meta.url);
96
- const mainPath = req.resolve("@harperfast/harper");
96
+ const mainPath = req.resolve("harper");
97
97
  const pkgPath = join(dirname(mainPath), "..", "package.json");
98
98
  if (existsSync(pkgPath)) {
99
99
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -34,6 +34,17 @@
34
34
  * (and its ownership gate) — its own auth model is verified-agent +
35
35
  * within-org + explicitly NO ownership requirement.
36
36
  *
37
+ * NO READ-SCOPE GATE — INTENTIONAL ASYMMETRY with citation-on-write
38
+ * (flair#775): this endpoint deliberately does NOT validate reported ids
39
+ * against the caller's read scope. Usage feedback is the cross-agent
40
+ * contract described above (agent B reports using agent A's memory
41
+ * regardless of A's visibility setting), and the no-enumeration response
42
+ * below already denies existence probing on this surface. Citation-on-write
43
+ * (./usage-recording.ts's recordCitations()) DOES scope-gate each cited id —
44
+ * it is a separate write surface with a narrower threat model; see that
45
+ * module's doc. Do not "unify" the two: the difference is a K&S binding
46
+ * condition on the flair#775 locked design, not drift.
47
+ *
37
48
  * WHY THIS ISN'T A @table-BACKED RESOURCE: the actual dedup ledger (one row
38
49
  * per (agentId, memoryId) contribution) lives in the `MemoryUsage` table
39
50
  * (schemas/memory.graphql), guarded by resources/MemoryUsage.ts. But this
@@ -82,7 +93,7 @@
82
93
  * sanitized (control-character-stripped, length-capped) and stored as-is,
83
94
  * for audit/analytics only. Treat it as untrusted data, always.
84
95
  */
85
- import { Resource } from "@harperfast/harper";
96
+ import { Resource } from "harper";
86
97
  import { resolveAgentAuth } from "./agent-auth.js";
87
98
  import { checkRateLimit, rateLimitResponse } from "./rate-limiter.js";
88
99
  import { recordUsageContribution, MAX_USAGE_IDS_PER_CALL } from "./usage-recording.js";
@@ -164,7 +175,10 @@ export class RecordUsage extends Resource {
164
175
  // ./usage-recording.ts's recordUsageContribution() — a shared,
165
176
  // single-implementation extraction (also used by citation-on-write,
166
177
  // resources/Memory.ts's post()/put()). Byte-identical behavior to
167
- // the former private _recordOne() this replaced.
178
+ // the former private _recordOne() this replaced. Deliberately NO
179
+ // read-scope check on memoryId here (flair#775 asymmetry — see the
180
+ // module doc's NO READ-SCOPE GATE paragraph; citation-on-write's
181
+ // recordCitations() is the surface that scope-gates).
168
182
  await recordUsageContribution(ctx, agentId, memoryId, attribution, now);
169
183
  }
170
184
  catch (err) {
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { resolveAgentAuth } from "./agent-auth.js";
3
3
  import { checkRateLimit, rateLimitResponse } from "./rate-limiter.js";
4
4
  import { localInstanceId } from "./instance-identity.js";
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from "@harperfast/harper";
1
+ import { Resource, databases } from "harper";
2
2
  import { resolveAgentAuth, allowVerified } from "./agent-auth.js";
3
3
  import { getEmbedding, getMode } from "./embeddings-provider.js";
4
4
  import { patchRecord } from "./table-helpers.js";
@@ -1,4 +1,4 @@
1
- import { Resource } from "@harperfast/harper";
1
+ import { Resource } from "harper";
2
2
  import { allowVerified } from "./agent-auth.js";
3
3
  import { scanSkillContent } from "./scan/skill-scanner.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { resolveAgentAuth } from "./agent-auth.js";
3
3
  import { localInstanceId } from "./instance-identity.js";
4
4
  import { makeAuthGate, stampAttribution, UNAUTH } from "./record-type-kit.js";
@@ -1,4 +1,4 @@
1
- import { Resource, databases } from '@harperfast/harper';
1
+ import { Resource, databases } from 'harper';
2
2
  import { allowVerified } from './agent-auth.js';
3
3
  export class FeedSouls extends Resource {
4
4
  // Self-authorize the subscription via the Ed25519 agent verify (auth reshape
@@ -4,7 +4,7 @@
4
4
  * GET /WorkspaceLatest/{agentId} — returns most recent WorkspaceState record.
5
5
  * Auth: requesting agent must match agentId in path (or be admin).
6
6
  */
7
- import { Resource, databases } from "@harperfast/harper";
7
+ import { Resource, databases } from "harper";
8
8
  import { allowVerified, resolveAgentAuth } from "./agent-auth.js";
9
9
  export class WorkspaceLatest extends Resource {
10
10
  // Self-authorize via the Ed25519 agent verify (auth reshape removes the gate's
@@ -7,7 +7,7 @@
7
7
  * Note: Harper's static methods call instance methods with positional args only.
8
8
  * Use this.getContext() to access request context (tpsAgent, tpsAgentIsAdmin).
9
9
  */
10
- import { databases } from "@harperfast/harper";
10
+ import { databases } from "harper";
11
11
  import { resolveAgentAuth } from "./agent-auth.js";
12
12
  import { invalidEntitiesResponse } from "./entity-vocab.js";
13
13
  import { makeAuthGate, makeReadScope, makeByIdReadGate, resolveAuthGate, stampAttribution, FORBIDDEN, UNAUTH, } from "./record-type-kit.js";
@@ -1,4 +1,4 @@
1
- import { databases } from "@harperfast/harper";
1
+ import { databases } from "harper";
2
2
  import { allowAdmin } from "./agent-auth.js";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { createRemoteJWKSet, jwtVerify } from "jose";
@@ -6,7 +6,7 @@
6
6
  // reflect the REAL listening port, or a remote A2A peer that follows discovery
7
7
  // hits a dead port.
8
8
  //
9
- // Kept free of any @harperfast/harper import so the resolution logic is
9
+ // Kept free of any harper import so the resolution logic is
10
10
  // unit-testable without spinning up Harper (mirrors agentcard-fields.ts —
11
11
  // avoids the simulator-pattern drift that let the AdminInstance predicate be
12
12
  // reproduced-not-imported).
@@ -15,7 +15,7 @@
15
15
  * verified against the agent's stored Ed25519 public key. Replay is bounded by a
16
16
  * 30s timestamp window + a per-(agent,nonce) seen-set pruned to that window.
17
17
  */
18
- import { databases } from "@harperfast/harper";
18
+ import { databases } from "harper";
19
19
  import { WINDOW_MS, isNonceReplay, recordNonce, importEd25519Key, b64ToArrayBuffer, parseTpsEd25519Header } from "./ed25519-auth.js";
20
20
  /**
21
21
  * Shared Harper user that verified Ed25519 agents resolve to (least-privilege
@@ -7,7 +7,7 @@
7
7
  // fallback that could surface a private soul (an operator's internal note,
8
8
  // prompt fragment, or credential reminder) on the public endpoint.
9
9
  //
10
- // Kept free of any @harperfast/harper import so the real logic is unit-testable
10
+ // Kept free of any harper import so the real logic is unit-testable
11
11
  // without spinning up Harper (avoids the simulator-pattern that let the
12
12
  // description-fallback leak ship untested).
13
13
  export function readSoulKind(entry) {
@@ -1,5 +1,5 @@
1
1
  import { patchRecord } from "./table-helpers.js";
2
- import { server, databases } from "@harperfast/harper";
2
+ import { server, databases } from "harper";
3
3
  import { getEmbedding } from "./embeddings-provider.js";
4
4
  import { isAdmin, FLAIR_AGENT_USERNAME } from "./agent-auth.js";
5
5
  import { WINDOW_MS, isNonceReplay, recordNonce, importEd25519Key, b64ToArrayBuffer, parseTpsEd25519Header } from "./ed25519-auth.js";
@@ -7,7 +7,7 @@
7
7
  * The previous mechanism (removed by this change) delivered the registration
8
8
  * as a `models.embedding.default` block via the `HARPER_CONFIG` env var
9
9
  * (src/cli.ts's old `buildEmbeddingsHarperConfigEnv`) — a "merge layer" that
10
- * Harper's environment-manager (`@harperfast/harper`'s
10
+ * Harper's environment-manager (`harper`'s
11
11
  * `config/harperConfigEnvVars.js`) reasserts on every boot AND PERSISTS into
12
12
  * the instance-root `harper-config.yaml`. That file proved to be config-as-
13
13
  * STATE, not config-as-intent: `flair#694`'s downgrade-and-revert CI lane
@@ -28,14 +28,14 @@
28
28
  * to), leaving `models.embedding.default: {}` — an empty shell —
29
29
  * persisted to disk.
30
30
  * 3. The next boot's config schema validator
31
- * (`@harperfast/harper`'s `validation/configValidator.js`) resolves the
31
+ * (`harper`'s `validation/configValidator.js`) resolves the
32
32
  * entry's backend via `Joi.alternatives().conditional('.backend', {...,
33
33
  * otherwise: unknownBackendEntrySchema})`; with `backend` absent, that
34
34
  * falls through to `unknownBackendEntrySchema = Joi.object({backend:
35
35
  * string.required()})`, which throws exactly: "Harper config file
36
36
  * validation error: 'models.embedding.default.backend' is required" —
37
- * Harper refuses to boot. Confirmed byte-identical in both @harperfast/
38
- * harper 5.1.15 and 5.1.17 (this is upstream env-var-config behavior,
37
+ * Harper refuses to boot. Confirmed byte-identical in both harper
38
+ * 5.1.15 and 5.1.17 (this is upstream env-var-config behavior,
39
39
  * not a schema difference between versions), and reproduced locally by
40
40
  * replaying the exact downgrade-and-revert sequence.
41
41
  *