@senguoyun/dsh-arkme 0.1.32 → 0.1.34
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/README.md +24 -0
- package/lib/client.js +4247 -4140
- package/lib/client.js.map +1 -1
- package/lib/extension-profile-restart-helper.js +17 -5
- package/lib/index.js +412 -23
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-CFeIg6aw.js → persistent-runtime-CZQTfyC1.js} +35814 -6704
- package/lib/types/arkme-service.d.ts +9 -1
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeExtensionRecoveryNotice.d.ts +9 -0
- package/lib/types/client/ArkmeExtensionRecoveryNotice.d.ts.map +1 -0
- package/lib/types/client/ArkmeFooterAction.d.ts +1 -7
- package/lib/types/client/ArkmeFooterAction.d.ts.map +1 -1
- package/lib/types/client/ArkmeFooterDropdown.d.ts.map +1 -1
- package/lib/types/client/ArkmeMarketplace.d.ts +2 -1
- package/lib/types/client/ArkmeMarketplace.d.ts.map +1 -1
- package/lib/types/client/ArkmeMessageSnapshotDialog.d.ts +17 -0
- package/lib/types/client/ArkmeMessageSnapshotDialog.d.ts.map +1 -0
- package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeProductNavigation.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichComposerInput.d.ts +3 -1
- package/lib/types/client/ArkmeRichComposerInput.d.ts.map +1 -1
- package/lib/types/client/ArkmeSettingsSurface.d.ts +4 -19
- package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeUpdateSurfaces.d.ts +38 -5
- package/lib/types/client/ArkmeUpdateSurfaces.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/desktop-quarantine-status.d.ts +3 -0
- package/lib/types/client/desktop-quarantine-status.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +0 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/record-capture-location.d.ts +8 -0
- package/lib/types/client/record-capture-location.d.ts.map +1 -0
- package/lib/types/client/update-presentation.d.ts +1 -1
- package/lib/types/client/update-presentation.d.ts.map +1 -1
- package/lib/types/client/update-ui-controller.d.ts +1 -1
- package/lib/types/client/update-ui-controller.d.ts.map +1 -1
- package/lib/types/extensions/desktop-quarantine.d.ts +79 -0
- package/lib/types/extensions/desktop-quarantine.d.ts.map +1 -0
- package/lib/types/extensions/profile-installer.d.ts +5 -0
- package/lib/types/extensions/profile-installer.d.ts.map +1 -1
- package/lib/types/extensions/profile-restart-helper.d.ts +3 -1
- package/lib/types/extensions/profile-restart-helper.d.ts.map +1 -1
- package/lib/types/host-api.d.ts +3 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/local-database.d.ts +1 -0
- package/lib/types/local-database.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +14 -1
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/group-ai-polish-service.d.ts +3 -1
- package/lib/types/services/group-ai-polish-service.d.ts.map +1 -1
- package/lib/types/services/record-service.d.ts +10 -3
- package/lib/types/services/record-service.d.ts.map +1 -1
- package/lib/types/state-store.d.ts.map +1 -1
- package/lib/types/types.d.ts +50 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +6 -5
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as securePrivateDirectory, c as securePrivateFileSync, i as prepareProfilePackageManager, n as isArkmeProfilePackageName, o as securePrivateDirectorySync, r as localExtensionPnpmArgs, s as securePrivateFile, t as applyArkmeProfileBundlePolicy } from "./profile-bundle-policy-CvojZuTD.js";
|
|
2
|
-
import { $ as ARKME_RUNTIME_INSTANCE_ID, A as inspectNativeBundleArtifactV3, D as bundleSha256, E as arkmeSandboxEntryId, F as assertExtensionArtifactSize, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, K as ARKME_DEFAULT_SHARE_WEBSITE, L as sha256Hex, M as packLocalNativeBundleDirectoryV3, N as readNativeBundleTarballV3, O as canonicalBundleJson, P as renderArkmeSandboxHostEntry, Q as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, R as unpackArkmeExtension, S as ARKME_BUNDLE_ARTIFACT_KIND, T as ArkmeBundleArtifactError, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, Z as ARKME_WORLD_PUBLISH_MAX_IMAGES, _ as arkmeClientContentDigest, at as ArkmePluginError, b as verifyExtensionResolutionSignature, c as persistentExtensionBundleDirectory, d as readPersistentExtensionActivation, et as ARKME_TOOL_FILE_MAX_BYTES, f as refreshPersistentClientWrapper, g as activeProfileExtensionOwnerConflicts, h as renderArkmeBundleClientBundle, i as invokePersistentArkmeExtension, it as isArkmeBotAvatarRef, j as packBundleFiles, k as inspectBundleArtifact, l as persistentExtensionPackageIdentity, m as writePersistentExtensionActivation, nt as arkmeNormalizedFileMimeType, o as persistentArkmeExtensionRuntimeState, ot as ArkmeOutgoingCallError, p as repairPersistentExtensionInstallation, q as ARKME_PROVIDER_CONTRACT_VERSION, r as deactivatePersistentArkmeExtension, rt as arkmePickedFileKind, s as materializePersistentExtensionBundle, t as activatePersistentArkmeExtension, tt as arkmeCanInlineLocalFile, u as quarantinePersistentExtension, v as arkmeClientContentDigestFromSource, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, x as verifyNativeBundleResolutionSignature, y as verifyBundleResolutionSignature, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-
|
|
2
|
+
import { $ as ARKME_RUNTIME_INSTANCE_ID, A as inspectNativeBundleArtifactV3, D as bundleSha256, E as arkmeSandboxEntryId, F as assertExtensionArtifactSize, G as validateVoiceprintPcm16Wav, I as canonicalExtensionJson, K as ARKME_DEFAULT_SHARE_WEBSITE, L as sha256Hex, M as packLocalNativeBundleDirectoryV3, N as readNativeBundleTarballV3, O as canonicalBundleJson, P as renderArkmeSandboxHostEntry, Q as ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, R as unpackArkmeExtension, S as ARKME_BUNDLE_ARTIFACT_KIND, T as ArkmeBundleArtifactError, U as ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE, W as ArkmeService, Z as ARKME_WORLD_PUBLISH_MAX_IMAGES, _ as arkmeClientContentDigest, at as ArkmePluginError, b as verifyExtensionResolutionSignature, c as persistentExtensionBundleDirectory, d as readPersistentExtensionActivation, et as ARKME_TOOL_FILE_MAX_BYTES, f as refreshPersistentClientWrapper, g as activeProfileExtensionOwnerConflicts, h as renderArkmeBundleClientBundle, i as invokePersistentArkmeExtension, it as isArkmeBotAvatarRef, j as packBundleFiles, k as inspectBundleArtifact, l as persistentExtensionPackageIdentity, m as writePersistentExtensionActivation, nt as arkmeNormalizedFileMimeType, o as persistentArkmeExtensionRuntimeState, ot as ArkmeOutgoingCallError, p as repairPersistentExtensionInstallation, q as ARKME_PROVIDER_CONTRACT_VERSION, r as deactivatePersistentArkmeExtension, rt as arkmePickedFileKind, s as materializePersistentExtensionBundle, t as activatePersistentArkmeExtension, tt as arkmeCanInlineLocalFile, u as quarantinePersistentExtension, v as arkmeClientContentDigestFromSource, w as ARKME_NATIVE_BUNDLE_ARTIFACT_KIND, x as verifyNativeBundleResolutionSignature, y as verifyBundleResolutionSignature, z as ARKME_EXTENSION_FORMAT } from "./persistent-runtime-CZQTfyC1.js";
|
|
3
3
|
import { _ as parsePluginUpdateManifest, b as validatePluginUpdateServiceOrigin, d as writePluginUpdateLifecycleLog, f as PluginUpdateInstallStateStore, g as existingCachedPluginArtifactPath, h as downloadAndCachePluginArtifact, m as PluginUpdateArtifactError, n as buildTargetInstallArgs, o as reconcilePluginUpdaterProfilePolicy, p as ARKME_PLUGIN_PACKAGE_NAME$1, t as assertTargetArtifactIntegrity, u as detachManagedProfilePluginLink, v as pluginUpdateEndpointUrl, y as validatePluginUpdateArtifactOrigin } from "./plugin-updater-helper-BByw0ZyG.js";
|
|
4
4
|
import { i as invokeArkmeBundle, n as arkmeBundleActive, r as deactivateArkmeBundle } from "./bundle-runtime-BTzRlc6V.js";
|
|
5
5
|
import { t as ArkmeExtensionInstallStore } from "./install-store-C1tAM346.js";
|
|
@@ -10,7 +10,7 @@ import { dirname, isAbsolute, join, relative, resolve, sep, win32 } from "node:p
|
|
|
10
10
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
11
|
import Schema from "@deepseek-ai/schemastery";
|
|
12
12
|
import { execFile, spawn } from "node:child_process";
|
|
13
|
-
import { chmod as chmod$1, mkdir, open, readFile, realpath, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
13
|
+
import { chmod as chmod$1, mkdir, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
14
14
|
import { promisify } from "node:util";
|
|
15
15
|
import { createServer } from "node:http";
|
|
16
16
|
import { Readable } from "node:stream";
|
|
@@ -1517,6 +1517,43 @@ function numberParam(params, key, fallback) {
|
|
|
1517
1517
|
const value = params[key];
|
|
1518
1518
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1519
1519
|
}
|
|
1520
|
+
function captureContextParam(params) {
|
|
1521
|
+
const raw = params.captureContext;
|
|
1522
|
+
if (raw === void 0) return void 0;
|
|
1523
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new ArkmePluginError("capture-context-invalid", "记忆快照参数无效", false, 400);
|
|
1524
|
+
const value = raw;
|
|
1525
|
+
const clientName = stringParam(value, "clientName").trim().slice(0, 120);
|
|
1526
|
+
const networkName = stringParam(value, "networkName").trim().slice(0, 120);
|
|
1527
|
+
const electric = typeof value.electric === "number" && Number.isFinite(value.electric) ? Math.trunc(value.electric) : void 0;
|
|
1528
|
+
const charge = Math.trunc(numberParam(value, "charge", 0));
|
|
1529
|
+
const context = {
|
|
1530
|
+
...clientName === "" ? {} : { clientName },
|
|
1531
|
+
...networkName === "" ? {} : { networkName },
|
|
1532
|
+
...electric === void 0 || electric < 0 || electric > 100 ? {} : { electric },
|
|
1533
|
+
...charge < 1 || charge > 3 ? {} : { charge }
|
|
1534
|
+
};
|
|
1535
|
+
return Object.keys(context).length === 0 ? void 0 : context;
|
|
1536
|
+
}
|
|
1537
|
+
function recordLocationCaptureParam(params) {
|
|
1538
|
+
const raw = params.location;
|
|
1539
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new ArkmePluginError("record-location-invalid", "位置快照参数无效", false, 400);
|
|
1540
|
+
const value = raw;
|
|
1541
|
+
const latitude = numberParam(value, "latitude", NaN);
|
|
1542
|
+
const longitude = numberParam(value, "longitude", NaN);
|
|
1543
|
+
if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90 || !Number.isFinite(longitude) || longitude < -180 || longitude > 180) throw new ArkmePluginError("record-location-invalid", "位置坐标无效", false, 400);
|
|
1544
|
+
const altitudeMeters = numberParam(value, "altitudeMeters", NaN);
|
|
1545
|
+
const speedMetersPerSecond = numberParam(value, "speedMetersPerSecond", NaN);
|
|
1546
|
+
const accuracyMeters = numberParam(value, "accuracyMeters", NaN);
|
|
1547
|
+
const capturedAtMillis = Math.trunc(numberParam(value, "capturedAtMillis", 0));
|
|
1548
|
+
return {
|
|
1549
|
+
latitude,
|
|
1550
|
+
longitude,
|
|
1551
|
+
capturedAtMillis: capturedAtMillis > 0 ? capturedAtMillis : Date.now(),
|
|
1552
|
+
...Number.isFinite(accuracyMeters) && accuracyMeters >= 0 ? { accuracyMeters } : {},
|
|
1553
|
+
...Number.isFinite(altitudeMeters) ? { altitudeMeters } : {},
|
|
1554
|
+
...Number.isFinite(speedMetersPerSecond) && speedMetersPerSecond >= 0 ? { speedMetersPerSecond } : {}
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1520
1557
|
const ARKME_DIRECTORY_SECTIONS = /* @__PURE__ */ new Set([
|
|
1521
1558
|
"groups",
|
|
1522
1559
|
"bots",
|
|
@@ -1773,6 +1810,8 @@ function botRefsParam(params) {
|
|
|
1773
1810
|
function richSendParam(params) {
|
|
1774
1811
|
const rawAssets = Array.isArray(params.assets) ? params.assets : [];
|
|
1775
1812
|
const thinkingDurationMillis = Math.max(0, Math.trunc(numberParam(params, "thinkingDurationMillis", 0)));
|
|
1813
|
+
const recordDurationMillis = Math.max(0, Math.trunc(numberParam(params, "recordDurationMillis", 0)));
|
|
1814
|
+
const captureContext = captureContextParam(params);
|
|
1776
1815
|
const humanMentions = humanMentionsParam(params);
|
|
1777
1816
|
const botMentions = botMentionsParam(params);
|
|
1778
1817
|
return {
|
|
@@ -1780,6 +1819,8 @@ function richSendParam(params) {
|
|
|
1780
1819
|
textContent: stringParam(params, "textContent"),
|
|
1781
1820
|
displayKind: numberParam(params, "displayKind", 0) === 1 ? 1 : 0,
|
|
1782
1821
|
...thinkingDurationMillis === 0 ? {} : { thinkingDurationMillis },
|
|
1822
|
+
...recordDurationMillis === 0 ? {} : { recordDurationMillis },
|
|
1823
|
+
...captureContext === void 0 ? {} : { captureContext },
|
|
1783
1824
|
...humanMentions.length === 0 ? {} : { humanMentions },
|
|
1784
1825
|
...botMentions.length === 0 ? {} : { botMentions },
|
|
1785
1826
|
assets: rawAssets.flatMap((raw) => {
|
|
@@ -1893,11 +1934,13 @@ function createArkmeHostApi(service, options) {
|
|
|
1893
1934
|
"extensions.persistent.invoke",
|
|
1894
1935
|
"extensions.bundle.invoke",
|
|
1895
1936
|
"extensions.mine.publish",
|
|
1937
|
+
"extensions.quarantine.dismiss",
|
|
1938
|
+
"extensions.quarantine.reenable",
|
|
1896
1939
|
"remote.renameDesktop"
|
|
1897
1940
|
].includes(request.operation) && origin === void 0) throw new ArkmePluginError("origin-required", "扩展变更必须从当前 DSH 页面发起", false, 403);
|
|
1898
1941
|
writeJson$4(res, 200, {
|
|
1899
1942
|
ok: true,
|
|
1900
|
-
value: await dispatchArkmeHostOperation(service, request.operation, params, options.updateManager, options.extensionManager?.(), options.extensionInstallTasks?.(), options.ownedExtensionInventory?.(), controller.signal, options.remoteHost?.())
|
|
1943
|
+
value: await dispatchArkmeHostOperation(service, request.operation, params, options.updateManager, options.extensionManager?.(), options.extensionInstallTasks?.(), options.ownedExtensionInventory?.(), controller.signal, options.remoteHost?.(), options.desktopQuarantine)
|
|
1901
1944
|
});
|
|
1902
1945
|
} catch (error) {
|
|
1903
1946
|
if (controller.signal.aborted && res.destroyed) return;
|
|
@@ -1915,7 +1958,7 @@ function createArkmeHostApi(service, options) {
|
|
|
1915
1958
|
}
|
|
1916
1959
|
};
|
|
1917
1960
|
}
|
|
1918
|
-
async function dispatchArkmeHostOperation(service, operation, params, updateManager, extensionManager, extensionInstallTasks, ownedExtensionInventory, requestSignal, remoteHost) {
|
|
1961
|
+
async function dispatchArkmeHostOperation(service, operation, params, updateManager, extensionManager, extensionInstallTasks, ownedExtensionInventory, requestSignal, remoteHost, desktopQuarantine) {
|
|
1919
1962
|
switch (operation) {
|
|
1920
1963
|
case "provider.capabilities": return service.providerCapabilities();
|
|
1921
1964
|
case "provider.instance": return { instanceId: ARKME_RUNTIME_INSTANCE_ID };
|
|
@@ -2238,6 +2281,10 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
|
|
|
2238
2281
|
case "source.message-copy-link.resolve": return await service.resolveMessageCopyLink(stringParam(params, "sid"), requestSignal === void 0 ? {} : { signal: requestSignal });
|
|
2239
2282
|
case "source.message-copy-link.extend": return await service.extendMessageCopyLink(stringParam(params, "sid"), numberParam(params, "itemIndex", 0), stringParam(params, "textContent"), stringParam(params, "recordUid"), requestSignal === void 0 ? {} : { signal: requestSignal });
|
|
2240
2283
|
case "source.shared-recording-detail": return await service.sharedRecordingDetail(stringParam(params, "detailRef"), requestSignal === void 0 ? {} : { signal: requestSignal });
|
|
2284
|
+
case "source.message-snapshot.detail": return await service.messageSnapshotDetail(stringParam(params, "sourceRef"), stringParam(params, "actionRef"), requestSignal === void 0 ? {} : { signal: requestSignal });
|
|
2285
|
+
case "source.message-location.set":
|
|
2286
|
+
await service.saveMessageLocation(stringParam(params, "sourceRef"), stringParam(params, "itemUid"), recordLocationCaptureParam(params), numberParam(params, "recordVersion", 0) || void 0, requestSignal === void 0 ? {} : { signal: requestSignal });
|
|
2287
|
+
return { ok: true };
|
|
2241
2288
|
case "source.forward-messages": return await service.forwardSourceMessages(stringParam(params, "sourceRef"), messageActionRefsParam(params), {
|
|
2242
2289
|
...stringParam(params, "targetSourceRef") === "" ? {} : { targetSourceRef: stringParam(params, "targetSourceRef") },
|
|
2243
2290
|
...stringParam(params, "recordUid") === "" ? {} : { recordUid: stringParam(params, "recordUid") },
|
|
@@ -2249,9 +2296,12 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
|
|
|
2249
2296
|
const botRefs = botRefsParam(params);
|
|
2250
2297
|
const humanMentions = humanMentionsParam(params);
|
|
2251
2298
|
const botMentions = botMentionsParam(params);
|
|
2299
|
+
const captureContext = captureContextParam(params);
|
|
2252
2300
|
return await service.sendSourceText(stringParam(params, "sourceRef"), stringParam(params, "textContent"), {
|
|
2253
2301
|
...stringParam(params, "recordUid") === "" ? {} : { recordUid: stringParam(params, "recordUid") },
|
|
2254
2302
|
...stringParam(params, "relationUid") === "" ? {} : { relationUid: stringParam(params, "relationUid") },
|
|
2303
|
+
...numberParam(params, "recordDurationMillis", 0) <= 0 ? {} : { recordDurationMillis: Math.max(0, Math.trunc(numberParam(params, "recordDurationMillis", 0))) },
|
|
2304
|
+
...captureContext === void 0 ? {} : { captureContext },
|
|
2255
2305
|
...booleanParam(params, "agentAuthored") ? { agentAuthored: true } : {},
|
|
2256
2306
|
...botRefs.length === 0 ? {} : { botRefs },
|
|
2257
2307
|
...humanMentions.length === 0 ? {} : { humanMentions },
|
|
@@ -2451,6 +2501,10 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
|
|
|
2451
2501
|
case "extensions.share.resolve": return (await enrichExtensionAuthors(service, [await requireExtensionManager(extensionManager).resolveSharedCatalogDetail(stringParam(params, "shareRef"))]))[0];
|
|
2452
2502
|
case "extensions.delete": return await requireOwnedExtensionInventory(ownedExtensionInventory).delete({ extensionId: stringParam(params, "extensionId") });
|
|
2453
2503
|
case "extensions.installed-list": return requireExtensionManager(extensionManager).listInstalled();
|
|
2504
|
+
case "extensions.quarantine.status": return await requireDesktopQuarantine(desktopQuarantine).status();
|
|
2505
|
+
case "extensions.quarantine.dismiss": return await requireDesktopQuarantine(desktopQuarantine).dismiss(stringParam(params, "packageName"));
|
|
2506
|
+
case "extensions.quarantine.reenable": return await requireDesktopQuarantine(desktopQuarantine).reenable(stringParam(params, "packageName"));
|
|
2507
|
+
case "extensions.quarantine.health": return await requireDesktopQuarantine(desktopQuarantine).health(stringParam(params, "packageName"));
|
|
2454
2508
|
case "extensions.mine.list": return await requireOwnedExtensionInventory(ownedExtensionInventory).list({ ...stringParam(params, "currentSessionId").trim() === "" ? {} : { currentSessionId: stringParam(params, "currentSessionId").trim() } });
|
|
2455
2509
|
case "extensions.mine.publish": return await requireOwnedExtensionInventory(ownedExtensionInventory).publish({
|
|
2456
2510
|
ownedRef: stringParam(params, "ownedRef"),
|
|
@@ -2531,6 +2585,10 @@ function requireExtensionManager(manager) {
|
|
|
2531
2585
|
if (manager === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "当前 DSH 未加载 Dynamic Cordis Runner,市集不可用", false, 503);
|
|
2532
2586
|
return manager;
|
|
2533
2587
|
}
|
|
2588
|
+
function requireDesktopQuarantine(quarantine) {
|
|
2589
|
+
if (quarantine === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "桌面扩展恢复状态尚未就绪", false, 503);
|
|
2590
|
+
return quarantine;
|
|
2591
|
+
}
|
|
2534
2592
|
function requireOwnedExtensionInventory(inventory) {
|
|
2535
2593
|
if (inventory === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "扩展运行时尚未就绪", true, 503);
|
|
2536
2594
|
return inventory;
|
|
@@ -3743,6 +3801,8 @@ var ArkmeLocalDatabase = class {
|
|
|
3743
3801
|
sync_state TEXT NOT NULL CHECK (sync_state IN ('synced', 'pending', 'failed')),
|
|
3744
3802
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
3745
3803
|
last_error TEXT,
|
|
3804
|
+
record_duration_millis INTEGER NOT NULL DEFAULT 0,
|
|
3805
|
+
capture_context_json TEXT,
|
|
3746
3806
|
created_at_millis INTEGER NOT NULL,
|
|
3747
3807
|
updated_at_millis INTEGER NOT NULL,
|
|
3748
3808
|
PRIMARY KEY (user_id, record_uid)
|
|
@@ -3796,6 +3856,9 @@ var ArkmeLocalDatabase = class {
|
|
|
3796
3856
|
CREATE UNIQUE INDEX IF NOT EXISTS extension_review_outbox_user_record
|
|
3797
3857
|
ON extension_review_outbox (user_id, record_uid);
|
|
3798
3858
|
`);
|
|
3859
|
+
const recordColumns = this.database.prepare("PRAGMA table_info(record_cache)").all();
|
|
3860
|
+
if (!recordColumns.some((column) => column.name === "record_duration_millis")) this.database.exec("ALTER TABLE record_cache ADD COLUMN record_duration_millis INTEGER NOT NULL DEFAULT 0");
|
|
3861
|
+
if (!recordColumns.some((column) => column.name === "capture_context_json")) this.database.exec("ALTER TABLE record_cache ADD COLUMN capture_context_json TEXT");
|
|
3799
3862
|
const metaColumns = this.database.prepare("PRAGMA table_info(cache_meta)").all();
|
|
3800
3863
|
if (!metaColumns.some((column) => column.name === "pagination_initialized")) this.database.exec("ALTER TABLE cache_meta ADD COLUMN pagination_initialized INTEGER NOT NULL DEFAULT 0");
|
|
3801
3864
|
if (!metaColumns.some((column) => column.name === "revision")) this.database.exec("ALTER TABLE cache_meta ADD COLUMN revision INTEGER NOT NULL DEFAULT 0");
|
|
@@ -3954,18 +4017,25 @@ var ArkmeLocalDatabase = class {
|
|
|
3954
4017
|
async listPending(userId) {
|
|
3955
4018
|
await this.ensureMigrated(userId);
|
|
3956
4019
|
return this.database.prepare(`
|
|
3957
|
-
SELECT record_uid, text_content, created_at_millis, send_at_millis, attempts, last_error
|
|
4020
|
+
SELECT record_uid, text_content, created_at_millis, send_at_millis, attempts, last_error,
|
|
4021
|
+
record_duration_millis, capture_context_json
|
|
3958
4022
|
FROM record_cache
|
|
3959
4023
|
WHERE user_id = ? AND sync_state IN ('pending', 'failed')
|
|
3960
4024
|
ORDER BY created_at_millis ASC, record_uid ASC
|
|
3961
|
-
`).all(userId).map((row) =>
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
4025
|
+
`).all(userId).map((row) => {
|
|
4026
|
+
const captureContext = this.pendingCaptureContext(row.capture_context_json);
|
|
4027
|
+
const recordDurationMillis = Math.max(0, Math.trunc(row.record_duration_millis ?? 0));
|
|
4028
|
+
return {
|
|
4029
|
+
recordUid: row.record_uid,
|
|
4030
|
+
textContent: row.text_content,
|
|
4031
|
+
createdAtMillis: row.created_at_millis,
|
|
4032
|
+
sendAtMillis: row.send_at_millis,
|
|
4033
|
+
attempts: row.attempts,
|
|
4034
|
+
...recordDurationMillis === 0 ? {} : { recordDurationMillis },
|
|
4035
|
+
...captureContext === void 0 ? {} : { captureContext },
|
|
4036
|
+
...row.last_error == null || row.last_error === "" ? {} : { lastError: row.last_error }
|
|
4037
|
+
};
|
|
4038
|
+
});
|
|
3969
4039
|
}
|
|
3970
4040
|
async putPending(userId, pending) {
|
|
3971
4041
|
await this.ensureMigrated(userId);
|
|
@@ -4101,12 +4171,14 @@ var ArkmeLocalDatabase = class {
|
|
|
4101
4171
|
}
|
|
4102
4172
|
insertPending(userId, pending) {
|
|
4103
4173
|
const now = Date.now();
|
|
4174
|
+
const recordDurationMillis = Math.max(0, Math.trunc(pending.recordDurationMillis ?? 0));
|
|
4175
|
+
const captureContextJson = pending.captureContext === void 0 ? null : JSON.stringify(pending.captureContext);
|
|
4104
4176
|
this.database.prepare(`
|
|
4105
4177
|
INSERT INTO record_cache (
|
|
4106
4178
|
user_id, record_uid, send_at_millis, title, text_content, template_kind,
|
|
4107
4179
|
status, version, sync_state, attempts, last_error,
|
|
4108
|
-
created_at_millis, updated_at_millis
|
|
4109
|
-
) VALUES (?, ?, ?, '', ?, 1, 0, 0, 'pending', ?, ?, ?, ?)
|
|
4180
|
+
record_duration_millis, capture_context_json, created_at_millis, updated_at_millis
|
|
4181
|
+
) VALUES (?, ?, ?, '', ?, 1, 0, 0, 'pending', ?, ?, ?, ?, ?, ?)
|
|
4110
4182
|
ON CONFLICT(user_id, record_uid) DO UPDATE SET
|
|
4111
4183
|
send_at_millis = excluded.send_at_millis,
|
|
4112
4184
|
text_content = excluded.text_content,
|
|
@@ -4114,8 +4186,31 @@ var ArkmeLocalDatabase = class {
|
|
|
4114
4186
|
sync_state = 'pending',
|
|
4115
4187
|
attempts = excluded.attempts,
|
|
4116
4188
|
last_error = excluded.last_error,
|
|
4189
|
+
record_duration_millis = excluded.record_duration_millis,
|
|
4190
|
+
capture_context_json = excluded.capture_context_json,
|
|
4117
4191
|
updated_at_millis = excluded.updated_at_millis
|
|
4118
|
-
`).run(userId, pending.recordUid, pending.sendAtMillis, pending.textContent, pending.attempts, pending.lastError ?? null, pending.createdAtMillis, now);
|
|
4192
|
+
`).run(userId, pending.recordUid, pending.sendAtMillis, pending.textContent, pending.attempts, pending.lastError ?? null, recordDurationMillis, captureContextJson, pending.createdAtMillis, now);
|
|
4193
|
+
}
|
|
4194
|
+
pendingCaptureContext(raw) {
|
|
4195
|
+
if (raw == null || raw === "") return void 0;
|
|
4196
|
+
try {
|
|
4197
|
+
const value = JSON.parse(raw);
|
|
4198
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
4199
|
+
const source = value;
|
|
4200
|
+
const clientName = typeof source.clientName === "string" ? source.clientName.trim().slice(0, 120) : "";
|
|
4201
|
+
const networkName = typeof source.networkName === "string" ? source.networkName.trim().slice(0, 120) : "";
|
|
4202
|
+
const electric = typeof source.electric === "number" && Number.isFinite(source.electric) ? Math.trunc(source.electric) : void 0;
|
|
4203
|
+
const charge = typeof source.charge === "number" && Number.isFinite(source.charge) ? Math.trunc(source.charge) : 0;
|
|
4204
|
+
const result = {
|
|
4205
|
+
...clientName === "" ? {} : { clientName },
|
|
4206
|
+
...networkName === "" ? {} : { networkName },
|
|
4207
|
+
...electric === void 0 || electric < 0 || electric > 100 ? {} : { electric },
|
|
4208
|
+
...charge < 1 || charge > 3 ? {} : { charge }
|
|
4209
|
+
};
|
|
4210
|
+
return Object.keys(result).length === 0 ? void 0 : result;
|
|
4211
|
+
} catch {
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4119
4214
|
}
|
|
4120
4215
|
upsertSyncedRecord(userId, item) {
|
|
4121
4216
|
const now = Date.now();
|
|
@@ -4638,6 +4733,247 @@ var ArkmeRealtimeEvents = class {
|
|
|
4638
4733
|
}
|
|
4639
4734
|
};
|
|
4640
4735
|
//#endregion
|
|
4736
|
+
//#region src/extensions/desktop-quarantine.ts
|
|
4737
|
+
const QUARANTINE_DIRECTORY_NAME = "desktop-extension-quarantine";
|
|
4738
|
+
const RECEIPT_FILE_NAME = "receipt.json";
|
|
4739
|
+
const PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
4740
|
+
const QUARANTINE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
4741
|
+
const RUNTIME_RELEASE_PATTERN = /^electron-runtime-v1-[a-f0-9]{32}$/;
|
|
4742
|
+
const MAX_FAILURE_SUMMARY_LENGTH = 2e3;
|
|
4743
|
+
const MAX_FAILURE_TAIL_LENGTH = 16384;
|
|
4744
|
+
var ArkmeDesktopExtensionQuarantine = class {
|
|
4745
|
+
options;
|
|
4746
|
+
now;
|
|
4747
|
+
constructor(options) {
|
|
4748
|
+
this.options = options;
|
|
4749
|
+
this.now = options.now ?? (() => Date.now());
|
|
4750
|
+
}
|
|
4751
|
+
async reconcile() {
|
|
4752
|
+
for (const stored of await this.readReceipts("active")) {
|
|
4753
|
+
let changed = false;
|
|
4754
|
+
for (const entry of stored.receipt.entries) {
|
|
4755
|
+
if (entry.resolvedAtMillis !== void 0) continue;
|
|
4756
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4757
|
+
if (installed !== void 0 && (installed.enabled || installed.active || installed.lastError !== stored.receipt.failureSummary)) this.options.installStore.put({
|
|
4758
|
+
...installed,
|
|
4759
|
+
enabled: false,
|
|
4760
|
+
active: false,
|
|
4761
|
+
lastError: stored.receipt.failureSummary
|
|
4762
|
+
});
|
|
4763
|
+
if (entry.synchronizedAtMillis === void 0) {
|
|
4764
|
+
entry.synchronizedAtMillis = this.now();
|
|
4765
|
+
changed = true;
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
if (changed) await this.writeStoredReceipt(stored);
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
async status() {
|
|
4772
|
+
const stored = (await this.readReceipts("active")).sort((left, right) => right.receipt.createdAtMillis - left.receipt.createdAtMillis)[0];
|
|
4773
|
+
if (stored === void 0) return {
|
|
4774
|
+
active: false,
|
|
4775
|
+
entries: []
|
|
4776
|
+
};
|
|
4777
|
+
return {
|
|
4778
|
+
active: true,
|
|
4779
|
+
quarantineId: stored.receipt.quarantineId,
|
|
4780
|
+
mode: stored.receipt.mode,
|
|
4781
|
+
failureSummary: stored.receipt.failureSummary,
|
|
4782
|
+
failureLogTail: stored.receipt.failureLogTail,
|
|
4783
|
+
entries: stored.receipt.entries.filter((entry) => entry.resolvedAtMillis === void 0).map((entry) => ({
|
|
4784
|
+
packageName: entry.packageName,
|
|
4785
|
+
...this.installedByPackage(entry.packageName) === void 0 ? {} : { extensionId: this.installedByPackage(entry.packageName).extensionId },
|
|
4786
|
+
dismissed: entry.notificationDismissedAtMillis !== void 0,
|
|
4787
|
+
resolved: false
|
|
4788
|
+
}))
|
|
4789
|
+
};
|
|
4790
|
+
}
|
|
4791
|
+
async dismiss(packageName) {
|
|
4792
|
+
const stored = await this.activeReceiptForPackage(packageName);
|
|
4793
|
+
const entry = stored.receipt.entries.find((item) => item.packageName === packageName);
|
|
4794
|
+
if (entry.notificationDismissedAtMillis === void 0) {
|
|
4795
|
+
entry.notificationDismissedAtMillis = this.now();
|
|
4796
|
+
await this.writeStoredReceipt(stored);
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
async reenable(packageName) {
|
|
4800
|
+
const stored = await this.activeReceiptForPackage(packageName);
|
|
4801
|
+
const entry = stored.receipt.entries.find((item) => item.packageName === packageName);
|
|
4802
|
+
entry.reenableRequestedAtMillis = this.now();
|
|
4803
|
+
await this.writeStoredReceipt(stored);
|
|
4804
|
+
let profileEnabled = false;
|
|
4805
|
+
try {
|
|
4806
|
+
await this.options.setProfileEnabled(packageName, true);
|
|
4807
|
+
profileEnabled = true;
|
|
4808
|
+
await this.options.requestRestart({
|
|
4809
|
+
packageName,
|
|
4810
|
+
previousProfileIncluded: false
|
|
4811
|
+
});
|
|
4812
|
+
} catch (error) {
|
|
4813
|
+
if (profileEnabled) await this.options.setProfileEnabled(packageName, false).catch(() => void 0);
|
|
4814
|
+
delete entry.reenableRequestedAtMillis;
|
|
4815
|
+
await this.writeStoredReceipt(stored).catch(() => void 0);
|
|
4816
|
+
throw error;
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
async resolveActive() {
|
|
4820
|
+
for (const stored of await this.readReceipts("active")) {
|
|
4821
|
+
let changed = false;
|
|
4822
|
+
for (const entry of stored.receipt.entries) {
|
|
4823
|
+
if (entry.resolvedAtMillis !== void 0) continue;
|
|
4824
|
+
if (entry.reenableRequestedAtMillis !== void 0 && this.options.isPackageActive(entry.packageName)) {
|
|
4825
|
+
entry.resolvedAtMillis = this.now();
|
|
4826
|
+
delete entry.reenableRequestedAtMillis;
|
|
4827
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4828
|
+
if (installed !== void 0) {
|
|
4829
|
+
const { lastError: _lastError, ...retained } = installed;
|
|
4830
|
+
this.options.installStore.put({
|
|
4831
|
+
...retained,
|
|
4832
|
+
enabled: true,
|
|
4833
|
+
active: true
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
changed = true;
|
|
4837
|
+
continue;
|
|
4838
|
+
}
|
|
4839
|
+
if (entry.reenableRequestedAtMillis !== void 0) {
|
|
4840
|
+
await this.options.setProfileEnabled(entry.packageName, false);
|
|
4841
|
+
delete entry.reenableRequestedAtMillis;
|
|
4842
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4843
|
+
if (installed !== void 0) this.options.installStore.put({
|
|
4844
|
+
...installed,
|
|
4845
|
+
enabled: false,
|
|
4846
|
+
active: false
|
|
4847
|
+
});
|
|
4848
|
+
changed = true;
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
if (stored.receipt.entries.every((entry) => entry.resolvedAtMillis !== void 0)) {
|
|
4852
|
+
stored.receipt.phase = "resolved";
|
|
4853
|
+
changed = true;
|
|
4854
|
+
}
|
|
4855
|
+
if (changed) await this.writeStoredReceipt(stored);
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
async health(packageName) {
|
|
4859
|
+
if ((await this.activeReceiptForPackage(packageName)).receipt.entries.find((item) => item.packageName === packageName).reenableRequestedAtMillis === void 0) throw new Error("该扩展尚未请求重新启用");
|
|
4860
|
+
const profileEnabled = await this.profileContains(packageName);
|
|
4861
|
+
const active = this.options.isPackageActive(packageName);
|
|
4862
|
+
if (profileEnabled && active) await this.resolveActive();
|
|
4863
|
+
return {
|
|
4864
|
+
profileEnabled,
|
|
4865
|
+
active
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4868
|
+
async activeReceiptForPackage(packageName) {
|
|
4869
|
+
if (!isPackageName(packageName) || isProtectedPackage(packageName)) throw new Error("隔离扩展包名无效");
|
|
4870
|
+
const matches = (await this.readReceipts("active")).filter((stored) => stored.receipt.entries.some((entry) => entry.packageName === packageName && entry.resolvedAtMillis === void 0));
|
|
4871
|
+
matches.sort((left, right) => right.receipt.createdAtMillis - left.receipt.createdAtMillis);
|
|
4872
|
+
if (matches[0] === void 0) throw new Error("该扩展没有活动的启动隔离记录");
|
|
4873
|
+
return matches[0];
|
|
4874
|
+
}
|
|
4875
|
+
installedByPackage(packageName) {
|
|
4876
|
+
return this.options.installStore.list().find((item) => item.profilePackageName === packageName);
|
|
4877
|
+
}
|
|
4878
|
+
async profileContains(packageName) {
|
|
4879
|
+
try {
|
|
4880
|
+
const value = JSON.parse(await readFile(join(this.options.dshHome, "profiles", "web", "package.json"), "utf8"));
|
|
4881
|
+
if (!isObject(value) || !isObject(value.dsh) || !isObject(value.dsh.profile) || !Array.isArray(value.dsh.profile.bundles)) return false;
|
|
4882
|
+
return value.dsh.profile.bundles.some((item) => item === packageName);
|
|
4883
|
+
} catch {
|
|
4884
|
+
return false;
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
async readReceipts(phase) {
|
|
4888
|
+
const root = join(this.options.dshHome, "arkme-self", QUARANTINE_DIRECTORY_NAME);
|
|
4889
|
+
const directories = await readdir(root, { withFileTypes: true }).catch((error) => {
|
|
4890
|
+
if (error.code === "ENOENT") return [];
|
|
4891
|
+
throw error;
|
|
4892
|
+
});
|
|
4893
|
+
const receipts = [];
|
|
4894
|
+
for (const directory of directories) {
|
|
4895
|
+
if (!directory.isDirectory() || !QUARANTINE_ID_PATTERN.test(directory.name)) continue;
|
|
4896
|
+
const receiptPath = join(root, directory.name, RECEIPT_FILE_NAME);
|
|
4897
|
+
try {
|
|
4898
|
+
const receipt = parseReceipt(await readFile(receiptPath, "utf8"));
|
|
4899
|
+
if (receipt.quarantineId !== directory.name || receipt.environment !== this.options.environment || phase !== void 0 && receipt.phase !== phase) continue;
|
|
4900
|
+
receipts.push({
|
|
4901
|
+
path: receiptPath,
|
|
4902
|
+
receipt
|
|
4903
|
+
});
|
|
4904
|
+
} catch {}
|
|
4905
|
+
}
|
|
4906
|
+
return receipts;
|
|
4907
|
+
}
|
|
4908
|
+
async writeStoredReceipt(stored) {
|
|
4909
|
+
stored.receipt.updatedAtMillis = this.now();
|
|
4910
|
+
await writeTextAtomically(stored.path, `${JSON.stringify(stored.receipt, void 0, 2)}\n`);
|
|
4911
|
+
}
|
|
4912
|
+
};
|
|
4913
|
+
function parseReceipt(text) {
|
|
4914
|
+
const value = JSON.parse(text);
|
|
4915
|
+
if (!isObject(value) || value.schemaVersion !== 1 || typeof value.quarantineId !== "string" || !QUARANTINE_ID_PATTERN.test(value.quarantineId) || value.environment !== "prod" && value.environment !== "test" || ![
|
|
4916
|
+
"pending",
|
|
4917
|
+
"active",
|
|
4918
|
+
"restored",
|
|
4919
|
+
"resolved"
|
|
4920
|
+
].includes(String(value.phase)) || value.mode !== "targeted" && value.mode !== "local-safe-mode" || !Number.isSafeInteger(value.createdAtMillis) || !Number.isSafeInteger(value.updatedAtMillis) || value.runtimeReleaseId !== void 0 && (typeof value.runtimeReleaseId !== "string" || !RUNTIME_RELEASE_PATTERN.test(value.runtimeReleaseId)) || typeof value.failureSummary !== "string" || value.failureSummary.trim() === "" || value.failureSummary.length > MAX_FAILURE_SUMMARY_LENGTH || typeof value.failureLogTail !== "string" || value.failureLogTail.length > MAX_FAILURE_TAIL_LENGTH || !Array.isArray(value.entries) || value.entries.length === 0) throw new Error("桌面扩展隔离记录无效");
|
|
4921
|
+
const entries = value.entries.map((raw) => parseEntry(raw));
|
|
4922
|
+
if (new Set(entries.map((entry) => entry.packageName)).size !== entries.length) throw new Error("桌面扩展隔离记录包含重复扩展");
|
|
4923
|
+
return {
|
|
4924
|
+
schemaVersion: 1,
|
|
4925
|
+
quarantineId: value.quarantineId,
|
|
4926
|
+
environment: value.environment,
|
|
4927
|
+
phase: value.phase,
|
|
4928
|
+
mode: value.mode,
|
|
4929
|
+
createdAtMillis: Number(value.createdAtMillis),
|
|
4930
|
+
updatedAtMillis: Number(value.updatedAtMillis),
|
|
4931
|
+
...typeof value.runtimeReleaseId === "string" ? { runtimeReleaseId: value.runtimeReleaseId } : {},
|
|
4932
|
+
failureSummary: value.failureSummary,
|
|
4933
|
+
failureLogTail: value.failureLogTail,
|
|
4934
|
+
entries
|
|
4935
|
+
};
|
|
4936
|
+
}
|
|
4937
|
+
function parseEntry(value) {
|
|
4938
|
+
if (!isObject(value) || typeof value.packageName !== "string" || !isPackageName(value.packageName) || isProtectedPackage(value.packageName) || typeof value.dependencySpec !== "string" || value.dependencySpec.length === 0 || value.dependencySpec.length > 4096 || !Number.isSafeInteger(value.originalBundleIndex) || Number(value.originalBundleIndex) < 0 || !optionalMillis(value.synchronizedAtMillis) || !optionalMillis(value.notificationDismissedAtMillis) || !optionalMillis(value.reenableRequestedAtMillis) || !optionalMillis(value.resolvedAtMillis)) throw new Error("桌面扩展隔离条目无效");
|
|
4939
|
+
return {
|
|
4940
|
+
packageName: value.packageName,
|
|
4941
|
+
dependencySpec: value.dependencySpec,
|
|
4942
|
+
originalBundleIndex: Number(value.originalBundleIndex),
|
|
4943
|
+
...value.synchronizedAtMillis === void 0 ? {} : { synchronizedAtMillis: Number(value.synchronizedAtMillis) },
|
|
4944
|
+
...value.notificationDismissedAtMillis === void 0 ? {} : { notificationDismissedAtMillis: Number(value.notificationDismissedAtMillis) },
|
|
4945
|
+
...value.reenableRequestedAtMillis === void 0 ? {} : { reenableRequestedAtMillis: Number(value.reenableRequestedAtMillis) },
|
|
4946
|
+
...value.resolvedAtMillis === void 0 ? {} : { resolvedAtMillis: Number(value.resolvedAtMillis) }
|
|
4947
|
+
};
|
|
4948
|
+
}
|
|
4949
|
+
function optionalMillis(value) {
|
|
4950
|
+
return value === void 0 || Number.isSafeInteger(value) && Number(value) >= 0;
|
|
4951
|
+
}
|
|
4952
|
+
function isObject(value) {
|
|
4953
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4954
|
+
}
|
|
4955
|
+
function isPackageName(value) {
|
|
4956
|
+
return PACKAGE_NAME_PATTERN.test(value);
|
|
4957
|
+
}
|
|
4958
|
+
function isProtectedPackage(packageName) {
|
|
4959
|
+
return packageName === "@senguoyun/dsh-arkme" || packageName.startsWith("@deepseek-ai/");
|
|
4960
|
+
}
|
|
4961
|
+
async function writeTextAtomically(filePath, text) {
|
|
4962
|
+
const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
4963
|
+
try {
|
|
4964
|
+
const handle = await open(temporaryPath, "wx", 384);
|
|
4965
|
+
try {
|
|
4966
|
+
await handle.writeFile(text, "utf8");
|
|
4967
|
+
await handle.sync();
|
|
4968
|
+
} finally {
|
|
4969
|
+
await handle.close();
|
|
4970
|
+
}
|
|
4971
|
+
await rename(temporaryPath, filePath);
|
|
4972
|
+
} finally {
|
|
4973
|
+
await rm(temporaryPath, { force: true }).catch(() => void 0);
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
//#endregion
|
|
4641
4977
|
//#region src/extensions/install-tasks.ts
|
|
4642
4978
|
const TASK_RETENTION_MILLIS = 600 * 1e3;
|
|
4643
4979
|
const MAX_RETAINED_TASKS = 100;
|
|
@@ -7915,7 +8251,7 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7915
8251
|
await this.mutationTail;
|
|
7916
8252
|
if (this.options.stateDirectory === void 0 || this.options.healthUrl === void 0 || this.options.helperPath === void 0 || this.options.restartArgv === void 0 || this.options.installStoreDirectory === void 0) return;
|
|
7917
8253
|
const plan = {
|
|
7918
|
-
schemaVersion: input.activationChange === true ? 3 : input.targetBundlePath?.endsWith(".tgz") === true || input.previousBundlePath?.endsWith(".tgz") === true || input.previousInstalled?.executionModel !== void 0 ? 2 : 1,
|
|
8254
|
+
schemaVersion: input.desktopQuarantineActivation === true ? 4 : input.activationChange === true ? 3 : input.targetBundlePath?.endsWith(".tgz") === true || input.previousBundlePath?.endsWith(".tgz") === true || input.previousInstalled?.executionModel !== void 0 ? 2 : 1,
|
|
7919
8255
|
parentPid: process.pid,
|
|
7920
8256
|
execPath: this.options.execPath,
|
|
7921
8257
|
dshBinPath: this.options.dshBinPath,
|
|
@@ -7935,8 +8271,10 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7935
8271
|
activationChange: true,
|
|
7936
8272
|
previousProfileIncluded: input.previousProfileIncluded === true
|
|
7937
8273
|
} : {},
|
|
8274
|
+
...input.desktopQuarantineActivation === true ? { desktopQuarantineActivation: true } : {},
|
|
7938
8275
|
healthUrl: this.options.healthUrl,
|
|
7939
|
-
logPath: join(this.options.stateDirectory, "extension-profile-restart.log")
|
|
8276
|
+
logPath: join(this.options.stateDirectory, "extension-profile-restart.log"),
|
|
8277
|
+
...this.options.runtimeReleaseId === void 0 ? {} : { runtimeReleaseId: this.options.runtimeReleaseId }
|
|
7940
8278
|
};
|
|
7941
8279
|
if (this.options.supervisedExitCode !== void 0) {
|
|
7942
8280
|
if (!Number.isSafeInteger(this.options.supervisedExitCode) || this.options.supervisedExitCode < 1 || this.options.supervisedExitCode > 255) throw new Error("受监督重启退出码无效");
|
|
@@ -7985,6 +8323,17 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7985
8323
|
setTimeout(() => process.kill(process.pid, "SIGTERM"), 800).unref?.();
|
|
7986
8324
|
}))();
|
|
7987
8325
|
}
|
|
8326
|
+
async restartDesktopQuarantine(input) {
|
|
8327
|
+
if (!isArkmeProfilePackageName(input.packageName)) throw new Error("扩展 Bundle 包名无效");
|
|
8328
|
+
await this.restart({
|
|
8329
|
+
extensionId: `desktop-quarantine:${input.packageName}`,
|
|
8330
|
+
packageName: input.packageName,
|
|
8331
|
+
expectActive: true,
|
|
8332
|
+
activationChange: true,
|
|
8333
|
+
desktopQuarantineActivation: true,
|
|
8334
|
+
previousProfileIncluded: false
|
|
8335
|
+
});
|
|
8336
|
+
}
|
|
7988
8337
|
async run(args) {
|
|
7989
8338
|
if (this.options.run !== void 0) return await this.options.run(args);
|
|
7990
8339
|
if (!existsSync(this.options.execPath) || !existsSync(this.options.dshBinPath)) throw new Error("当前 DSH 运行方式不支持修改 Profile 插件");
|
|
@@ -8756,6 +9105,21 @@ function normalizedLongArticleDraft(value) {
|
|
|
8756
9105
|
function longArticleDraftKey(sourceRef, itemUid) {
|
|
8757
9106
|
return `${sourceRef}\u0000${itemUid ?? ""}`;
|
|
8758
9107
|
}
|
|
9108
|
+
function normalizedCaptureContext(value) {
|
|
9109
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
9110
|
+
const source = value;
|
|
9111
|
+
const clientName = typeof source.clientName === "string" ? source.clientName.trim().slice(0, 120) : "";
|
|
9112
|
+
const networkName = typeof source.networkName === "string" ? source.networkName.trim().slice(0, 120) : "";
|
|
9113
|
+
const electric = typeof source.electric === "number" && Number.isFinite(source.electric) ? Math.trunc(source.electric) : void 0;
|
|
9114
|
+
const charge = typeof source.charge === "number" && Number.isFinite(source.charge) ? Math.trunc(source.charge) : 0;
|
|
9115
|
+
const result = {
|
|
9116
|
+
...clientName === "" ? {} : { clientName },
|
|
9117
|
+
...networkName === "" ? {} : { networkName },
|
|
9118
|
+
...electric === void 0 || electric < 0 || electric > 100 ? {} : { electric },
|
|
9119
|
+
...charge < 1 || charge > 3 ? {} : { charge }
|
|
9120
|
+
};
|
|
9121
|
+
return Object.keys(result).length === 0 ? void 0 : result;
|
|
9122
|
+
}
|
|
8759
9123
|
function normalizedPending(value) {
|
|
8760
9124
|
if (!Array.isArray(value)) return [];
|
|
8761
9125
|
const result = [];
|
|
@@ -8764,12 +9128,16 @@ function normalizedPending(value) {
|
|
|
8764
9128
|
const source = item;
|
|
8765
9129
|
if (typeof source.recordUid !== "string" || source.recordUid.trim() === "") continue;
|
|
8766
9130
|
if (typeof source.textContent !== "string" || source.textContent.trim() === "") continue;
|
|
9131
|
+
const recordDurationMillis = typeof source.recordDurationMillis === "number" && Number.isFinite(source.recordDurationMillis) ? Math.max(0, Math.trunc(source.recordDurationMillis)) : 0;
|
|
9132
|
+
const captureContext = normalizedCaptureContext(source.captureContext);
|
|
8767
9133
|
result.push({
|
|
8768
9134
|
recordUid: source.recordUid,
|
|
8769
9135
|
textContent: source.textContent,
|
|
8770
9136
|
createdAtMillis: typeof source.createdAtMillis === "number" ? source.createdAtMillis : 0,
|
|
8771
9137
|
sendAtMillis: typeof source.sendAtMillis === "number" ? source.sendAtMillis : 0,
|
|
8772
9138
|
attempts: typeof source.attempts === "number" ? source.attempts : 0,
|
|
9139
|
+
...recordDurationMillis === 0 ? {} : { recordDurationMillis },
|
|
9140
|
+
...captureContext === void 0 ? {} : { captureContext },
|
|
8773
9141
|
...typeof source.lastError === "string" && source.lastError !== "" ? { lastError: source.lastError } : {}
|
|
8774
9142
|
});
|
|
8775
9143
|
}
|
|
@@ -18300,6 +18668,9 @@ function resolveArkmeAppVersion(configuredAppVersion, environment = process.env)
|
|
|
18300
18668
|
const injected = environment.ARKME_APP_VERSION?.trim();
|
|
18301
18669
|
return injected === void 0 || injected === "" ? void 0 : injected;
|
|
18302
18670
|
}
|
|
18671
|
+
function resolvePluginUpdateEnabled(configured, environment = process.env) {
|
|
18672
|
+
return configured && environment.ARKME_RUNTIME_MANAGED !== "1";
|
|
18673
|
+
}
|
|
18303
18674
|
function dshRemoteClientId(accessToken) {
|
|
18304
18675
|
const parts = accessToken.split(".");
|
|
18305
18676
|
if (parts.length !== 3) return void 0;
|
|
@@ -18344,7 +18715,7 @@ function apply(ctx, config) {
|
|
|
18344
18715
|
const extensionStore = new ArkmeExtensionInstallStore(extensionDirectory);
|
|
18345
18716
|
const clientModules = ctx.clientModules;
|
|
18346
18717
|
const updateManager = new ArkmePluginUpdateManager({
|
|
18347
|
-
enabled: config.updateCheckEnabled,
|
|
18718
|
+
enabled: resolvePluginUpdateEnabled(config.updateCheckEnabled),
|
|
18348
18719
|
channel: config.updateChannel,
|
|
18349
18720
|
updateServiceBaseUrl: config.updateServiceBaseUrl,
|
|
18350
18721
|
...config.updateArtifactBaseUrl.trim() === "" ? {} : { updateArtifactBaseUrl: config.updateArtifactBaseUrl },
|
|
@@ -18386,9 +18757,26 @@ function apply(ctx, config) {
|
|
|
18386
18757
|
installStoreDirectory: extensionDirectory,
|
|
18387
18758
|
...process.env.ARKME_DESKTOP_MANAGED_RESTART === "1" && process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH !== void 0 ? {
|
|
18388
18759
|
supervisedExitCode: 75,
|
|
18389
|
-
supervisedPlanPath: process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH
|
|
18760
|
+
supervisedPlanPath: process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH,
|
|
18761
|
+
...process.env.ARKME_RUNTIME_RELEASE_ID === void 0 ? {} : { runtimeReleaseId: process.env.ARKME_RUNTIME_RELEASE_ID }
|
|
18390
18762
|
} : {}
|
|
18391
18763
|
});
|
|
18764
|
+
const pluginInventory = ctx.get("pluginInventory");
|
|
18765
|
+
const desktopQuarantine = new ArkmeDesktopExtensionQuarantine({
|
|
18766
|
+
dshHome,
|
|
18767
|
+
environment: config.environment,
|
|
18768
|
+
installStore: extensionStore,
|
|
18769
|
+
setProfileEnabled: async (packageName, enabled) => {
|
|
18770
|
+
await extensionProfileInstaller.setEnabled(packageName, enabled);
|
|
18771
|
+
},
|
|
18772
|
+
requestRestart: async ({ packageName }) => {
|
|
18773
|
+
await extensionProfileInstaller.restartDesktopQuarantine({ packageName });
|
|
18774
|
+
},
|
|
18775
|
+
isPackageActive: (packageName) => pluginInventory.list().entries.some((entry) => entry.moduleName === packageName && entry.enabled && entry.fiberPhase === "active")
|
|
18776
|
+
});
|
|
18777
|
+
desktopQuarantine.reconcile().catch((error) => {
|
|
18778
|
+
ctx.logger.warn("Arkme desktop extension quarantine reconciliation failed: %s", error instanceof Error ? error.message : String(error));
|
|
18779
|
+
});
|
|
18392
18780
|
const ownedExtensionStore = new ArkmeOwnedExtensionStore(extensionDirectory);
|
|
18393
18781
|
const ownedExtensionRefs = new ArkmeOwnedExtensionRefs();
|
|
18394
18782
|
const ownedExtensionHostInstanceId = randomUUID();
|
|
@@ -18414,7 +18802,7 @@ function apply(ctx, config) {
|
|
|
18414
18802
|
profileDirectory: extensionProfileDirectory,
|
|
18415
18803
|
profileInstaller: extensionProfileInstaller,
|
|
18416
18804
|
clientApiPath: config.routePath,
|
|
18417
|
-
pluginInventory
|
|
18805
|
+
pluginInventory,
|
|
18418
18806
|
...dshRuntimeVersion === void 0 ? {} : { dshRuntimeVersion }
|
|
18419
18807
|
});
|
|
18420
18808
|
extensionManager = manager;
|
|
@@ -18523,7 +18911,8 @@ function apply(ctx, config) {
|
|
|
18523
18911
|
extensionManager: () => extensionManager,
|
|
18524
18912
|
extensionInstallTasks: () => extensionInstallTasks,
|
|
18525
18913
|
ownedExtensionInventory: () => ownedExtensionInventory,
|
|
18526
|
-
remoteHost: () => remoteHost
|
|
18914
|
+
remoteHost: () => remoteHost,
|
|
18915
|
+
desktopQuarantine
|
|
18527
18916
|
});
|
|
18528
18917
|
const callAssetHandler = createOutgoingCallAssetHandler({ routePrefix: `${config.routePath}/call` });
|
|
18529
18918
|
const richMediaOptions = {
|
|
@@ -18718,4 +19107,4 @@ function validateConfig(ctx, config) {
|
|
|
18718
19107
|
}
|
|
18719
19108
|
}
|
|
18720
19109
|
//#endregion
|
|
18721
|
-
export { ARKME_PRODUCTION_TRUSTED_SIGNING_KEYS, ARKME_PROVIDER_CONTRACT_VERSION, ARKME_WORLD_PUBLISH_MAX_IMAGES, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, ArkmeOutgoingCallError, ArkmeService, Config, apply, createOpenClawCliAdapter, inject, name, readDshRuntimeVersion, resolveArkmeAppVersion, resolveArkmeConfig };
|
|
19110
|
+
export { ARKME_PRODUCTION_TRUSTED_SIGNING_KEYS, ARKME_PROVIDER_CONTRACT_VERSION, ARKME_WORLD_PUBLISH_MAX_IMAGES, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES, ArkmeOutgoingCallError, ArkmeService, Config, apply, createOpenClawCliAdapter, inject, name, readDshRuntimeVersion, resolveArkmeAppVersion, resolveArkmeConfig, resolvePluginUpdateEnabled };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as persistentArkmeExtensionActive, i as invokePersistentArkmeExtension, n as applyPersistentArkmeHostExtension, o as persistentArkmeExtensionRuntimeState, r as deactivatePersistentArkmeExtension, t as activatePersistentArkmeExtension } from "./persistent-runtime-
|
|
1
|
+
import { a as persistentArkmeExtensionActive, i as invokePersistentArkmeExtension, n as applyPersistentArkmeHostExtension, o as persistentArkmeExtensionRuntimeState, r as deactivatePersistentArkmeExtension, t as activatePersistentArkmeExtension } from "./persistent-runtime-CZQTfyC1.js";
|
|
2
2
|
export { activatePersistentArkmeExtension, applyPersistentArkmeHostExtension, deactivatePersistentArkmeExtension, invokePersistentArkmeExtension, persistentArkmeExtensionActive, persistentArkmeExtensionRuntimeState };
|