@xopcai/xopc 0.0.225 → 0.0.227

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 (155) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CtTYnku4.js → activity-store-BevwE16n.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dizuqu_4.js → agent-avatar-dicebear-BggVQrEZ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-TJpjRHnr.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-CLRMz2BT.js → api-Bx_BpIt8.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnk-DtQh.js → app-management-settings-panel-BtKP9n2r.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-wP0rogVI.js → appearance-settings-BoH2NAUX.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-CZ4Da51l.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-Cpzsm-DM.js → archive-plugin-DnceUyxm.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Bd2OOoEK.js → attachment-load-Bh8_9gkr.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-DNqhguyk.js → automations-page-ZKeAAVxD.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-workspace-2Y00PvJU.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-Dcma5HdI.js → binary-plugins-Cy9er6w-.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-D-B8ThwK.js → block-editor-Cc0wWvNX.js} +3 -3
  16. package/dist/gateway/static/root/assets/browser-settings-page-CbJD27_j.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAPZIXrs.js → browser-workflow-inputs-BS7rpLLl.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-DHtaSKEh.js → browser-workflows-page-BdBVUZXm.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-Dv8y6OuP.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-zsZQ7im3.js → capability-presets-api-D1Lqz0Tt.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-TZmjzWzt.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-Cp8iaaXp.js → channel-recipient-api-CGuEl-l2.js} +1 -1
  23. package/dist/gateway/static/root/assets/{channels-settings-CFW7zBoT.js → channels-settings-g-68dutA.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-status-swr-D7KsAeWh.js +1 -0
  25. package/dist/gateway/static/root/assets/{chat-terminal-dock-Dr6Rq2ln.js → chat-terminal-dock-CdX_7aQh.js} +1 -1
  26. package/dist/gateway/static/root/assets/connectors-page-DXA0rAvQ.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-BiXrpzmo.js → cron-expression-BnSQc4Ek.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-BPuRtwKt.js → date-picker-BbuG7zQ_.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-BNC_W7wI.js → dependency-picker-snZeqOmG.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-DzOpt5nI.js → desktop-pet-DJQ8JoR1.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-BW0brCvH.js → desktop-pet-settings-B9txsRtv.js} +1 -1
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-Baml0uTS.js → directory-picker-path-field-D7WKWkNB.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-CBXyKmfS.js → extension-debug-page-D_7cOCj2.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-BBhcr_SZ.js → extension-page-Bwu47iUb.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-4rwWpN9_.js → extension-settings-page-Dwg4dSZM.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-api-Dg-BlBe4.js → gateway-config-api-jURUSte_.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-Du0MvK9s.js → gateway-config-swr-6SQXF1yR.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-BOuYZOYe.js → gateway-settings-UklJOMLX.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-JbjcHCaN.js → gateway-startup-retry-DqWaxyvZ.js} +1 -1
  40. package/dist/gateway/static/root/assets/heartbeat-settings-Djs_nduD.js +1 -0
  41. package/dist/gateway/static/root/assets/{home-page-BIXkO0Ck.js → home-page-i6bXCHdo.js} +1 -1
  42. package/dist/gateway/static/root/assets/{image-generation-api-G2tfPvKP.js → image-generation-api-Bxmt6LEr.js} +1 -1
  43. package/dist/gateway/static/root/assets/index-BBBE89vm.css +2 -0
  44. package/dist/gateway/static/root/assets/index-BsD5wygl.js +74 -0
  45. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-L1Vtxgp9.js → keyboard-shortcuts-settings-ByVsCH3d.js} +1 -1
  46. package/dist/gateway/static/root/assets/{local-app-workbench-page-D-eacBcO.js → local-app-workbench-page-BCKEDMlP.js} +2 -2
  47. package/dist/gateway/static/root/assets/{local-apps-page--thlkBLS.js → local-apps-page-D19R-xsz.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-DqJz-cOR.js → locale-store-Ci1Qi0Q-.js} +1 -1
  49. package/dist/gateway/static/root/assets/{logs-page-BRCglHvd.js → logs-page-Cy9YQK7j.js} +2 -2
  50. package/dist/gateway/static/root/assets/{management-settings-p55fR4XO.js → management-settings-G0y7zmfY.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-DwMcRlBR.js → markdown-split-B69d2HWt.js} +1 -1
  52. package/dist/gateway/static/root/assets/{markdown-view-CTB9u15e.js → markdown-view-CBM-v2ph.js} +1 -1
  53. package/dist/gateway/static/root/assets/{media-plugins-O6H3GZn7.js → media-plugins-6TWEQgN_.js} +1 -1
  54. package/dist/gateway/static/root/assets/messages-CtOJwGW3.js +3 -0
  55. package/dist/gateway/static/root/assets/{notes-api-CrjQbmk1.js → notes-api-DLsnnZCS.js} +1 -1
  56. package/dist/gateway/static/root/assets/{notes-page-miO9ig9C.js → notes-page-CkRJJKDm.js} +1 -1
  57. package/dist/gateway/static/root/assets/notes-workbench-B10T3hGX.js +4 -0
  58. package/dist/gateway/static/root/assets/{product-open-page-BOu07nXf.js → product-open-page-HxArIvoN.js} +1 -1
  59. package/dist/gateway/static/root/assets/project-detail-page-DsqRlgsy.js +1 -0
  60. package/dist/gateway/static/root/assets/{projects-page-CY03RxVr.js → projects-page-Bu2PN8OK.js} +1 -1
  61. package/dist/gateway/static/root/assets/{registry-api-Bf_HDLUJ.js → registry-api-lEar5FOV.js} +1 -1
  62. package/dist/gateway/static/root/assets/remote-access-hub-CXACdJ2f.js +1 -0
  63. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DthuRqUH.js → runtime-tools-settings-panel-Bf03UNGD.js} +2 -2
  64. package/dist/gateway/static/root/assets/{schema-form-8W8PhXxa.js → schema-form-CIXMBgx5.js} +1 -1
  65. package/dist/gateway/static/root/assets/sessions-page-CS2knWDT.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-ByFGk0q_.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-form-section-CrsKGYiG.js → settings-form-section-DgdB26mE.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-loading-skeleton-WJtI0AAq.js → settings-loading-skeleton-efk5W6lG.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-PCjwRF47.js → settings-page-BHVf4gEP.js} +1 -1
  70. package/dist/gateway/static/root/assets/{setup-status-panel-D65CwlNC.js → setup-status-panel-WK0dGNMv.js} +1 -1
  71. package/dist/gateway/static/root/assets/{share-preview-page-BGtvLLeZ.js → share-preview-page-Cod-w2qm.js} +1 -1
  72. package/dist/gateway/static/root/assets/shares-settings-CUqQ31gt.js +1 -0
  73. package/dist/gateway/static/root/assets/skill-reload-api-DweAPjI8.js +1 -0
  74. package/dist/gateway/static/root/assets/{skills-page-C_npyryI.js → skills-page-DwCcipqK.js} +1 -1
  75. package/dist/gateway/static/root/assets/{skills-page.utils-C46Sd78k.js → skills-page.utils-3WSbtl3S.js} +1 -1
  76. package/dist/gateway/static/root/assets/{system-settings-panel-DomTLwki.js → system-settings-panel-C5VxqC_s.js} +1 -1
  77. package/dist/gateway/static/root/assets/task-detail-page-DEj-BFMP.js +1 -0
  78. package/dist/gateway/static/root/assets/{theme-store-Ce7wq__X.js → theme-store-Dd89g_ki.js} +1 -1
  79. package/dist/gateway/static/root/assets/{use-autosave-Do9mCRcY.js → use-autosave-CeV8VJh2.js} +1 -1
  80. package/dist/gateway/static/root/assets/user-context-page-f7yh7aD5.js +1 -0
  81. package/dist/gateway/static/root/assets/{voice-api-key-field-Bc5p-0tX.js → voice-api-key-field-EmJ-8aZu.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-BieqsmT1.js → work-discovery-overlay-zsk6E3Mi.js} +1 -1
  83. package/dist/gateway/static/root/assets/workflow-run-setup-panel-CBAYvm3G.js +3 -0
  84. package/dist/gateway/static/root/assets/workflows-page-BN0JmHrG.js +5 -0
  85. package/dist/gateway/static/root/index.html +11 -11
  86. package/dist/package.js +1 -1
  87. package/dist/src/agent/agent-manager.d.ts +3 -1
  88. package/dist/src/agent/agent-manager.js +22 -5
  89. package/dist/src/agent/memory/understanding/service.js +1 -0
  90. package/dist/src/agent/memory/understanding/types.d.ts +1 -0
  91. package/dist/src/agent/service.d.ts +2 -0
  92. package/dist/src/agent/service.js +6 -0
  93. package/dist/src/agent/skills/index.d.ts +22 -2
  94. package/dist/src/agent/skills/index.js +74 -32
  95. package/dist/src/agent/skills/skill-sources.d.ts +0 -1
  96. package/dist/src/agent/skills/skill-sources.js +1 -11
  97. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  98. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  99. package/dist/src/connectors/connected-source-understanding.js +1 -1
  100. package/dist/src/gateway/heartbeat/service.js +1 -1
  101. package/dist/src/gateway/hono/routes/connectors.js +18 -16
  102. package/dist/src/gateway/hono/routes/project-skills.js +30 -2
  103. package/dist/src/gateway/hono/routes/voice.js +1 -1
  104. package/dist/src/gateway/hono/routes/you.js +52 -0
  105. package/dist/src/heartbeat/index.js +1 -1
  106. package/dist/src/infra/update-restart.js +1 -1
  107. package/dist/src/knowledge/connected-understanding-pipeline.js +12 -3
  108. package/dist/src/knowledge/index.d.ts +0 -1
  109. package/dist/src/knowledge/index.js +1 -2
  110. package/dist/src/projects/project-skill-service.d.ts +28 -6
  111. package/dist/src/projects/project-skill-service.js +76 -29
  112. package/dist/src/storage/sqlite/index.d.ts +1 -0
  113. package/dist/src/storage/sqlite/index.js +2 -1
  114. package/dist/src/storage/sqlite/migrations/135_user_people.sql +59 -0
  115. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  116. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  117. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  118. package/dist/src/storage/sqlite/schema.js +1 -1
  119. package/dist/src/storage/sqlite/user-people-repository.d.ts +32 -0
  120. package/dist/src/storage/sqlite/user-people-repository.js +246 -0
  121. package/dist/src/user-context/relationships/indexer.d.ts +13 -0
  122. package/dist/src/user-context/relationships/indexer.js +185 -0
  123. package/dist/src/user-context/relationships/service.d.ts +22 -0
  124. package/dist/src/user-context/relationships/service.js +50 -0
  125. package/dist/src/user-context/relationships/types.d.ts +55 -0
  126. package/dist/src/user-context/relationships/types.js +10 -0
  127. package/dist/src/user-context/sources/repository.d.ts +1 -1
  128. package/dist/src/user-context/sources/repository.js +8 -2
  129. package/dist/src/work-discovery/service.js +1 -1
  130. package/package.json +1 -1
  131. package/dist/gateway/static/root/assets/agents-DeEEFZJ4.js +0 -68
  132. package/dist/gateway/static/root/assets/apps-page-Db5YNHVM.js +0 -1
  133. package/dist/gateway/static/root/assets/automations-workspace-CNT05YTb.js +0 -6
  134. package/dist/gateway/static/root/assets/browser-settings-page-UbDj3LIq.js +0 -8
  135. package/dist/gateway/static/root/assets/capabilities-settings-panel-CiO152QS.js +0 -7
  136. package/dist/gateway/static/root/assets/capability-presets-settings-panel-Bc_hRwfL.js +0 -3
  137. package/dist/gateway/static/root/assets/channels-status-swr-5rNVq7iI.js +0 -1
  138. package/dist/gateway/static/root/assets/connectors-page-DLBr5nre.js +0 -2
  139. package/dist/gateway/static/root/assets/heartbeat-settings-Dq4YAlSx.js +0 -1
  140. package/dist/gateway/static/root/assets/index-Csccu8sa.js +0 -74
  141. package/dist/gateway/static/root/assets/index-D3_xSYKd.css +0 -2
  142. package/dist/gateway/static/root/assets/messages-CeydamsI.js +0 -3
  143. package/dist/gateway/static/root/assets/notes-workbench-_13lmvmF.js +0 -4
  144. package/dist/gateway/static/root/assets/project-detail-page-BStRkOQr.js +0 -1
  145. package/dist/gateway/static/root/assets/remote-access-hub-B19llkld.js +0 -1
  146. package/dist/gateway/static/root/assets/sessions-page-BDA2qbTd.js +0 -1
  147. package/dist/gateway/static/root/assets/settings-advanced-gate-BONIDX4v.js +0 -1
  148. package/dist/gateway/static/root/assets/shares-settings-CdzVKrBl.js +0 -1
  149. package/dist/gateway/static/root/assets/skill-reload-api-CsRWid5h.js +0 -1
  150. package/dist/gateway/static/root/assets/task-detail-page-B6YFX7kK.js +0 -1
  151. package/dist/gateway/static/root/assets/user-context-page-CiCQA40E.js +0 -1
  152. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DVj8iYvm.js +0 -3
  153. package/dist/gateway/static/root/assets/workflows-page-AG04TTuH.js +0 -5
  154. package/dist/src/knowledge/people-graph.d.ts +0 -25
  155. package/dist/src/knowledge/people-graph.js +0 -92
@@ -0,0 +1,185 @@
1
+ import { getSqliteDatabase } from "../../storage/sqlite/transaction.js";
2
+ import { getUserPeopleIndexState, replaceUserPeopleIndex } from "../../storage/sqlite/user-people-repository.js";
3
+ import { listKnowledgeSourceItems } from "../../storage/sqlite/knowledge-repository.js";
4
+ import "../../storage/sqlite/index.js";
5
+ import { listUnderstandingSourceGrants } from "../sources/repository.js";
6
+ import { createHash } from "node:crypto";
7
+ //#region src/user-context/relationships/indexer.ts
8
+ function hash(value) {
9
+ return createHash("sha256").update(value).digest("hex").slice(0, 20);
10
+ }
11
+ function normalized(value) {
12
+ return value?.trim().toLocaleLowerCase() || void 0;
13
+ }
14
+ function readSignal(value) {
15
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
16
+ const row = value;
17
+ const read = (key) => typeof row[key] === "string" && row[key].trim() ? row[key].trim().slice(0, 160) : void 0;
18
+ const signal = {
19
+ name: read("name"),
20
+ email: read("email"),
21
+ username: read("username")
22
+ };
23
+ return signal.name || signal.email || signal.username ? signal : void 0;
24
+ }
25
+ function providerScope(sourceInstanceId) {
26
+ if (!sourceInstanceId.startsWith("composio:")) return sourceInstanceId.toLocaleLowerCase();
27
+ return sourceInstanceId.split(":")[1]?.toLocaleLowerCase() ?? sourceInstanceId.toLocaleLowerCase();
28
+ }
29
+ function personIdentityKey(signal, sourceInstanceId) {
30
+ const email = normalized(signal.email);
31
+ if (email) return `email:${email}`;
32
+ const username = normalized(signal.username);
33
+ if (username) return `provider:${providerScope(sourceInstanceId)}:${username}`;
34
+ const name = normalized(signal.name);
35
+ return name ? `name:${sourceInstanceId.toLocaleLowerCase()}:${name}` : void 0;
36
+ }
37
+ function personIdForIdentity(signal, sourceInstanceId) {
38
+ const key = personIdentityKey(signal, sourceInstanceId);
39
+ return key ? `person_${hash(key)}` : void 0;
40
+ }
41
+ function inferredKind(signal) {
42
+ const name = normalized(signal.name) ?? "";
43
+ const username = normalized(signal.username) ?? "";
44
+ const emailLocal = (normalized(signal.email) ?? "").split("@")[0] ?? "";
45
+ if (/\[bot\]|(?:^|[-_.])bot(?:$|[-_.])|bot$/.test(`${name} ${username}`)) return "bot";
46
+ if (/^(?:no[-_.]?reply|do[-_.]?not[-_.]?reply|notifications?|alerts?|mailer[-_.]?daemon)(?:$|[-+_.])/.test(emailLocal)) return "service";
47
+ if (/^(?:team|group|all|everyone|support|help|sales|contact)(?:$|[-+_.])/.test(emailLocal)) return "group";
48
+ if (!signal.name && !signal.email && signal.username) return "unknown";
49
+ return "person";
50
+ }
51
+ function confidence(signal) {
52
+ if (signal.email) return signal.name ? .95 : .88;
53
+ if (signal.username) return signal.name ? .86 : .72;
54
+ return .55;
55
+ }
56
+ function observedAt(item) {
57
+ const value = Date.parse(item.occurredAt ?? item.sourceUpdatedAt ?? item.updatedAt);
58
+ return Number.isFinite(value) ? value : Date.now();
59
+ }
60
+ function handle(personId, type, value, sourceInstanceId, time) {
61
+ return {
62
+ id: `handle_${hash(`${type}:${normalized(value)}:${sourceInstanceId}`)}`,
63
+ type,
64
+ value,
65
+ sourceInstanceId,
66
+ verification: type === "display_name" ? "inferred" : "observed",
67
+ firstObservedAt: time,
68
+ lastObservedAt: time
69
+ };
70
+ }
71
+ function activeConnectorSources() {
72
+ return new Set(listUnderstandingSourceGrants().flatMap((grant) => {
73
+ const sourceInstanceId = typeof grant.config.sourceInstanceId === "string" ? grant.config.sourceInstanceId.trim() : "";
74
+ if (sourceInstanceId) return [sourceInstanceId];
75
+ const connectorId = typeof grant.config.connectorId === "string" ? grant.config.connectorId.trim() : "";
76
+ const accountId = typeof grant.config.accountId === "string" ? grant.config.accountId.trim() : "";
77
+ return connectorId && accountId ? [`composio:${connectorId}:${accountId}`] : [];
78
+ }));
79
+ }
80
+ function loadActiveSourceItems() {
81
+ const activeSources = activeConnectorSources();
82
+ const items = [];
83
+ let offset = 0;
84
+ while (true) {
85
+ const page = listKnowledgeSourceItems({
86
+ includeDeleted: false,
87
+ limit: 500,
88
+ offset
89
+ });
90
+ items.push(...page.filter((item) => item.synthesisPipeline === "connected_knowledge" && item.sensitivity !== "secret" && item.sensitivity !== "regulated" && item.metadata.observationKind !== "inventory" && (!item.sourceInstanceId.startsWith("composio:") || activeSources.has(item.sourceInstanceId))));
91
+ if (page.length < 500) break;
92
+ offset += page.length;
93
+ }
94
+ return items;
95
+ }
96
+ function currentIndexRevision() {
97
+ const db = getSqliteDatabase();
98
+ return {
99
+ sourceChangeSequence: Number(db.prepare("SELECT COALESCE(MAX(sequence), 0) AS value FROM knowledge_source_changes").get().value),
100
+ sourceGrantsUpdatedAt: Number(db.prepare("SELECT COALESCE(MAX(updated_at), 0) AS value FROM understanding_source_grants").get().value)
101
+ };
102
+ }
103
+ function buildUserPeopleIndex(items) {
104
+ const owners = new Set(items.flatMap((item) => Array.isArray(item.metadata.ownerIdentities) ? item.metadata.ownerIdentities.filter((value) => typeof value === "string").map((value) => value.trim().toLocaleLowerCase()).filter(Boolean) : []));
105
+ const people = /* @__PURE__ */ new Map();
106
+ for (const item of items) {
107
+ const values = Array.isArray(item.metadata.personEntities) ? item.metadata.personEntities : [];
108
+ const seenInItem = /* @__PURE__ */ new Set();
109
+ for (const value of values) {
110
+ const signal = readSignal(value);
111
+ if (!signal) continue;
112
+ const strongIdentity = normalized(signal.email) ?? normalized(signal.username);
113
+ if (strongIdentity && owners.has(strongIdentity)) continue;
114
+ const identityKey = personIdentityKey(signal, item.sourceInstanceId);
115
+ const id = personIdForIdentity(signal, item.sourceInstanceId);
116
+ if (!identityKey || !id || seenInItem.has(identityKey)) continue;
117
+ seenInItem.add(identityKey);
118
+ const time = observedAt(item);
119
+ const name = signal.name ?? signal.email ?? signal.username;
120
+ const current = people.get(identityKey) ?? {
121
+ id,
122
+ displayName: name,
123
+ inferredKind: inferredKind(signal),
124
+ confidence: confidence(signal),
125
+ firstObservedAt: time,
126
+ lastObservedAt: time,
127
+ handles: /* @__PURE__ */ new Map(),
128
+ sources: /* @__PURE__ */ new Map()
129
+ };
130
+ if (signal.name && (!current.displayName || current.displayName.includes("@"))) current.displayName = signal.name;
131
+ current.inferredKind = current.inferredKind === "unknown" ? inferredKind(signal) : current.inferredKind;
132
+ current.confidence = Math.max(current.confidence, confidence(signal));
133
+ current.firstObservedAt = Math.min(current.firstObservedAt, time);
134
+ current.lastObservedAt = Math.max(current.lastObservedAt, time);
135
+ for (const [type, displayValue] of [
136
+ ["email", signal.email],
137
+ ["username", signal.username],
138
+ ["display_name", signal.name]
139
+ ]) {
140
+ if (!displayValue) continue;
141
+ const next = handle(id, type, displayValue, item.sourceInstanceId, time);
142
+ const key = `${type}:${normalized(displayValue)}:${item.sourceInstanceId}`;
143
+ const previous = current.handles.get(key);
144
+ if (previous) {
145
+ previous.firstObservedAt = Math.min(previous.firstObservedAt, time);
146
+ previous.lastObservedAt = Math.max(previous.lastObservedAt, time);
147
+ } else current.handles.set(key, next);
148
+ }
149
+ const source = current.sources.get(item.sourceInstanceId) ?? {
150
+ sourceInstanceId: item.sourceInstanceId,
151
+ interactionCount: 0,
152
+ firstObservedAt: time,
153
+ lastObservedAt: time
154
+ };
155
+ source.interactionCount += 1;
156
+ source.firstObservedAt = Math.min(source.firstObservedAt, time);
157
+ source.lastObservedAt = Math.max(source.lastObservedAt, time);
158
+ current.sources.set(item.sourceInstanceId, source);
159
+ people.set(identityKey, current);
160
+ }
161
+ }
162
+ return [...people.values()].map((person) => ({
163
+ id: person.id,
164
+ displayName: person.displayName,
165
+ inferredKind: person.inferredKind,
166
+ confidence: person.confidence,
167
+ firstObservedAt: person.firstObservedAt,
168
+ lastObservedAt: person.lastObservedAt,
169
+ handles: [...person.handles.values()],
170
+ sources: [...person.sources.values()]
171
+ }));
172
+ }
173
+ function rebuildUserPeopleIndex() {
174
+ const revision = currentIndexRevision();
175
+ const entries = buildUserPeopleIndex(loadActiveSourceItems());
176
+ replaceUserPeopleIndex(entries, revision);
177
+ return entries;
178
+ }
179
+ function ensureUserPeopleIndex() {
180
+ const revision = currentIndexRevision();
181
+ const state = getUserPeopleIndexState();
182
+ if (!state || state.sourceChangeSequence !== revision.sourceChangeSequence || state.sourceGrantsUpdatedAt !== revision.sourceGrantsUpdatedAt) rebuildUserPeopleIndex();
183
+ }
184
+ //#endregion
185
+ export { buildUserPeopleIndex, ensureUserPeopleIndex, personIdForIdentity, personIdentityKey, rebuildUserPeopleIndex };
@@ -0,0 +1,22 @@
1
+ import type { UserPerson, UserPersonKind } from './types.js';
2
+ export declare function listUserRelationships(options?: {
3
+ query?: string;
4
+ kind?: UserPersonKind;
5
+ sourceInstanceId?: string;
6
+ includeHidden?: boolean;
7
+ hiddenOnly?: boolean;
8
+ cursor?: string;
9
+ limit?: number;
10
+ }): {
11
+ nextCursor?: string;
12
+ items: UserPerson[];
13
+ summary: import("./types.js").UserRelationshipSummary;
14
+ total: number;
15
+ };
16
+ export declare function getUserRelationship(personId: string): UserPerson | null;
17
+ export declare function patchUserRelationship(personId: string, patch: {
18
+ displayName?: string | null;
19
+ kind?: UserPersonKind | null;
20
+ hidden?: boolean;
21
+ }): UserPerson | null;
22
+ export declare function mergeUserRelationships(sourcePersonId: string, targetPersonId: string): UserPerson | null;
@@ -0,0 +1,50 @@
1
+ import { listUnderstandings } from "../../storage/sqlite/user-context-repository.js";
2
+ import { getUserPerson, listUserPeople, mergeUserPeople, summarizeUserPeople, updateUserPerson } from "../../storage/sqlite/user-people-repository.js";
3
+ import "../../storage/sqlite/index.js";
4
+ import { ensureUserPeopleIndex } from "./indexer.js";
5
+ //#region src/user-context/relationships/service.ts
6
+ function withUnderstanding(person) {
7
+ const understanding = listUnderstandings().find((item) => item.kind === "relationship" && item.payload.personId === person.id && !["archived", "rejected"].includes(item.status));
8
+ return understanding ? {
9
+ ...person,
10
+ relationshipUnderstanding: {
11
+ id: understanding.id,
12
+ statement: understanding.statement,
13
+ status: understanding.status
14
+ }
15
+ } : person;
16
+ }
17
+ function listUserRelationships(options = {}) {
18
+ ensureUserPeopleIndex();
19
+ const offset = options.cursor && /^\d+$/.test(options.cursor) ? Number(options.cursor) : 0;
20
+ const result = listUserPeople({
21
+ query: options.query,
22
+ kind: options.kind,
23
+ sourceInstanceId: options.sourceInstanceId,
24
+ includeHidden: options.includeHidden,
25
+ hiddenOnly: options.hiddenOnly,
26
+ offset,
27
+ limit: options.limit
28
+ });
29
+ return {
30
+ items: result.items.map(withUnderstanding),
31
+ summary: summarizeUserPeople(),
32
+ total: result.total,
33
+ ...result.nextOffset === void 0 ? {} : { nextCursor: String(result.nextOffset) }
34
+ };
35
+ }
36
+ function getUserRelationship(personId) {
37
+ ensureUserPeopleIndex();
38
+ const person = getUserPerson(personId);
39
+ return person ? withUnderstanding(person) : null;
40
+ }
41
+ function patchUserRelationship(personId, patch) {
42
+ const person = updateUserPerson(personId, patch);
43
+ return person ? withUnderstanding(person) : null;
44
+ }
45
+ function mergeUserRelationships(sourcePersonId, targetPersonId) {
46
+ const person = mergeUserPeople(sourcePersonId, targetPersonId);
47
+ return person ? withUnderstanding(person) : null;
48
+ }
49
+ //#endregion
50
+ export { getUserRelationship, listUserRelationships, mergeUserRelationships, patchUserRelationship };
@@ -0,0 +1,55 @@
1
+ export declare const USER_PERSON_KINDS: readonly ["person", "bot", "service", "group", "unknown"];
2
+ export type UserPersonKind = typeof USER_PERSON_KINDS[number];
3
+ export type UserPersonHandle = {
4
+ id: string;
5
+ type: 'email' | 'provider_user' | 'username' | 'display_name';
6
+ value: string;
7
+ sourceInstanceId: string;
8
+ verification: 'observed' | 'inferred' | 'user_confirmed';
9
+ firstObservedAt: number;
10
+ lastObservedAt: number;
11
+ };
12
+ export type UserPersonSource = {
13
+ sourceInstanceId: string;
14
+ connectorId?: string;
15
+ toolkit?: string;
16
+ interactionCount: number;
17
+ firstObservedAt: number;
18
+ lastObservedAt: number;
19
+ };
20
+ export type UserPerson = {
21
+ id: string;
22
+ displayName: string;
23
+ kind: UserPersonKind;
24
+ hidden: boolean;
25
+ confidence: number;
26
+ primaryHandle?: string;
27
+ interactionCount: number;
28
+ firstObservedAt: number;
29
+ lastObservedAt: number;
30
+ handles: UserPersonHandle[];
31
+ sources: UserPersonSource[];
32
+ relationshipUnderstanding?: {
33
+ id: string;
34
+ statement: string;
35
+ status: 'candidate' | 'active' | 'needs_review' | 'stale' | 'archived' | 'rejected';
36
+ };
37
+ };
38
+ export type UserRelationshipSummary = {
39
+ people: number;
40
+ automatedAccounts: number;
41
+ needsReview: number;
42
+ hidden: number;
43
+ sources: number;
44
+ lastUpdatedAt?: number;
45
+ };
46
+ export type UserPersonIndexEntry = {
47
+ id: string;
48
+ displayName: string;
49
+ inferredKind: UserPersonKind;
50
+ confidence: number;
51
+ firstObservedAt: number;
52
+ lastObservedAt: number;
53
+ handles: UserPersonHandle[];
54
+ sources: UserPersonSource[];
55
+ };
@@ -0,0 +1,10 @@
1
+ //#region src/user-context/relationships/types.ts
2
+ const USER_PERSON_KINDS = [
3
+ "person",
4
+ "bot",
5
+ "service",
6
+ "group",
7
+ "unknown"
8
+ ];
9
+ //#endregion
10
+ export { USER_PERSON_KINDS };
@@ -55,6 +55,6 @@ export declare function updateUnderstandingSourceRun(id: string, patch: {
55
55
  }): UnderstandingSourceRun | null;
56
56
  export declare function upsertUserFocus(input: UserFocusInput): UserFocus;
57
57
  export declare function listUserFocuses(statuses?: UserFocus['status'][]): UserFocus[];
58
- export declare function updateUserFocus(id: string, patch: Partial<Pick<UserFocus, 'title' | 'summary' | 'status'>>, nowMs?: number): UserFocus | null;
58
+ export declare function updateUserFocus(id: string, patch: Partial<Pick<UserFocus, 'title' | 'summary' | 'status' | 'validFrom' | 'validTo' | 'reviewAt'>>, nowMs?: number): UserFocus | null;
59
59
  export declare function deleteUserFocus(id: string): boolean;
60
60
  export {};
@@ -1,5 +1,6 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
2
  import "../domain.js";
3
+ import { focusLifecycle } from "../focus-lifecycle.js";
3
4
  import { randomUUID } from "node:crypto";
4
5
  //#region src/user-context/sources/repository.ts
5
6
  function record(value) {
@@ -261,11 +262,16 @@ function updateUserFocus(id, patch, nowMs = Date.now()) {
261
262
  const currentRow = getSqliteDatabase().prepare("SELECT * FROM user_focuses WHERE focus_id = ?").get(id);
262
263
  if (!currentRow) return null;
263
264
  const current = focusFromRow(currentRow);
264
- if ((patch.title ?? current.title) === current.title && (patch.summary ?? current.summary) === current.summary && (patch.status ?? current.status) === current.status) return current;
265
+ const renewedLifecycle = patch.status === "active" && (current.status !== "active" || current.reviewAt !== void 0 && current.reviewAt <= nowMs || current.validTo !== void 0 && current.validTo <= nowMs) ? focusLifecycle(current.horizon, nowMs) : {};
266
+ const nextValidFrom = patch.validFrom ?? renewedLifecycle.validFrom ?? current.validFrom;
267
+ const nextValidTo = patch.validTo ?? renewedLifecycle.validTo ?? current.validTo;
268
+ const nextReviewAt = patch.reviewAt ?? renewedLifecycle.reviewAt ?? current.reviewAt;
269
+ if ((patch.title ?? current.title) === current.title && (patch.summary ?? current.summary) === current.summary && (patch.status ?? current.status) === current.status && nextValidFrom === current.validFrom && nextValidTo === current.validTo && nextReviewAt === current.reviewAt) return current;
265
270
  const versionId = randomUUID();
266
271
  runSqliteWriteTransaction((db) => {
267
272
  db.prepare(`UPDATE user_focuses
268
- SET title = ?, summary = ?, status = ?, updated_at = ? WHERE focus_id = ?`).run(patch.title ?? current.title, patch.summary ?? current.summary, patch.status ?? current.status, nowMs, id);
273
+ SET title = ?, summary = ?, status = ?, valid_from = ?, valid_to = ?, review_at = ?, updated_at = ?
274
+ WHERE focus_id = ?`).run(patch.title ?? current.title, patch.summary ?? current.summary, patch.status ?? current.status, nextValidFrom ?? null, nextValidTo ?? null, nextReviewAt ?? null, nowMs, id);
269
275
  const nextRow = db.prepare("SELECT * FROM user_focuses WHERE focus_id = ?").get(id);
270
276
  db.prepare(`INSERT INTO user_focus_versions (
271
277
  version_id, focus_id, title, summary, snapshot_json, created_by, change_reason, created_at
@@ -8,8 +8,8 @@ import { buildSessionKey, init_session_key } from "../routing/session-key.js";
8
8
  import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
9
9
  import { init_providers, resolveModel } from "../providers/index.js";
10
10
  import { isLocalModelBaseUrl } from "../providers/model-call.js";
11
- import { createUnderstandingSourceRun, getUnderstandingSourceRun, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant, upsertUserFocus } from "../user-context/sources/repository.js";
12
11
  import { focusLifecycle } from "../user-context/focus-lifecycle.js";
12
+ import { createUnderstandingSourceRun, getUnderstandingSourceRun, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant, upsertUserFocus } from "../user-context/sources/repository.js";
13
13
  import { allowsRemoteSourceProcessing } from "../user-context/sources/processing-policy.js";
14
14
  import { analyzeUnderstandingSources, analyzeWorkContext, workDiscoveryResultMarkdown } from "./analyzer.js";
15
15
  import { previewWorkDiscoveryRoot, probeWorkDiscoveryRoot, summarizeWorkContextSnapshot } from "./probe.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.225",
3
+ "version": "0.0.227",
4
4
  "description": "Local-first personal AI assistant with reviewable user understanding, durable tasks, workflows, automations, and local or cloud models.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",