@xopcai/xopc 0.0.266 → 0.0.267
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/dist/assets/{auth-CknJ00ae.js → auth-D_IL6naL.js} +603 -203
- package/dist/browser-ext/dist/assets/sidepanel-CEPaVLjr.css +155 -0
- package/dist/browser-ext/dist/background.js +698 -169
- package/dist/browser-ext/dist/sidepanel.html +3 -3
- package/dist/browser-ext/dist/sidepanel.js +148 -391
- package/dist/browser-ext/manifest.json +3 -6
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Qrp5ALCF.js → agent-avatar-dicebear-ZrSAMchm.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-DwinST48.js → agent-defaults-settings-panel-DiNFN8qS.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-Dlr0YyNt.js → agents-Bu6Hf59K.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-bLNvz93c.js → app-management-settings-panel-D-L6yjS7.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-D5qgIepF.js → appearance-settings-BW5eb53j.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BQVlXhIb.js → apps-page-CiQIdz3N.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-BEA7VAA4.js → archive-plugin-DwXvu1p9.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-B1RyF3uu.js → attachment-load-DqU2BYBp.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BfH0FdKa.js → automations-page-C7qoj9Sd.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-C37AlD3E.js → automations-workspace-CIARTLHO.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-EU884ZXi.js → binary-plugins-CfplDak2.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Bjr3naHb.js → block-editor-CzLs38ru.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-CDrYrNGy.js → browser-automations-page-_SKi8s9b.js} +1 -1
- package/dist/gateway/static/root/assets/browser-settings-page-DTdx66sX.js +8 -0
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-slt1o04n.js → capabilities-settings-panel-Ck9U0Olx.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-oHTTX6Jy.js → channels-settings-I_vDpbnl.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-DEYQdv6n.js → chat-terminal-dock-snvAu3hJ.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-olrbxHIT.js → connectors-page-BmKTnzo1.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-expression-DFrbDWpP.js → cron-expression-BhGZSbT6.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CYriYKpH.js → date-picker-Cep5f9b-.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-XY3qUErs.js → dependency-picker-BzSEBQku.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-Dsc__ynA.js → desktop-pet-BwX_6Gah.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-EpuX3C08.js → desktop-pet-settings-WrbVsU2b.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-B_NeLV4K.js → extension-debug-page-BdXSwtAZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D3JC6mLB.js → extension-page-I95ukbRb.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CXTQt1lp.js → extension-settings-page-8zUisBay.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-yeYm_UPE.js → gateway-settings-DGj5b9Yv.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-coh1LFsg.js → heartbeat-settings-BGQxU-Ug.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-CAgoBZqp.js → home-page-BZPpK0A3.js} +1 -1
- package/dist/gateway/static/root/assets/{index-Cn__9Un2.js → index-D2OtD9Wa.js} +7 -7
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Cu1bI3Bg.js → keyboard-shortcuts-settings-BUe_om99.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-C9s2lFaI.js → local-app-workbench-page-CbQnffS9.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-CJ03Umjr.js → local-apps-page-BZaLzfms.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-CY_DQKJ2.js → logs-page-WWCHqW_x.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-YPEemeMo.js → management-settings-Duf8w-Bl.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BjT6jlrA.js → media-plugins-2-QfzHmg.js} +1 -1
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-A8eLtV6v.js → mobile-pairing-wizard-DRaVIAt1.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-panel-DHT2QksJ.js → note-detail-panel-BT-fWGxX.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-page-BRFQiivM.js → notes-page-C4705PzN.js} +1 -1
- package/dist/gateway/static/root/assets/{page-tabs-DNUwulnl.js → page-tabs-DaZ7QpNO.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-B33KsKkJ.js → preview-open-alternatives-CWEuqCmv.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-CItEFVt9.js → project-detail-page-BZegJ6an.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-Bmy-c_lL.js → projects-page-B7hUHeLI.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-H6B1cA2V.js → remote-access-hub-BE9hZpdh.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BsCovC39.js → runtime-tools-settings-panel-CslkSM-m.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-NsPb_Vam.js → schema-form-B2gvVrBq.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-CyYLSXk_.js → sessions-page-DmAAPMo1.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CvBocGDA.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BzPIPe1-.js → settings-form-section-CmlnuSO3.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-4idpMhsw.js → settings-page-DWWgyelT.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-D2ds_TTD.js → setup-status-panel-CJrN3m1o.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-Djo3VTaC.js → share-preview-page-C12oyIKk.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-fhRzNfRp.js → shares-settings-D4BtSiLq.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-Ct8tUju_.js → skill-reload-api-CzKGn056.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-riM7FytZ.js → skills-page-yhW7LLqk.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-B3G8LBb-.js → skills-page.utils-FaTlq8t-.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CW91jjnB.js → system-settings-panel-CMrkoJLN.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-BBXKvl0k.js → task-detail-page-BUaO62cy.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-DILER0Yb.js → tunnel-api-C2tAZaJz.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-GxnP8vLO.js → use-autosave-BsDRt4QI.js} +1 -1
- package/dist/gateway/static/root/assets/{user-model-page-I1H4XRfA.js → user-model-page-Dy8h1SSJ.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CI3sXyl4.js → voice-api-key-field-CS5heYMP.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DZC9Exn3.js → work-discovery-overlay-BeSz5Th5.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CaBaQER2.js → workflow-run-setup-panel-BebW0CDK.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-C-_Dxihw.js → workflows-page-CU8jFgPF.js} +1 -1
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/dist/packages/browser-control-contract/src/index.js +30 -1
- package/dist/src/agent/external-tools/endpoint-provider.js +3 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/browser/automations/runtime-service.d.ts +2 -0
- package/dist/src/browser/automations/runtime-service.js +1 -1
- package/dist/src/browser/drivers/create-driver.d.ts +2 -1
- package/dist/src/browser/drivers/create-driver.js +4 -6
- package/dist/src/browser/drivers/extension-driver.d.ts +7 -2
- package/dist/src/browser/enrollment.d.ts +8 -0
- package/dist/src/browser/enrollment.js +25 -0
- package/dist/src/browser/extension-identity.d.ts +2 -0
- package/dist/src/browser/extension-identity.js +5 -0
- package/dist/src/browser/native-messaging-host.d.ts +6 -3
- package/dist/src/browser/native-messaging-host.js +23 -5
- package/dist/src/browser/providers/browser-ext-install.d.ts +4 -1
- package/dist/src/browser/providers/browser-ext-install.js +46 -7
- package/dist/src/browser/providers/extension.js +1 -1
- package/dist/src/browser/providers/realtime-extension.d.ts +29 -0
- package/dist/src/browser/providers/realtime-extension.js +83 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/endpoint-tools/policy.js +10 -3
- package/dist/src/gateway/hono/app.js +6 -1
- package/dist/src/gateway/hono/routes/browser.js +20 -30
- package/dist/src/gateway/security/origin-check.js +5 -0
- package/dist/src/gateway/service/config-coordinator.d.ts +0 -2
- package/dist/src/gateway/service/config-coordinator.js +0 -2
- package/dist/src/gateway/service.d.ts +0 -11
- package/dist/src/gateway/service.js +7 -85
- package/dist/src/storage/sqlite/device-pairing-approval.js +24 -3
- package/dist/src/storage/sqlite/device-pairing-repository.d.ts +10 -1
- package/dist/src/storage/sqlite/device-pairing-repository.js +6 -5
- package/dist/src/storage/sqlite/migrations/157_browser_endpoint_principals.sql +50 -0
- package/dist/src/storage/sqlite/migrations/158_browser_native_enrollment.sql +4 -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/package.json +3 -3
- package/dist/browser-ext/dist/assets/sidepanel-C69P3v9u.css +0 -113
- package/dist/gateway/static/root/assets/browser-settings-page-DOmUkj2k.js +0 -8
- package/dist/gateway/static/root/assets/settings-advanced-gate-3T4rPk4A.js +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deleteBrowserTabBinding, getBrowserTabBinding, setBrowserTabBinding } from "../../../storage/sqlite/browser-tab-binding-repository.js";
|
|
2
2
|
import { browserTabBindingRequestSchema } from "../../../../packages/gateway-contract/src/browser-tab-binding.js";
|
|
3
3
|
import { getDevice } from "../../../storage/sqlite/device-access-repository.js";
|
|
4
|
+
import "../../../../packages/browser-control-contract/src/index.js";
|
|
4
5
|
import { decideBrowserApproval, listBrowserApprovals } from "../../../browser/policy/approval-store.js";
|
|
5
6
|
import { createBrowserDriver } from "../../../browser/drivers/create-driver.js";
|
|
6
7
|
import { checkBrowserReadiness } from "../../../browser/readiness.js";
|
|
@@ -9,34 +10,19 @@ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
|
9
10
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
10
11
|
//#region src/gateway/hono/routes/browser.ts
|
|
11
12
|
/** Browser Control status, approvals, and driver diagnostics. */
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
let running = snapshot.active;
|
|
17
|
-
let socketConnected = false;
|
|
18
|
-
let connected = false;
|
|
19
|
-
let protocolVersion = null;
|
|
20
|
-
let expectedProtocolVersion = null;
|
|
21
|
-
let extensionVersion = null;
|
|
22
|
-
try {
|
|
23
|
-
const payload = await (await fetch(EXTENSION_ENDPOINT, { signal: AbortSignal.timeout(2e3) })).json();
|
|
24
|
-
running ||= payload.ok === true;
|
|
25
|
-
socketConnected = payload.socketConnected ?? payload.connected === true;
|
|
26
|
-
connected = payload.connected === true;
|
|
27
|
-
protocolVersion = typeof payload.protocolVersion === "number" ? payload.protocolVersion : null;
|
|
28
|
-
expectedProtocolVersion = typeof payload.expectedProtocolVersion === "number" ? payload.expectedProtocolVersion : null;
|
|
29
|
-
extensionVersion = typeof payload.extensionVersion === "string" ? payload.extensionVersion : null;
|
|
30
|
-
} catch {}
|
|
13
|
+
async function extensionStatus(service) {
|
|
14
|
+
const endpoint = service.endpointTools.registry.list().filter((item) => item.kind === "browser" && item.tools.some((tool) => tool.descriptor.name === "browser.control")).sort((left, right) => right.lastHeartbeatAt - left.lastHeartbeatAt)[0];
|
|
15
|
+
const connected = Boolean(endpoint);
|
|
16
|
+
const extensionVersion = endpoint?.appVersion ?? null;
|
|
31
17
|
const { browserExtDoctor } = await import("../../../browser/providers/browser-ext-install.js");
|
|
32
18
|
const doctor = await browserExtDoctor({ runtimeExtensionVersion: extensionVersion ?? void 0 });
|
|
33
19
|
return {
|
|
34
|
-
running,
|
|
35
|
-
socketConnected,
|
|
20
|
+
running: true,
|
|
21
|
+
socketConnected: connected,
|
|
36
22
|
connected,
|
|
37
23
|
driverKind: "extension",
|
|
38
|
-
protocolVersion,
|
|
39
|
-
expectedProtocolVersion,
|
|
24
|
+
protocolVersion: connected ? 4 : null,
|
|
25
|
+
expectedProtocolVersion: 4,
|
|
40
26
|
extensionVersion,
|
|
41
27
|
artifacts: {
|
|
42
28
|
installed: doctor.installed,
|
|
@@ -45,10 +31,12 @@ async function extensionStatus() {
|
|
|
45
31
|
xopcVersion: doctor.xopcVersion,
|
|
46
32
|
installedVersion: doctor.installedVersion,
|
|
47
33
|
needsRefresh: doctor.needsRefresh,
|
|
48
|
-
needsChromeReload: doctor.needsChromeReload
|
|
34
|
+
needsChromeReload: doctor.needsChromeReload,
|
|
35
|
+
nativeHost: doctor.nativeHost
|
|
49
36
|
},
|
|
50
|
-
bridgeHeld:
|
|
51
|
-
refCount:
|
|
37
|
+
bridgeHeld: false,
|
|
38
|
+
refCount: connected ? 1 : 0,
|
|
39
|
+
transport: "gateway-realtime"
|
|
52
40
|
};
|
|
53
41
|
}
|
|
54
42
|
function isLocalOwnerRequest(c, service) {
|
|
@@ -156,7 +144,7 @@ function registerBrowserRoutes(authenticated, deps) {
|
|
|
156
144
|
});
|
|
157
145
|
authenticated.get("/api/browser/extension-status", async (c) => {
|
|
158
146
|
try {
|
|
159
|
-
return c.json(await extensionStatus());
|
|
147
|
+
return c.json(await extensionStatus(service));
|
|
160
148
|
} catch (error) {
|
|
161
149
|
return c.json({
|
|
162
150
|
running: false,
|
|
@@ -177,7 +165,7 @@ function registerBrowserRoutes(authenticated, deps) {
|
|
|
177
165
|
}
|
|
178
166
|
});
|
|
179
167
|
const readiness = await checkBrowserReadiness(service.currentConfig);
|
|
180
|
-
const driverStatus = config.driver.kind === "extension" ? await extensionStatus().catch((error) => ({ error: error instanceof Error ? error.message : String(error) })) : config.driver.kind === "playwright" ? await import("../../../browser/providers/playwright-doctor.js").then(({ playwrightChromiumDoctor }) => playwrightChromiumDoctor()) : void 0;
|
|
168
|
+
const driverStatus = config.driver.kind === "extension" ? await extensionStatus(service).catch((error) => ({ error: error instanceof Error ? error.message : String(error) })) : config.driver.kind === "playwright" ? await import("../../../browser/providers/playwright-doctor.js").then(({ playwrightChromiumDoctor }) => playwrightChromiumDoctor()) : void 0;
|
|
181
169
|
const extensionConnected = config.driver.kind === "extension" ? driverStatus.connected === true : true;
|
|
182
170
|
const extensionProtocolDetail = config.driver.kind === "extension" && "socketConnected" in driverStatus && driverStatus.socketConnected && !driverStatus.connected ? `Chrome extension protocol ${driverStatus.protocolVersion ?? "unknown"} does not match ${driverStatus.expectedProtocolVersion ?? "the gateway"}. Reload the extension in Chrome.` : void 0;
|
|
183
171
|
return c.json({
|
|
@@ -204,7 +192,7 @@ function registerBrowserRoutes(authenticated, deps) {
|
|
|
204
192
|
const startedAt = Date.now();
|
|
205
193
|
let driver;
|
|
206
194
|
try {
|
|
207
|
-
driver = await createBrowserDriver(service.currentConfig.browser);
|
|
195
|
+
driver = await createBrowserDriver(service.currentConfig.browser, service.endpointTools);
|
|
208
196
|
await driver.connect();
|
|
209
197
|
return c.json({
|
|
210
198
|
ok: true,
|
|
@@ -229,12 +217,14 @@ function registerBrowserRoutes(authenticated, deps) {
|
|
|
229
217
|
}, 403);
|
|
230
218
|
const body = await c.req.json().catch(() => ({}));
|
|
231
219
|
try {
|
|
232
|
-
const { browserExtDoctor, ensureBrowserExtensionArtifacts } = await import("../../../browser/providers/browser-ext-install.js");
|
|
220
|
+
const { browserExtDoctor, ensureBrowserExtensionArtifacts, installBrowserNativeMessagingHost } = await import("../../../browser/providers/browser-ext-install.js");
|
|
233
221
|
const result = await ensureBrowserExtensionArtifacts({ force: body.force === true });
|
|
222
|
+
const nativeHost = await installBrowserNativeMessagingHost({ configPath: service.getHealth().configPath });
|
|
234
223
|
return c.json({
|
|
235
224
|
ok: true,
|
|
236
225
|
payload: {
|
|
237
226
|
...result,
|
|
227
|
+
nativeHost,
|
|
238
228
|
doctor: await browserExtDoctor()
|
|
239
229
|
}
|
|
240
230
|
});
|
|
@@ -15,6 +15,11 @@ function isLoopbackHost(hostname) {
|
|
|
15
15
|
function parseOriginHost(originRaw) {
|
|
16
16
|
const trimmed = (originRaw ?? "").trim();
|
|
17
17
|
if (!trimmed || trimmed === "null") return null;
|
|
18
|
+
if (isChromeExtensionOrigin(trimmed)) return {
|
|
19
|
+
origin: trimmed.toLowerCase(),
|
|
20
|
+
host: "",
|
|
21
|
+
hostname: ""
|
|
22
|
+
};
|
|
18
23
|
try {
|
|
19
24
|
const url = new URL(trimmed);
|
|
20
25
|
return {
|
|
@@ -41,8 +41,6 @@ export interface GatewayConfigCoordinatorOptions {
|
|
|
41
41
|
getChannelManager: () => ChannelManager;
|
|
42
42
|
getHeartbeatService: () => HeartbeatService | null;
|
|
43
43
|
getExtensionLoader: () => ExtensionLoader | null;
|
|
44
|
-
/** Re-evaluate browser-extension server attachment after agent defaults change. */
|
|
45
|
-
reconcileBrowserExtensionServer: () => Promise<void>;
|
|
46
44
|
/** Sync deterministic user-model maintenance automations after config changes. */
|
|
47
45
|
reconcileMemoryMaintenanceAutomations: () => Promise<void>;
|
|
48
46
|
/** Latest channel status snapshot for the `channels.status` event. */
|
|
@@ -223,7 +223,6 @@ var GatewayConfigCoordinator = class {
|
|
|
223
223
|
log.debug("Reloading agent defaults...");
|
|
224
224
|
this.opts.setConfig(newConfig);
|
|
225
225
|
this.opts.getAgentService().applyAgentDefaultsFromConfig(newConfig);
|
|
226
|
-
this.opts.reconcileBrowserExtensionServer();
|
|
227
226
|
this.opts.reconcileMemoryMaintenanceAutomations().catch((err) => {
|
|
228
227
|
const em = err instanceof Error ? err.message : String(err);
|
|
229
228
|
log.warn({
|
|
@@ -350,7 +349,6 @@ var GatewayConfigCoordinator = class {
|
|
|
350
349
|
this.opts.setConfig(reloaded);
|
|
351
350
|
if (sanitizeTunnelConfig(reloaded)) await saveConfig(reloaded, this.opts.configPath);
|
|
352
351
|
this.opts.getAgentService().applyAgentDefaultsFromConfig(reloaded);
|
|
353
|
-
await this.opts.reconcileBrowserExtensionServer();
|
|
354
352
|
await this.opts.reconcileMemoryMaintenanceAutomations().catch((err) => {
|
|
355
353
|
const em = err instanceof Error ? err.message : String(err);
|
|
356
354
|
log.warn({
|
|
@@ -39,10 +39,6 @@ export declare class GatewayService {
|
|
|
39
39
|
private notesService;
|
|
40
40
|
private extensionLoader;
|
|
41
41
|
private extensionMetadataSnapshot;
|
|
42
|
-
private browserExtensionProvider;
|
|
43
|
-
private browserExtensionRelease;
|
|
44
|
-
/** `${host}:${port}` when the gateway holds the extension bridge listener. */
|
|
45
|
-
private browserExtensionBindKey;
|
|
46
42
|
private heartbeatService;
|
|
47
43
|
private sessionIndex;
|
|
48
44
|
private running;
|
|
@@ -198,13 +194,6 @@ export declare class GatewayService {
|
|
|
198
194
|
*/
|
|
199
195
|
onHttpListening(): Promise<void>;
|
|
200
196
|
stop(): Promise<void>;
|
|
201
|
-
/** Start the browser extension WebSocket server when its driver is active. */
|
|
202
|
-
private startBrowserExtensionServerIfNeeded;
|
|
203
|
-
/**
|
|
204
|
-
* Start/stop/rebind the Chrome extension bridge.
|
|
205
|
-
* PATCH saves update config in memory without re-running gateway startup, so this must run on save too.
|
|
206
|
-
*/
|
|
207
|
-
reconcileBrowserExtensionServer(): Promise<void>;
|
|
208
197
|
/**
|
|
209
198
|
* Start processing outbound messages and send through channels
|
|
210
199
|
*/
|
|
@@ -54,12 +54,6 @@ import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
|
|
|
54
54
|
import { ChannelManager } from "../channels/manager.js";
|
|
55
55
|
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
56
56
|
import "../config/index.js";
|
|
57
|
-
import { DiscussionService } from "../discussions/service.js";
|
|
58
|
-
import { DiscussionOrganizer } from "../discussions/organizer.js";
|
|
59
|
-
import { DiscussionLiveWorker } from "../discussions/live-worker.js";
|
|
60
|
-
import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
|
|
61
|
-
import { DiscussionSealer } from "../discussions/sealer.js";
|
|
62
|
-
import "../discussions/index.js";
|
|
63
57
|
import { ManagedComposioEventPoller } from "../connectors/composio-managed-events.js";
|
|
64
58
|
import { startConnectedKnowledgeCoordinator } from "../knowledge/coordinator.js";
|
|
65
59
|
import "../knowledge/index.js";
|
|
@@ -67,6 +61,12 @@ import { ConnectionRecoveryService } from "../connectors/connection-recovery-ser
|
|
|
67
61
|
import { startConnectorLearningCoordinator } from "../connectors/learning-coordinator.js";
|
|
68
62
|
import { ConnectedSourceChangePublisher } from "../connectors/source-change-publisher.js";
|
|
69
63
|
import { startConnectorSupervisor } from "../connectors/supervisor.js";
|
|
64
|
+
import { DiscussionService } from "../discussions/service.js";
|
|
65
|
+
import { DiscussionOrganizer } from "../discussions/organizer.js";
|
|
66
|
+
import { DiscussionLiveWorker } from "../discussions/live-worker.js";
|
|
67
|
+
import { DiscussionOrganizerWorker } from "../discussions/organizer-worker.js";
|
|
68
|
+
import { DiscussionSealer } from "../discussions/sealer.js";
|
|
69
|
+
import "../discussions/index.js";
|
|
70
70
|
import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
|
|
71
71
|
import "../endpoint-tools/index.js";
|
|
72
72
|
import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
|
|
@@ -152,10 +152,6 @@ var GatewayService = class {
|
|
|
152
152
|
notesService;
|
|
153
153
|
extensionLoader = null;
|
|
154
154
|
extensionMetadataSnapshot = null;
|
|
155
|
-
browserExtensionProvider = null;
|
|
156
|
-
browserExtensionRelease = null;
|
|
157
|
-
/** `${host}:${port}` when the gateway holds the extension bridge listener. */
|
|
158
|
-
browserExtensionBindKey = null;
|
|
159
155
|
heartbeatService = null;
|
|
160
156
|
sessionIndex;
|
|
161
157
|
running = false;
|
|
@@ -249,6 +245,7 @@ var GatewayService = class {
|
|
|
249
245
|
get browserAutomations() {
|
|
250
246
|
if (!this.browserAutomationService) this.browserAutomationService = createRuntimeBrowserAutomationService({
|
|
251
247
|
getConfig: () => this.config,
|
|
248
|
+
endpointTools: this.endpointTools,
|
|
252
249
|
emit: (type, payload) => this.emit(type, payload)
|
|
253
250
|
});
|
|
254
251
|
return this.browserAutomationService;
|
|
@@ -520,7 +517,6 @@ var GatewayService = class {
|
|
|
520
517
|
getChannelManager: () => this.channelManager,
|
|
521
518
|
getHeartbeatService: () => this.heartbeatService,
|
|
522
519
|
getExtensionLoader: () => this.extensionLoader,
|
|
523
|
-
reconcileBrowserExtensionServer: () => this.reconcileBrowserExtensionServer(),
|
|
524
520
|
reconcileMemoryMaintenanceAutomations: () => this.reconcileMemoryMaintenanceAutomations(),
|
|
525
521
|
getChannelsStatus: () => this.getChannelsStatus(),
|
|
526
522
|
emit: (type, payload) => this.emit(type, payload)
|
|
@@ -1099,7 +1095,6 @@ var GatewayService = class {
|
|
|
1099
1095
|
workspaceId: this.currentWorkspacePath
|
|
1100
1096
|
}) });
|
|
1101
1097
|
import("../browser/providers/browser-ext-install.js").then(({ ensureBrowserExtensionOnStartup }) => ensureBrowserExtensionOnStartup(this.config)).catch((err) => log.warn({ err }, "Browser extension artifact ensure failed"));
|
|
1102
|
-
await trace.measure("browser-extension.start", () => this.startBrowserExtensionServerIfNeeded());
|
|
1103
1098
|
this.agentService.start().catch((err) => {
|
|
1104
1099
|
log.error({ err }, "Agent service error");
|
|
1105
1100
|
});
|
|
@@ -1260,12 +1255,6 @@ var GatewayService = class {
|
|
|
1260
1255
|
this.connectedKnowledgeCoordinator?.stop();
|
|
1261
1256
|
this.connectedKnowledgeCoordinator = null;
|
|
1262
1257
|
await this.browserAutomationService?.shutdown();
|
|
1263
|
-
if (this.browserExtensionRelease) {
|
|
1264
|
-
await this.browserExtensionRelease();
|
|
1265
|
-
this.browserExtensionRelease = null;
|
|
1266
|
-
}
|
|
1267
|
-
this.browserExtensionProvider = null;
|
|
1268
|
-
this.browserExtensionBindKey = null;
|
|
1269
1258
|
registerClarificationChannelRuntime(null);
|
|
1270
1259
|
this.connectionRecovery.stop();
|
|
1271
1260
|
this.agentRunner.disposeClarifications();
|
|
@@ -1288,73 +1277,6 @@ var GatewayService = class {
|
|
|
1288
1277
|
closeXopcDatabase();
|
|
1289
1278
|
log.debug("Gateway service stopped");
|
|
1290
1279
|
}
|
|
1291
|
-
/** Start the browser extension WebSocket server when its driver is active. */
|
|
1292
|
-
async startBrowserExtensionServerIfNeeded() {
|
|
1293
|
-
await this.reconcileBrowserExtensionServer();
|
|
1294
|
-
}
|
|
1295
|
-
/**
|
|
1296
|
-
* Start/stop/rebind the Chrome extension bridge.
|
|
1297
|
-
* PATCH saves update config in memory without re-running gateway startup, so this must run on save too.
|
|
1298
|
-
*/
|
|
1299
|
-
async reconcileBrowserExtensionServer() {
|
|
1300
|
-
const driver = this.config.browser.driver;
|
|
1301
|
-
const bridgeConfig = this.config.browser.enabled && driver.kind === "extension" ? {
|
|
1302
|
-
host: "127.0.0.1",
|
|
1303
|
-
port: 19820,
|
|
1304
|
-
connectionTimeout: this.config.browser.limits.actionTimeoutMs,
|
|
1305
|
-
commandTimeout: this.config.browser.limits.actionTimeoutMs
|
|
1306
|
-
} : null;
|
|
1307
|
-
if (!bridgeConfig) {
|
|
1308
|
-
if (this.browserExtensionRelease) {
|
|
1309
|
-
await this.browserExtensionRelease();
|
|
1310
|
-
this.browserExtensionRelease = null;
|
|
1311
|
-
this.browserExtensionProvider = null;
|
|
1312
|
-
this.browserExtensionBindKey = null;
|
|
1313
|
-
log.debug("Browser extension WebSocket server stopped because its driver is inactive");
|
|
1314
|
-
}
|
|
1315
|
-
return;
|
|
1316
|
-
}
|
|
1317
|
-
const { port, host, connectionTimeout, commandTimeout } = bridgeConfig;
|
|
1318
|
-
const bindKey = `${host}:${port}`;
|
|
1319
|
-
if (this.browserExtensionRelease && this.browserExtensionBindKey === bindKey) return;
|
|
1320
|
-
if (this.browserExtensionRelease) {
|
|
1321
|
-
await this.browserExtensionRelease();
|
|
1322
|
-
this.browserExtensionRelease = null;
|
|
1323
|
-
this.browserExtensionProvider = null;
|
|
1324
|
-
this.browserExtensionBindKey = null;
|
|
1325
|
-
}
|
|
1326
|
-
try {
|
|
1327
|
-
const { acquireExtensionBrowserServer } = await import("../browser/providers/extension-ws-acquire.js");
|
|
1328
|
-
const { provider, release } = await acquireExtensionBrowserServer({
|
|
1329
|
-
port,
|
|
1330
|
-
host,
|
|
1331
|
-
connectionTimeout,
|
|
1332
|
-
commandTimeout
|
|
1333
|
-
});
|
|
1334
|
-
this.browserExtensionProvider = provider;
|
|
1335
|
-
this.browserExtensionRelease = release;
|
|
1336
|
-
this.browserExtensionBindKey = bindKey;
|
|
1337
|
-
log.info({
|
|
1338
|
-
port,
|
|
1339
|
-
host
|
|
1340
|
-
}, "Browser extension WS server started");
|
|
1341
|
-
} catch (err) {
|
|
1342
|
-
if ((err && typeof err === "object" && "code" in err ? err.code : void 0) === "EADDRINUSE") {
|
|
1343
|
-
log.warn({
|
|
1344
|
-
err,
|
|
1345
|
-
phase: "browser_extension_ws",
|
|
1346
|
-
bindPort: port,
|
|
1347
|
-
bindHost: host,
|
|
1348
|
-
hint: "Another process holds the browser extension bridge port 19820. Stop it before starting xopc."
|
|
1349
|
-
}, `Browser extension WS server port is already in use: ${host}:${port}`);
|
|
1350
|
-
return;
|
|
1351
|
-
}
|
|
1352
|
-
log.error({
|
|
1353
|
-
err,
|
|
1354
|
-
phase: "browser_extension_ws"
|
|
1355
|
-
}, `Failed to start browser extension WS server: ${err instanceof Error ? err.message : String(err)}`);
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
1280
|
/**
|
|
1359
1281
|
* Start processing outbound messages and send through channels
|
|
1360
1282
|
*/
|
|
@@ -3,6 +3,8 @@ import { buildDevicePairingProof, devicePairingCompleteSchema, devicePairingDevi
|
|
|
3
3
|
import { DEFAULT_BROWSER_EXTENSION_SCOPES, DEFAULT_MOBILE_SCOPES } from "../../gateway/security/gateway-scopes.js";
|
|
4
4
|
import { createDevice, getDevice, registerInitialDeviceRefreshToken, revokeDevice } from "./device-access-repository.js";
|
|
5
5
|
import { getOrCreateGatewayIdentity } from "./gateway-identity-repository.js";
|
|
6
|
+
import { browserEnrollmentPublicKeyThumbprint } from "../../browser/enrollment.js";
|
|
7
|
+
import "../../browser/extension-identity.js";
|
|
6
8
|
import crypto from "node:crypto";
|
|
7
9
|
//#region src/storage/sqlite/device-pairing-approval.ts
|
|
8
10
|
const PROOF_WINDOW_MS = 5 * 6e4;
|
|
@@ -20,6 +22,23 @@ const fail = (code, status) => {
|
|
|
20
22
|
throw new DevicePairingError(code, status);
|
|
21
23
|
};
|
|
22
24
|
const scopesForPlatform = (platform) => platform === "chrome" ? DEFAULT_BROWSER_EXTENSION_SCOPES : DEFAULT_MOBILE_SCOPES;
|
|
25
|
+
function isTrustedLocalBrowserSetup(setup, deviceJson) {
|
|
26
|
+
const device = devicePairingDeviceSchema.parse(JSON.parse(deviceJson));
|
|
27
|
+
if (device.platform !== "chrome" || device.extensionId !== "gopbfhaojnnhiheiikblejnpgmfmkmgd" || setup.enrollment_issuer !== "browser-native-host" || setup.enrollment_extension_id !== device.extensionId || !setup.enrollment_public_key_thumbprint || browserEnrollmentPublicKeyThumbprint(device.publicKeyJwk) !== setup.enrollment_public_key_thumbprint || !setup.enrollment_nonce) return false;
|
|
28
|
+
const routes = JSON.parse(setup.routes_json);
|
|
29
|
+
if (routes.length !== 1 || routes[0]?.kind !== "local-browser") return false;
|
|
30
|
+
try {
|
|
31
|
+
const url = new URL(routes[0].url);
|
|
32
|
+
return url.protocol === "http:" && url.hostname === "127.0.0.1";
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function approveTrustedLocalBrowserRequest(setup, row, now) {
|
|
38
|
+
if (row.status !== "pending" || !isTrustedLocalBrowserSetup(setup, row.device_json)) return row;
|
|
39
|
+
getSqliteDatabase().prepare("UPDATE device_pairing_requests SET status = 'approved', revision = revision + 1 WHERE request_id = ? AND status = 'pending'").run(row.request_id);
|
|
40
|
+
return requestRow(row.request_id, now);
|
|
41
|
+
}
|
|
23
42
|
function requestRow(id, now) {
|
|
24
43
|
const db = getSqliteDatabase();
|
|
25
44
|
db.prepare(`UPDATE device_pairing_requests SET status = 'expired', revision = revision + 1
|
|
@@ -75,18 +94,19 @@ function submitDevicePairingRequest(body, now = Date.now()) {
|
|
|
75
94
|
const setup = verifiedSetup(String(body.pairingToken), now);
|
|
76
95
|
const device = devicePairingDeviceSchema.parse(body.device);
|
|
77
96
|
const deviceJson = JSON.stringify(device);
|
|
97
|
+
const autoApprove = isTrustedLocalBrowserSetup(setup, deviceJson);
|
|
78
98
|
verifyProof("request", body, deviceJson, now);
|
|
79
99
|
return runSqliteWriteTransaction((db) => {
|
|
80
100
|
const existing = db.prepare("SELECT request_id, device_json FROM device_pairing_requests WHERE pairing_id = ?").get(setup.pairing_id);
|
|
81
101
|
if (existing) {
|
|
82
102
|
if (existing.request_id !== body.requestId || existing.device_json !== deviceJson) return fail("PAIRING_BUSY");
|
|
83
|
-
return statusFromRow(requestRow(existing.request_id, now), now);
|
|
103
|
+
return statusFromRow(approveTrustedLocalBrowserRequest(setup, requestRow(existing.request_id, now), now), now);
|
|
84
104
|
}
|
|
85
105
|
if (setup.consumed_at !== null) return fail("PAIRING_CANCELLED");
|
|
86
106
|
if (setup.expires_at <= now) return fail("PAIRING_EXPIRED");
|
|
87
107
|
const expiresAt = Math.min(setup.expires_at, now + APPROVAL_WINDOW_MS);
|
|
88
108
|
db.prepare(`INSERT INTO device_pairing_requests (request_id, pairing_id, device_json, status,
|
|
89
|
-
confirmation_code, expires_at, recovery_until, created_at) VALUES (?, ?, ?,
|
|
109
|
+
confirmation_code, expires_at, recovery_until, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(String(body.requestId), setup.pairing_id, deviceJson, autoApprove ? "approved" : "pending", crypto.randomInt(0, 1e6).toString().padStart(6, "0"), expiresAt, setup.expires_at + RECOVERY_WINDOW_MS, now);
|
|
90
110
|
return statusFromRow(requestRow(String(body.requestId), now), now);
|
|
91
111
|
});
|
|
92
112
|
}
|
|
@@ -115,9 +135,10 @@ function cancelDevicePairingSetup(id, now = Date.now()) {
|
|
|
115
135
|
}
|
|
116
136
|
function operateDevicePairingRequest(action, body, now = Date.now()) {
|
|
117
137
|
const setup = verifiedSetup(String(body.pairingToken), now);
|
|
118
|
-
|
|
138
|
+
let row = requestRow(String(body.requestId), now);
|
|
119
139
|
if (row.pairing_id !== setup.pairing_id) return fail("PAIRING_DENIED", 401);
|
|
120
140
|
verifyProof(action, body, row.device_json, now);
|
|
141
|
+
if (action === "status") row = approveTrustedLocalBrowserRequest(setup, row, now);
|
|
121
142
|
if (action !== "cancel" && row.device_id && getDevice(row.device_id)?.revokedAt !== void 0) return fail("DEVICE_REVOKED", 401);
|
|
122
143
|
if (now >= row.recovery_until) return fail("PAIRING_EXPIRED");
|
|
123
144
|
if (action === "cancel") runSqliteWriteTransaction((db) => {
|
|
@@ -9,6 +9,12 @@ export type DevicePairingSetup = {
|
|
|
9
9
|
routes: DeviceRoute[];
|
|
10
10
|
expiresAt: number;
|
|
11
11
|
};
|
|
12
|
+
export type DevicePairingEnrollment = {
|
|
13
|
+
issuer: 'browser-native-host';
|
|
14
|
+
extensionId: string;
|
|
15
|
+
publicKeyThumbprint: string;
|
|
16
|
+
nonce: string;
|
|
17
|
+
};
|
|
12
18
|
export type PairingConsumeResult = {
|
|
13
19
|
ok: true;
|
|
14
20
|
pairingId: string;
|
|
@@ -17,6 +23,9 @@ export type PairingConsumeResult = {
|
|
|
17
23
|
ok: false;
|
|
18
24
|
reason: 'invalid' | 'expired' | 'consumed';
|
|
19
25
|
};
|
|
20
|
-
export declare function createDevicePairingSetup(routes: readonly DeviceRoute[], now?: number, protocolVersion?: 2 | 3
|
|
26
|
+
export declare function createDevicePairingSetup(routes: readonly DeviceRoute[], now?: number, protocolVersion?: 2 | 3, options?: {
|
|
27
|
+
ttlMs?: number;
|
|
28
|
+
enrollment?: DevicePairingEnrollment;
|
|
29
|
+
}): DevicePairingSetup;
|
|
21
30
|
export declare function consumeDevicePairingToken(token: string, now?: number): PairingConsumeResult;
|
|
22
31
|
export declare function isDevicePairingSetupActive(pairingId: string, now?: number): boolean;
|
|
@@ -16,11 +16,11 @@ function tokenId(token) {
|
|
|
16
16
|
if (separator <= 10 || separator === token.length - 1) return void 0;
|
|
17
17
|
return token.slice(10, separator);
|
|
18
18
|
}
|
|
19
|
-
function createDevicePairingSetup(routes, now = Date.now(), protocolVersion = 2) {
|
|
19
|
+
function createDevicePairingSetup(routes, now = Date.now(), protocolVersion = 2, options) {
|
|
20
20
|
if (routes.length === 0) throw new Error("No secure mobile route is available");
|
|
21
21
|
const id = crypto.randomUUID();
|
|
22
22
|
const token = `${PAIRING_TOKEN_PREFIX}${id}_${crypto.randomBytes(32).toString("base64url")}`;
|
|
23
|
-
const expiresAt = now + PAIRING_TTL_MS;
|
|
23
|
+
const expiresAt = now + (options?.ttlMs ?? PAIRING_TTL_MS);
|
|
24
24
|
runSqliteWriteTransaction((db) => {
|
|
25
25
|
db.prepare(`DELETE FROM device_pairing_sessions WHERE
|
|
26
26
|
(protocol_version = 2 AND (expires_at <= ? OR consumed_at IS NOT NULL)) OR
|
|
@@ -28,9 +28,10 @@ function createDevicePairingSetup(routes, now = Date.now(), protocolVersion = 2)
|
|
|
28
28
|
db.prepare(`
|
|
29
29
|
INSERT INTO device_pairing_sessions (
|
|
30
30
|
pairing_id, secret_hash, routes_json, expires_at, attempts_remaining, created_at
|
|
31
|
-
, protocol_version
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
, protocol_version, enrollment_issuer, enrollment_extension_id,
|
|
32
|
+
enrollment_public_key_thumbprint, enrollment_nonce
|
|
33
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
34
|
+
`).run(id, hashToken(token), JSON.stringify(routes), expiresAt, PAIRING_ATTEMPTS, now, protocolVersion, options?.enrollment?.issuer ?? null, options?.enrollment?.extensionId ?? null, options?.enrollment?.publicKeyThumbprint ?? null, options?.enrollment?.nonce ?? null);
|
|
34
35
|
});
|
|
35
36
|
return {
|
|
36
37
|
id,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
PRAGMA defer_foreign_keys = ON;
|
|
2
|
+
|
|
3
|
+
-- Rebuild the related tables because SQLite rewrites the child foreign-key target
|
|
4
|
+
-- when the parent table is renamed.
|
|
5
|
+
ALTER TABLE endpoint_session_bindings RENAME TO endpoint_session_bindings_v156;
|
|
6
|
+
ALTER TABLE endpoint_instance_bindings RENAME TO endpoint_instance_bindings_v156;
|
|
7
|
+
ALTER TABLE endpoint_principals RENAME TO endpoint_principals_v156;
|
|
8
|
+
|
|
9
|
+
DROP INDEX idx_endpoint_session_bindings_endpoint;
|
|
10
|
+
DROP INDEX idx_endpoint_instance_bindings_principal;
|
|
11
|
+
DROP INDEX idx_endpoint_principals_active;
|
|
12
|
+
|
|
13
|
+
CREATE TABLE endpoint_principals (
|
|
14
|
+
id TEXT PRIMARY KEY,
|
|
15
|
+
kind TEXT NOT NULL CHECK(kind IN ('web', 'desktop', 'mobile', 'browser')),
|
|
16
|
+
display_name TEXT NOT NULL,
|
|
17
|
+
platform TEXT NOT NULL,
|
|
18
|
+
public_key TEXT NOT NULL,
|
|
19
|
+
created_at INTEGER NOT NULL,
|
|
20
|
+
last_seen_at INTEGER,
|
|
21
|
+
revoked_at INTEGER
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE TABLE endpoint_instance_bindings (
|
|
25
|
+
endpoint_id TEXT PRIMARY KEY,
|
|
26
|
+
principal_id TEXT NOT NULL REFERENCES endpoint_principals(id),
|
|
27
|
+
bound_at INTEGER NOT NULL
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE endpoint_session_bindings (
|
|
31
|
+
session_key TEXT PRIMARY KEY,
|
|
32
|
+
endpoint_id TEXT NOT NULL REFERENCES endpoint_instance_bindings(endpoint_id),
|
|
33
|
+
bound_at INTEGER NOT NULL
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
INSERT INTO endpoint_principals SELECT * FROM endpoint_principals_v156;
|
|
37
|
+
INSERT INTO endpoint_instance_bindings SELECT * FROM endpoint_instance_bindings_v156;
|
|
38
|
+
INSERT INTO endpoint_session_bindings SELECT * FROM endpoint_session_bindings_v156;
|
|
39
|
+
|
|
40
|
+
DROP TABLE endpoint_session_bindings_v156;
|
|
41
|
+
DROP TABLE endpoint_instance_bindings_v156;
|
|
42
|
+
DROP TABLE endpoint_principals_v156;
|
|
43
|
+
|
|
44
|
+
CREATE INDEX idx_endpoint_principals_active
|
|
45
|
+
ON endpoint_principals(kind, last_seen_at DESC)
|
|
46
|
+
WHERE revoked_at IS NULL;
|
|
47
|
+
CREATE INDEX idx_endpoint_instance_bindings_principal
|
|
48
|
+
ON endpoint_instance_bindings(principal_id);
|
|
49
|
+
CREATE INDEX idx_endpoint_session_bindings_endpoint
|
|
50
|
+
ON endpoint_session_bindings(endpoint_id);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
ALTER TABLE device_pairing_sessions ADD COLUMN enrollment_issuer TEXT;
|
|
2
|
+
ALTER TABLE device_pairing_sessions ADD COLUMN enrollment_extension_id TEXT;
|
|
3
|
+
ALTER TABLE device_pairing_sessions ADD COLUMN enrollment_public_key_thumbprint TEXT;
|
|
4
|
+
ALTER TABLE device_pairing_sessions ADD COLUMN enrollment_nonce TEXT;
|
|
@@ -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 = 158;
|
|
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 = 158;
|
|
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 ?? 158;
|
|
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 ?? 158;
|
|
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 = 158;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.267",
|
|
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",
|
|
@@ -165,9 +165,9 @@
|
|
|
165
165
|
"vue": "^3.5.35",
|
|
166
166
|
"@xopcai/browser-control-contract": "0.1.0",
|
|
167
167
|
"@xopcai/endpoint-tools-protocol": "0.0.0",
|
|
168
|
+
"@xopcai/gateway-contract": "0.0.0",
|
|
168
169
|
"@xopcai/realtime-client": "0.0.0",
|
|
169
|
-
"@xopcai/realtime-protocol": "0.0.0"
|
|
170
|
-
"@xopcai/gateway-contract": "0.0.0"
|
|
170
|
+
"@xopcai/realtime-protocol": "0.0.0"
|
|
171
171
|
},
|
|
172
172
|
"scripts": {
|
|
173
173
|
"assets:brand": "node scripts/generate-brand-assets.mjs",
|