@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CtTYnku4.js → activity-store-BevwE16n.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dizuqu_4.js → agent-avatar-dicebear-BggVQrEZ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-TJpjRHnr.js +68 -0
- package/dist/gateway/static/root/assets/{api-CLRMz2BT.js → api-Bx_BpIt8.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnk-DtQh.js → app-management-settings-panel-BtKP9n2r.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-wP0rogVI.js → appearance-settings-BoH2NAUX.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CZ4Da51l.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Cpzsm-DM.js → archive-plugin-DnceUyxm.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Bd2OOoEK.js → attachment-load-Bh8_9gkr.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-DNqhguyk.js → automations-page-ZKeAAVxD.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-2Y00PvJU.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-Dcma5HdI.js → binary-plugins-Cy9er6w-.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D-B8ThwK.js → block-editor-Cc0wWvNX.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-CbJD27_j.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAPZIXrs.js → browser-workflow-inputs-BS7rpLLl.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DHtaSKEh.js → browser-workflows-page-BdBVUZXm.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Dv8y6OuP.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-zsZQ7im3.js → capability-presets-api-D1Lqz0Tt.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-TZmjzWzt.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-Cp8iaaXp.js → channel-recipient-api-CGuEl-l2.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-CFW7zBoT.js → channels-settings-g-68dutA.js} +1 -1
- package/dist/gateway/static/root/assets/channels-status-swr-D7KsAeWh.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-Dr6Rq2ln.js → chat-terminal-dock-CdX_7aQh.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DXA0rAvQ.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-BiXrpzmo.js → cron-expression-BnSQc4Ek.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BPuRtwKt.js → date-picker-BbuG7zQ_.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-BNC_W7wI.js → dependency-picker-snZeqOmG.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DzOpt5nI.js → desktop-pet-DJQ8JoR1.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BW0brCvH.js → desktop-pet-settings-B9txsRtv.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Baml0uTS.js → directory-picker-path-field-D7WKWkNB.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CBXyKmfS.js → extension-debug-page-D_7cOCj2.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BBhcr_SZ.js → extension-page-Bwu47iUb.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-4rwWpN9_.js → extension-settings-page-Dwg4dSZM.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Dg-BlBe4.js → gateway-config-api-jURUSte_.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Du0MvK9s.js → gateway-config-swr-6SQXF1yR.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BOuYZOYe.js → gateway-settings-UklJOMLX.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-JbjcHCaN.js → gateway-startup-retry-DqWaxyvZ.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-Djs_nduD.js +1 -0
- package/dist/gateway/static/root/assets/{home-page-BIXkO0Ck.js → home-page-i6bXCHdo.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-G2tfPvKP.js → image-generation-api-Bxmt6LEr.js} +1 -1
- package/dist/gateway/static/root/assets/index-BBBE89vm.css +2 -0
- package/dist/gateway/static/root/assets/index-BsD5wygl.js +74 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-L1Vtxgp9.js → keyboard-shortcuts-settings-ByVsCH3d.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-D-eacBcO.js → local-app-workbench-page-BCKEDMlP.js} +2 -2
- package/dist/gateway/static/root/assets/{local-apps-page--thlkBLS.js → local-apps-page-D19R-xsz.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DqJz-cOR.js → locale-store-Ci1Qi0Q-.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-BRCglHvd.js → logs-page-Cy9YQK7j.js} +2 -2
- package/dist/gateway/static/root/assets/{management-settings-p55fR4XO.js → management-settings-G0y7zmfY.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DwMcRlBR.js → markdown-split-B69d2HWt.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-CTB9u15e.js → markdown-view-CBM-v2ph.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-O6H3GZn7.js → media-plugins-6TWEQgN_.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CtOJwGW3.js +3 -0
- package/dist/gateway/static/root/assets/{notes-api-CrjQbmk1.js → notes-api-DLsnnZCS.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-miO9ig9C.js → notes-page-CkRJJKDm.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-B10T3hGX.js +4 -0
- package/dist/gateway/static/root/assets/{product-open-page-BOu07nXf.js → product-open-page-HxArIvoN.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DsqRlgsy.js +1 -0
- package/dist/gateway/static/root/assets/{projects-page-CY03RxVr.js → projects-page-Bu2PN8OK.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-Bf_HDLUJ.js → registry-api-lEar5FOV.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXACdJ2f.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DthuRqUH.js → runtime-tools-settings-panel-Bf03UNGD.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-8W8PhXxa.js → schema-form-CIXMBgx5.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CS2knWDT.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-ByFGk0q_.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CrsKGYiG.js → settings-form-section-DgdB26mE.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-WJtI0AAq.js → settings-loading-skeleton-efk5W6lG.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-PCjwRF47.js → settings-page-BHVf4gEP.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-D65CwlNC.js → setup-status-panel-WK0dGNMv.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BGtvLLeZ.js → share-preview-page-Cod-w2qm.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CUqQ31gt.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DweAPjI8.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-C_npyryI.js → skills-page-DwCcipqK.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-C46Sd78k.js → skills-page.utils-3WSbtl3S.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-DomTLwki.js → system-settings-panel-C5VxqC_s.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-DEj-BFMP.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Ce7wq__X.js → theme-store-Dd89g_ki.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-Do9mCRcY.js → use-autosave-CeV8VJh2.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-f7yh7aD5.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-Bc5p-0tX.js → voice-api-key-field-EmJ-8aZu.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BieqsmT1.js → work-discovery-overlay-zsk6E3Mi.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-CBAYvm3G.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-BN0JmHrG.js +5 -0
- package/dist/gateway/static/root/index.html +11 -11
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +3 -1
- package/dist/src/agent/agent-manager.js +22 -5
- package/dist/src/agent/memory/understanding/service.js +1 -0
- package/dist/src/agent/memory/understanding/types.d.ts +1 -0
- package/dist/src/agent/service.d.ts +2 -0
- package/dist/src/agent/service.js +6 -0
- package/dist/src/agent/skills/index.d.ts +22 -2
- package/dist/src/agent/skills/index.js +74 -32
- package/dist/src/agent/skills/skill-sources.d.ts +0 -1
- package/dist/src/agent/skills/skill-sources.js +1 -11
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/connectors/connected-source-understanding.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +18 -16
- package/dist/src/gateway/hono/routes/project-skills.js +30 -2
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/hono/routes/you.js +52 -0
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/knowledge/connected-understanding-pipeline.js +12 -3
- package/dist/src/knowledge/index.d.ts +0 -1
- package/dist/src/knowledge/index.js +1 -2
- package/dist/src/projects/project-skill-service.d.ts +28 -6
- package/dist/src/projects/project-skill-service.js +76 -29
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/135_user_people.sql +59 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/user-people-repository.d.ts +32 -0
- package/dist/src/storage/sqlite/user-people-repository.js +246 -0
- package/dist/src/user-context/relationships/indexer.d.ts +13 -0
- package/dist/src/user-context/relationships/indexer.js +185 -0
- package/dist/src/user-context/relationships/service.d.ts +22 -0
- package/dist/src/user-context/relationships/service.js +50 -0
- package/dist/src/user-context/relationships/types.d.ts +55 -0
- package/dist/src/user-context/relationships/types.js +10 -0
- package/dist/src/user-context/sources/repository.d.ts +1 -1
- package/dist/src/user-context/sources/repository.js +8 -2
- package/dist/src/work-discovery/service.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-DeEEFZJ4.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-Db5YNHVM.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CNT05YTb.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-UbDj3LIq.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CiO152QS.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Bc_hRwfL.js +0 -3
- package/dist/gateway/static/root/assets/channels-status-swr-5rNVq7iI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DLBr5nre.js +0 -2
- package/dist/gateway/static/root/assets/heartbeat-settings-Dq4YAlSx.js +0 -1
- package/dist/gateway/static/root/assets/index-Csccu8sa.js +0 -74
- package/dist/gateway/static/root/assets/index-D3_xSYKd.css +0 -2
- package/dist/gateway/static/root/assets/messages-CeydamsI.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-_13lmvmF.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-BStRkOQr.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-B19llkld.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BDA2qbTd.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BONIDX4v.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CdzVKrBl.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CsRWid5h.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-B6YFX7kK.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CiCQA40E.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DVj8iYvm.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-AG04TTuH.js +0 -5
- package/dist/src/knowledge/people-graph.d.ts +0 -25
- package/dist/src/knowledge/people-graph.js +0 -92
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { init_paths, resolveBundledSkillsDir } from "../config/paths.js";
|
|
1
2
|
import { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath } from "../agent/skills/workspace-skills-dir.js";
|
|
2
|
-
import {
|
|
3
|
+
import { loadSkills, loadWorkspaceSkillInventory } from "../agent/skills/index.js";
|
|
3
4
|
import { removeSkillsLockEntry } from "../agent/skills/hub-lock.js";
|
|
4
5
|
import { deleteManagedSkill, installSkillFromZip, isValidSkillId } from "../agent/skills/managed-store.js";
|
|
5
6
|
import { pullSkillFromSource } from "../agent/skills/hub-pull.js";
|
|
@@ -7,6 +8,7 @@ import { downloadFromMarketplace } from "../agent/skills/skills-marketplace.js";
|
|
|
7
8
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
8
9
|
import { accessSync, constants, existsSync, statSync } from "node:fs";
|
|
9
10
|
//#region src/projects/project-skill-service.ts
|
|
11
|
+
init_paths();
|
|
10
12
|
var ProjectSkillError = class extends Error {
|
|
11
13
|
constructor(code, status, message) {
|
|
12
14
|
super(message);
|
|
@@ -20,21 +22,44 @@ var ProjectSkillService = class {
|
|
|
20
22
|
this.options = options;
|
|
21
23
|
}
|
|
22
24
|
list(projectId) {
|
|
23
|
-
const location = this.
|
|
24
|
-
const loaded = loadWorkspaceSkills(location.workspaceRoot);
|
|
25
|
+
const { location, loaded, inherited, trust } = this.loadCatalog(projectId);
|
|
25
26
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
workspaceRoot: location.workspaceRoot,
|
|
28
|
+
sources: loaded.sources,
|
|
29
|
+
trust,
|
|
30
|
+
items: loaded.entries.map((entry) => this.toSummary(entry)),
|
|
31
|
+
inheritedItems: inherited.skills.map((skill) => this.toSummary({
|
|
32
|
+
skill,
|
|
33
|
+
effective: true
|
|
34
|
+
})),
|
|
35
|
+
diagnostics: inherited.diagnostics
|
|
29
36
|
};
|
|
30
37
|
}
|
|
31
|
-
getContent(projectId,
|
|
32
|
-
const {
|
|
38
|
+
getContent(projectId, skillKey) {
|
|
39
|
+
const { loaded, inherited } = this.loadCatalog(projectId);
|
|
40
|
+
const entry = loaded.entries.find((candidate) => this.skillKey(candidate.skill) === skillKey);
|
|
41
|
+
if (entry) return {
|
|
42
|
+
...this.toSummary(entry),
|
|
43
|
+
bodyMarkdown: entry.skill.content
|
|
44
|
+
};
|
|
45
|
+
const inheritedSkill = inherited.skills.find((candidate) => this.skillKey(candidate) === skillKey);
|
|
46
|
+
if (!inheritedSkill) throw new ProjectSkillError("skill_not_found", 404, "Project skill not found");
|
|
33
47
|
return {
|
|
34
|
-
...this.toSummary(
|
|
35
|
-
|
|
48
|
+
...this.toSummary({
|
|
49
|
+
skill: inheritedSkill,
|
|
50
|
+
effective: true
|
|
51
|
+
}),
|
|
52
|
+
bodyMarkdown: inheritedSkill.content
|
|
36
53
|
};
|
|
37
54
|
}
|
|
55
|
+
getWorkspaceTrust(projectId) {
|
|
56
|
+
const location = this.resolveLocation(projectId, false);
|
|
57
|
+
return this.options.getWorkspaceTrust(location.workspaceRoot);
|
|
58
|
+
}
|
|
59
|
+
setWorkspaceTrust(projectId, trusted) {
|
|
60
|
+
const location = this.resolveLocation(projectId, false);
|
|
61
|
+
return this.options.setWorkspaceTrust(location.workspaceRoot, trusted);
|
|
62
|
+
}
|
|
38
63
|
async installZip(projectId, buffer, input = {}) {
|
|
39
64
|
const location = this.resolveLocation(projectId, true);
|
|
40
65
|
const installed = installSkillFromZip(buffer, {
|
|
@@ -44,7 +69,7 @@ var ProjectSkillService = class {
|
|
|
44
69
|
});
|
|
45
70
|
removeSkillsLockEntry(installed.skillId, resolveWorkspaceSkillsLockPath(location.workspaceRoot));
|
|
46
71
|
await this.options.refreshSkills();
|
|
47
|
-
return this.getContent(projectId, installed.skillId);
|
|
72
|
+
return this.getContent(projectId, this.encodeSkillKey("xopc-workspace", installed.skillId));
|
|
48
73
|
}
|
|
49
74
|
async installMarketplace(projectId, input) {
|
|
50
75
|
const downloaded = await downloadFromMarketplace(this.options.getConfig(), input.name, input.version, input.provider);
|
|
@@ -64,7 +89,7 @@ var ProjectSkillService = class {
|
|
|
64
89
|
lockPath: resolveWorkspaceSkillsLockPath(location.workspaceRoot)
|
|
65
90
|
});
|
|
66
91
|
await this.options.refreshSkills();
|
|
67
|
-
return this.getContent(projectId, installed.skillId);
|
|
92
|
+
return this.getContent(projectId, this.encodeSkillKey("xopc-workspace", installed.skillId));
|
|
68
93
|
}
|
|
69
94
|
async remove(projectId, skillId) {
|
|
70
95
|
const location = this.resolveLocation(projectId, true);
|
|
@@ -74,18 +99,6 @@ var ProjectSkillService = class {
|
|
|
74
99
|
removeSkillsLockEntry(skillId, resolveWorkspaceSkillsLockPath(location.workspaceRoot));
|
|
75
100
|
await this.options.refreshSkills();
|
|
76
101
|
}
|
|
77
|
-
findSkill(projectId, skillId) {
|
|
78
|
-
if (!isValidSkillId(skillId)) throw new ProjectSkillError("invalid_skill_id", 400, "Invalid skill id");
|
|
79
|
-
const location = this.resolveLocation(projectId, false);
|
|
80
|
-
const skill = loadWorkspaceSkills(location.workspaceRoot).skills.find((item) => {
|
|
81
|
-
return !relative(location.skillsRoot, item.baseDir).includes(sep) && basename(item.baseDir) === skillId;
|
|
82
|
-
});
|
|
83
|
-
if (!skill) throw new ProjectSkillError("skill_not_found", 404, "Project skill not found");
|
|
84
|
-
return {
|
|
85
|
-
skill,
|
|
86
|
-
skillsRoot: location.skillsRoot
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
102
|
resolveLocation(projectId, requireWritable) {
|
|
90
103
|
const project = this.options.projects.get(projectId);
|
|
91
104
|
if (!project) throw new ProjectSkillError("project_not_found", 404, "Project not found");
|
|
@@ -110,16 +123,50 @@ var ProjectSkillService = class {
|
|
|
110
123
|
skillsRoot
|
|
111
124
|
};
|
|
112
125
|
}
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
126
|
+
loadCatalog(projectId) {
|
|
127
|
+
const location = this.resolveLocation(projectId, false);
|
|
128
|
+
const trust = this.options.getWorkspaceTrust(location.workspaceRoot);
|
|
129
|
+
const loaded = loadWorkspaceSkillInventory(location.workspaceRoot, { workspaceTrust: trust.trusted ? "trusted" : "untrusted" });
|
|
130
|
+
const all = loadSkills({
|
|
131
|
+
workspaceDir: location.workspaceRoot,
|
|
132
|
+
builtinDir: resolveBundledSkillsDir(),
|
|
133
|
+
workspaceTrust: trust.trusted ? "trusted" : "untrusted"
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
location,
|
|
137
|
+
loaded,
|
|
138
|
+
inherited: {
|
|
139
|
+
skills: all.skills.filter((skill) => skill.origin.scope !== "workspace"),
|
|
140
|
+
diagnostics: all.diagnostics
|
|
141
|
+
},
|
|
142
|
+
trust
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
skillKey(skill) {
|
|
146
|
+
const rel = relative(skill.origin.rootDir, skill.baseDir).split(sep).join("/");
|
|
147
|
+
return this.encodeSkillKey(skill.origin.id, rel);
|
|
148
|
+
}
|
|
149
|
+
encodeSkillKey(origin, relativeDir) {
|
|
150
|
+
return Buffer.from(`${origin}\0${relativeDir}`, "utf8").toString("base64url");
|
|
116
151
|
}
|
|
117
|
-
toSummary(
|
|
152
|
+
toSummary(entry) {
|
|
153
|
+
const { skill } = entry;
|
|
154
|
+
const id = basename(skill.baseDir);
|
|
155
|
+
const relativeDir = relative(skill.origin.rootDir, skill.baseDir);
|
|
156
|
+
const removable = skill.origin.id === "xopc-workspace" && !relativeDir.includes(sep) && isValidSkillId(id);
|
|
118
157
|
return {
|
|
119
|
-
|
|
158
|
+
key: this.skillKey(skill),
|
|
159
|
+
directoryId: id,
|
|
120
160
|
name: skill.name,
|
|
121
161
|
description: skill.description,
|
|
122
162
|
category: skill.category,
|
|
163
|
+
origin: skill.origin.id,
|
|
164
|
+
path: skill.baseDir,
|
|
165
|
+
managed: skill.origin.managed,
|
|
166
|
+
writable: skill.origin.writable,
|
|
167
|
+
removable,
|
|
168
|
+
effective: entry.effective,
|
|
169
|
+
shadowedBy: entry.shadowedBy,
|
|
123
170
|
disableModelInvocation: skill.disableModelInvocation,
|
|
124
171
|
metadata: skill.metadata,
|
|
125
172
|
toolConditions: skill.toolConditions,
|
|
@@ -10,6 +10,7 @@ export { closeTemporalAssertions, createTemporalAssertion, linkContextObjects, l
|
|
|
10
10
|
export { finishContextConsolidationRun, getContextConsolidationRun, listContextConsolidationDecisions, listContextConsolidationRuns, recordContextConsolidationDecision, startContextConsolidationRun, type ContextConsolidationDecision, type ContextConsolidationRun, } from './context-consolidation-repository.js';
|
|
11
11
|
export { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality, type UnderstandingFeedbackSummary, type UserUnderstandingQualityMetrics, } from './user-context-quality-repository.js';
|
|
12
12
|
export { createCollaborationRule, createContextEvidence, createUnderstanding, closeUnderstandingValidity, consumeContextConsent, deleteCollaborationRule, deleteUnderstanding, decideContextConsent, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, linkUnderstandingEvidence, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile, type CreateUnderstandingInput, } from './user-context-repository.js';
|
|
13
|
+
export { getUserPerson, getUserPeopleIndexState, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson, } from './user-people-repository.js';
|
|
13
14
|
export { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputState, getSessionInputById, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus, type SessionInput, type SessionInputDelivery, type SessionInputState, type SessionInputStatus, } from './session-input-repository.js';
|
|
14
15
|
export { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget, type ReplaceLatestSessionTurnInput, type ReplaceLatestSessionTurnResult, } from './session-turn-replace-repository.js';
|
|
15
16
|
export { acknowledgeHomeAttention, isHomeAttentionAcknowledged, type HomeAttentionSubjectKind, } from './home-attention-repository.js';
|
|
@@ -11,6 +11,7 @@ import { closeTemporalAssertions, createTemporalAssertion, linkContextObjects, l
|
|
|
11
11
|
import { finishContextConsolidationRun, getContextConsolidationRun, listContextConsolidationDecisions, listContextConsolidationRuns, recordContextConsolidationDecision, startContextConsolidationRun } from "./context-consolidation-repository.js";
|
|
12
12
|
import { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality } from "./user-context-quality-repository.js";
|
|
13
13
|
import { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile } from "./user-context-repository.js";
|
|
14
|
+
import { getUserPeopleIndexState, getUserPerson, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson } from "./user-people-repository.js";
|
|
14
15
|
import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
|
|
15
16
|
import { buildDefaultSessionMetadata } from "./session-metadata.js";
|
|
16
17
|
import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
|
|
@@ -35,4 +36,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
|
|
|
35
36
|
import { getConnectorAccount, listConnectorAccounts, reconcileConnectorAccount, refreshConnectorAccountCurrent } from "./connector-account-repository.js";
|
|
36
37
|
import { getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, listConnectorSyncPolicies, upsertConnectorSyncPolicy } from "./connector-sync-policy-repository.js";
|
|
37
38
|
import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
|
|
38
|
-
export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeTemporalAssertions, closeUnderstandingValidity, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, countKnowledgeSourceItems, countMemoryRecordsBySourceInstanceId, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteKnowledgeSourceItems, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteMemoryRecordsBySourceInstanceId, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getContextExtractionRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasIndependentExtractionOutput, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkContextObjects, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUnderstandingEvidence, listUnderstandings, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchActiveUnderstandings, searchMemoryRecords, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
|
|
39
|
+
export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, closeTemporalAssertions, closeUnderstandingValidity, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeContextConsent, countKnowledgeSourceItems, countMemoryRecordsBySourceInstanceId, createCollaborationRule, createConnectorApproval, createContextEvidence, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, createUnderstanding, decideConnectorApproval, decideContextConsent, deleteCollaborationRule, deleteConnectorConnection, deleteConnectorInstallation, deleteKnowledgeSourceItems, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteMemoryRecordsBySourceInstanceId, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, deleteUnderstanding, discoverSqlMigrations, enqueueConnectorLearningJob, ensureContextConsent, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextConsolidationRun, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextConsolidationRun, getContextExtractionRun, getCurrentSessionId, getEndpointPrincipal, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getMemoryTurnFeedback, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getTurnPersonalization, getUnderstanding, getUserPeopleIndexState, getUserPerson, getUserProfile, getUserTrustPolicy, getXopcDatabase, hasContextConsent, hasIndependentExtractionOutput, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isUnderstandingSuppressed, isXopcDatabaseOpen, linkContextObjects, linkUnderstandingEvidence, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextConsolidationDecisions, listContextConsolidationRuns, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUnderstandingEvidence, listUnderstandings, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recordContextConsolidationDecision, recordContextFeedback, recordContextRun, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, rejectUnderstanding, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, reviseCollaborationRule, reviseUnderstanding, revokeEndpointPrincipal, runSqliteWriteTransaction, searchActiveUnderstandings, searchMemoryRecords, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setCollaborationRuleStatus, setConnectorLearningPaused, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setMemoryProviderState, setMemoryRecordStatus, setMemoryTurnFeedback, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUnderstandingStatus, setUserTrustPolicy, startContextConsolidationRun, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUnderstandingFeedback, summarizeUserPeople, summarizeUserUnderstandingQuality, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserPerson, updateUserProfile, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
CREATE TABLE user_people (
|
|
2
|
+
person_id TEXT PRIMARY KEY,
|
|
3
|
+
principal_id TEXT NOT NULL,
|
|
4
|
+
display_name TEXT NOT NULL,
|
|
5
|
+
user_display_name TEXT,
|
|
6
|
+
inferred_kind TEXT NOT NULL CHECK (inferred_kind IN ('person', 'bot', 'service', 'group', 'unknown')),
|
|
7
|
+
user_kind TEXT CHECK (user_kind IS NULL OR user_kind IN ('person', 'bot', 'service', 'group', 'unknown')),
|
|
8
|
+
hidden INTEGER NOT NULL DEFAULT 0 CHECK (hidden IN (0, 1)),
|
|
9
|
+
merged_into_person_id TEXT REFERENCES user_people(person_id) ON DELETE SET NULL,
|
|
10
|
+
confidence REAL NOT NULL CHECK (confidence >= 0 AND confidence <= 1),
|
|
11
|
+
first_observed_at INTEGER NOT NULL,
|
|
12
|
+
last_observed_at INTEGER NOT NULL,
|
|
13
|
+
created_at INTEGER NOT NULL,
|
|
14
|
+
updated_at INTEGER NOT NULL
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX idx_user_people_principal_kind
|
|
18
|
+
ON user_people(principal_id, inferred_kind, last_observed_at DESC);
|
|
19
|
+
CREATE INDEX idx_user_people_merge_target
|
|
20
|
+
ON user_people(merged_into_person_id);
|
|
21
|
+
|
|
22
|
+
CREATE TABLE user_person_handles (
|
|
23
|
+
handle_id TEXT PRIMARY KEY,
|
|
24
|
+
person_id TEXT NOT NULL REFERENCES user_people(person_id) ON DELETE CASCADE,
|
|
25
|
+
handle_type TEXT NOT NULL CHECK (handle_type IN ('email', 'provider_user', 'username', 'display_name')),
|
|
26
|
+
normalized_value TEXT NOT NULL,
|
|
27
|
+
display_value TEXT NOT NULL,
|
|
28
|
+
source_instance_id TEXT NOT NULL,
|
|
29
|
+
verification TEXT NOT NULL CHECK (verification IN ('observed', 'inferred', 'user_confirmed')),
|
|
30
|
+
first_observed_at INTEGER NOT NULL,
|
|
31
|
+
last_observed_at INTEGER NOT NULL,
|
|
32
|
+
created_at INTEGER NOT NULL,
|
|
33
|
+
updated_at INTEGER NOT NULL,
|
|
34
|
+
UNIQUE(handle_type, normalized_value, source_instance_id)
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE INDEX idx_user_person_handles_person ON user_person_handles(person_id);
|
|
38
|
+
CREATE INDEX idx_user_person_handles_lookup ON user_person_handles(handle_type, normalized_value);
|
|
39
|
+
|
|
40
|
+
CREATE TABLE user_person_source_stats (
|
|
41
|
+
person_id TEXT NOT NULL REFERENCES user_people(person_id) ON DELETE CASCADE,
|
|
42
|
+
source_instance_id TEXT NOT NULL,
|
|
43
|
+
interaction_count INTEGER NOT NULL CHECK (interaction_count >= 0),
|
|
44
|
+
first_observed_at INTEGER NOT NULL,
|
|
45
|
+
last_observed_at INTEGER NOT NULL,
|
|
46
|
+
last_source_item_id TEXT,
|
|
47
|
+
updated_at INTEGER NOT NULL,
|
|
48
|
+
PRIMARY KEY(person_id, source_instance_id)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
CREATE INDEX idx_user_person_source_stats_source
|
|
52
|
+
ON user_person_source_stats(source_instance_id, last_observed_at DESC);
|
|
53
|
+
|
|
54
|
+
CREATE TABLE user_people_index_state (
|
|
55
|
+
principal_id TEXT PRIMARY KEY,
|
|
56
|
+
source_change_sequence INTEGER NOT NULL,
|
|
57
|
+
source_grants_updated_at INTEGER NOT NULL,
|
|
58
|
+
rebuilt_at INTEGER NOT NULL
|
|
59
|
+
);
|
|
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
|
|
|
3
3
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
4
4
|
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
5
5
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
6
|
-
export declare const XOPC_DB_SCHEMA_VERSION =
|
|
6
|
+
export declare const XOPC_DB_SCHEMA_VERSION = 135;
|
|
7
7
|
export declare function resolveMigrationsDir(override?: string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
|
|
|
12
12
|
/** Baseline schema version applied from schema.sql on first open. */
|
|
13
13
|
const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
14
14
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
15
|
-
const XOPC_DB_SCHEMA_VERSION =
|
|
15
|
+
const XOPC_DB_SCHEMA_VERSION = 135;
|
|
16
16
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
17
|
function backupBeforeTaskCutover(db, databasePath) {
|
|
18
18
|
db.exec("PRAGMA wal_checkpoint(FULL)");
|
|
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
|
|
|
57
57
|
* Each step runs in its own transaction and updates schema_meta on success.
|
|
58
58
|
*/
|
|
59
59
|
function applyPendingMigrations(db, options = {}) {
|
|
60
|
-
const targetVersion = options.targetVersion ??
|
|
60
|
+
const targetVersion = options.targetVersion ?? 135;
|
|
61
61
|
let currentVersion = readSchemaVersion(db);
|
|
62
62
|
if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
|
|
63
63
|
if (currentVersion >= targetVersion) return currentVersion;
|
|
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
|
|
|
94
94
|
}
|
|
95
95
|
/** Inspect schema version without mutating the database. */
|
|
96
96
|
function inspectSchemaMigrationStatus(db, options = {}) {
|
|
97
|
-
const appVersion = options.targetVersion ??
|
|
97
|
+
const appVersion = options.targetVersion ?? 135;
|
|
98
98
|
const dbVersion = readSchemaVersion(db);
|
|
99
99
|
if (dbVersion > appVersion) return {
|
|
100
100
|
dbVersion,
|
|
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
|
|
|
19
19
|
export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
|
|
20
20
|
|
|
21
21
|
/** Latest schema version this release supports (increment when adding migrations). */
|
|
22
|
-
export const XOPC_DB_SCHEMA_VERSION =
|
|
22
|
+
export const XOPC_DB_SCHEMA_VERSION = 135;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { UserPerson, UserPersonIndexEntry, UserPersonKind, UserRelationshipSummary } from '../../user-context/relationships/types.js';
|
|
2
|
+
export declare function replaceUserPeopleIndex(entries: UserPersonIndexEntry[], revision: {
|
|
3
|
+
sourceChangeSequence: number;
|
|
4
|
+
sourceGrantsUpdatedAt: number;
|
|
5
|
+
}, principalId?: string, nowMs?: number): void;
|
|
6
|
+
export declare function getUserPeopleIndexState(principalId?: string): {
|
|
7
|
+
sourceChangeSequence: number;
|
|
8
|
+
sourceGrantsUpdatedAt: number;
|
|
9
|
+
rebuiltAt: number;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare function listUserPeople(options?: {
|
|
12
|
+
query?: string;
|
|
13
|
+
kind?: UserPersonKind;
|
|
14
|
+
sourceInstanceId?: string;
|
|
15
|
+
includeHidden?: boolean;
|
|
16
|
+
hiddenOnly?: boolean;
|
|
17
|
+
offset?: number;
|
|
18
|
+
limit?: number;
|
|
19
|
+
principalId?: string;
|
|
20
|
+
}): {
|
|
21
|
+
items: UserPerson[];
|
|
22
|
+
total: number;
|
|
23
|
+
nextOffset?: number;
|
|
24
|
+
};
|
|
25
|
+
export declare function getUserPerson(personId: string, principalId?: string): UserPerson | null;
|
|
26
|
+
export declare function updateUserPerson(personId: string, patch: {
|
|
27
|
+
displayName?: string | null;
|
|
28
|
+
kind?: UserPersonKind | null;
|
|
29
|
+
hidden?: boolean;
|
|
30
|
+
}, principalId?: string): UserPerson | null;
|
|
31
|
+
export declare function summarizeUserPeople(principalId?: string): UserRelationshipSummary;
|
|
32
|
+
export declare function mergeUserPeople(sourcePersonId: string, targetPersonId: string, principalId?: string): UserPerson | null;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
2
|
+
import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
|
|
3
|
+
//#region src/storage/sqlite/user-people-repository.ts
|
|
4
|
+
function sourceMetadata(sourceInstanceId) {
|
|
5
|
+
if (!sourceInstanceId.startsWith("composio:")) return {};
|
|
6
|
+
const connectorId = sourceInstanceId.split(":")[1];
|
|
7
|
+
if (!connectorId) return {};
|
|
8
|
+
return {
|
|
9
|
+
connectorId,
|
|
10
|
+
toolkit: connectorId.replace(/^composio-/, "")
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function handlesFor(personId) {
|
|
14
|
+
return getSqliteDatabase().prepare(`SELECT handle_id, handle_type, display_value,
|
|
15
|
+
source_instance_id, verification, first_observed_at, last_observed_at
|
|
16
|
+
FROM user_person_handles WHERE person_id = ?
|
|
17
|
+
ORDER BY CASE handle_type WHEN 'email' THEN 0 WHEN 'provider_user' THEN 1 WHEN 'username' THEN 2 ELSE 3 END,
|
|
18
|
+
last_observed_at DESC`).all(personId).map((row) => ({
|
|
19
|
+
id: row.handle_id,
|
|
20
|
+
type: row.handle_type,
|
|
21
|
+
value: row.display_value,
|
|
22
|
+
sourceInstanceId: row.source_instance_id,
|
|
23
|
+
verification: row.verification,
|
|
24
|
+
firstObservedAt: row.first_observed_at,
|
|
25
|
+
lastObservedAt: row.last_observed_at
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
function sourcesFor(personId) {
|
|
29
|
+
return getSqliteDatabase().prepare(`SELECT source_instance_id, interaction_count,
|
|
30
|
+
first_observed_at, last_observed_at FROM user_person_source_stats
|
|
31
|
+
WHERE person_id = ? ORDER BY last_observed_at DESC`).all(personId).map((row) => ({
|
|
32
|
+
sourceInstanceId: row.source_instance_id,
|
|
33
|
+
...sourceMetadata(row.source_instance_id),
|
|
34
|
+
interactionCount: row.interaction_count,
|
|
35
|
+
firstObservedAt: row.first_observed_at,
|
|
36
|
+
lastObservedAt: row.last_observed_at
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
function fromRow(row, includeDetails = false) {
|
|
40
|
+
const handles = handlesFor(row.person_id);
|
|
41
|
+
const sources = sourcesFor(row.person_id);
|
|
42
|
+
const primaryHandle = handles.find((handle) => handle.type === "email")?.value ?? handles.find((handle) => handle.type === "provider_user" || handle.type === "username")?.value;
|
|
43
|
+
return {
|
|
44
|
+
id: row.person_id,
|
|
45
|
+
displayName: row.user_display_name ?? row.display_name,
|
|
46
|
+
kind: row.user_kind ?? row.inferred_kind,
|
|
47
|
+
hidden: row.hidden === 1,
|
|
48
|
+
confidence: row.confidence,
|
|
49
|
+
...primaryHandle ? { primaryHandle } : {},
|
|
50
|
+
interactionCount: sources.reduce((total, source) => total + source.interactionCount, 0),
|
|
51
|
+
firstObservedAt: row.first_observed_at,
|
|
52
|
+
lastObservedAt: row.last_observed_at,
|
|
53
|
+
handles: includeDetails ? handles : [],
|
|
54
|
+
sources
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function replaceUserPeopleIndex(entries, revision, principalId = USER_CONTEXT_PRINCIPAL_ID, nowMs = Date.now()) {
|
|
58
|
+
runSqliteWriteTransaction((db) => {
|
|
59
|
+
const mergedRows = db.prepare(`SELECT person_id, merged_into_person_id FROM user_people
|
|
60
|
+
WHERE principal_id = ? AND merged_into_person_id IS NOT NULL`).all(principalId);
|
|
61
|
+
const mergedTargets = new Map(mergedRows.map((row) => [row.person_id, row.merged_into_person_id]));
|
|
62
|
+
const targetFor = (personId) => {
|
|
63
|
+
const seen = /* @__PURE__ */ new Set();
|
|
64
|
+
let current = personId;
|
|
65
|
+
while (mergedTargets.has(current) && !seen.has(current)) {
|
|
66
|
+
seen.add(current);
|
|
67
|
+
current = mergedTargets.get(current);
|
|
68
|
+
}
|
|
69
|
+
return current;
|
|
70
|
+
};
|
|
71
|
+
db.prepare(`DELETE FROM user_person_source_stats
|
|
72
|
+
WHERE person_id IN (SELECT person_id FROM user_people WHERE principal_id = ?)`).run(principalId);
|
|
73
|
+
db.prepare(`DELETE FROM user_person_handles
|
|
74
|
+
WHERE person_id IN (SELECT person_id FROM user_people WHERE principal_id = ?)
|
|
75
|
+
AND verification != 'user_confirmed'`).run(principalId);
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const personId = targetFor(entry.id);
|
|
78
|
+
if (personId === entry.id) db.prepare(`INSERT INTO user_people (
|
|
79
|
+
person_id, principal_id, display_name, inferred_kind, confidence,
|
|
80
|
+
first_observed_at, last_observed_at, created_at, updated_at
|
|
81
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
82
|
+
ON CONFLICT(person_id) DO UPDATE SET
|
|
83
|
+
display_name = excluded.display_name,
|
|
84
|
+
inferred_kind = excluded.inferred_kind,
|
|
85
|
+
confidence = excluded.confidence,
|
|
86
|
+
first_observed_at = MIN(user_people.first_observed_at, excluded.first_observed_at),
|
|
87
|
+
last_observed_at = excluded.last_observed_at,
|
|
88
|
+
updated_at = excluded.updated_at`).run(entry.id, principalId, entry.displayName, entry.inferredKind, entry.confidence, entry.firstObservedAt, entry.lastObservedAt, nowMs, nowMs);
|
|
89
|
+
for (const handle of entry.handles) db.prepare(`INSERT INTO user_person_handles (
|
|
90
|
+
handle_id, person_id, handle_type, normalized_value, display_value,
|
|
91
|
+
source_instance_id, verification, first_observed_at, last_observed_at, created_at, updated_at
|
|
92
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
93
|
+
ON CONFLICT(handle_type, normalized_value, source_instance_id) DO UPDATE SET
|
|
94
|
+
person_id = excluded.person_id,
|
|
95
|
+
display_value = excluded.display_value,
|
|
96
|
+
verification = CASE WHEN user_person_handles.verification = 'user_confirmed'
|
|
97
|
+
THEN 'user_confirmed' ELSE excluded.verification END,
|
|
98
|
+
first_observed_at = MIN(user_person_handles.first_observed_at, excluded.first_observed_at),
|
|
99
|
+
last_observed_at = excluded.last_observed_at,
|
|
100
|
+
updated_at = excluded.updated_at`).run(handle.id, personId, handle.type, handle.value.toLocaleLowerCase(), handle.value, handle.sourceInstanceId, handle.verification, handle.firstObservedAt, handle.lastObservedAt, nowMs, nowMs);
|
|
101
|
+
for (const source of entry.sources) db.prepare(`INSERT INTO user_person_source_stats (
|
|
102
|
+
person_id, source_instance_id, interaction_count, first_observed_at,
|
|
103
|
+
last_observed_at, updated_at
|
|
104
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
105
|
+
ON CONFLICT(person_id, source_instance_id) DO UPDATE SET
|
|
106
|
+
interaction_count = user_person_source_stats.interaction_count + excluded.interaction_count,
|
|
107
|
+
first_observed_at = MIN(user_person_source_stats.first_observed_at, excluded.first_observed_at),
|
|
108
|
+
last_observed_at = MAX(user_person_source_stats.last_observed_at, excluded.last_observed_at),
|
|
109
|
+
updated_at = excluded.updated_at`).run(personId, source.sourceInstanceId, source.interactionCount, source.firstObservedAt, source.lastObservedAt, nowMs);
|
|
110
|
+
}
|
|
111
|
+
db.prepare(`DELETE FROM user_people
|
|
112
|
+
WHERE principal_id = ? AND merged_into_person_id IS NULL AND hidden = 0
|
|
113
|
+
AND user_display_name IS NULL AND user_kind IS NULL
|
|
114
|
+
AND NOT EXISTS (SELECT 1 FROM user_person_source_stats s WHERE s.person_id = user_people.person_id)
|
|
115
|
+
AND NOT EXISTS (SELECT 1 FROM user_person_handles h WHERE h.person_id = user_people.person_id)`).run(principalId);
|
|
116
|
+
db.prepare(`INSERT INTO user_people_index_state (
|
|
117
|
+
principal_id, source_change_sequence, source_grants_updated_at, rebuilt_at
|
|
118
|
+
) VALUES (?, ?, ?, ?)
|
|
119
|
+
ON CONFLICT(principal_id) DO UPDATE SET
|
|
120
|
+
source_change_sequence = excluded.source_change_sequence,
|
|
121
|
+
source_grants_updated_at = excluded.source_grants_updated_at,
|
|
122
|
+
rebuilt_at = excluded.rebuilt_at`).run(principalId, revision.sourceChangeSequence, revision.sourceGrantsUpdatedAt, nowMs);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function getUserPeopleIndexState(principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
126
|
+
const row = getSqliteDatabase().prepare(`SELECT source_change_sequence, source_grants_updated_at, rebuilt_at
|
|
127
|
+
FROM user_people_index_state WHERE principal_id = ?`).get(principalId);
|
|
128
|
+
return row ? {
|
|
129
|
+
sourceChangeSequence: row.source_change_sequence,
|
|
130
|
+
sourceGrantsUpdatedAt: row.source_grants_updated_at,
|
|
131
|
+
rebuiltAt: row.rebuilt_at
|
|
132
|
+
} : null;
|
|
133
|
+
}
|
|
134
|
+
function listUserPeople(options = {}) {
|
|
135
|
+
const principalId = options.principalId ?? "local-owner";
|
|
136
|
+
const clauses = [
|
|
137
|
+
"p.principal_id = ?",
|
|
138
|
+
"p.merged_into_person_id IS NULL",
|
|
139
|
+
"EXISTS (SELECT 1 FROM user_person_source_stats active_source WHERE active_source.person_id = p.person_id)"
|
|
140
|
+
];
|
|
141
|
+
const params = [principalId];
|
|
142
|
+
if (options.hiddenOnly) clauses.push("p.hidden = 1");
|
|
143
|
+
else if (!options.includeHidden) clauses.push("p.hidden = 0");
|
|
144
|
+
if (options.kind) {
|
|
145
|
+
clauses.push("COALESCE(p.user_kind, p.inferred_kind) = ?");
|
|
146
|
+
params.push(options.kind);
|
|
147
|
+
}
|
|
148
|
+
if (options.sourceInstanceId) {
|
|
149
|
+
clauses.push("EXISTS (SELECT 1 FROM user_person_source_stats filtered_source WHERE filtered_source.person_id = p.person_id AND filtered_source.source_instance_id = ?)");
|
|
150
|
+
params.push(options.sourceInstanceId);
|
|
151
|
+
}
|
|
152
|
+
const query = options.query?.trim().toLocaleLowerCase();
|
|
153
|
+
if (query) {
|
|
154
|
+
clauses.push(`(LOWER(COALESCE(p.user_display_name, p.display_name)) LIKE ? OR EXISTS (
|
|
155
|
+
SELECT 1 FROM user_person_handles search_handle
|
|
156
|
+
WHERE search_handle.person_id = p.person_id AND search_handle.normalized_value LIKE ?
|
|
157
|
+
))`);
|
|
158
|
+
params.push(`%${query}%`, `%${query}%`);
|
|
159
|
+
}
|
|
160
|
+
const where = clauses.join(" AND ");
|
|
161
|
+
const total = Number(getSqliteDatabase().prepare(`SELECT COUNT(*) AS count FROM user_people p WHERE ${where}`).get(...params).count);
|
|
162
|
+
const limit = Math.max(1, Math.min(100, Math.floor(options.limit ?? 30)));
|
|
163
|
+
const offset = Math.max(0, Math.floor(options.offset ?? 0));
|
|
164
|
+
const rows = getSqliteDatabase().prepare(`SELECT p.* FROM user_people p WHERE ${where}
|
|
165
|
+
ORDER BY p.last_observed_at DESC, COALESCE(p.user_display_name, p.display_name) ASC
|
|
166
|
+
LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
167
|
+
return {
|
|
168
|
+
items: rows.map((row) => fromRow(row)),
|
|
169
|
+
total,
|
|
170
|
+
...offset + rows.length < total ? { nextOffset: offset + rows.length } : {}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function getUserPerson(personId, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
174
|
+
const row = getSqliteDatabase().prepare(`SELECT * FROM user_people
|
|
175
|
+
WHERE person_id = ? AND principal_id = ? AND merged_into_person_id IS NULL`).get(personId, principalId);
|
|
176
|
+
return row ? fromRow(row, true) : null;
|
|
177
|
+
}
|
|
178
|
+
function updateUserPerson(personId, patch, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
179
|
+
const current = getUserPerson(personId, principalId);
|
|
180
|
+
if (!current) return null;
|
|
181
|
+
runSqliteWriteTransaction((db) => db.prepare(`UPDATE user_people SET
|
|
182
|
+
user_display_name = ?, user_kind = ?, hidden = ?, updated_at = ?
|
|
183
|
+
WHERE person_id = ? AND principal_id = ?`).run(patch.displayName === void 0 ? getUserDisplayName(personId) : patch.displayName, patch.kind === void 0 ? getUserKind(personId) : patch.kind, patch.hidden === void 0 ? Number(current.hidden) : Number(patch.hidden), Date.now(), personId, principalId));
|
|
184
|
+
return getUserPerson(personId, principalId);
|
|
185
|
+
}
|
|
186
|
+
function getUserDisplayName(personId) {
|
|
187
|
+
return getSqliteDatabase().prepare("SELECT user_display_name AS value FROM user_people WHERE person_id = ?").get(personId)?.value ?? null;
|
|
188
|
+
}
|
|
189
|
+
function getUserKind(personId) {
|
|
190
|
+
return getSqliteDatabase().prepare("SELECT user_kind AS value FROM user_people WHERE person_id = ?").get(personId)?.value ?? null;
|
|
191
|
+
}
|
|
192
|
+
function summarizeUserPeople(principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
193
|
+
const row = getSqliteDatabase().prepare(`SELECT
|
|
194
|
+
SUM(CASE WHEN hidden = 0 AND COALESCE(user_kind, inferred_kind) = 'person' THEN 1 ELSE 0 END) AS people,
|
|
195
|
+
SUM(CASE WHEN hidden = 0 AND COALESCE(user_kind, inferred_kind) IN ('bot', 'service', 'group') THEN 1 ELSE 0 END) AS automated,
|
|
196
|
+
SUM(CASE WHEN hidden = 0 AND COALESCE(user_kind, inferred_kind) = 'unknown' THEN 1 ELSE 0 END) AS needs_review,
|
|
197
|
+
SUM(CASE WHEN hidden = 1 THEN 1 ELSE 0 END) AS hidden,
|
|
198
|
+
MAX(last_observed_at) AS last_updated_at
|
|
199
|
+
FROM user_people p WHERE principal_id = ? AND merged_into_person_id IS NULL
|
|
200
|
+
AND EXISTS (SELECT 1 FROM user_person_source_stats s WHERE s.person_id = p.person_id)`).get(principalId);
|
|
201
|
+
const sources = Number(getSqliteDatabase().prepare(`SELECT COUNT(DISTINCT source_instance_id) AS count
|
|
202
|
+
FROM user_person_source_stats s JOIN user_people p ON p.person_id = s.person_id
|
|
203
|
+
WHERE p.principal_id = ? AND p.merged_into_person_id IS NULL`).get(principalId).count);
|
|
204
|
+
return {
|
|
205
|
+
people: Number(row.people ?? 0),
|
|
206
|
+
automatedAccounts: Number(row.automated ?? 0),
|
|
207
|
+
needsReview: Number(row.needs_review ?? 0),
|
|
208
|
+
hidden: Number(row.hidden ?? 0),
|
|
209
|
+
sources,
|
|
210
|
+
...row.last_updated_at == null ? {} : { lastUpdatedAt: row.last_updated_at }
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function mergeUserPeople(sourcePersonId, targetPersonId, principalId = USER_CONTEXT_PRINCIPAL_ID) {
|
|
214
|
+
if (sourcePersonId === targetPersonId) return getUserPerson(targetPersonId, principalId);
|
|
215
|
+
const source = getUserPerson(sourcePersonId, principalId);
|
|
216
|
+
const target = getUserPerson(targetPersonId, principalId);
|
|
217
|
+
if (!source || !target) return null;
|
|
218
|
+
runSqliteWriteTransaction((db) => {
|
|
219
|
+
const duplicateHandles = db.prepare(`SELECT source.handle_id FROM user_person_handles source
|
|
220
|
+
JOIN user_person_handles target
|
|
221
|
+
ON target.person_id = ? AND target.handle_type = source.handle_type
|
|
222
|
+
AND target.normalized_value = source.normalized_value
|
|
223
|
+
AND target.source_instance_id = source.source_instance_id
|
|
224
|
+
WHERE source.person_id = ?`).all(targetPersonId, sourcePersonId);
|
|
225
|
+
for (const duplicate of duplicateHandles) db.prepare("DELETE FROM user_person_handles WHERE handle_id = ?").run(duplicate.handle_id);
|
|
226
|
+
db.prepare("UPDATE user_person_handles SET person_id = ?, updated_at = ? WHERE person_id = ?").run(targetPersonId, Date.now(), sourcePersonId);
|
|
227
|
+
const sourceStats = db.prepare("SELECT * FROM user_person_source_stats WHERE person_id = ?").all(sourcePersonId);
|
|
228
|
+
for (const stat of sourceStats) db.prepare(`INSERT INTO user_person_source_stats (
|
|
229
|
+
person_id, source_instance_id, interaction_count, first_observed_at,
|
|
230
|
+
last_observed_at, last_source_item_id, updated_at
|
|
231
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
232
|
+
ON CONFLICT(person_id, source_instance_id) DO UPDATE SET
|
|
233
|
+
interaction_count = user_person_source_stats.interaction_count + excluded.interaction_count,
|
|
234
|
+
first_observed_at = MIN(user_person_source_stats.first_observed_at, excluded.first_observed_at),
|
|
235
|
+
last_observed_at = MAX(user_person_source_stats.last_observed_at, excluded.last_observed_at),
|
|
236
|
+
last_source_item_id = CASE WHEN excluded.last_observed_at >= user_person_source_stats.last_observed_at
|
|
237
|
+
THEN excluded.last_source_item_id ELSE user_person_source_stats.last_source_item_id END,
|
|
238
|
+
updated_at = excluded.updated_at`).run(targetPersonId, stat.source_instance_id, stat.interaction_count, stat.first_observed_at, stat.last_observed_at, stat.last_source_item_id, Date.now());
|
|
239
|
+
db.prepare("DELETE FROM user_person_source_stats WHERE person_id = ?").run(sourcePersonId);
|
|
240
|
+
db.prepare(`UPDATE user_people SET merged_into_person_id = ?, updated_at = ?
|
|
241
|
+
WHERE person_id = ? AND principal_id = ?`).run(targetPersonId, Date.now(), sourcePersonId, principalId);
|
|
242
|
+
});
|
|
243
|
+
return getUserPerson(targetPersonId, principalId);
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
export { getUserPeopleIndexState, getUserPerson, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { KnowledgeSourceItem } from '../../knowledge/types.js';
|
|
2
|
+
import type { UserPersonIndexEntry } from './types.js';
|
|
3
|
+
type PersonSignal = {
|
|
4
|
+
name?: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
username?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function personIdentityKey(signal: PersonSignal, sourceInstanceId: string): string | undefined;
|
|
9
|
+
export declare function personIdForIdentity(signal: PersonSignal, sourceInstanceId: string): string | undefined;
|
|
10
|
+
export declare function buildUserPeopleIndex(items: KnowledgeSourceItem[]): UserPersonIndexEntry[];
|
|
11
|
+
export declare function rebuildUserPeopleIndex(): UserPersonIndexEntry[];
|
|
12
|
+
export declare function ensureUserPeopleIndex(): void;
|
|
13
|
+
export {};
|