@senguoyun/dsh-arkme 0.1.32 → 0.1.33
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 +514 -1546
- package/lib/client.js.map +1 -1
- package/lib/extension-profile-restart-helper.js +17 -5
- package/lib/index.js +296 -11
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-CFeIg6aw.js → persistent-runtime-DUqdJv8K.js} +28508 -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/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeProductNavigation.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.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/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/types.d.ts +1 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +6 -5
|
@@ -35,15 +35,18 @@ function parseExtensionProfileRestartPlan(value) {
|
|
|
35
35
|
installStoreDirectory: stringValue(source.installStoreDirectory),
|
|
36
36
|
previousInstalled: source.previousInstalled !== null && typeof source.previousInstalled === "object" ? source.previousInstalled : void 0,
|
|
37
37
|
activationChange: source.activationChange === true ? true : void 0,
|
|
38
|
+
desktopQuarantineActivation: source.desktopQuarantineActivation === true ? true : void 0,
|
|
38
39
|
previousProfileIncluded: typeof source.previousProfileIncluded === "boolean" ? source.previousProfileIncluded : void 0,
|
|
39
40
|
healthUrl: stringValue(source.healthUrl),
|
|
40
|
-
logPath: stringValue(source.logPath)
|
|
41
|
+
logPath: stringValue(source.logPath),
|
|
42
|
+
runtimeReleaseId: stringValue(source.runtimeReleaseId)
|
|
41
43
|
};
|
|
42
44
|
if (![
|
|
43
45
|
1,
|
|
44
46
|
2,
|
|
45
|
-
3
|
|
46
|
-
|
|
47
|
+
3,
|
|
48
|
+
4
|
|
49
|
+
].includes(plan.schemaVersion) || typeof plan.parentPid !== "number" || !Number.isSafeInteger(plan.parentPid) || plan.parentPid <= 0 || plan.execPath === void 0 || plan.dshBinPath === void 0 || plan.restartArgv.length === 0 || plan.dshHome === void 0 || plan.profileName === void 0 || plan.packageName === void 0 || plan.extensionId === void 0 || typeof plan.expectActive !== "boolean" || plan.installStoreDirectory === void 0 || plan.healthUrl === void 0 || plan.logPath === void 0 || plan.runtimeReleaseId !== void 0 && !/^electron-runtime-v1-[a-f0-9]{32}$/.test(plan.runtimeReleaseId) || plan.schemaVersion === 3 && (plan.activationChange !== true || plan.desktopQuarantineActivation === true || plan.previousInstalled === void 0 || plan.previousProfileIncluded === void 0) || plan.schemaVersion === 4 && (plan.activationChange !== true || plan.desktopQuarantineActivation !== true || plan.previousInstalled !== void 0 || plan.previousProfileIncluded !== false || plan.expectActive !== true || plan.extensionId !== `desktop-quarantine:${plan.packageName}`) || ![3, 4].includes(plan.schemaVersion) && plan.activationChange === true || plan.schemaVersion !== 4 && plan.desktopQuarantineActivation === true || (plan.schemaVersion === 1 ? !/^@arkme-local\/ext-[a-f0-9]{16}$/.test(plan.packageName) : !/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(plan.packageName))) throw new Error("extension restart plan is incomplete");
|
|
47
50
|
const health = new URL(plan.healthUrl);
|
|
48
51
|
if (health.protocol !== "http:" || !["127.0.0.1", "localhost"].includes(health.hostname)) throw new Error("extension restart health URL must be loopback HTTP");
|
|
49
52
|
return {
|
|
@@ -88,12 +91,21 @@ async function healthy(plan) {
|
|
|
88
91
|
"Content-Type": "application/json",
|
|
89
92
|
Origin: new URL(plan.healthUrl).origin
|
|
90
93
|
},
|
|
91
|
-
body: JSON.stringify(
|
|
94
|
+
body: JSON.stringify(plan.desktopQuarantineActivation === true ? {
|
|
95
|
+
operation: "extensions.quarantine.health",
|
|
96
|
+
params: { packageName: plan.packageName }
|
|
97
|
+
} : { operation: "extensions.installed-list" }),
|
|
92
98
|
signal: AbortSignal.timeout(2e3)
|
|
93
99
|
});
|
|
94
100
|
if (response.ok) {
|
|
95
101
|
const body = await response.json();
|
|
96
|
-
|
|
102
|
+
if (plan.desktopQuarantineActivation === true) {
|
|
103
|
+
const status = body.value;
|
|
104
|
+
if (body.ok === true && status?.profileEnabled === true && status.active === true) return true;
|
|
105
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const installed = Array.isArray(body.value) ? body.value.find((item) => item.extensionId === plan.extensionId) : void 0;
|
|
97
109
|
if (body.ok === true && (plan.activationChange === true ? plan.expectActive ? installed?.enabled === true && installed.active === true : installed?.enabled === false && installed.active === false : plan.expectActive ? installed?.active === true : installed === void 0)) return true;
|
|
98
110
|
}
|
|
99
111
|
} catch {}
|
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-DUqdJv8K.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";
|
|
@@ -1893,11 +1893,13 @@ function createArkmeHostApi(service, options) {
|
|
|
1893
1893
|
"extensions.persistent.invoke",
|
|
1894
1894
|
"extensions.bundle.invoke",
|
|
1895
1895
|
"extensions.mine.publish",
|
|
1896
|
+
"extensions.quarantine.dismiss",
|
|
1897
|
+
"extensions.quarantine.reenable",
|
|
1896
1898
|
"remote.renameDesktop"
|
|
1897
1899
|
].includes(request.operation) && origin === void 0) throw new ArkmePluginError("origin-required", "扩展变更必须从当前 DSH 页面发起", false, 403);
|
|
1898
1900
|
writeJson$4(res, 200, {
|
|
1899
1901
|
ok: true,
|
|
1900
|
-
value: await dispatchArkmeHostOperation(service, request.operation, params, options.updateManager, options.extensionManager?.(), options.extensionInstallTasks?.(), options.ownedExtensionInventory?.(), controller.signal, options.remoteHost?.())
|
|
1902
|
+
value: await dispatchArkmeHostOperation(service, request.operation, params, options.updateManager, options.extensionManager?.(), options.extensionInstallTasks?.(), options.ownedExtensionInventory?.(), controller.signal, options.remoteHost?.(), options.desktopQuarantine)
|
|
1901
1903
|
});
|
|
1902
1904
|
} catch (error) {
|
|
1903
1905
|
if (controller.signal.aborted && res.destroyed) return;
|
|
@@ -1915,7 +1917,7 @@ function createArkmeHostApi(service, options) {
|
|
|
1915
1917
|
}
|
|
1916
1918
|
};
|
|
1917
1919
|
}
|
|
1918
|
-
async function dispatchArkmeHostOperation(service, operation, params, updateManager, extensionManager, extensionInstallTasks, ownedExtensionInventory, requestSignal, remoteHost) {
|
|
1920
|
+
async function dispatchArkmeHostOperation(service, operation, params, updateManager, extensionManager, extensionInstallTasks, ownedExtensionInventory, requestSignal, remoteHost, desktopQuarantine) {
|
|
1919
1921
|
switch (operation) {
|
|
1920
1922
|
case "provider.capabilities": return service.providerCapabilities();
|
|
1921
1923
|
case "provider.instance": return { instanceId: ARKME_RUNTIME_INSTANCE_ID };
|
|
@@ -2451,6 +2453,10 @@ async function dispatchArkmeHostOperation(service, operation, params, updateMana
|
|
|
2451
2453
|
case "extensions.share.resolve": return (await enrichExtensionAuthors(service, [await requireExtensionManager(extensionManager).resolveSharedCatalogDetail(stringParam(params, "shareRef"))]))[0];
|
|
2452
2454
|
case "extensions.delete": return await requireOwnedExtensionInventory(ownedExtensionInventory).delete({ extensionId: stringParam(params, "extensionId") });
|
|
2453
2455
|
case "extensions.installed-list": return requireExtensionManager(extensionManager).listInstalled();
|
|
2456
|
+
case "extensions.quarantine.status": return await requireDesktopQuarantine(desktopQuarantine).status();
|
|
2457
|
+
case "extensions.quarantine.dismiss": return await requireDesktopQuarantine(desktopQuarantine).dismiss(stringParam(params, "packageName"));
|
|
2458
|
+
case "extensions.quarantine.reenable": return await requireDesktopQuarantine(desktopQuarantine).reenable(stringParam(params, "packageName"));
|
|
2459
|
+
case "extensions.quarantine.health": return await requireDesktopQuarantine(desktopQuarantine).health(stringParam(params, "packageName"));
|
|
2454
2460
|
case "extensions.mine.list": return await requireOwnedExtensionInventory(ownedExtensionInventory).list({ ...stringParam(params, "currentSessionId").trim() === "" ? {} : { currentSessionId: stringParam(params, "currentSessionId").trim() } });
|
|
2455
2461
|
case "extensions.mine.publish": return await requireOwnedExtensionInventory(ownedExtensionInventory).publish({
|
|
2456
2462
|
ownedRef: stringParam(params, "ownedRef"),
|
|
@@ -2531,6 +2537,10 @@ function requireExtensionManager(manager) {
|
|
|
2531
2537
|
if (manager === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "当前 DSH 未加载 Dynamic Cordis Runner,市集不可用", false, 503);
|
|
2532
2538
|
return manager;
|
|
2533
2539
|
}
|
|
2540
|
+
function requireDesktopQuarantine(quarantine) {
|
|
2541
|
+
if (quarantine === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "桌面扩展恢复状态尚未就绪", false, 503);
|
|
2542
|
+
return quarantine;
|
|
2543
|
+
}
|
|
2534
2544
|
function requireOwnedExtensionInventory(inventory) {
|
|
2535
2545
|
if (inventory === void 0) throw new ArkmePluginError("extension-runtime-unavailable", "扩展运行时尚未就绪", true, 503);
|
|
2536
2546
|
return inventory;
|
|
@@ -4638,6 +4648,247 @@ var ArkmeRealtimeEvents = class {
|
|
|
4638
4648
|
}
|
|
4639
4649
|
};
|
|
4640
4650
|
//#endregion
|
|
4651
|
+
//#region src/extensions/desktop-quarantine.ts
|
|
4652
|
+
const QUARANTINE_DIRECTORY_NAME = "desktop-extension-quarantine";
|
|
4653
|
+
const RECEIPT_FILE_NAME = "receipt.json";
|
|
4654
|
+
const PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
4655
|
+
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}$/;
|
|
4656
|
+
const RUNTIME_RELEASE_PATTERN = /^electron-runtime-v1-[a-f0-9]{32}$/;
|
|
4657
|
+
const MAX_FAILURE_SUMMARY_LENGTH = 2e3;
|
|
4658
|
+
const MAX_FAILURE_TAIL_LENGTH = 16384;
|
|
4659
|
+
var ArkmeDesktopExtensionQuarantine = class {
|
|
4660
|
+
options;
|
|
4661
|
+
now;
|
|
4662
|
+
constructor(options) {
|
|
4663
|
+
this.options = options;
|
|
4664
|
+
this.now = options.now ?? (() => Date.now());
|
|
4665
|
+
}
|
|
4666
|
+
async reconcile() {
|
|
4667
|
+
for (const stored of await this.readReceipts("active")) {
|
|
4668
|
+
let changed = false;
|
|
4669
|
+
for (const entry of stored.receipt.entries) {
|
|
4670
|
+
if (entry.resolvedAtMillis !== void 0) continue;
|
|
4671
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4672
|
+
if (installed !== void 0 && (installed.enabled || installed.active || installed.lastError !== stored.receipt.failureSummary)) this.options.installStore.put({
|
|
4673
|
+
...installed,
|
|
4674
|
+
enabled: false,
|
|
4675
|
+
active: false,
|
|
4676
|
+
lastError: stored.receipt.failureSummary
|
|
4677
|
+
});
|
|
4678
|
+
if (entry.synchronizedAtMillis === void 0) {
|
|
4679
|
+
entry.synchronizedAtMillis = this.now();
|
|
4680
|
+
changed = true;
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
if (changed) await this.writeStoredReceipt(stored);
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
async status() {
|
|
4687
|
+
const stored = (await this.readReceipts("active")).sort((left, right) => right.receipt.createdAtMillis - left.receipt.createdAtMillis)[0];
|
|
4688
|
+
if (stored === void 0) return {
|
|
4689
|
+
active: false,
|
|
4690
|
+
entries: []
|
|
4691
|
+
};
|
|
4692
|
+
return {
|
|
4693
|
+
active: true,
|
|
4694
|
+
quarantineId: stored.receipt.quarantineId,
|
|
4695
|
+
mode: stored.receipt.mode,
|
|
4696
|
+
failureSummary: stored.receipt.failureSummary,
|
|
4697
|
+
failureLogTail: stored.receipt.failureLogTail,
|
|
4698
|
+
entries: stored.receipt.entries.filter((entry) => entry.resolvedAtMillis === void 0).map((entry) => ({
|
|
4699
|
+
packageName: entry.packageName,
|
|
4700
|
+
...this.installedByPackage(entry.packageName) === void 0 ? {} : { extensionId: this.installedByPackage(entry.packageName).extensionId },
|
|
4701
|
+
dismissed: entry.notificationDismissedAtMillis !== void 0,
|
|
4702
|
+
resolved: false
|
|
4703
|
+
}))
|
|
4704
|
+
};
|
|
4705
|
+
}
|
|
4706
|
+
async dismiss(packageName) {
|
|
4707
|
+
const stored = await this.activeReceiptForPackage(packageName);
|
|
4708
|
+
const entry = stored.receipt.entries.find((item) => item.packageName === packageName);
|
|
4709
|
+
if (entry.notificationDismissedAtMillis === void 0) {
|
|
4710
|
+
entry.notificationDismissedAtMillis = this.now();
|
|
4711
|
+
await this.writeStoredReceipt(stored);
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
async reenable(packageName) {
|
|
4715
|
+
const stored = await this.activeReceiptForPackage(packageName);
|
|
4716
|
+
const entry = stored.receipt.entries.find((item) => item.packageName === packageName);
|
|
4717
|
+
entry.reenableRequestedAtMillis = this.now();
|
|
4718
|
+
await this.writeStoredReceipt(stored);
|
|
4719
|
+
let profileEnabled = false;
|
|
4720
|
+
try {
|
|
4721
|
+
await this.options.setProfileEnabled(packageName, true);
|
|
4722
|
+
profileEnabled = true;
|
|
4723
|
+
await this.options.requestRestart({
|
|
4724
|
+
packageName,
|
|
4725
|
+
previousProfileIncluded: false
|
|
4726
|
+
});
|
|
4727
|
+
} catch (error) {
|
|
4728
|
+
if (profileEnabled) await this.options.setProfileEnabled(packageName, false).catch(() => void 0);
|
|
4729
|
+
delete entry.reenableRequestedAtMillis;
|
|
4730
|
+
await this.writeStoredReceipt(stored).catch(() => void 0);
|
|
4731
|
+
throw error;
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
async resolveActive() {
|
|
4735
|
+
for (const stored of await this.readReceipts("active")) {
|
|
4736
|
+
let changed = false;
|
|
4737
|
+
for (const entry of stored.receipt.entries) {
|
|
4738
|
+
if (entry.resolvedAtMillis !== void 0) continue;
|
|
4739
|
+
if (entry.reenableRequestedAtMillis !== void 0 && this.options.isPackageActive(entry.packageName)) {
|
|
4740
|
+
entry.resolvedAtMillis = this.now();
|
|
4741
|
+
delete entry.reenableRequestedAtMillis;
|
|
4742
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4743
|
+
if (installed !== void 0) {
|
|
4744
|
+
const { lastError: _lastError, ...retained } = installed;
|
|
4745
|
+
this.options.installStore.put({
|
|
4746
|
+
...retained,
|
|
4747
|
+
enabled: true,
|
|
4748
|
+
active: true
|
|
4749
|
+
});
|
|
4750
|
+
}
|
|
4751
|
+
changed = true;
|
|
4752
|
+
continue;
|
|
4753
|
+
}
|
|
4754
|
+
if (entry.reenableRequestedAtMillis !== void 0) {
|
|
4755
|
+
await this.options.setProfileEnabled(entry.packageName, false);
|
|
4756
|
+
delete entry.reenableRequestedAtMillis;
|
|
4757
|
+
const installed = this.installedByPackage(entry.packageName);
|
|
4758
|
+
if (installed !== void 0) this.options.installStore.put({
|
|
4759
|
+
...installed,
|
|
4760
|
+
enabled: false,
|
|
4761
|
+
active: false
|
|
4762
|
+
});
|
|
4763
|
+
changed = true;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
if (stored.receipt.entries.every((entry) => entry.resolvedAtMillis !== void 0)) {
|
|
4767
|
+
stored.receipt.phase = "resolved";
|
|
4768
|
+
changed = true;
|
|
4769
|
+
}
|
|
4770
|
+
if (changed) await this.writeStoredReceipt(stored);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
async health(packageName) {
|
|
4774
|
+
if ((await this.activeReceiptForPackage(packageName)).receipt.entries.find((item) => item.packageName === packageName).reenableRequestedAtMillis === void 0) throw new Error("该扩展尚未请求重新启用");
|
|
4775
|
+
const profileEnabled = await this.profileContains(packageName);
|
|
4776
|
+
const active = this.options.isPackageActive(packageName);
|
|
4777
|
+
if (profileEnabled && active) await this.resolveActive();
|
|
4778
|
+
return {
|
|
4779
|
+
profileEnabled,
|
|
4780
|
+
active
|
|
4781
|
+
};
|
|
4782
|
+
}
|
|
4783
|
+
async activeReceiptForPackage(packageName) {
|
|
4784
|
+
if (!isPackageName(packageName) || isProtectedPackage(packageName)) throw new Error("隔离扩展包名无效");
|
|
4785
|
+
const matches = (await this.readReceipts("active")).filter((stored) => stored.receipt.entries.some((entry) => entry.packageName === packageName && entry.resolvedAtMillis === void 0));
|
|
4786
|
+
matches.sort((left, right) => right.receipt.createdAtMillis - left.receipt.createdAtMillis);
|
|
4787
|
+
if (matches[0] === void 0) throw new Error("该扩展没有活动的启动隔离记录");
|
|
4788
|
+
return matches[0];
|
|
4789
|
+
}
|
|
4790
|
+
installedByPackage(packageName) {
|
|
4791
|
+
return this.options.installStore.list().find((item) => item.profilePackageName === packageName);
|
|
4792
|
+
}
|
|
4793
|
+
async profileContains(packageName) {
|
|
4794
|
+
try {
|
|
4795
|
+
const value = JSON.parse(await readFile(join(this.options.dshHome, "profiles", "web", "package.json"), "utf8"));
|
|
4796
|
+
if (!isObject(value) || !isObject(value.dsh) || !isObject(value.dsh.profile) || !Array.isArray(value.dsh.profile.bundles)) return false;
|
|
4797
|
+
return value.dsh.profile.bundles.some((item) => item === packageName);
|
|
4798
|
+
} catch {
|
|
4799
|
+
return false;
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
async readReceipts(phase) {
|
|
4803
|
+
const root = join(this.options.dshHome, "arkme-self", QUARANTINE_DIRECTORY_NAME);
|
|
4804
|
+
const directories = await readdir(root, { withFileTypes: true }).catch((error) => {
|
|
4805
|
+
if (error.code === "ENOENT") return [];
|
|
4806
|
+
throw error;
|
|
4807
|
+
});
|
|
4808
|
+
const receipts = [];
|
|
4809
|
+
for (const directory of directories) {
|
|
4810
|
+
if (!directory.isDirectory() || !QUARANTINE_ID_PATTERN.test(directory.name)) continue;
|
|
4811
|
+
const receiptPath = join(root, directory.name, RECEIPT_FILE_NAME);
|
|
4812
|
+
try {
|
|
4813
|
+
const receipt = parseReceipt(await readFile(receiptPath, "utf8"));
|
|
4814
|
+
if (receipt.quarantineId !== directory.name || receipt.environment !== this.options.environment || phase !== void 0 && receipt.phase !== phase) continue;
|
|
4815
|
+
receipts.push({
|
|
4816
|
+
path: receiptPath,
|
|
4817
|
+
receipt
|
|
4818
|
+
});
|
|
4819
|
+
} catch {}
|
|
4820
|
+
}
|
|
4821
|
+
return receipts;
|
|
4822
|
+
}
|
|
4823
|
+
async writeStoredReceipt(stored) {
|
|
4824
|
+
stored.receipt.updatedAtMillis = this.now();
|
|
4825
|
+
await writeTextAtomically(stored.path, `${JSON.stringify(stored.receipt, void 0, 2)}\n`);
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
function parseReceipt(text) {
|
|
4829
|
+
const value = JSON.parse(text);
|
|
4830
|
+
if (!isObject(value) || value.schemaVersion !== 1 || typeof value.quarantineId !== "string" || !QUARANTINE_ID_PATTERN.test(value.quarantineId) || value.environment !== "prod" && value.environment !== "test" || ![
|
|
4831
|
+
"pending",
|
|
4832
|
+
"active",
|
|
4833
|
+
"restored",
|
|
4834
|
+
"resolved"
|
|
4835
|
+
].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("桌面扩展隔离记录无效");
|
|
4836
|
+
const entries = value.entries.map((raw) => parseEntry(raw));
|
|
4837
|
+
if (new Set(entries.map((entry) => entry.packageName)).size !== entries.length) throw new Error("桌面扩展隔离记录包含重复扩展");
|
|
4838
|
+
return {
|
|
4839
|
+
schemaVersion: 1,
|
|
4840
|
+
quarantineId: value.quarantineId,
|
|
4841
|
+
environment: value.environment,
|
|
4842
|
+
phase: value.phase,
|
|
4843
|
+
mode: value.mode,
|
|
4844
|
+
createdAtMillis: Number(value.createdAtMillis),
|
|
4845
|
+
updatedAtMillis: Number(value.updatedAtMillis),
|
|
4846
|
+
...typeof value.runtimeReleaseId === "string" ? { runtimeReleaseId: value.runtimeReleaseId } : {},
|
|
4847
|
+
failureSummary: value.failureSummary,
|
|
4848
|
+
failureLogTail: value.failureLogTail,
|
|
4849
|
+
entries
|
|
4850
|
+
};
|
|
4851
|
+
}
|
|
4852
|
+
function parseEntry(value) {
|
|
4853
|
+
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("桌面扩展隔离条目无效");
|
|
4854
|
+
return {
|
|
4855
|
+
packageName: value.packageName,
|
|
4856
|
+
dependencySpec: value.dependencySpec,
|
|
4857
|
+
originalBundleIndex: Number(value.originalBundleIndex),
|
|
4858
|
+
...value.synchronizedAtMillis === void 0 ? {} : { synchronizedAtMillis: Number(value.synchronizedAtMillis) },
|
|
4859
|
+
...value.notificationDismissedAtMillis === void 0 ? {} : { notificationDismissedAtMillis: Number(value.notificationDismissedAtMillis) },
|
|
4860
|
+
...value.reenableRequestedAtMillis === void 0 ? {} : { reenableRequestedAtMillis: Number(value.reenableRequestedAtMillis) },
|
|
4861
|
+
...value.resolvedAtMillis === void 0 ? {} : { resolvedAtMillis: Number(value.resolvedAtMillis) }
|
|
4862
|
+
};
|
|
4863
|
+
}
|
|
4864
|
+
function optionalMillis(value) {
|
|
4865
|
+
return value === void 0 || Number.isSafeInteger(value) && Number(value) >= 0;
|
|
4866
|
+
}
|
|
4867
|
+
function isObject(value) {
|
|
4868
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4869
|
+
}
|
|
4870
|
+
function isPackageName(value) {
|
|
4871
|
+
return PACKAGE_NAME_PATTERN.test(value);
|
|
4872
|
+
}
|
|
4873
|
+
function isProtectedPackage(packageName) {
|
|
4874
|
+
return packageName === "@senguoyun/dsh-arkme" || packageName.startsWith("@deepseek-ai/");
|
|
4875
|
+
}
|
|
4876
|
+
async function writeTextAtomically(filePath, text) {
|
|
4877
|
+
const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
4878
|
+
try {
|
|
4879
|
+
const handle = await open(temporaryPath, "wx", 384);
|
|
4880
|
+
try {
|
|
4881
|
+
await handle.writeFile(text, "utf8");
|
|
4882
|
+
await handle.sync();
|
|
4883
|
+
} finally {
|
|
4884
|
+
await handle.close();
|
|
4885
|
+
}
|
|
4886
|
+
await rename(temporaryPath, filePath);
|
|
4887
|
+
} finally {
|
|
4888
|
+
await rm(temporaryPath, { force: true }).catch(() => void 0);
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
//#endregion
|
|
4641
4892
|
//#region src/extensions/install-tasks.ts
|
|
4642
4893
|
const TASK_RETENTION_MILLIS = 600 * 1e3;
|
|
4643
4894
|
const MAX_RETAINED_TASKS = 100;
|
|
@@ -7915,7 +8166,7 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7915
8166
|
await this.mutationTail;
|
|
7916
8167
|
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
8168
|
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,
|
|
8169
|
+
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
8170
|
parentPid: process.pid,
|
|
7920
8171
|
execPath: this.options.execPath,
|
|
7921
8172
|
dshBinPath: this.options.dshBinPath,
|
|
@@ -7935,8 +8186,10 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7935
8186
|
activationChange: true,
|
|
7936
8187
|
previousProfileIncluded: input.previousProfileIncluded === true
|
|
7937
8188
|
} : {},
|
|
8189
|
+
...input.desktopQuarantineActivation === true ? { desktopQuarantineActivation: true } : {},
|
|
7938
8190
|
healthUrl: this.options.healthUrl,
|
|
7939
|
-
logPath: join(this.options.stateDirectory, "extension-profile-restart.log")
|
|
8191
|
+
logPath: join(this.options.stateDirectory, "extension-profile-restart.log"),
|
|
8192
|
+
...this.options.runtimeReleaseId === void 0 ? {} : { runtimeReleaseId: this.options.runtimeReleaseId }
|
|
7940
8193
|
};
|
|
7941
8194
|
if (this.options.supervisedExitCode !== void 0) {
|
|
7942
8195
|
if (!Number.isSafeInteger(this.options.supervisedExitCode) || this.options.supervisedExitCode < 1 || this.options.supervisedExitCode > 255) throw new Error("受监督重启退出码无效");
|
|
@@ -7985,6 +8238,17 @@ var ArkmeExtensionProfileInstaller = class {
|
|
|
7985
8238
|
setTimeout(() => process.kill(process.pid, "SIGTERM"), 800).unref?.();
|
|
7986
8239
|
}))();
|
|
7987
8240
|
}
|
|
8241
|
+
async restartDesktopQuarantine(input) {
|
|
8242
|
+
if (!isArkmeProfilePackageName(input.packageName)) throw new Error("扩展 Bundle 包名无效");
|
|
8243
|
+
await this.restart({
|
|
8244
|
+
extensionId: `desktop-quarantine:${input.packageName}`,
|
|
8245
|
+
packageName: input.packageName,
|
|
8246
|
+
expectActive: true,
|
|
8247
|
+
activationChange: true,
|
|
8248
|
+
desktopQuarantineActivation: true,
|
|
8249
|
+
previousProfileIncluded: false
|
|
8250
|
+
});
|
|
8251
|
+
}
|
|
7988
8252
|
async run(args) {
|
|
7989
8253
|
if (this.options.run !== void 0) return await this.options.run(args);
|
|
7990
8254
|
if (!existsSync(this.options.execPath) || !existsSync(this.options.dshBinPath)) throw new Error("当前 DSH 运行方式不支持修改 Profile 插件");
|
|
@@ -18300,6 +18564,9 @@ function resolveArkmeAppVersion(configuredAppVersion, environment = process.env)
|
|
|
18300
18564
|
const injected = environment.ARKME_APP_VERSION?.trim();
|
|
18301
18565
|
return injected === void 0 || injected === "" ? void 0 : injected;
|
|
18302
18566
|
}
|
|
18567
|
+
function resolvePluginUpdateEnabled(configured, environment = process.env) {
|
|
18568
|
+
return configured && environment.ARKME_RUNTIME_MANAGED !== "1";
|
|
18569
|
+
}
|
|
18303
18570
|
function dshRemoteClientId(accessToken) {
|
|
18304
18571
|
const parts = accessToken.split(".");
|
|
18305
18572
|
if (parts.length !== 3) return void 0;
|
|
@@ -18344,7 +18611,7 @@ function apply(ctx, config) {
|
|
|
18344
18611
|
const extensionStore = new ArkmeExtensionInstallStore(extensionDirectory);
|
|
18345
18612
|
const clientModules = ctx.clientModules;
|
|
18346
18613
|
const updateManager = new ArkmePluginUpdateManager({
|
|
18347
|
-
enabled: config.updateCheckEnabled,
|
|
18614
|
+
enabled: resolvePluginUpdateEnabled(config.updateCheckEnabled),
|
|
18348
18615
|
channel: config.updateChannel,
|
|
18349
18616
|
updateServiceBaseUrl: config.updateServiceBaseUrl,
|
|
18350
18617
|
...config.updateArtifactBaseUrl.trim() === "" ? {} : { updateArtifactBaseUrl: config.updateArtifactBaseUrl },
|
|
@@ -18386,9 +18653,26 @@ function apply(ctx, config) {
|
|
|
18386
18653
|
installStoreDirectory: extensionDirectory,
|
|
18387
18654
|
...process.env.ARKME_DESKTOP_MANAGED_RESTART === "1" && process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH !== void 0 ? {
|
|
18388
18655
|
supervisedExitCode: 75,
|
|
18389
|
-
supervisedPlanPath: process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH
|
|
18656
|
+
supervisedPlanPath: process.env.ARKME_DESKTOP_MANAGED_RESTART_PLAN_PATH,
|
|
18657
|
+
...process.env.ARKME_RUNTIME_RELEASE_ID === void 0 ? {} : { runtimeReleaseId: process.env.ARKME_RUNTIME_RELEASE_ID }
|
|
18390
18658
|
} : {}
|
|
18391
18659
|
});
|
|
18660
|
+
const pluginInventory = ctx.get("pluginInventory");
|
|
18661
|
+
const desktopQuarantine = new ArkmeDesktopExtensionQuarantine({
|
|
18662
|
+
dshHome,
|
|
18663
|
+
environment: config.environment,
|
|
18664
|
+
installStore: extensionStore,
|
|
18665
|
+
setProfileEnabled: async (packageName, enabled) => {
|
|
18666
|
+
await extensionProfileInstaller.setEnabled(packageName, enabled);
|
|
18667
|
+
},
|
|
18668
|
+
requestRestart: async ({ packageName }) => {
|
|
18669
|
+
await extensionProfileInstaller.restartDesktopQuarantine({ packageName });
|
|
18670
|
+
},
|
|
18671
|
+
isPackageActive: (packageName) => pluginInventory.list().entries.some((entry) => entry.moduleName === packageName && entry.enabled && entry.fiberPhase === "active")
|
|
18672
|
+
});
|
|
18673
|
+
desktopQuarantine.reconcile().catch((error) => {
|
|
18674
|
+
ctx.logger.warn("Arkme desktop extension quarantine reconciliation failed: %s", error instanceof Error ? error.message : String(error));
|
|
18675
|
+
});
|
|
18392
18676
|
const ownedExtensionStore = new ArkmeOwnedExtensionStore(extensionDirectory);
|
|
18393
18677
|
const ownedExtensionRefs = new ArkmeOwnedExtensionRefs();
|
|
18394
18678
|
const ownedExtensionHostInstanceId = randomUUID();
|
|
@@ -18414,7 +18698,7 @@ function apply(ctx, config) {
|
|
|
18414
18698
|
profileDirectory: extensionProfileDirectory,
|
|
18415
18699
|
profileInstaller: extensionProfileInstaller,
|
|
18416
18700
|
clientApiPath: config.routePath,
|
|
18417
|
-
pluginInventory
|
|
18701
|
+
pluginInventory,
|
|
18418
18702
|
...dshRuntimeVersion === void 0 ? {} : { dshRuntimeVersion }
|
|
18419
18703
|
});
|
|
18420
18704
|
extensionManager = manager;
|
|
@@ -18523,7 +18807,8 @@ function apply(ctx, config) {
|
|
|
18523
18807
|
extensionManager: () => extensionManager,
|
|
18524
18808
|
extensionInstallTasks: () => extensionInstallTasks,
|
|
18525
18809
|
ownedExtensionInventory: () => ownedExtensionInventory,
|
|
18526
|
-
remoteHost: () => remoteHost
|
|
18810
|
+
remoteHost: () => remoteHost,
|
|
18811
|
+
desktopQuarantine
|
|
18527
18812
|
});
|
|
18528
18813
|
const callAssetHandler = createOutgoingCallAssetHandler({ routePrefix: `${config.routePath}/call` });
|
|
18529
18814
|
const richMediaOptions = {
|
|
@@ -18718,4 +19003,4 @@ function validateConfig(ctx, config) {
|
|
|
18718
19003
|
}
|
|
18719
19004
|
}
|
|
18720
19005
|
//#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 };
|
|
19006
|
+
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-DUqdJv8K.js";
|
|
2
2
|
export { activatePersistentArkmeExtension, applyPersistentArkmeHostExtension, deactivatePersistentArkmeExtension, invokePersistentArkmeExtension, persistentArkmeExtensionActive, persistentArkmeExtensionRuntimeState };
|