@tekmidian/pai 0.49.0 → 0.51.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 (109) hide show
  1. package/dist/{aibroker-client-D5NT0S1N.mjs → aibroker-client-Bu72yPKj.mjs} +1 -1
  2. package/dist/{aibroker-client-Bn9SnGMa.mjs → aibroker-client-CDIXmq-e.mjs} +1 -1
  3. package/dist/{aibroker-client-Bn9SnGMa.mjs.map → aibroker-client-CDIXmq-e.mjs.map} +1 -1
  4. package/dist/{chain-CNSa0A3G.mjs → chain-BBbVbWVv.mjs} +4 -4
  5. package/dist/{chain-CNSa0A3G.mjs.map → chain-BBbVbWVv.mjs.map} +1 -1
  6. package/dist/cli/index.mjs +14 -14
  7. package/dist/cli/program.mjs +14 -14
  8. package/dist/config-Bn9jpblO.mjs +653 -0
  9. package/dist/config-Bn9jpblO.mjs.map +1 -0
  10. package/dist/{config-DxMZjpvY.mjs → config-DYXARgk8.mjs} +180 -151
  11. package/dist/config-DYXARgk8.mjs.map +1 -0
  12. package/dist/config-RjeVGJ7K.mjs +3 -0
  13. package/dist/{context-handover-cache-B9NKSjwR.mjs → context-handover-cache-yOuK9RIk.mjs} +5 -5
  14. package/dist/{context-handover-cache-B9NKSjwR.mjs.map → context-handover-cache-yOuK9RIk.mjs.map} +1 -1
  15. package/dist/daemon/index.mjs +13 -12
  16. package/dist/daemon/index.mjs.map +1 -1
  17. package/dist/{daemon-DZ4Q0jrs.mjs → daemon-CBTQYtHF.mjs} +49 -30
  18. package/dist/daemon-CBTQYtHF.mjs.map +1 -0
  19. package/dist/daemon-Vf7pHnjR.mjs +25 -0
  20. package/dist/daemon-mcp/index.mjs +186 -23
  21. package/dist/daemon-mcp/index.mjs.map +1 -1
  22. package/dist/factory-Ba8j9K7q.mjs +3 -0
  23. package/dist/{factory-DNYAqjH0.mjs → factory-Bt7TWQje.mjs} +3 -3
  24. package/dist/{factory-DNYAqjH0.mjs.map → factory-Bt7TWQje.mjs.map} +1 -1
  25. package/dist/{fallback-IeR2FrFn.mjs → fallback-CIGspCSi.mjs} +260 -10
  26. package/dist/fallback-CIGspCSi.mjs.map +1 -0
  27. package/dist/hooks/capture-all-events.mjs +80 -8
  28. package/dist/hooks/capture-all-events.mjs.map +4 -4
  29. package/dist/hooks/context-compression-hook.mjs +54 -39
  30. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  31. package/dist/hooks/post-compact-inject.mjs +54 -39
  32. package/dist/hooks/post-compact-inject.mjs.map +4 -4
  33. package/dist/hooks/route-agents-to-worker.mjs +204 -109
  34. package/dist/hooks/route-agents-to-worker.mjs.map +4 -4
  35. package/dist/hooks/whisper-rules.mjs +7613 -9
  36. package/dist/hooks/whisper-rules.mjs.map +4 -4
  37. package/dist/hooks/worker-proxy.mjs +204 -109
  38. package/dist/hooks/worker-proxy.mjs.map +4 -4
  39. package/dist/hooks/worker-status-line.mjs +211 -116
  40. package/dist/hooks/worker-status-line.mjs.map +4 -4
  41. package/dist/hooks/worker-supervision.mjs +208 -113
  42. package/dist/hooks/worker-supervision.mjs.map +4 -4
  43. package/dist/{kg-entity-BSjM5xZh.mjs → kg-entity-BSW7ra8i.mjs} +1 -1
  44. package/dist/{kg-entity-BSjM5xZh.mjs.map → kg-entity-BSW7ra8i.mjs.map} +1 -1
  45. package/dist/main-resolver-BTastpp4.mjs +7 -0
  46. package/dist/{main-resolver-DvYu9jbl.mjs → main-resolver-BmZPCmgj.mjs} +3 -3
  47. package/dist/{main-resolver-DvYu9jbl.mjs.map → main-resolver-BmZPCmgj.mjs.map} +1 -1
  48. package/dist/{planner-Cn8HmT7l.mjs → planner-BiH9msqq.mjs} +6 -6
  49. package/dist/{planner-Cn8HmT7l.mjs.map → planner-BiH9msqq.mjs.map} +1 -1
  50. package/dist/{program-D9-wfmkZ.mjs → program-srUeFUfW.mjs} +5806 -5615
  51. package/dist/program-srUeFUfW.mjs.map +1 -0
  52. package/dist/query-feedback-Bm6XvCmg.mjs +3 -0
  53. package/dist/{query-feedback-CYyOGi3y.mjs → query-feedback-CTs_jx6i.mjs} +1 -1
  54. package/dist/{query-feedback-CYyOGi3y.mjs.map → query-feedback-CTs_jx6i.mjs.map} +1 -1
  55. package/dist/{run-Cls0YGgV.mjs → run-TChOnMO_.mjs} +1388 -1183
  56. package/dist/run-TChOnMO_.mjs.map +1 -0
  57. package/dist/{server-Ch99xt5K.mjs → server-R9UkCn3v.mjs} +42 -3
  58. package/dist/server-R9UkCn3v.mjs.map +1 -0
  59. package/dist/session-keepalive-BuG3wvik.mjs +579 -0
  60. package/dist/session-keepalive-BuG3wvik.mjs.map +1 -0
  61. package/dist/skills/VaultContext/SKILL.md +1 -1
  62. package/dist/{state-DnYGRmS7.mjs → state-Ca0ltLgI.mjs} +1 -1
  63. package/dist/{state-PJrgfDLW.mjs → state-DwrsOoMi.mjs} +1 -1
  64. package/dist/{state-PJrgfDLW.mjs.map → state-DwrsOoMi.mjs.map} +1 -1
  65. package/dist/{tools-B77WHeVZ.mjs → tools-BEqiJt_j.mjs} +13 -13
  66. package/dist/{tools-B77WHeVZ.mjs.map → tools-BEqiJt_j.mjs.map} +1 -1
  67. package/dist/{tools-NnR_n-Ja.mjs → tools-BwsOTmjh.mjs} +2 -2
  68. package/dist/{wakeup-UrhiW-KU.mjs → wakeup-Yk5lQ0jb.mjs} +1 -1
  69. package/dist/{wakeup-UrhiW-KU.mjs.map → wakeup-Yk5lQ0jb.mjs.map} +1 -1
  70. package/dist/{work-queue-worker-BA5IDBwQ.mjs → work-queue-worker-B9zVWImP.mjs} +3 -3
  71. package/dist/{work-queue-worker-BA5IDBwQ.mjs.map → work-queue-worker-B9zVWImP.mjs.map} +1 -1
  72. package/dist/work-queue-worker-D-DnQ7oh.mjs +14 -0
  73. package/dist/{zettelkasten-BBjA7GcP.mjs → zettelkasten-DezbXghl.mjs} +2 -2
  74. package/dist/{zettelkasten-BBjA7GcP.mjs.map → zettelkasten-DezbXghl.mjs.map} +1 -1
  75. package/docs/cache-keepalive.md +138 -0
  76. package/docs/commands/README.md +7 -0
  77. package/docs/commands/audit.md +1 -1
  78. package/docs/commands/config.md +84 -0
  79. package/docs/commands/daemon.md +6 -0
  80. package/docs/commands/worker.md +37 -2
  81. package/docs/config.md +171 -0
  82. package/docs/model-catalogue.md +502 -0
  83. package/docs/provider-independence-details.md +1 -1
  84. package/docs/task-bus.md +1 -1
  85. package/docs/worker.md +33 -5
  86. package/docs/workers-config.md +105 -12
  87. package/package.json +1 -1
  88. package/src/hooks/ts/capture-all-events.test.ts +71 -0
  89. package/src/hooks/ts/capture-all-events.ts +10 -3
  90. package/src/hooks/ts/lib/context-fill.test.ts +124 -46
  91. package/src/hooks/ts/lib/context-fill.ts +57 -14
  92. package/src/hooks/ts/user-prompt/whisper-rules.test.ts +56 -1
  93. package/src/hooks/ts/user-prompt/whisper-rules.ts +24 -0
  94. package/statusline-command.sh +103 -16
  95. package/dist/config-DCu8THKi.mjs +0 -228
  96. package/dist/config-DCu8THKi.mjs.map +0 -1
  97. package/dist/config-DeqFqa1N.mjs +0 -3
  98. package/dist/config-DxMZjpvY.mjs.map +0 -1
  99. package/dist/daemon-CYpVy_Dw.mjs +0 -24
  100. package/dist/daemon-DZ4Q0jrs.mjs.map +0 -1
  101. package/dist/factory-47Qf_df7.mjs +0 -3
  102. package/dist/fallback-IeR2FrFn.mjs.map +0 -1
  103. package/dist/indexer-C5Le7XE7.mjs +0 -1
  104. package/dist/main-resolver-CnfnWa8C.mjs +0 -7
  105. package/dist/program-D9-wfmkZ.mjs.map +0 -1
  106. package/dist/query-feedback-C7rSfiXU.mjs +0 -3
  107. package/dist/run-Cls0YGgV.mjs.map +0 -1
  108. package/dist/server-Ch99xt5K.mjs.map +0 -1
  109. package/dist/work-queue-worker-DLM2wlqM.mjs +0 -14
@@ -173,4 +173,4 @@ function updateEntityFeedbackWeight(db, entityId, normalizedRating, alpha = .1)
173
173
 
174
174
  //#endregion
175
175
  export { kgContradictions as a, kgAdd as i, updateEntityFeedbackWeight as n, kgInvalidate as o, upsertKgEntity as r, kgQuery as s, listKgEntities as t };
176
- //# sourceMappingURL=kg-entity-BSjM5xZh.mjs.map
176
+ //# sourceMappingURL=kg-entity-BSW7ra8i.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"kg-entity-BSjM5xZh.mjs","names":[],"sources":["../src/memory/kg.ts","../src/memory/kg-entity.ts"],"sourcesContent":["/**\n * Temporal Knowledge Graph — kg_triples CRUD layer.\n *\n * Uses the Postgres connection pool from the storage backend.\n * Triples are time-scoped: valid_from/valid_to enable point-in-time queries.\n * Invalidation sets valid_to = NOW() instead of deleting rows.\n */\n\nimport type { Pool } from \"pg\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KgTriple {\n id: number;\n subject: string;\n predicate: string;\n object: string;\n project_id?: number;\n source_session?: string;\n valid_from: Date;\n valid_to?: Date;\n confidence: \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\";\n created_at: Date;\n}\n\nexport interface KgAddParams {\n subject: string;\n predicate: string;\n object: string;\n project_id?: number;\n source_session?: string;\n confidence?: \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\";\n}\n\nexport interface KgQueryParams {\n subject?: string;\n predicate?: string;\n object?: string;\n project_id?: number;\n as_of?: Date;\n include_invalidated?: boolean;\n}\n\nexport interface KgContradiction {\n subject: string;\n predicate: string;\n objects: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction rowToTriple(row: Record<string, unknown>): KgTriple {\n return {\n id: row.id as number,\n subject: row.subject as string,\n predicate: row.predicate as string,\n object: row.object as string,\n project_id: row.project_id as number | undefined,\n source_session: row.source_session as string | undefined,\n valid_from: new Date(row.valid_from as string),\n valid_to: row.valid_to ? new Date(row.valid_to as string) : undefined,\n confidence: row.confidence as \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\",\n created_at: new Date(row.created_at as string),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Core operations\n// ---------------------------------------------------------------------------\n\n/**\n * Add a new triple to the knowledge graph.\n * Returns the inserted triple.\n */\nexport async function kgAdd(pool: Pool, params: KgAddParams): Promise<KgTriple> {\n const confidence = params.confidence ?? \"EXTRACTED\";\n const result = await pool.query<Record<string, unknown>>(\n `INSERT INTO kg_triples\n (subject, predicate, object, project_id, source_session, confidence)\n VALUES ($1, $2, $3, $4, $5, $6)\n RETURNING *`,\n [\n params.subject,\n params.predicate,\n params.object,\n params.project_id ?? null,\n params.source_session ?? null,\n confidence,\n ]\n );\n return rowToTriple(result.rows[0]);\n}\n\n/**\n * Query triples by subject, predicate, object, and/or project.\n * Supports point-in-time queries via as_of.\n * By default only returns currently-valid triples (valid_to IS NULL).\n */\nexport async function kgQuery(pool: Pool, params: KgQueryParams): Promise<KgTriple[]> {\n const conditions: string[] = [];\n const values: unknown[] = [];\n let idx = 1;\n\n if (params.subject !== undefined) {\n conditions.push(`subject = $${idx++}`);\n values.push(params.subject);\n }\n if (params.predicate !== undefined) {\n conditions.push(`predicate = $${idx++}`);\n values.push(params.predicate);\n }\n if (params.object !== undefined) {\n conditions.push(`object = $${idx++}`);\n values.push(params.object);\n }\n if (params.project_id !== undefined) {\n conditions.push(`project_id = $${idx++}`);\n values.push(params.project_id);\n }\n\n if (params.as_of !== undefined) {\n // Valid at the given timestamp: started before or at as_of, and not yet ended\n conditions.push(`valid_from <= $${idx++}`);\n values.push(params.as_of);\n conditions.push(`(valid_to IS NULL OR valid_to > $${idx++})`);\n values.push(params.as_of);\n } else if (!params.include_invalidated) {\n // Default: only currently-valid (no valid_to set)\n conditions.push(`valid_to IS NULL`);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const result = await pool.query<Record<string, unknown>>(\n `SELECT * FROM kg_triples ${where} ORDER BY valid_from DESC`,\n values\n );\n return result.rows.map(rowToTriple);\n}\n\n/**\n * Invalidate a triple by setting valid_to = NOW().\n * Does not delete the row — preserves history.\n */\nexport async function kgInvalidate(pool: Pool, tripleId: number): Promise<void> {\n await pool.query(\n `UPDATE kg_triples SET valid_to = NOW() WHERE id = $1 AND valid_to IS NULL`,\n [tripleId]\n );\n}\n\n/**\n * Find contradictions: cases where the same (subject, predicate) pair has\n * multiple currently-valid objects.\n */\nexport async function kgContradictions(\n pool: Pool,\n subject: string\n): Promise<KgContradiction[]> {\n const result = await pool.query<{ subject: string; predicate: string; objects: string[] }>(\n `SELECT subject, predicate, array_agg(object ORDER BY object) AS objects\n FROM kg_triples\n WHERE subject = $1\n AND valid_to IS NULL\n GROUP BY subject, predicate\n HAVING COUNT(*) > 1`,\n [subject]\n );\n return result.rows.map((row) => ({\n subject: row.subject,\n predicate: row.predicate,\n objects: row.objects,\n }));\n}\n","/**\n * kg-entity.ts — Entity content-addressing with multi-tenant support.\n *\n * Provides UUID5-style deterministic content hashes for KG entities and edges,\n * ensuring that the same entity name always maps to the same ID within a tenant.\n * This enables idempotent upserts and stable foreign keys for kg_triples.\n *\n * Multi-tenant support: each tenant namespace gets its own entity ID space.\n * The default tenant is \"default\" for single-user deployments.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Database } from \"better-sqlite3\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KgEntity {\n entity_id: string;\n tenant_id: string;\n name: string;\n type: string;\n description?: string;\n first_seen?: number;\n last_seen?: number;\n mention_count: number;\n feedback_weight: number;\n}\n\nexport interface KgEntityUpsertParams {\n name: string;\n type?: string;\n description?: string;\n tenantId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Content addressing\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a deterministic entity ID (UUID5-style) for a given name and tenant.\n *\n * The ID is a hex digest derived from \"tenant_id:name\" so the same entity\n * always receives the same ID within a tenant namespace.\n *\n * @param name Entity name (case-preserved)\n * @param tenantId Tenant namespace (default: \"default\")\n */\nexport function entityContentId(name: string, tenantId = \"default\"): string {\n return createHash(\"sha256\")\n .update(`entity:${tenantId}:${name}`)\n .digest(\"hex\")\n .slice(0, 32); // 128-bit hex string — UUID5-compatible length\n}\n\n/**\n * Generate a deterministic edge ID for a (source, relation, target) triple\n * within a tenant namespace.\n *\n * @param source Source entity name\n * @param relation Relation/predicate verb phrase\n * @param target Target entity name\n * @param tenantId Tenant namespace (default: \"default\")\n */\nexport function edgeContentId(\n source: string,\n relation: string,\n target: string,\n tenantId = \"default\"\n): string {\n return createHash(\"sha256\")\n .update(`edge:${tenantId}:${source}:${relation}:${target}`)\n .digest(\"hex\")\n .slice(0, 32);\n}\n\n// ---------------------------------------------------------------------------\n// SQLite entity upsert (for federation.db)\n// ---------------------------------------------------------------------------\n\n/**\n * Upsert a KG entity in the federation SQLite database.\n *\n * If the entity already exists for this tenant:\n * - Updates last_seen to now\n * - Increments mention_count\n * - Updates description if provided (overwrites older description)\n *\n * Returns the entity_id for use as a foreign key in kg_triples.\n */\nexport function upsertKgEntity(\n db: Database,\n params: KgEntityUpsertParams\n): string {\n const tenantId = params.tenantId ?? \"default\";\n const entityId = entityContentId(params.name, tenantId);\n const now = Date.now();\n\n db.prepare(`\n INSERT INTO kg_entities\n (entity_id, tenant_id, name, type, description, first_seen, last_seen, mention_count, feedback_weight)\n VALUES\n (?, ?, ?, ?, ?, ?, ?, 1, 0.5)\n ON CONFLICT(entity_id) DO UPDATE SET\n last_seen = excluded.last_seen,\n mention_count = mention_count + 1,\n description = COALESCE(excluded.description, description),\n type = CASE WHEN excluded.type != 'unknown' THEN excluded.type ELSE type END\n `).run(\n entityId,\n tenantId,\n params.name,\n params.type ?? \"unknown\",\n params.description ?? null,\n now,\n now\n );\n\n return entityId;\n}\n\n/**\n * Look up a KG entity by name within a tenant.\n * Returns null if the entity does not exist.\n */\nexport function findKgEntity(\n db: Database,\n name: string,\n tenantId = \"default\"\n): KgEntity | null {\n const entityId = entityContentId(name, tenantId);\n const row = db.prepare(\n \"SELECT * FROM kg_entities WHERE entity_id = ? AND tenant_id = ?\"\n ).get(entityId, tenantId) as KgEntity | undefined;\n return row ?? null;\n}\n\n/**\n * List KG entities for a tenant, optionally filtered by type.\n *\n * @param db Federation SQLite database\n * @param tenantId Tenant namespace (default: \"default\")\n * @param type Optional entity type filter\n * @param limit Maximum entities to return (default: 100)\n */\nexport function listKgEntities(\n db: Database,\n tenantId = \"default\",\n type?: string,\n limit = 100\n): KgEntity[] {\n if (type) {\n return db.prepare(\n \"SELECT * FROM kg_entities WHERE tenant_id = ? AND type = ? ORDER BY mention_count DESC LIMIT ?\"\n ).all(tenantId, type, limit) as KgEntity[];\n }\n return db.prepare(\n \"SELECT * FROM kg_entities WHERE tenant_id = ? ORDER BY mention_count DESC LIMIT ?\"\n ).all(tenantId, limit) as KgEntity[];\n}\n\n// ---------------------------------------------------------------------------\n// Feedback weight update (MR2 — EMA)\n// ---------------------------------------------------------------------------\n\n/**\n * Apply an EMA (Exponential Moving Average) feedback update to an entity's weight.\n *\n * EMA formula: new_weight = old_weight + alpha * (target - old_weight)\n *\n * @param db Federation SQLite database\n * @param entityId Entity ID to update\n * @param normalizedRating Rating normalized to [0, 1] (e.g., rating/5 for 1-5 scale)\n * @param alpha EMA learning rate (default: 0.1)\n */\nexport function updateEntityFeedbackWeight(\n db: Database,\n entityId: string,\n normalizedRating: number,\n alpha = 0.1\n): void {\n const row = db.prepare(\n \"SELECT feedback_weight FROM kg_entities WHERE entity_id = ?\"\n ).get(entityId) as { feedback_weight: number } | undefined;\n\n if (!row) return;\n\n const newWeight = row.feedback_weight + alpha * (normalizedRating - row.feedback_weight);\n db.prepare(\n \"UPDATE kg_entities SET feedback_weight = ? WHERE entity_id = ?\"\n ).run(newWeight, entityId);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"kg-entity-BSW7ra8i.mjs","names":[],"sources":["../src/memory/kg.ts","../src/memory/kg-entity.ts"],"sourcesContent":["/**\n * Temporal Knowledge Graph — kg_triples CRUD layer.\n *\n * Uses the Postgres connection pool from the storage backend.\n * Triples are time-scoped: valid_from/valid_to enable point-in-time queries.\n * Invalidation sets valid_to = NOW() instead of deleting rows.\n */\n\nimport type { Pool } from \"pg\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KgTriple {\n id: number;\n subject: string;\n predicate: string;\n object: string;\n project_id?: number;\n source_session?: string;\n valid_from: Date;\n valid_to?: Date;\n confidence: \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\";\n created_at: Date;\n}\n\nexport interface KgAddParams {\n subject: string;\n predicate: string;\n object: string;\n project_id?: number;\n source_session?: string;\n confidence?: \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\";\n}\n\nexport interface KgQueryParams {\n subject?: string;\n predicate?: string;\n object?: string;\n project_id?: number;\n as_of?: Date;\n include_invalidated?: boolean;\n}\n\nexport interface KgContradiction {\n subject: string;\n predicate: string;\n objects: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction rowToTriple(row: Record<string, unknown>): KgTriple {\n return {\n id: row.id as number,\n subject: row.subject as string,\n predicate: row.predicate as string,\n object: row.object as string,\n project_id: row.project_id as number | undefined,\n source_session: row.source_session as string | undefined,\n valid_from: new Date(row.valid_from as string),\n valid_to: row.valid_to ? new Date(row.valid_to as string) : undefined,\n confidence: row.confidence as \"EXTRACTED\" | \"INFERRED\" | \"AMBIGUOUS\",\n created_at: new Date(row.created_at as string),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Core operations\n// ---------------------------------------------------------------------------\n\n/**\n * Add a new triple to the knowledge graph.\n * Returns the inserted triple.\n */\nexport async function kgAdd(pool: Pool, params: KgAddParams): Promise<KgTriple> {\n const confidence = params.confidence ?? \"EXTRACTED\";\n const result = await pool.query<Record<string, unknown>>(\n `INSERT INTO kg_triples\n (subject, predicate, object, project_id, source_session, confidence)\n VALUES ($1, $2, $3, $4, $5, $6)\n RETURNING *`,\n [\n params.subject,\n params.predicate,\n params.object,\n params.project_id ?? null,\n params.source_session ?? null,\n confidence,\n ]\n );\n return rowToTriple(result.rows[0]);\n}\n\n/**\n * Query triples by subject, predicate, object, and/or project.\n * Supports point-in-time queries via as_of.\n * By default only returns currently-valid triples (valid_to IS NULL).\n */\nexport async function kgQuery(pool: Pool, params: KgQueryParams): Promise<KgTriple[]> {\n const conditions: string[] = [];\n const values: unknown[] = [];\n let idx = 1;\n\n if (params.subject !== undefined) {\n conditions.push(`subject = $${idx++}`);\n values.push(params.subject);\n }\n if (params.predicate !== undefined) {\n conditions.push(`predicate = $${idx++}`);\n values.push(params.predicate);\n }\n if (params.object !== undefined) {\n conditions.push(`object = $${idx++}`);\n values.push(params.object);\n }\n if (params.project_id !== undefined) {\n conditions.push(`project_id = $${idx++}`);\n values.push(params.project_id);\n }\n\n if (params.as_of !== undefined) {\n // Valid at the given timestamp: started before or at as_of, and not yet ended\n conditions.push(`valid_from <= $${idx++}`);\n values.push(params.as_of);\n conditions.push(`(valid_to IS NULL OR valid_to > $${idx++})`);\n values.push(params.as_of);\n } else if (!params.include_invalidated) {\n // Default: only currently-valid (no valid_to set)\n conditions.push(`valid_to IS NULL`);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const result = await pool.query<Record<string, unknown>>(\n `SELECT * FROM kg_triples ${where} ORDER BY valid_from DESC`,\n values\n );\n return result.rows.map(rowToTriple);\n}\n\n/**\n * Invalidate a triple by setting valid_to = NOW().\n * Does not delete the row — preserves history.\n */\nexport async function kgInvalidate(pool: Pool, tripleId: number): Promise<void> {\n await pool.query(\n `UPDATE kg_triples SET valid_to = NOW() WHERE id = $1 AND valid_to IS NULL`,\n [tripleId]\n );\n}\n\n/**\n * Find contradictions: cases where the same (subject, predicate) pair has\n * multiple currently-valid objects.\n */\nexport async function kgContradictions(\n pool: Pool,\n subject: string\n): Promise<KgContradiction[]> {\n const result = await pool.query<{ subject: string; predicate: string; objects: string[] }>(\n `SELECT subject, predicate, array_agg(object ORDER BY object) AS objects\n FROM kg_triples\n WHERE subject = $1\n AND valid_to IS NULL\n GROUP BY subject, predicate\n HAVING COUNT(*) > 1`,\n [subject]\n );\n return result.rows.map((row) => ({\n subject: row.subject,\n predicate: row.predicate,\n objects: row.objects,\n }));\n}\n","/**\n * kg-entity.ts — Entity content-addressing with multi-tenant support.\n *\n * Provides UUID5-style deterministic content hashes for KG entities and edges,\n * ensuring that the same entity name always maps to the same ID within a tenant.\n * This enables idempotent upserts and stable foreign keys for kg_triples.\n *\n * Multi-tenant support: each tenant namespace gets its own entity ID space.\n * The default tenant is \"default\" for single-user deployments.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Database } from \"better-sqlite3\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KgEntity {\n entity_id: string;\n tenant_id: string;\n name: string;\n type: string;\n description?: string;\n first_seen?: number;\n last_seen?: number;\n mention_count: number;\n feedback_weight: number;\n}\n\nexport interface KgEntityUpsertParams {\n name: string;\n type?: string;\n description?: string;\n tenantId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Content addressing\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a deterministic entity ID (UUID5-style) for a given name and tenant.\n *\n * The ID is a hex digest derived from \"tenant_id:name\" so the same entity\n * always receives the same ID within a tenant namespace.\n *\n * @param name Entity name (case-preserved)\n * @param tenantId Tenant namespace (default: \"default\")\n */\nexport function entityContentId(name: string, tenantId = \"default\"): string {\n return createHash(\"sha256\")\n .update(`entity:${tenantId}:${name}`)\n .digest(\"hex\")\n .slice(0, 32); // 128-bit hex string — UUID5-compatible length\n}\n\n/**\n * Generate a deterministic edge ID for a (source, relation, target) triple\n * within a tenant namespace.\n *\n * @param source Source entity name\n * @param relation Relation/predicate verb phrase\n * @param target Target entity name\n * @param tenantId Tenant namespace (default: \"default\")\n */\nexport function edgeContentId(\n source: string,\n relation: string,\n target: string,\n tenantId = \"default\"\n): string {\n return createHash(\"sha256\")\n .update(`edge:${tenantId}:${source}:${relation}:${target}`)\n .digest(\"hex\")\n .slice(0, 32);\n}\n\n// ---------------------------------------------------------------------------\n// SQLite entity upsert (for federation.db)\n// ---------------------------------------------------------------------------\n\n/**\n * Upsert a KG entity in the federation SQLite database.\n *\n * If the entity already exists for this tenant:\n * - Updates last_seen to now\n * - Increments mention_count\n * - Updates description if provided (overwrites older description)\n *\n * Returns the entity_id for use as a foreign key in kg_triples.\n */\nexport function upsertKgEntity(\n db: Database,\n params: KgEntityUpsertParams\n): string {\n const tenantId = params.tenantId ?? \"default\";\n const entityId = entityContentId(params.name, tenantId);\n const now = Date.now();\n\n db.prepare(`\n INSERT INTO kg_entities\n (entity_id, tenant_id, name, type, description, first_seen, last_seen, mention_count, feedback_weight)\n VALUES\n (?, ?, ?, ?, ?, ?, ?, 1, 0.5)\n ON CONFLICT(entity_id) DO UPDATE SET\n last_seen = excluded.last_seen,\n mention_count = mention_count + 1,\n description = COALESCE(excluded.description, description),\n type = CASE WHEN excluded.type != 'unknown' THEN excluded.type ELSE type END\n `).run(\n entityId,\n tenantId,\n params.name,\n params.type ?? \"unknown\",\n params.description ?? null,\n now,\n now\n );\n\n return entityId;\n}\n\n/**\n * Look up a KG entity by name within a tenant.\n * Returns null if the entity does not exist.\n */\nexport function findKgEntity(\n db: Database,\n name: string,\n tenantId = \"default\"\n): KgEntity | null {\n const entityId = entityContentId(name, tenantId);\n const row = db.prepare(\n \"SELECT * FROM kg_entities WHERE entity_id = ? AND tenant_id = ?\"\n ).get(entityId, tenantId) as KgEntity | undefined;\n return row ?? null;\n}\n\n/**\n * List KG entities for a tenant, optionally filtered by type.\n *\n * @param db Federation SQLite database\n * @param tenantId Tenant namespace (default: \"default\")\n * @param type Optional entity type filter\n * @param limit Maximum entities to return (default: 100)\n */\nexport function listKgEntities(\n db: Database,\n tenantId = \"default\",\n type?: string,\n limit = 100\n): KgEntity[] {\n if (type) {\n return db.prepare(\n \"SELECT * FROM kg_entities WHERE tenant_id = ? AND type = ? ORDER BY mention_count DESC LIMIT ?\"\n ).all(tenantId, type, limit) as KgEntity[];\n }\n return db.prepare(\n \"SELECT * FROM kg_entities WHERE tenant_id = ? ORDER BY mention_count DESC LIMIT ?\"\n ).all(tenantId, limit) as KgEntity[];\n}\n\n// ---------------------------------------------------------------------------\n// Feedback weight update (MR2 — EMA)\n// ---------------------------------------------------------------------------\n\n/**\n * Apply an EMA (Exponential Moving Average) feedback update to an entity's weight.\n *\n * EMA formula: new_weight = old_weight + alpha * (target - old_weight)\n *\n * @param db Federation SQLite database\n * @param entityId Entity ID to update\n * @param normalizedRating Rating normalized to [0, 1] (e.g., rating/5 for 1-5 scale)\n * @param alpha EMA learning rate (default: 0.1)\n */\nexport function updateEntityFeedbackWeight(\n db: Database,\n entityId: string,\n normalizedRating: number,\n alpha = 0.1\n): void {\n const row = db.prepare(\n \"SELECT feedback_weight FROM kg_entities WHERE entity_id = ?\"\n ).get(entityId) as { feedback_weight: number } | undefined;\n\n if (!row) return;\n\n const newWeight = row.feedback_weight + alpha * (normalizedRating - row.feedback_weight);\n db.prepare(\n \"UPDATE kg_entities SET feedback_weight = ? WHERE entity_id = ?\"\n ).run(newWeight, entityId);\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import "./utils-CJymHkYm.mjs";
2
+ import "./config-Bn9jpblO.mjs";
3
+ import "./config-DYXARgk8.mjs";
4
+ import { n as resolveSessionDir, t as cmdMain } from "./main-resolver-BmZPCmgj.mjs";
5
+ import "./aibroker-client-CDIXmq-e.mjs";
6
+
7
+ export { cmdMain };
@@ -1,7 +1,7 @@
1
1
  import { a as paiHomePath, o as resolvePaiFile, r as migratePaiFile } from "./pai-home-ChAOupZc.mjs";
2
2
  import { _ as warn, c as ok, g as smartDecodeDir, i as err, n as dim, o as header, u as renderTable } from "./utils-CJymHkYm.mjs";
3
- import { v as readWorkersSection } from "./config-DxMZjpvY.mjs";
4
- import { a as switchToSession, n as fetchLiveSessions } from "./aibroker-client-Bn9SnGMa.mjs";
3
+ import { C as readWorkersSection } from "./config-DYXARgk8.mjs";
4
+ import { a as switchToSession, n as fetchLiveSessions } from "./aibroker-client-CDIXmq-e.mjs";
5
5
  import { closeSync, copyFileSync, createReadStream, existsSync, linkSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
6
6
  import { homedir } from "node:os";
7
7
  import { basename, join } from "node:path";
@@ -1683,4 +1683,4 @@ async function cmdMain(db, query, pickN, opts) {
1683
1683
 
1684
1684
  //#endregion
1685
1685
  export { renderDedupedSessions as a, probeResume as c, fmtAge as d, migrateSessionScanCache as f, scanSessions as h, normalizeName as i, restoreTopLevel as l, scanCacheFilePath as m, resolveSessionDir as n, hasConversation as o, resolveSessionByNameOrId as p, buildDeduped as r, launchInDir as s, cmdMain as t, printExitDir as u };
1686
- //# sourceMappingURL=main-resolver-DvYu9jbl.mjs.map
1686
+ //# sourceMappingURL=main-resolver-BmZPCmgj.mjs.map