@xfxstudio/claworld 2026.6.3-testing.2 → 2026.6.3-testing.3
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/openclaw.plugin.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"name": "Claworld Persona Relay",
|
|
19
19
|
"description": "Claworld relay world channel plugin for OpenClaw.",
|
|
20
|
-
"version": "2026.6.3-testing.
|
|
20
|
+
"version": "2026.6.3-testing.3",
|
|
21
21
|
"configSchema": {
|
|
22
22
|
"type": "object",
|
|
23
23
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -267,6 +267,10 @@ function normalizeClaworldText(value, fallback = null) {
|
|
|
267
267
|
return normalized || fallback;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
function isClaworldPlainObject(value) {
|
|
271
|
+
return value && typeof value === 'object' && !Array.isArray(value);
|
|
272
|
+
}
|
|
273
|
+
|
|
270
274
|
function resolveNormalizedText(value, fallback = null) {
|
|
271
275
|
return normalizeClaworldText(value, fallback);
|
|
272
276
|
}
|
|
@@ -3309,48 +3313,196 @@ export function createClaworldChannelPlugin({
|
|
|
3309
3313
|
return promise;
|
|
3310
3314
|
}
|
|
3311
3315
|
|
|
3312
|
-
|
|
3316
|
+
function buildRuntimeAppTokenAccountConfig(existingAccount = {}, {
|
|
3317
|
+
accountId,
|
|
3318
|
+
appToken,
|
|
3319
|
+
relayAgentId = null,
|
|
3320
|
+
runtimeConfig = null,
|
|
3321
|
+
} = {}) {
|
|
3322
|
+
const account = isClaworldPlainObject(existingAccount) ? existingAccount : {};
|
|
3323
|
+
const sourceRuntimeConfig = isClaworldPlainObject(runtimeConfig) ? runtimeConfig : {};
|
|
3324
|
+
const existingRelay = isClaworldPlainObject(account.relay) ? account.relay : {};
|
|
3325
|
+
const runtimeRelay = isClaworldPlainObject(sourceRuntimeConfig.relay) ? sourceRuntimeConfig.relay : {};
|
|
3326
|
+
const normalizedAccountId = normalizeClaworldText(accountId, normalizeClaworldText(sourceRuntimeConfig.accountId, null));
|
|
3327
|
+
const normalizedRelayAgentId = normalizeClaworldText(
|
|
3328
|
+
relayAgentId,
|
|
3329
|
+
normalizeClaworldText(existingRelay.agentId, normalizeClaworldText(runtimeRelay.agentId, null)),
|
|
3330
|
+
);
|
|
3331
|
+
const normalizedAppToken = normalizeClaworldText(appToken, resolveRuntimeAppToken(sourceRuntimeConfig));
|
|
3332
|
+
const serverUrl = normalizeClaworldText(account.serverUrl, normalizeClaworldText(sourceRuntimeConfig.serverUrl, null));
|
|
3333
|
+
const apiKey = normalizeClaworldText(account.apiKey, normalizeClaworldText(sourceRuntimeConfig.apiKey, null));
|
|
3334
|
+
const name = normalizeClaworldText(account.name, normalizeClaworldText(sourceRuntimeConfig.name, null));
|
|
3335
|
+
const toolProfile = normalizeClaworldText(account.toolProfile, normalizeClaworldText(sourceRuntimeConfig.toolProfile, null));
|
|
3336
|
+
const heartbeatSeconds = Number.isInteger(account.heartbeatSeconds)
|
|
3337
|
+
? account.heartbeatSeconds
|
|
3338
|
+
: (Number.isInteger(sourceRuntimeConfig.heartbeatSeconds) ? sourceRuntimeConfig.heartbeatSeconds : null);
|
|
3339
|
+
const reconnect = typeof account.reconnect === 'boolean'
|
|
3340
|
+
? account.reconnect
|
|
3341
|
+
: (typeof sourceRuntimeConfig.reconnect === 'boolean' ? sourceRuntimeConfig.reconnect : null);
|
|
3342
|
+
const routing = isClaworldPlainObject(account.routing)
|
|
3343
|
+
? account.routing
|
|
3344
|
+
: (isClaworldPlainObject(sourceRuntimeConfig.routing) ? sourceRuntimeConfig.routing : null);
|
|
3345
|
+
const testing = isClaworldPlainObject(account.testing)
|
|
3346
|
+
? account.testing
|
|
3347
|
+
: (isClaworldPlainObject(sourceRuntimeConfig.testing) ? sourceRuntimeConfig.testing : null);
|
|
3348
|
+
|
|
3349
|
+
const nextAccount = {
|
|
3350
|
+
...account,
|
|
3351
|
+
enabled: typeof account.enabled === 'boolean'
|
|
3352
|
+
? account.enabled
|
|
3353
|
+
: (typeof sourceRuntimeConfig.enabled === 'boolean' ? sourceRuntimeConfig.enabled : true),
|
|
3354
|
+
...(serverUrl ? { serverUrl } : {}),
|
|
3355
|
+
...(apiKey ? { apiKey } : {}),
|
|
3356
|
+
...(normalizedAccountId ? { accountId: normalizedAccountId } : {}),
|
|
3357
|
+
...(normalizedAppToken ? { appToken: normalizedAppToken } : {}),
|
|
3358
|
+
...(name ? { name } : {}),
|
|
3359
|
+
...(toolProfile ? { toolProfile } : {}),
|
|
3360
|
+
...(heartbeatSeconds ? { heartbeatSeconds } : {}),
|
|
3361
|
+
...(typeof reconnect === 'boolean' ? { reconnect } : {}),
|
|
3362
|
+
...(routing ? { routing } : {}),
|
|
3363
|
+
...(testing ? { testing } : {}),
|
|
3364
|
+
};
|
|
3365
|
+
|
|
3366
|
+
const relayAppToken = normalizeClaworldText(existingRelay.appToken, normalizeClaworldText(runtimeRelay.appToken, null));
|
|
3367
|
+
const relayCredentialToken = normalizeClaworldText(
|
|
3368
|
+
existingRelay.credentialToken,
|
|
3369
|
+
normalizeClaworldText(runtimeRelay.credentialToken, null),
|
|
3370
|
+
);
|
|
3371
|
+
const relayDefaultTargetAgentId = normalizeClaworldText(
|
|
3372
|
+
existingRelay.defaultTargetAgentId,
|
|
3373
|
+
normalizeClaworldText(runtimeRelay.defaultTargetAgentId, null),
|
|
3374
|
+
);
|
|
3375
|
+
const relay = {
|
|
3376
|
+
...(relayAppToken ? { appToken: relayAppToken } : {}),
|
|
3377
|
+
...(relayCredentialToken ? { credentialToken: relayCredentialToken } : {}),
|
|
3378
|
+
...(relayDefaultTargetAgentId ? { defaultTargetAgentId: relayDefaultTargetAgentId } : {}),
|
|
3379
|
+
...(normalizedRelayAgentId ? { agentId: normalizedRelayAgentId } : {}),
|
|
3380
|
+
};
|
|
3381
|
+
if (Object.keys(relay).length > 0) nextAccount.relay = relay;
|
|
3382
|
+
else delete nextAccount.relay;
|
|
3383
|
+
delete nextAccount.registration;
|
|
3384
|
+
|
|
3385
|
+
const missingRequired = [];
|
|
3386
|
+
if (typeof nextAccount.enabled !== 'boolean') missingRequired.push('enabled');
|
|
3387
|
+
if (!normalizeClaworldText(nextAccount.serverUrl, null)) missingRequired.push('serverUrl');
|
|
3388
|
+
if (!normalizeClaworldText(nextAccount.apiKey, null)) missingRequired.push('apiKey');
|
|
3389
|
+
if (!normalizeClaworldText(nextAccount.accountId, null)) missingRequired.push('accountId');
|
|
3390
|
+
|
|
3391
|
+
return { account: nextAccount, missingRequired };
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
function applyRuntimeAppTokenConfigMutation(configDraft, {
|
|
3395
|
+
accountId,
|
|
3396
|
+
appToken,
|
|
3397
|
+
relayAgentId = null,
|
|
3398
|
+
runtimeConfig = null,
|
|
3399
|
+
} = {}) {
|
|
3400
|
+
if (!isClaworldPlainObject(configDraft)) {
|
|
3401
|
+
return { skipped: true, reason: 'invalid_config_draft' };
|
|
3402
|
+
}
|
|
3403
|
+
const normalizedAccountId = normalizeClaworldText(accountId, normalizeClaworldText(runtimeConfig?.accountId, null));
|
|
3404
|
+
if (!normalizedAccountId || !normalizeClaworldText(appToken, resolveRuntimeAppToken(runtimeConfig))) {
|
|
3405
|
+
return { skipped: true, reason: 'missing_account_or_token' };
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
configDraft.channels = isClaworldPlainObject(configDraft.channels) ? configDraft.channels : {};
|
|
3409
|
+
const claworldRoot = isClaworldPlainObject(configDraft.channels.claworld)
|
|
3410
|
+
? configDraft.channels.claworld
|
|
3411
|
+
: {};
|
|
3412
|
+
const accounts = isClaworldPlainObject(claworldRoot.accounts) ? claworldRoot.accounts : {};
|
|
3413
|
+
const currentAccount = isClaworldPlainObject(accounts[normalizedAccountId])
|
|
3414
|
+
? accounts[normalizedAccountId]
|
|
3415
|
+
: {};
|
|
3416
|
+
const built = buildRuntimeAppTokenAccountConfig(currentAccount, {
|
|
3417
|
+
accountId: normalizedAccountId,
|
|
3418
|
+
appToken,
|
|
3419
|
+
relayAgentId,
|
|
3420
|
+
runtimeConfig,
|
|
3421
|
+
});
|
|
3422
|
+
if (built.missingRequired.length > 0) {
|
|
3423
|
+
return {
|
|
3424
|
+
skipped: true,
|
|
3425
|
+
reason: 'missing_required_config_fields',
|
|
3426
|
+
accountId: normalizedAccountId,
|
|
3427
|
+
missingRequired: built.missingRequired,
|
|
3428
|
+
};
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
if (JSON.stringify(currentAccount) === JSON.stringify(built.account)) {
|
|
3432
|
+
return {
|
|
3433
|
+
skipped: true,
|
|
3434
|
+
reason: 'already_persisted',
|
|
3435
|
+
accountId: normalizedAccountId,
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
accounts[normalizedAccountId] = built.account;
|
|
3440
|
+
claworldRoot.accounts = accounts;
|
|
3441
|
+
if (!normalizeClaworldText(claworldRoot.defaultAccount, null)) {
|
|
3442
|
+
claworldRoot.defaultAccount = normalizedAccountId;
|
|
3443
|
+
}
|
|
3444
|
+
configDraft.channels.claworld = claworldRoot;
|
|
3445
|
+
return {
|
|
3446
|
+
skipped: false,
|
|
3447
|
+
ok: true,
|
|
3448
|
+
accountId: normalizedAccountId,
|
|
3449
|
+
};
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
async function persistRuntimeAppToken({ runtime, accountId, appToken, relayAgentId = null, runtimeConfig = null }) {
|
|
3313
3453
|
if (!accountId || !appToken) {
|
|
3314
3454
|
return { skipped: true, reason: 'missing_account_or_token' };
|
|
3315
3455
|
}
|
|
3316
3456
|
|
|
3317
3457
|
let configPersistResult = { skipped: true, reason: 'missing_runtime_config_io' };
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
: {};
|
|
3333
|
-
|
|
3334
|
-
const normalizedRelayAgentId = normalizeClaworldText(relayAgentId, normalizeClaworldText(account?.relay?.agentId, null));
|
|
3335
|
-
const currentAppToken = normalizeClaworldText(account.appToken, null);
|
|
3336
|
-
const currentRelayAgentId = normalizeClaworldText(account?.relay?.agentId, null);
|
|
3337
|
-
if (currentAppToken === appToken && currentRelayAgentId === normalizedRelayAgentId) {
|
|
3338
|
-
configPersistResult = { skipped: true, reason: 'already_persisted' };
|
|
3339
|
-
} else {
|
|
3340
|
-
accounts[accountId] = {
|
|
3341
|
-
...account,
|
|
3342
|
-
appToken,
|
|
3343
|
-
relay: {
|
|
3344
|
-
...(account?.relay && typeof account.relay === 'object' && !Array.isArray(account.relay) ? account.relay : {}),
|
|
3345
|
-
...(normalizedRelayAgentId ? { agentId: normalizedRelayAgentId } : {}),
|
|
3458
|
+
try {
|
|
3459
|
+
if (typeof runtime?.config?.mutateConfigFile === 'function') {
|
|
3460
|
+
let mutationOutcome = null;
|
|
3461
|
+
const mutationParams = {
|
|
3462
|
+
base: 'source',
|
|
3463
|
+
afterWrite: { mode: 'auto' },
|
|
3464
|
+
mutate: (draft) => {
|
|
3465
|
+
mutationOutcome = applyRuntimeAppTokenConfigMutation(draft, {
|
|
3466
|
+
accountId,
|
|
3467
|
+
appToken,
|
|
3468
|
+
relayAgentId,
|
|
3469
|
+
runtimeConfig,
|
|
3470
|
+
});
|
|
3471
|
+
return mutationOutcome;
|
|
3346
3472
|
},
|
|
3347
3473
|
};
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3474
|
+
const mutationResult = await runtime.config.mutateConfigFile(mutationParams);
|
|
3475
|
+
configPersistResult = {
|
|
3476
|
+
...(mutationResult?.result || mutationOutcome || { skipped: false, ok: true }),
|
|
3477
|
+
method: 'mutateConfigFile',
|
|
3478
|
+
};
|
|
3479
|
+
} else if (runtime?.config?.loadConfig && runtime?.config?.writeConfigFile) {
|
|
3480
|
+
const currentCfg = await runtime.config.loadConfig();
|
|
3481
|
+
const nextCfg = JSON.parse(JSON.stringify(currentCfg || {}));
|
|
3482
|
+
const mutationOutcome = applyRuntimeAppTokenConfigMutation(nextCfg, {
|
|
3483
|
+
accountId,
|
|
3484
|
+
appToken,
|
|
3485
|
+
relayAgentId,
|
|
3486
|
+
runtimeConfig,
|
|
3487
|
+
});
|
|
3488
|
+
configPersistResult = {
|
|
3489
|
+
...mutationOutcome,
|
|
3490
|
+
method: 'loadConfig_writeConfigFile',
|
|
3491
|
+
};
|
|
3492
|
+
if (!mutationOutcome.skipped) {
|
|
3493
|
+
await runtime.config.writeConfigFile(nextCfg);
|
|
3494
|
+
}
|
|
3353
3495
|
}
|
|
3496
|
+
} catch (error) {
|
|
3497
|
+
configPersistResult = {
|
|
3498
|
+
skipped: true,
|
|
3499
|
+
reason: 'config_persist_failed',
|
|
3500
|
+
error: error?.message || String(error),
|
|
3501
|
+
};
|
|
3502
|
+
logger.warn?.(`[claworld:${accountId || 'default'}] failed to persist runtime appToken to OpenClaw config`, {
|
|
3503
|
+
accountId,
|
|
3504
|
+
error: configPersistResult.error,
|
|
3505
|
+
});
|
|
3354
3506
|
}
|
|
3355
3507
|
|
|
3356
3508
|
let backupPersistResult = { skipped: true, reason: 'missing_runtime_config_loader' };
|
|
@@ -3358,6 +3510,9 @@ export function createClaworldChannelPlugin({
|
|
|
3358
3510
|
backupPersistResult = await persistClaworldRuntimeBackup({
|
|
3359
3511
|
runtime,
|
|
3360
3512
|
accountId,
|
|
3513
|
+
runtimeConfig,
|
|
3514
|
+
appToken,
|
|
3515
|
+
relayAgentId,
|
|
3361
3516
|
});
|
|
3362
3517
|
} catch (error) {
|
|
3363
3518
|
backupPersistResult = {
|
|
@@ -3399,8 +3554,10 @@ export function createClaworldChannelPlugin({
|
|
|
3399
3554
|
};
|
|
3400
3555
|
}
|
|
3401
3556
|
|
|
3557
|
+
const backupAgentId = normalizeClaworldText(backup?.agentId, null);
|
|
3402
3558
|
const restoredRuntimeConfig = applyRuntimeIdentity(runtimeConfig, {
|
|
3403
3559
|
appToken: backupToken,
|
|
3560
|
+
agentId: backupAgentId,
|
|
3404
3561
|
});
|
|
3405
3562
|
|
|
3406
3563
|
try {
|
|
@@ -3408,6 +3565,8 @@ export function createClaworldChannelPlugin({
|
|
|
3408
3565
|
runtime,
|
|
3409
3566
|
accountId,
|
|
3410
3567
|
appToken: backupToken,
|
|
3568
|
+
relayAgentId: backupAgentId,
|
|
3569
|
+
runtimeConfig: restoredRuntimeConfig,
|
|
3411
3570
|
});
|
|
3412
3571
|
} catch (error) {
|
|
3413
3572
|
logger.warn?.(`[claworld:${accountId || 'default'}] failed to persist restored runtime appToken`, {
|
|
@@ -3621,6 +3780,7 @@ export function createClaworldChannelPlugin({
|
|
|
3621
3780
|
accountId: runtimeConfig.accountId,
|
|
3622
3781
|
appToken: resolveRuntimeAppToken(runtimeConfig),
|
|
3623
3782
|
relayAgentId: runtimeConfig.relay?.agentId || null,
|
|
3783
|
+
runtimeConfig,
|
|
3624
3784
|
});
|
|
3625
3785
|
if (!persisted.skipped || persisted.backup?.skipped === false) {
|
|
3626
3786
|
logger.info?.(`[claworld:${runtimeAccountId}] persisted runtime binding state`, {
|
|
@@ -3874,6 +4034,7 @@ async function updateRuntimePublicIdentity(context = {}) {
|
|
|
3874
4034
|
accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
|
|
3875
4035
|
appToken: nextAppToken,
|
|
3876
4036
|
relayAgentId: nextAgentId,
|
|
4037
|
+
runtimeConfig: boundRuntimeConfig,
|
|
3877
4038
|
});
|
|
3878
4039
|
} catch (error) {
|
|
3879
4040
|
logger.warn?.('[claworld:profile] failed to persist activated runtime binding', {
|
|
@@ -2061,14 +2061,16 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2061
2061
|
}));
|
|
2062
2062
|
}
|
|
2063
2063
|
|
|
2064
|
-
const
|
|
2065
|
-
const
|
|
2066
|
-
const
|
|
2064
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
2065
|
+
const cfg = context.cfg || await loadCurrentConfig(api);
|
|
2066
|
+
const accountId = context.accountId;
|
|
2067
|
+
const runtimeConfig = context.runtimeConfig || plugin.config.resolveRuntimeConfig(cfg, accountId);
|
|
2067
2068
|
const identityPayload = await plugin.runtime.productShell.profile.getPublicIdentity({
|
|
2069
|
+
...context,
|
|
2068
2070
|
cfg,
|
|
2069
2071
|
accountId,
|
|
2070
2072
|
runtimeConfig,
|
|
2071
|
-
agentId: runtimeConfig.relay?.agentId || null,
|
|
2073
|
+
agentId: context.agentId || runtimeConfig.relay?.agentId || null,
|
|
2072
2074
|
generateShareCard,
|
|
2073
2075
|
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
2074
2076
|
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
setClaworldManagedRuntimeBackupState,
|
|
9
9
|
stripClaworldManagedRuntimeConfig,
|
|
10
10
|
} from './managed-config.js';
|
|
11
|
+
import { resolveRuntimeAppToken } from './account-identity.js';
|
|
11
12
|
|
|
12
13
|
function normalizeText(value, fallback = null) {
|
|
13
14
|
if (value == null) return fallback;
|
|
@@ -67,18 +68,53 @@ export async function persistClaworldRuntimeBackup({
|
|
|
67
68
|
runtime = null,
|
|
68
69
|
accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
69
70
|
configPath = resolveDefaultOpenClawConfigPath(),
|
|
71
|
+
runtimeConfig = null,
|
|
72
|
+
appToken = null,
|
|
73
|
+
relayAgentId = null,
|
|
70
74
|
} = {}) {
|
|
71
|
-
if (!runtime?.config?.loadConfig) {
|
|
75
|
+
if (!runtime?.config?.loadConfig && !runtimeConfig && !appToken) {
|
|
72
76
|
return { skipped: true, reason: 'missing_runtime_config_loader' };
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
let currentConfig = {};
|
|
80
|
+
if (runtime?.config?.loadConfig) {
|
|
81
|
+
try {
|
|
82
|
+
currentConfig = await runtime.config.loadConfig();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (!runtimeConfig && !appToken) throw error;
|
|
85
|
+
currentConfig = {};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const { backup: configBackup } = stripClaworldManagedRuntimeConfig(currentConfig, {
|
|
77
89
|
accountId,
|
|
78
90
|
preserveBackup: true,
|
|
79
91
|
});
|
|
92
|
+
const explicitRuntimeConfig = runtimeConfig && typeof runtimeConfig === 'object' && !Array.isArray(runtimeConfig)
|
|
93
|
+
? runtimeConfig
|
|
94
|
+
: {};
|
|
95
|
+
const backup = {
|
|
96
|
+
...configBackup,
|
|
97
|
+
version: configBackup?.version || 1,
|
|
98
|
+
accountId: normalizeText(configBackup?.accountId, normalizeText(explicitRuntimeConfig.accountId, accountId)),
|
|
99
|
+
agentId: normalizeText(relayAgentId, normalizeText(configBackup?.agentId, normalizeText(explicitRuntimeConfig?.relay?.agentId, null))),
|
|
100
|
+
serverUrl: normalizeText(configBackup?.serverUrl, normalizeText(explicitRuntimeConfig.serverUrl, null)),
|
|
101
|
+
apiKey: normalizeText(configBackup?.apiKey, normalizeText(explicitRuntimeConfig.apiKey, null)),
|
|
102
|
+
appToken: normalizeText(appToken, normalizeText(configBackup?.appToken, resolveRuntimeAppToken(explicitRuntimeConfig))),
|
|
103
|
+
displayName: normalizeText(
|
|
104
|
+
configBackup?.displayName,
|
|
105
|
+
normalizeText(explicitRuntimeConfig.name, normalizeText(explicitRuntimeConfig.registration?.displayName, null)),
|
|
106
|
+
),
|
|
107
|
+
name: normalizeText(configBackup?.name, normalizeText(explicitRuntimeConfig.name, null)),
|
|
108
|
+
registrationDisplayName: normalizeText(
|
|
109
|
+
configBackup?.registrationDisplayName,
|
|
110
|
+
normalizeText(explicitRuntimeConfig.registration?.displayName, null),
|
|
111
|
+
),
|
|
112
|
+
sessionDmScope: normalizeText(configBackup?.sessionDmScope, null),
|
|
113
|
+
toolProfile: normalizeText(configBackup?.toolProfile, null),
|
|
114
|
+
preservedAt: new Date().toISOString(),
|
|
115
|
+
};
|
|
80
116
|
|
|
81
|
-
if (!backup
|
|
117
|
+
if (!backup.appToken) {
|
|
82
118
|
return { skipped: true, reason: 'missing_app_token', backup: null };
|
|
83
119
|
}
|
|
84
120
|
|